diff --git a/.github/stale.yml b/.github/stale.yml index 2c77dc1c0..e50822a1b 100644 --- a/.github/stale.yml +++ b/.github/stale.yml @@ -34,9 +34,10 @@ staleLabel: wontfix # Comment to post when marking as stale. Set to `false` to disable markComment: > - This issue has been automatically marked as stale because it has not had - recent activity. It will be closed if no further activity occurs. Thank you - for your contributions. + This issue has been automatically marked as stale because it has not had recent activity. The resources of the VCLab team are limited, and so we are asking for your help. + If this is a bug and you can still reproduce this error on the last release of MeshLab, please reply with all of the information you have about it in order to keep the issue open. + If this is a feature request, and you feel that it is still relevant and valuable, please tell us why. + This issue will automatically be closed in the near future if no further activity occurs. Thank you for all your contributions. # Comment to post when removing the stale label. # unmarkComment: > diff --git a/.github/workflows/CreateRelease.yml b/.github/workflows/CreateRelease.yml index e3efc79eb..71feb6740 100644 --- a/.github/workflows/CreateRelease.yml +++ b/.github/workflows/CreateRelease.yml @@ -8,10 +8,6 @@ on: description: 'New MeshLab Version' required: true default: 'YYYY.MM' - release_candidate: - description: 'Is release candidate' - required: true - default: 'false' jobs: @@ -40,7 +36,7 @@ jobs: linux_build: needs: [update_ml_version] name: Build MeshLab (Linux) - runs-on: ubuntu-16.04 #in order to deploy, need to use oldest supported version + runs-on: ubuntu-18.04 #in order to deploy, need to use oldest supported version strategy: matrix: precision: [single_precision, double_precision] @@ -54,7 +50,7 @@ jobs: uses: jurplel/install-qt-action@v2 - name: Install dependencies run: | - sudo apt-get install -y mesa-common-dev libglu1-mesa-dev libgmp-dev + sudo apt-get install -y mesa-common-dev libglu1-mesa-dev libgmp-dev libcgal-dev libboost-all-dev #needed by qt 5.15 on linux sudo apt-get install libxcb-icccm4-dev libxcb-image0-dev libxcb-keysyms1-dev libxcb-render-util0-dev libxcb-xinerama0-dev - name: Setup env variables @@ -66,15 +62,10 @@ jobs: else echo ::set-output name=artifact_suffix::"" fi - if [ "${{ github.event.inputs.release_candidate }}" == "true" ]; then - echo ::set-output name=rc_option::"-rc" - else - echo ::set-output name=rc_option::"" - fi - name: Configure and Build shell: bash run: | - bash scripts/${{ runner.os }}/1_build.sh --${{ matrix.precision }} ${{steps.envs.outputs.rc_option}} + bash scripts/${{ runner.os }}/1_build.sh --${{ matrix.precision }} - name: Deploy shell: bash run: | @@ -109,7 +100,7 @@ jobs: submodules: true - name: Install dependencies run: | - brew install libomp xerces-c + brew install libomp cgal xerces-c npm install -g appdmg - name: Install Qt uses: jurplel/install-qt-action@v2 @@ -122,19 +113,32 @@ jobs: else echo ::set-output name=artifact_suffix::"" fi - if [ "${{ github.event.inputs.release_candidate }}" == "true" ]; then - echo ::set-output name=rc_option::"-rc" - else - echo ::set-output name=rc_option::"" - fi - name: Configure and Build shell: bash run: | - bash scripts/${{ runner.os }}/1_build.sh --${{ matrix.precision }} ${{steps.envs.outputs.rc_option}} + bash scripts/${{ runner.os }}/1_build.sh --${{ matrix.precision }} - name: Deploy shell: bash run: | bash scripts/${{ runner.os }}/2_deploy.sh + - name: Import Cert and Key + uses: apple-actions/import-codesign-certs@v1 + with: + p12-file-base64: ${{ secrets.MACOS_CERTIFICATE }} + p12-password: ${{ secrets.MACOS_CERTIFICATE_PWD }} + - name: Sign + run: | + codesign --options "runtime" --timestamp --force --deep --sign ${{ secrets.MACOS_CERT_ID }} src/install/meshlab.app + - name: Notarize + uses: devbotsxyz/xcode-notarize@v1 + with: + product-path: "src/install/meshlab.app" + appstore-connect-username: ${{ secrets.MACOS_NOTARIZATION_USER }} + appstore-connect-password: ${{ secrets.MACOS_NOTARIZATION_PSSW }} + - name: "Staple Release" + uses: devbotsxyz/xcode-staple@v1 + with: + product-path: "src/install/meshlab.app" - name: Create MeshLab DMG shell: bash run: | @@ -176,16 +180,26 @@ jobs: else echo ::set-output name=artifact_suffix::"" fi - if [ "${{ github.event.inputs.release_candidate }}" == "true" ]; then - echo ::set-output name=rc_option::"-rc" - else - echo ::set-output name=rc_option::"" - fi echo "VCINSTALLDIR=C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC" >> $GITHUB_ENV + - name: Expand PATH for wget + run: | + echo "C:\msys64\usr\bin\" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append + - name: Set Certificate + run: | + New-Item -ItemType directory -Path certificate + Set-Content -Path certificate\certificate.txt -Value '${{ secrets.WIN_CERTIFICATE }}' + certutil -decode certificate\certificate.txt certificate\certificate.pfx + - name: Download external libraries + shell: bash + run: | + bash scripts/${{ runner.os }}/0_download_ext.sh - name: Configure and Build shell: bash run: | - bash scripts/${{ runner.os }}/1_build.sh --${{ matrix.precision }} ${{steps.envs.outputs.rc_option}} + bash scripts/${{ runner.os }}/1_build.sh --${{ matrix.precision }} + - name: Sign Portable content + run: | + .\scripts\Windows\resources\windows_sign_dlls.ps1 -pssw '${{ secrets.WIN_CERTIFICATE_PWD }}' -path 'src\install\' - name: Deploy shell: bash run: | @@ -201,7 +215,11 @@ jobs: - name: Move Installer shell: bash run: | - mv src/install/MeshLab*-windows.exe src/ + mkdir src/installer + mv src/install/MeshLab*-windows.exe src/installer + - name: Sign Installer + run: | + .\scripts\Windows\resources\windows_sign_dlls.ps1 -pssw '${{ secrets.WIN_CERTIFICATE_PWD }}' -path 'src\installer\' - name: Uploading MeshLab Portable uses: actions/upload-artifact@v2 with: @@ -211,7 +229,7 @@ jobs: uses: actions/upload-artifact@v2 with: name: meshlab_windows_installer${{steps.envs.outputs.artifact_suffix}} - path: src/MeshLab*-windows.exe + path: src/installer/MeshLab*-windows.exe #after building MeshLab for the three platforms, we create a release in github create_release: @@ -259,10 +277,11 @@ jobs: chmod +x meshlab_linux_portable_double/AppRun - name: Create MeshLab Portable Linux Archive run: | - mv meshlab_linux_portable MeshLab${{ github.event.inputs.version }}${{steps.envs.outputs.rc_suffix}} - tar -cvzf MeshLab${{ github.event.inputs.version }}${{steps.envs.outputs.rc_suffix}}-linux.tar.gz MeshLab${{ github.event.inputs.version }}${{steps.envs.outputs.rc_suffix}}/ - mv meshlab_linux_portable_double MeshLab${{ github.event.inputs.version }}d${{steps.envs.outputs.rc_suffix}} - tar -cvzf MeshLab${{ github.event.inputs.version }}d${{steps.envs.outputs.rc_suffix}}-linux.tar.gz MeshLab${{ github.event.inputs.version }}d${{steps.envs.outputs.rc_suffix}}/ + cd meshlab_linux_portable + tar -cvzf ../MeshLab${{ github.event.inputs.version }}${{steps.envs.outputs.rc_suffix}}-linux.tar.gz * + cd ../meshlab_linux_portable_double + tar -cvzf ../MeshLab${{ github.event.inputs.version }}d${{steps.envs.outputs.rc_suffix}}-linux.tar.gz * + cd .. #Download MacOS Package - name: Download MacOS DMG @@ -285,13 +304,17 @@ jobs: with: name: meshlab_macos_portable_double path: meshlab_macos_portable_double + - name: Change Permissions + run: | + chmod +x meshlab_macos_portable/MeshLab*.app/Contents/MacOS/meshlab + chmod +x meshlab_macos_portable_double/MeshLab*.app/Contents/MacOS/meshlab - name: Create MeshLab Portable MacOS run: | - mv meshlab_macos_portable MeshLab${{ github.event.inputs.version }}${{steps.envs.outputs.rc_suffix}}.app - zip -r MeshLab${{ github.event.inputs.version }}${{steps.envs.outputs.rc_suffix}}-macos.zip MeshLab${{ github.event.inputs.version }}${{steps.envs.outputs.rc_suffix}}.app/ - rm -r MeshLab${{ github.event.inputs.version }}${{steps.envs.outputs.rc_suffix}}.app - mv meshlab_macos_portable_double MeshLab${{ github.event.inputs.version }}d${{steps.envs.outputs.rc_suffix}}.app - zip -r MeshLab${{ github.event.inputs.version }}d${{steps.envs.outputs.rc_suffix}}-macos.zip MeshLab${{ github.event.inputs.version }}d${{steps.envs.outputs.rc_suffix}}.app/ + cd meshlab_macos_portable + tar -cvzf ../MeshLab${{ github.event.inputs.version }}${{steps.envs.outputs.rc_suffix}}-macos.tar.gz * + cd ../meshlab_macos_portable_double + tar -cvzf ../MeshLab${{ github.event.inputs.version }}d${{steps.envs.outputs.rc_suffix}}-macos.tar.gz * + cd .. #Download Windows Packages - name: Download Windows ZIP @@ -316,10 +339,11 @@ jobs: path: meshlab_windows_installer_double - name: Create MeshLab Portable Windows Archive run: | - mv meshlab_windows_portable MeshLab${{ github.event.inputs.version }}${{steps.envs.outputs.rc_suffix}} - zip -r MeshLab${{ github.event.inputs.version }}${{steps.envs.outputs.rc_suffix}}-windows.zip MeshLab${{ github.event.inputs.version }}${{steps.envs.outputs.rc_suffix}}/ - mv meshlab_windows_portable_double MeshLab${{ github.event.inputs.version }}d${{steps.envs.outputs.rc_suffix}} - zip -r MeshLab${{ github.event.inputs.version }}d${{steps.envs.outputs.rc_suffix}}-windows.zip MeshLab${{ github.event.inputs.version }}d${{steps.envs.outputs.rc_suffix}}/ + cd meshlab_windows_portable + zip -r ../MeshLab${{ github.event.inputs.version }}${{steps.envs.outputs.rc_suffix}}-windows.zip * + cd ../meshlab_windows_portable_double + zip -r ../MeshLab${{ github.event.inputs.version }}d${{steps.envs.outputs.rc_suffix}}-windows.zip * + cd .. #Create release and upload @@ -402,8 +426,8 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: MeshLab${{ github.event.inputs.version }}${{steps.envs.outputs.rc_suffix}}-macos.zip - asset_name: MeshLab${{ github.event.inputs.version }}${{steps.envs.outputs.rc_suffix}}-macos.zip + asset_path: MeshLab${{ github.event.inputs.version }}${{steps.envs.outputs.rc_suffix}}-macos.tar.gz + asset_name: MeshLab${{ github.event.inputs.version }}${{steps.envs.outputs.rc_suffix}}-macos.tar.gz asset_content_type: MeshLab Portable for MacOS - name: Upload ReleaseMacOSPortable-d id: upload-release-macos-portable-d @@ -412,8 +436,8 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: MeshLab${{ github.event.inputs.version }}d${{steps.envs.outputs.rc_suffix}}-macos.zip - asset_name: MeshLab${{ github.event.inputs.version }}d${{steps.envs.outputs.rc_suffix}}-macos.zip + asset_path: MeshLab${{ github.event.inputs.version }}d${{steps.envs.outputs.rc_suffix}}-macos.tar.gz + asset_name: MeshLab${{ github.event.inputs.version }}d${{steps.envs.outputs.rc_suffix}}-macos.tar.gz asset_content_type: MeshLab Portable for MacOS #Windows - name: Upload ReleaseWindowsPortable diff --git a/.github/workflows/Linux.yml b/.github/workflows/Linux.yml index e929adcc6..388ea30d7 100644 --- a/.github/workflows/Linux.yml +++ b/.github/workflows/Linux.yml @@ -6,7 +6,7 @@ on: jobs: linux_build: name: Build MeshLab (Linux) - runs-on: ubuntu-16.04 #in order to deploy, need to use oldest supported version + runs-on: ubuntu-18.04 #in order to deploy, need to use oldest supported version strategy: matrix: precision: [single_precision, double_precision] @@ -19,7 +19,7 @@ jobs: uses: jurplel/install-qt-action@v2 - name: Install dependencies run: | - sudo apt-get install -y mesa-common-dev libglu1-mesa-dev libgmp-dev + sudo apt-get install -y mesa-common-dev libglu1-mesa-dev libgmp-dev libcgal-dev libboost-all-dev #needed by qt 5.15 on linux sudo apt-get install libxcb-icccm4-dev libxcb-image0-dev libxcb-keysyms1-dev libxcb-render-util0-dev libxcb-xinerama0-dev - name: Setup env variables diff --git a/.github/workflows/MacOS.yml b/.github/workflows/MacOS.yml index 396dd8386..8d3414754 100644 --- a/.github/workflows/MacOS.yml +++ b/.github/workflows/MacOS.yml @@ -17,7 +17,7 @@ jobs: submodules: true - name: Install dependencies run: | - brew install libomp xerces-c + brew install libomp cgal xerces-c npm install -g appdmg - name: Install Qt uses: jurplel/install-qt-action@v2 diff --git a/.github/workflows/QmakeBuilds.yml b/.github/workflows/QmakeBuilds.yml index f4e22cf21..959c1505d 100644 --- a/.github/workflows/QmakeBuilds.yml +++ b/.github/workflows/QmakeBuilds.yml @@ -5,7 +5,7 @@ on: [push, pull_request] jobs: ubuntu_build: name: Build MeshLab (Ubuntu - QMake) - runs-on: ubuntu-16.04 #in order to deploy, need to use oldest supported version + runs-on: ubuntu-18.04 #in order to deploy, need to use oldest supported version steps: - uses: actions/checkout@v2 diff --git a/.github/workflows/Windows.yml b/.github/workflows/Windows.yml index 517d948cd..aad3ede70 100644 --- a/.github/workflows/Windows.yml +++ b/.github/workflows/Windows.yml @@ -28,6 +28,13 @@ jobs: echo ::set-output name=artifact_suffix::"" fi echo "VCINSTALLDIR=C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC" >> $GITHUB_ENV + - name: Expand PATH for wget + run: | + echo "C:\msys64\usr\bin\" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append + - name: Download external libraries + shell: bash + run: | + bash scripts/${{ runner.os }}/0_download_ext.sh - name: Configure and Build shell: bash run: | @@ -47,7 +54,8 @@ jobs: - name: Move Installer shell: bash run: | - mv src/install/MeshLab*-windows.exe src/ + mkdir src/installer + mv src/install/MeshLab*-windows.exe src/installer/ - name: Uploading MeshLab Portable uses: actions/upload-artifact@v2 with: @@ -57,4 +65,4 @@ jobs: uses: actions/upload-artifact@v2 with: name: meshlab_windows_installer${{steps.envs.outputs.artifact_suffix}} - path: src/MeshLab*-windows.exe + path: src/installer/MeshLab*-windows.exe diff --git a/.gitignore b/.gitignore index c2b4b17fb..efbed3b20 100644 --- a/.gitignore +++ b/.gitignore @@ -20,6 +20,8 @@ distrib* src/build/* src/install/* +src/external/boost_1_75_0 +src/external/CGAL-5.2.1 install/macos/resources/meshlab_dmg_final.json install/windows/resources/meshlab_final.nsi install/windows/resources/MeshLab*.exe diff --git a/ML_VERSION b/ML_VERSION index ee102115d..70814c3c6 100644 --- a/ML_VERSION +++ b/ML_VERSION @@ -1 +1 @@ -2020.12 \ No newline at end of file +2021.05 \ No newline at end of file diff --git a/scripts/Linux/1_build.sh b/scripts/Linux/1_build.sh index fe733c245..3ee569bd7 100644 --- a/scripts/Linux/1_build.sh +++ b/scripts/Linux/1_build.sh @@ -19,7 +19,6 @@ INSTALL_PATH=$SOURCE_PATH/install/usr/ CORES="-j4" DOUBLE_PRECISION_OPTION="" NIGHTLY_OPTION="" -RC_OPTION="" #check parameters for i in "$@" @@ -45,10 +44,6 @@ case $i in NIGHTLY_OPTION="-DMESHLAB_IS_NIGHTLY_VERSION=ON" shift # past argument=value ;; - -rc|--release_candidate) - RC_OPTION="-DMESHLAB_IS_RELEASE_CANDIDATE_VERSION=ON" - shift # past argument=value - ;; *) # unknown option ;; @@ -71,6 +66,6 @@ BUILD_PATH=$(realpath $BUILD_PATH) INSTALL_PATH=$(realpath $INSTALL_PATH) cd $BUILD_PATH -cmake -DCMAKE_BUILD_TYPE=MinSizeRel -DCMAKE_INSTALL_PREFIX=$INSTALL_PATH $DOUBLE_PRECISION_OPTION $NIGHTLY_OPTION $RC_OPTION $SOURCE_PATH +cmake -DCMAKE_BUILD_TYPE=MinSizeRel -DCMAKE_INSTALL_PREFIX=$INSTALL_PATH $DOUBLE_PRECISION_OPTION $NIGHTLY_OPTION $SOURCE_PATH make $CORES make install diff --git a/scripts/Linux/2_deploy.sh b/scripts/Linux/2_deploy.sh index cc876c949..a0f61fb6a 100644 --- a/scripts/Linux/2_deploy.sh +++ b/scripts/Linux/2_deploy.sh @@ -35,6 +35,7 @@ $SCRIPTS_PATH/resources/linuxdeployqt $INSTALL_PATH/usr/share/applications/meshl -executable=$INSTALL_PATH/usr/lib/meshlab/plugins/libfilter_sketchfab.so \ -executable=$INSTALL_PATH/usr/lib/meshlab/plugins/libio_3ds.so \ -executable=$INSTALL_PATH/usr/lib/meshlab/plugins/libio_ctm.so \ + -executable=$INSTALL_PATH/usr/lib/meshlab/plugins/libfilter_mesh_booleans.so \ -executable=$INSTALL_PATH/usr/lib/meshlab/plugins/libio_e57.so diff --git a/scripts/Linux/resources/linuxdeployqt b/scripts/Linux/resources/linuxdeployqt index 917645b94..b719d214d 100755 Binary files a/scripts/Linux/resources/linuxdeployqt and b/scripts/Linux/resources/linuxdeployqt differ diff --git a/scripts/Linux/resources/make_bundle.sh b/scripts/Linux/resources/make_bundle.sh index 7dafa6980..ac8ce4d8d 100644 --- a/scripts/Linux/resources/make_bundle.sh +++ b/scripts/Linux/resources/make_bundle.sh @@ -25,16 +25,14 @@ LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$INSTALL_PATH #check if we have an exec in distrib if ! [ -f $INSTALL_PATH/usr/bin/meshlab ] then - echo "ERROR: meshlab bin not found inside $INSTALL_PATH/usr/bin/" - exit 1 + echo "ERROR: meshlab bin not found inside $INSTALL_PATH/usr/bin/" + exit 1 fi mkdir -p $INSTALL_PATH/usr/share/doc/meshlab -mkdir -p $INSTALL_PATH/usr/share/icons/hicolor/512x512/apps/ mkdir -p $INSTALL_PATH/usr/share/icons/Yaru/512x512/apps/ cp $SCRIPTS_PATH/resources/meshlab_appimage.desktop $INSTALL_PATH/usr/share/applications/meshlab.desktop -cp $DISTRIB_PATH/meshlab.png $INSTALL_PATH/usr/share/icons/hicolor/512x512/apps/meshlab.png cp $DISTRIB_PATH/meshlab.png $INSTALL_PATH/usr/share/icons/Yaru/512x512/apps/meshlab.png cp $DISTRIB_PATH/LICENSE.txt $INSTALL_PATH/usr/share/doc/meshlab/ cp $DISTRIB_PATH/privacy.txt $INSTALL_PATH/usr/share/doc/meshlab/ diff --git a/scripts/Linux/resources/meshlab.desktop b/scripts/Linux/resources/meshlab.desktop index 44b5a09d7..253a6403b 100644 --- a/scripts/Linux/resources/meshlab.desktop +++ b/scripts/Linux/resources/meshlab.desktop @@ -7,7 +7,7 @@ GenericName[en_GB]=Mesh processing Comment=View and process meshes Type=Application Exec=meshlab %F -Icon=/usr/share/pixmaps/meshlab.png +Icon=meshlab Terminal=false MimeType=model/mesh;application/x-3ds;image/x-3ds;model/x-ply;application/sla;model/x-quad-object;model/x-geomview-off;application/x-cyclone-ptx;application/x-vmi;application/x-bre;model/vnd.collada+xml;model/openctm;application/x-expe-binary;application/x-expe-ascii;application/x-xyz;application/x-gts;chemical/x-pdb;application/x-tri;application/x-asc;model/x3d+xml;model/x3d+vrml;model/vrml;model/u3d;model/idtf; Categories=Graphics;3DGraphics;Viewer;Qt; diff --git a/scripts/Linux/resources/snap/snap_noversion.yaml b/scripts/Linux/resources/snap/snap_noversion.yaml index 014fd9b3b..b5e163922 100644 --- a/scripts/Linux/resources/snap/snap_noversion.yaml +++ b/scripts/Linux/resources/snap/snap_noversion.yaml @@ -18,9 +18,14 @@ apps: meshlab: command: AppRun extensions: [kde-neon] - plugs: [home, opengl, removable-media] desktop: usr/share/applications/meshlab.desktop - + environment: + DISABLE_WAYLAND: 1 + plugs: + - home + - opengl + - removable-media + - mount-observe parts: meshlab: @@ -43,6 +48,8 @@ parts: - patchelf - rsync - libqt5opengl5-dev + - libcgal-dev + - libboost-all-dev stage-packages: - lib3ds-1-3 - libgomp1 diff --git a/scripts/Windows/0_download_ext.sh b/scripts/Windows/0_download_ext.sh new file mode 100644 index 000000000..aad08b5cd --- /dev/null +++ b/scripts/Windows/0_download_ext.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +#default paths wrt the script folder +SCRIPTS_PATH="$(dirname "$(realpath "$0")")" +EXTERNAL_PATH=$SCRIPTS_PATH/../../src/external + +cd $EXTERNAL_PATH + +wget https://boostorg.jfrog.io/artifactory/main/release/1.75.0/source/boost_1_75_0.zip +unzip boost_1_75_0.zip +rm boost_1_75_0.zip + +wget https://github.com/CGAL/cgal/releases/download/v5.2.1/CGAL-5.2.1.zip +unzip CGAL-5.2.1.zip +rm CGAL-5.2.1.zip + +wget https://github.com/CGAL/cgal/releases/download/v5.2.1/CGAL-5.2.1-win64-auxiliary-libraries-gmp-mpfr.zip +unzip -o CGAL-5.2.1-win64-auxiliary-libraries-gmp-mpfr.zip -d CGAL-5.2.1/ +rm CGAL-5.2.1-win64-auxiliary-libraries-gmp-mpfr.zip diff --git a/scripts/Windows/1_build.sh b/scripts/Windows/1_build.sh index e9faa9aab..1b9ff4857 100644 --- a/scripts/Windows/1_build.sh +++ b/scripts/Windows/1_build.sh @@ -18,7 +18,6 @@ BUILD_PATH=$SOURCE_PATH/build INSTALL_PATH=$SOURCE_PATH/install DOUBLE_PRECISION_OPTION="" NIGHTLY_OPTION="" -RC_OPTION="" #check parameters for i in "$@" @@ -40,10 +39,6 @@ case $i in NIGHTLY_OPTION="-DMESHLAB_IS_NIGHTLY_VERSION=ON" shift # past argument=value ;; - -rc|--release_candidate) - RC_OPTION="-DMESHLAB_IS_RELEASE_CANDIDATE_VERSION=ON" - shift # past argument=value - ;; *) # unknown option ;; @@ -70,6 +65,6 @@ echo "INSTALL PATH: "$INSTALL_PATH echo "SCRIPTS PATH: "$SCRIPTS_PATH cd $BUILD_PATH -cmake -GNinja -DCMAKE_BUILD_TYPE=MinSizeRel -DCMAKE_INSTALL_PREFIX=$INSTALL_PATH $DOUBLE_PRECISION_OPTION $NIGHTLY_OPTION $RC_OPTION $SOURCE_PATH +cmake -GNinja -DCMAKE_BUILD_TYPE=MinSizeRel -DCMAKE_INSTALL_PREFIX=$INSTALL_PATH $DOUBLE_PRECISION_OPTION $NIGHTLY_OPTION $SOURCE_PATH ninja ninja install diff --git a/scripts/Windows/resources/windows_sign_dlls.ps1 b/scripts/Windows/resources/windows_sign_dlls.ps1 new file mode 100644 index 000000000..e54fc05aa --- /dev/null +++ b/scripts/Windows/resources/windows_sign_dlls.ps1 @@ -0,0 +1,12 @@ +param($pssw, $path, $cert_path="") + +if ([string]::IsNullOrEmpty($cert_path)) { + $cert_path = Join-Path $PSScriptRoot ..\..\..\certificate\certificate.pfx +} + +$files = Get-ChildItem $path -include ('*.exe', '*.dll') -Recurse + +for ($i=0; $i -lt $files.Count; $i++) { + $file = $files[$i].FullName + signtool.exe sign /f $cert_path /p $pssw /t http://timestamp.comodoca.com/authenticode $file +} diff --git a/scripts/macOS/1_build.sh b/scripts/macOS/1_build.sh index e0342cc52..d00193ee1 100644 --- a/scripts/macOS/1_build.sh +++ b/scripts/macOS/1_build.sh @@ -24,7 +24,6 @@ INSTALL_PATH=$SOURCE_PATH/install CORES="-j4" DOUBLE_PRECISION_OPTION="" NIGHTLY_OPTION="" -RC_OPTION="" #check parameters for i in "$@" @@ -50,10 +49,6 @@ case $i in NIGHTLY_OPTION="-DMESHLAB_IS_NIGHTLY_VERSION=ON" shift # past argument=value ;; - -rc|--release_candidate) - RC_OPTION="-DMESHLAB_IS_RELEASE_CANDIDATE_VERSION=ON" - shift # past argument=value - ;; *) # unknown option ;; @@ -73,6 +68,6 @@ then fi cd $BUILD_PATH -cmake -DCMAKE_BUILD_TYPE=MinSizeRel -DCMAKE_INSTALL_PREFIX=$INSTALL_PATH $DOUBLE_PRECISION_OPTION $NIGHTLY_OPTION $RC_OPTION $SOURCE_PATH +cmake -DCMAKE_BUILD_TYPE=MinSizeRel -DCMAKE_INSTALL_PREFIX=$INSTALL_PATH $DOUBLE_PRECISION_OPTION $NIGHTLY_OPTION $SOURCE_PATH make $CORES make install diff --git a/scripts/macOS/2_deploy.sh b/scripts/macOS/2_deploy.sh index aadea6e33..3082eccda 100755 --- a/scripts/macOS/2_deploy.sh +++ b/scripts/macOS/2_deploy.sh @@ -47,4 +47,11 @@ else MACDEPLOYQT_EXE=macdeployqt fi -${MACDEPLOYQT_EXE} $INSTALL_PATH/$APPNAME -executable=$INSTALL_PATH/$APPNAME/Contents/PlugIns/libedit_align.so -executable=$INSTALL_PATH/$APPNAME/Contents/PlugIns/libfilter_csg.so -executable=$INSTALL_PATH/$APPNAME/Contents/PlugIns/libfilter_isoparametrization.so -executable=$INSTALL_PATH/$APPNAME/Contents/PlugIns/libfilter_screened_poisson.so -executable=$INSTALL_PATH/$APPNAME/Contents/PlugIns/libfilter_sketchfab.so -executable=$INSTALL_PATH/$APPNAME/Contents/PlugIns/libio_e57.so +${MACDEPLOYQT_EXE} $INSTALL_PATH/$APPNAME \ + -executable=$INSTALL_PATH/$APPNAME/Contents/PlugIns/libedit_align.so \ + -executable=$INSTALL_PATH/$APPNAME/Contents/PlugIns/libfilter_csg.so \ + -executable=$INSTALL_PATH/$APPNAME/Contents/PlugIns/libfilter_isoparametrization.so \ + -executable=$INSTALL_PATH/$APPNAME/Contents/PlugIns/libfilter_mesh_booleans.so \ + -executable=$INSTALL_PATH/$APPNAME/Contents/PlugIns/libfilter_screened_poisson.so \ + -executable=$INSTALL_PATH/$APPNAME/Contents/PlugIns/libfilter_sketchfab.so \ + -executable=$INSTALL_PATH/$APPNAME/Contents/PlugIns/libio_e57.so diff --git a/snapcraft.yaml b/snapcraft.yaml index 53e7ff4e1..623eaf61d 100644 --- a/snapcraft.yaml +++ b/snapcraft.yaml @@ -1,7 +1,7 @@ # Known to build in Ubuntu 18.04, 20.04 name: meshlab base: core18 -version: '2020.12' +version: '2021.05' summary: MeshLab description: | The open source system for processing and editing 3D triangular meshes. @@ -18,9 +18,14 @@ apps: meshlab: command: AppRun extensions: [kde-neon] - plugs: [home, opengl, removable-media] desktop: usr/share/applications/meshlab.desktop - + environment: + DISABLE_WAYLAND: 1 + plugs: + - home + - opengl + - removable-media + - mount-observe parts: meshlab: diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 10bd4847e..0fbd03138 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -2,24 +2,18 @@ # Copyright 2019, 2021, Visual Computing Lab, ISTI - Italian National Research Council # SPDX-License-Identifier: BSL-1.0 -cmake_minimum_required(VERSION 3.13) +cmake_minimum_required(VERSION 3.10) project(MeshLab) -set(CMAKE_CXX_STANDARD 11) -set(CMAKE_CXX_STANDARD_REQUIRED ON) - ### Build options -option(ALLOW_BUNDLED_EXTERNAL_MESHLAB_LIBRARIES "Allow to build bundled external libraries sources" ON) option(BUILD_MINI "Build only a minimal set of plugins" OFF) -option(BUILD_SERVER "Build a command-line server application" OFF) option(BUILD_STRICT "Strictly enforce resolution of all symbols" ON) option(BUILD_WITH_DOUBLE_SCALAR "Use double type instead of float type for scalars" OFF) option(BUILD_ONLY_MESHLAB_LIBRARIES "Build only meshlab-common and plugins" OFF) option(USE_DEFAULT_BUILD_AND_INSTALL_DIRS "If set to OFF, it expects that you set manually the binary and install directories" ON) -option(MESHLAB_IS_RELEASE_CANDIDATE_VERSION "" OFF) -option(MESHLAB_IS_NIGHTLY_VERSION "" OFF) +option(MESHLAB_IS_NIGHTLY_VERSION "Nightly version of meshlab will be used instead of ML_VERSION" OFF) ### Dependencies list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") @@ -112,18 +106,12 @@ endif() # External set(EXTERNAL_DIR ${CMAKE_CURRENT_SOURCE_DIR}/external) -include(${EXTERNAL_DIR}/external_common.cmake) -if((NOT BUILD_MINI) AND (ALLOW_BUNDLED_EXTERNAL_MESHLAB_LIBRARIES)) - add_subdirectory(${EXTERNAL_DIR}) -endif() +add_subdirectory(${EXTERNAL_DIR}) add_subdirectory(common) if (NOT BUILD_ONLY_MESHLAB_LIBRARIES) add_subdirectory(meshlab) - if(BUILD_SERVER) - add_subdirectory(meshlabserver) - endif() if(WIN32 AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/use_cpu_opengl") add_subdirectory(use_cpu_opengl) endif() @@ -172,7 +160,6 @@ if(NOT DEFINED MESHLAB_PLUGINS) # it may be already defined in parent directory meshlabplugins/filter_color_projection meshlabplugins/filter_colorproc meshlabplugins/filter_create - meshlabplugins/filter_csg meshlabplugins/filter_dirt meshlabplugins/filter_fractal meshlabplugins/filter_func @@ -180,6 +167,7 @@ if(NOT DEFINED MESHLAB_PLUGINS) # it may be already defined in parent directory meshlabplugins/filter_isoparametrization meshlabplugins/filter_layer meshlabplugins/filter_measure + meshlabplugins/filter_mesh_booleans meshlabplugins/filter_meshing meshlabplugins/filter_mls meshlabplugins/filter_mutualglobal @@ -194,6 +182,7 @@ if(NOT DEFINED MESHLAB_PLUGINS) # it may be already defined in parent directory meshlabplugins/filter_sketchfab meshlabplugins/filter_ssynth meshlabplugins/filter_texture + meshlabplugins/filter_texture_defragmentation meshlabplugins/filter_trioptimize meshlabplugins/filter_unsharp meshlabplugins/filter_voronoi @@ -279,7 +268,7 @@ if (NOT BUILD_ONLY_MESHLAB_LIBRARIES) if(NOT WIN32 AND NOT APPLE) install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/../scripts/Linux/resources/meshlab.desktop" DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/applications) - install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/../scripts/meshlab.png" DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/pixmaps) + install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/../scripts/meshlab.png" DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/512x512/apps) endif() endif() diff --git a/src/README.md b/src/README.md index 9810e861a..7dad58ffb 100644 --- a/src/README.md +++ b/src/README.md @@ -8,7 +8,6 @@ The source code of MeshLab is structured in the following directories: * [external](https://github.com/cnr-isti-vclab/meshlab/tree/master/src/external): it contains a series of external libraries needed by several plugins. Some of these libraries are compiled before the compilation of meshlab, if a corresponding system library is not found and then linked; other are header-only libraries that are just included; * [common](https://github.com/cnr-isti-vclab/meshlab/tree/master/src/common): a series of utility classes and functions used by MeshLab and its plugins; * [meshlab](https://github.com/cnr-isti-vclab/meshlab/tree/master/src/meshlab): GUI and core of MeshLab; - * [meshlabserver](https://github.com/cnr-isti-vclab/meshlab/tree/master/src/meshlabserver): a tool that allows to compute mesh operations through command line; * [meshlabplugins](https://github.com/cnr-isti-vclab/meshlab/tree/master/src/meshlabplugins): all the plugins that can be added to MeshLab; * [use_cpu_opengl](https://github.com/cnr-isti-vclab/meshlab/tree/master/src/use_cpu_opengl): a tool compiled only under windows that allows to use non-GPU accelerated OpenGL calls; * [vcglib](https://github.com/cnr-isti-vclab/meshlab/tree/master/src/vcglib): submodule containing the vcglib. diff --git a/src/cmake/meshlab_global_settings.cmake b/src/cmake/meshlab_global_settings.cmake index 7c593f57f..0aa198c00 100644 --- a/src/cmake/meshlab_global_settings.cmake +++ b/src/cmake/meshlab_global_settings.cmake @@ -2,14 +2,15 @@ # Copyright 2019, 2020, Visual Computing Lab, ISTI - Italian National Research Council # SPDX-License-Identifier: BSL-1.0 -# Prefer GLVND +# Prefer OpenGL GLVND if(POLICY CMP0072) cmake_policy(SET CMP0072 NEW) endif() ### Build settings set(CMAKE_C_STANDARD 99) -set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD 14) +set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) set(CMAKE_OSX_DEPLOYMENT_TARGET "10.11" CACHE STRING "Minimum OS X deployment version" FORCE) diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index b1f377488..ccafc27ff 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -1,15 +1,13 @@ #version management string(TIMESTAMP MESHLAB_VERSION "%Y.%m") -if (MESHLAB_IS_RELEASE_CANDIDATE_VERSION AND MESHLAB_IS_NIGHTLY_VERSION) - message(FATAL_ERROR "Both nightly and release candidate options are set to ON. Choose one.") -endif() + if (MESHLAB_IS_NIGHTLY_VERSION) # nightly version is in the form: # YYYY.mm[d]_nightly_GIT_SHA1 # YYYY and mm are computed by cmake and not read from file find_package(Git) execute_process(COMMAND - "${GIT_EXECUTABLE}" describe --match=NeVeRmAtCh --always --abbrev=6 + "${GIT_EXECUTABLE}" describe --match=NeVeRmAtCh --always --abbrev=7 WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" OUTPUT_VARIABLE GIT_SHA1 ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) @@ -23,13 +21,9 @@ else() file(READ "${CMAKE_CURRENT_SOURCE_DIR}/../../ML_VERSION" MESHLAB_VERSION) endif() # if double precision version, "d" is appended - # if release candidate, "_rc" is appended if (BUILD_WITH_DOUBLE_SCALAR) set(MESHLAB_VERSION "${MESHLAB_VERSION}d") endif() - if (MESHLAB_IS_RELEASE_CANDIDATE_VERSION) - set(MESHLAB_VERSION "${MESHLAB_VERSION}_rc") - endif() endif() message(STATUS "MeshLab version: ${MESHLAB_VERSION}") @@ -82,9 +76,6 @@ set(HEADERS GLExtensionsManager.h GLLogStream.h filterscript.h - mainwindow_interface.h - meshlabdocumentbundler.h - meshlabdocumentxml.h ml_selection_buffers.h ml_thread_safe_memory_info.h mlapplication.h @@ -125,13 +116,12 @@ set(SOURCES GLExtensionsManager.cpp GLLogStream.cpp filterscript.cpp - meshlabdocumentbundler.cpp - meshlabdocumentxml.cpp ml_selection_buffers.cpp ml_thread_safe_memory_info.cpp mlapplication.cpp - searcher.cpp - ${EXTERNAL_DIR}/easyexif/exif.cpp) + searcher.cpp) + +set(RESOURCES meshlab-common.qrc) set(TARGET_TYPE SHARED) if(WIN32) @@ -145,8 +135,6 @@ target_compile_definitions(meshlab-common MESHLAB_SCALAR=${MESHLAB_SCALAR}) target_include_directories(meshlab-common - PRIVATE - ${EXTERNAL_DIR}/easyexif/ PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/..) @@ -160,6 +148,7 @@ target_link_libraries( Qt5::Network vcglib external-glew + external-exif ) set_property(TARGET meshlab-common PROPERTY FOLDER Core) diff --git a/src/common/GLExtensionsManager.cpp b/src/common/GLExtensionsManager.cpp index 985260d56..e9aa7134e 100644 --- a/src/common/GLExtensionsManager.cpp +++ b/src/common/GLExtensionsManager.cpp @@ -61,7 +61,7 @@ void GLExtensionsManager::initializeGLextensions() if (!glewInitialized) { glewExperimental = GL_TRUE; GLenum err = glewInit(); - if (err != GLEW_OK && err != GLEW_ERROR_NO_GLX_DISPLAY) { + if (err != GLEW_OK) { throw MLException(QString("GLEW initialization failed: %1\n") .arg((const char *)glewGetErrorString(err))); } diff --git a/src/common/common.pro b/src/common/common.pro index 2a8346c3a..b80f4f6dd 100644 --- a/src/common/common.pro +++ b/src/common/common.pro @@ -75,12 +75,10 @@ HEADERS += \ GLExtensionsManager.h \ filterscript.h \ GLLogStream.h \ - mainwindow_interface.h \ mlexception.h \ mlapplication.h \ - meshlabdocumentxml.h \ - ml_selection_buffers.h \ - meshlabdocumentxml.h + ml_selection_buffers.h + SOURCES += \ globals.cpp \ @@ -118,11 +116,12 @@ SOURCES += \ GLLogStream.cpp \ mlapplication.cpp \ searcher.cpp \ - meshlabdocumentxml.cpp \ - meshlabdocumentbundler.cpp \ ml_selection_buffers.cpp \ $$MESHLAB_EXTERNAL_DIRECTORY/easyexif/exif.cpp +RESOURCES += \ + meshlab-common.qrc + macx:QMAKE_POST_LINK = "\ if [ -d $$MESHLAB_DISTRIB_DIRECTORY/meshlab.app/Contents/Frameworks/ ]; \ then \ diff --git a/src/common/img/dummy.png b/src/common/img/dummy.png new file mode 100644 index 000000000..03c4c8d2c Binary files /dev/null and b/src/common/img/dummy.png differ diff --git a/src/common/meshlab-common.qrc b/src/common/meshlab-common.qrc new file mode 100644 index 000000000..e7301593c --- /dev/null +++ b/src/common/meshlab-common.qrc @@ -0,0 +1,5 @@ + + + img/dummy.png + + diff --git a/src/common/meshlabdocumentbundler.cpp b/src/common/meshlabdocumentbundler.cpp deleted file mode 100644 index 6244c706b..000000000 --- a/src/common/meshlabdocumentbundler.cpp +++ /dev/null @@ -1,98 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -#include "ml_document/mesh_document.h" -#include -#include "meshlabdocumentbundler.h" - -#include - -#include -#include - -bool MeshDocumentFromBundler(MeshDocument &md, QString filename_out,QString image_list_filename, QString model_filename) -{ - md.addNewMesh(model_filename,QString("model")); - std::vector shots; - const QString path = QFileInfo(filename_out).absolutePath(); - const QString path_im = QFileInfo(image_list_filename).absolutePath()+QString("/"); - - std::vector image_filenames; - vcg::tri::io::ImporterOUT::Open(md.mm()->cm,shots,image_filenames, qUtf8Printable(filename_out), qUtf8Printable(image_list_filename)); - md.mm()->updateDataMask(MeshModel::MM_VERTCOLOR); - - QString curr_path = QDir::currentPath(); - QFileInfo imi(image_list_filename); - - // - QStringList image_filenames_q; - for(unsigned int i = 0; i < image_filenames.size(); ++i) - { - QImageReader sizeImg(QString::fromStdString(image_filenames[i])); - if(sizeImg.size()==QSize(-1,-1)) - image_filenames_q.push_back(path_im+QString::fromStdString(image_filenames[i])); - else - image_filenames_q.push_back(QString::fromStdString(image_filenames[i])); - } - QDir::setCurrent(imi.absoluteDir().absolutePath()); - - for(size_t i=0 ; iaddPlane(new RasterPlane(fullpath_image_filename,RasterPlane::RGBA)); - int count=fullpath_image_filename.count('\\'); - if (count==0) - { - count=fullpath_image_filename.count('/'); - md.rm()->setLabel(fullpath_image_filename.section('/',count,1)); - } - else - md.rm()->setLabel(fullpath_image_filename.section('\\',count,1)); - md.rm()->shot = shots[i]; - } - QDir::setCurrent(curr_path); - - return true; -} - -bool MeshDocumentFromNvm(MeshDocument &md, QString filename_nvm, QString model_filename) -{ - md.addNewMesh(model_filename,QString("model")); - std::vector shots; - const QString path = QFileInfo(filename_nvm).absolutePath(); - //const QString path_im = QFileInfo(image_list_filename).absolutePath()+QString("/"); - - std::vector image_filenames; - vcg::tri::io::ImporterNVM::Open(md.mm()->cm,shots,image_filenames, qUtf8Printable(filename_nvm)); - md.mm()->updateDataMask(MeshModel::MM_VERTCOLOR); - - QString curr_path = QDir::currentPath(); - //QFileInfo imi(image_list_filename); - - //QDir::setCurrent(imi.absoluteDir().absolutePath()); - QStringList image_filenames_q; - for(size_t i = 0; i < image_filenames.size(); ++i) - image_filenames_q.push_back(QString::fromStdString(image_filenames[int(i)])); - - for(size_t i=0 ; iaddPlane(new RasterPlane(fullpath_image_filename,RasterPlane::RGBA)); - md.rm()->setLabel(image_filenames_q[int(i)].section('/',1,2)); - md.rm()->shot = shots[int(i)]; - /*md.rm()->shot.Intrinsics.ViewportPx[0]=md.rm()->currentPlane->image.width(); - md.rm()->shot.Intrinsics.ViewportPx[1]=md.rm()->currentPlane->image.height(); - md.rm()->shot.Intrinsics.CenterPx[0]=(int)((double)md.rm()->shot.Intrinsics.ViewportPx[0]/2.0f); - md.rm()->shot.Intrinsics.CenterPx[1]=(int)((double)md.rm()->shot.Intrinsics.ViewportPx[1]/2.0f);*/ - - } - QDir::setCurrent(curr_path); - - return true; -} diff --git a/src/common/meshlabdocumentbundler.h b/src/common/meshlabdocumentbundler.h deleted file mode 100644 index 5d0db63b2..000000000 --- a/src/common/meshlabdocumentbundler.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef __MESHLABDOC_BUNDLER_H -#define __MESHLABDOC_BUNDLER_H - -#include "ml_document/mesh_model.h" - -bool MeshDocumentFromBundler(MeshDocument &md, QString filename_out, QString image_list_filename, QString model_filename); -bool MeshDocumentFromNvm(MeshDocument &md, QString filename_nvm, QString model_filename); - -#endif // __MESHLABDOC_BUNDLER_H diff --git a/src/common/meshlabdocumentxml.cpp b/src/common/meshlabdocumentxml.cpp deleted file mode 100644 index 5594542df..000000000 --- a/src/common/meshlabdocumentxml.cpp +++ /dev/null @@ -1,297 +0,0 @@ -#include -#include -#include -#include - -#include "meshlabdocumentxml.h" -#include - -bool MeshDocumentToXMLFile(MeshDocument &md, QString filename, bool onlyVisibleLayers, bool saveViewState, bool binary, const std::map& rendOpt) -{ - md.setFileName(filename); - QFileInfo fi(filename); - QDir tmpDir = QDir::current(); - QDir::setCurrent(fi.absoluteDir().absolutePath()); - QDomDocument doc = MeshDocumentToXML(md, onlyVisibleLayers, saveViewState, binary, rendOpt); - QFile file(filename); - file.open(QIODevice::WriteOnly); - QTextStream qstream(&file); - doc.save(qstream, 1); - file.close(); - QDir::setCurrent(tmpDir.absolutePath()); - return true; -} - -QDomElement Matrix44mToXML(Matrix44m &m, QDomDocument &doc) -{ - QDomElement matrixElem = doc.createElement("MLMatrix44"); - QString Row[4]; - for (int i = 0; i < 4; ++i) - Row[i] = QString("%1 %2 %3 %4 \n").arg(m[i][0]).arg(m[i][1]).arg(m[i][2]).arg(m[i][3]); - - QDomText nd = doc.createTextNode("\n" + Row[0] + Row[1] + Row[2] + Row[3]); - matrixElem.appendChild(nd); - - return matrixElem; -} - -QDomElement Matrix44mToBinaryXML(Matrix44m &m, QDomDocument &doc) -{ - QDomElement matrixElem = doc.createElement("MLMatrix44"); - QByteArray value = QByteArray::fromRawData((char *)m.V(), sizeof(Matrix44m::ScalarType) * 16).toBase64(); - QDomText nd = doc.createTextNode(QString(value)); - matrixElem.appendChild(nd); - return matrixElem; -} - -bool MeshDocumentFromXML(MeshDocument &md, QString filename, bool binary, std::map& rendOpt) -{ - QFile qf(filename); - QFileInfo qfInfo(filename); - QDir tmpDir = QDir::current(); - QDir::setCurrent(qfInfo.absoluteDir().absolutePath()); - if (!qf.open(QIODevice::ReadOnly)) - return false; - - QString project_path = qfInfo.absoluteFilePath(); - - QDomDocument doc("MeshLabDocument"); //It represents the XML document - if (!doc.setContent(&qf)) - return false; - - QDomElement root = doc.documentElement(); - - QDomNode node; - - node = root.firstChild(); - - //Devices - while (!node.isNull()) { - if (QString::compare(node.nodeName(), "MeshGroup") == 0) - { - QDomNode mesh; QString filen, label; - mesh = node.firstChild(); - while (!mesh.isNull()) { - //return true; - filen = mesh.attributes().namedItem("filename").nodeValue(); - label = mesh.attributes().namedItem("label").nodeValue(); - bool visible = true; - if (mesh.attributes().contains("visible")) - visible = (mesh.attributes().namedItem("visible").nodeValue().toInt() == 1); - MeshModel* mm = md.addNewMesh(filen, label); - mm->visible = visible; - - if (mesh.attributes().contains("idInFile")) - mm->setIdInFile(mesh.attributes().namedItem("idInFile").nodeValue().toInt()); - - QDomNode tr = mesh.firstChildElement("MLMatrix44"); - - if (!tr.isNull()) - { - vcg::Matrix44f trm; - if (tr.childNodes().size() == 1) - { - if (!binary) - { - QStringList rows = tr.firstChild().nodeValue().split("\n", QString::SkipEmptyParts); - int i = 0; - for (const QString& row : qAsConst(rows)){ - if (rows.size() > 0) { - QStringList values = row.split(" ", QString::SkipEmptyParts); - int j = 0; - for (const QString& value : qAsConst(values)) { - if (i < 4 && j < 4) { - md.mm()->cm.Tr[i][j] = value.toFloat(); - j++; - } - } - i++; - } - } - } - else - { - QString str = tr.firstChild().nodeValue(); - QByteArray value = QByteArray::fromBase64(str.toLocal8Bit()); - memcpy(md.mm()->cm.Tr.V(), value.data(), sizeof(Matrix44m::ScalarType) * 16); - } - } - } - - QDomNode renderingOpt = mesh.firstChildElement("RenderingOption"); - if (!renderingOpt.isNull()) - { - QString value = renderingOpt.firstChild().nodeValue(); - MLRenderingData::GLOptionsType opt; - if (renderingOpt.attributes().contains("pointSize")) - opt._perpoint_pointsize = renderingOpt.attributes().namedItem("pointSize").nodeValue().toFloat(); - if (renderingOpt.attributes().contains("wireWidth")) - opt._perwire_wirewidth = renderingOpt.attributes().namedItem("wireWidth").nodeValue().toFloat(); - if (renderingOpt.attributes().contains("boxColor")) - { - QStringList values = renderingOpt.attributes().namedItem("boxColor").nodeValue().split(" ", QString::SkipEmptyParts); - opt._perbbox_fixed_color = vcg::Color4b(values[0].toInt(), values[1].toInt(), values[2].toInt(), values[3].toInt()); - } - if (renderingOpt.attributes().contains("pointColor")) - { - QStringList values = renderingOpt.attributes().namedItem("pointColor").nodeValue().split(" ", QString::SkipEmptyParts); - opt._perpoint_fixed_color = vcg::Color4b(values[0].toInt(), values[1].toInt(), values[2].toInt(), values[3].toInt()); - } - if (renderingOpt.attributes().contains("wireColor")) - { - QStringList values = renderingOpt.attributes().namedItem("wireColor").nodeValue().split(" ", QString::SkipEmptyParts); - opt._perwire_fixed_color = vcg::Color4b(values[0].toInt(), values[1].toInt(), values[2].toInt(), values[3].toInt()); - } - if (renderingOpt.attributes().contains("solidColor")) - { - QStringList values = renderingOpt.attributes().namedItem("solidColor").nodeValue().split(" ", QString::SkipEmptyParts); - opt._persolid_fixed_color = vcg::Color4b(values[0].toInt(), values[1].toInt(), values[2].toInt(), values[3].toInt()); - } - MLRenderingData data; - data.set(opt); - if (data.deserialize(value.toStdString())) - rendOpt.insert(std::pair(mm->id(), data)); - } - - mesh = mesh.nextSibling(); - } - } - // READ IN POINT CORRESPONDECES INCOMPLETO!! - else if (QString::compare(node.nodeName(), "RasterGroup") == 0) - { - QDomNode raster; QString filen, label; - raster = node.firstChild(); - while (!raster.isNull()) - { - //return true; - md.addNewRaster(); - QString labelRaster = raster.attributes().namedItem("label").nodeValue(); - md.rm()->setLabel(labelRaster); - QDomNode sh = raster.firstChild(); - ReadShotFromQDomNode(md.rm()->shot, sh); - - QDomElement el = raster.firstChildElement("Plane"); - while (!el.isNull()) - { - QString filen = el.attribute("fileName"); - QFileInfo fi(filen); - QString sem = el.attribute("semantic"); - QString nm = fi.absoluteFilePath(); - md.rm()->addPlane(new RasterPlane(fi.absoluteFilePath(), RasterPlane::RGBA)); - el = node.nextSiblingElement("Plane"); - } - raster = raster.nextSibling(); - } - } - node = node.nextSibling(); - } - - QDir::setCurrent(tmpDir.absolutePath()); - qf.close(); - return true; -} - -QDomElement MeshModelToXML(MeshModel *mp, QDomDocument &doc, bool binary, bool saveViewState, const MLRenderingData& rendOpt = MLRenderingData()) -{ - QDomElement meshElem = doc.createElement("MLMesh"); - meshElem.setAttribute("label", mp->label()); - meshElem.setAttribute("filename", mp->relativePathName()); - meshElem.setAttribute("visible", saveViewState?mp->isVisible():true); - meshElem.setAttribute("idInFile", mp->idInFile()); - if (binary) - meshElem.appendChild(Matrix44mToBinaryXML(mp->cm.Tr, doc)); - else - meshElem.appendChild(Matrix44mToXML(mp->cm.Tr, doc)); - - if (saveViewState) - { - QDomElement renderingElem = doc.createElement("RenderingOption"); - std::string text; - rendOpt.serialize(text); - QDomText nd = doc.createTextNode(QString(text.c_str())); - renderingElem.appendChild(nd); - MLRenderingData::GLOptionsType opt; - if (rendOpt.get(opt)) - { - renderingElem.setAttribute("boxColor", QString("%1 %2 %3 %4").arg(opt._perbbox_fixed_color[0]).arg(opt._perbbox_fixed_color[1]).arg(opt._perbbox_fixed_color[2]).arg(opt._perbbox_fixed_color[3])); - renderingElem.setAttribute("pointColor", QString("%1 %2 %3 %4").arg(opt._perpoint_fixed_color[0]).arg(opt._perpoint_fixed_color[1]).arg(opt._perpoint_fixed_color[2]).arg(opt._perpoint_fixed_color[3])); - renderingElem.setAttribute("wireColor", QString("%1 %2 %3 %4").arg(opt._perwire_fixed_color[0]).arg(opt._perwire_fixed_color[1]).arg(opt._perwire_fixed_color[2]).arg(opt._perwire_fixed_color[3])); - renderingElem.setAttribute("solidColor", QString("%1 %2 %3 %4").arg(opt._persolid_fixed_color[0]).arg(opt._persolid_fixed_color[1]).arg(opt._persolid_fixed_color[2]).arg(opt._persolid_fixed_color[3])); - renderingElem.setAttribute("pointSize", opt._perpoint_pointsize); - renderingElem.setAttribute("wireWidth", opt._perwire_wirewidth); - } - meshElem.appendChild(renderingElem); - } - - return meshElem; -} - -QDomElement RasterModelToXML(RasterModel *mp, QDomDocument &doc, bool binary) -{ - QDomElement rasterElem = doc.createElement("MLRaster"); - rasterElem.setAttribute("label", mp->label()); - if (binary) - rasterElem.appendChild(WriteShotToQDomNodeBinary(mp->shot, doc)); - else - rasterElem.appendChild(WriteShotToQDomNode(mp->shot, doc)); - for (int ii = 0; ii < mp->planeList.size(); ++ii) - rasterElem.appendChild(PlaneToXML(mp->planeList[ii], mp->par->pathName(), doc)); - return rasterElem; -} - -QDomElement PlaneToXML(RasterPlane* pl, const QString& basePath, QDomDocument& doc) -{ - QDomElement planeElem = doc.createElement("Plane"); - QDir dir(basePath); - planeElem.setAttribute("fileName", dir.relativeFilePath(pl->fullPathFileName)); - planeElem.setAttribute("semantic", pl->semantic); - return planeElem; -} - -QDomDocument MeshDocumentToXML(MeshDocument &md, bool onlyVisibleLayers, bool saveViewState, bool binary, const std::map& rendOpt) -{ - QDomDocument ddoc("MeshLabDocument"); - - QDomElement root = ddoc.createElement("MeshLabProject"); - ddoc.appendChild(root); - QDomElement mgroot = ddoc.createElement("MeshGroup"); - - for(MeshModel *mmp : md.meshList) - { - if ((!onlyVisibleLayers) || (mmp->visible)) - { - QDomElement meshElem; - if (rendOpt.find(mmp->id()) != rendOpt.end()) - meshElem = MeshModelToXML(mmp, ddoc, binary, saveViewState, rendOpt.at(mmp->id())); - else - meshElem = MeshModelToXML(mmp, ddoc, binary, saveViewState); - mgroot.appendChild(meshElem); - } - } - root.appendChild(mgroot); - - QDomElement rgroot = ddoc.createElement("RasterGroup"); - - foreach(RasterModel *rmp, md.rasterList) - { - QDomElement rasterElem = RasterModelToXML(rmp, ddoc, binary); - rgroot.appendChild(rasterElem); - } - - root.appendChild(rgroot); - - // tag.setAttribute(QString("name"),(*ii).first); - // RichParameterSet &par=(*ii).second; - // QList::iterator jj; - // RichParameterXMLVisitor v(doc); - // for(jj=par.paramList.begin();jj!=par.paramList.end();++jj) - // { - // (*jj)->accept(v); - // tag.appendChild(v.parElem); - // } - // root.appendChild(tag); - // } - // - return ddoc; -} - diff --git a/src/common/meshlabdocumentxml.h b/src/common/meshlabdocumentxml.h deleted file mode 100644 index 19af062d7..000000000 --- a/src/common/meshlabdocumentxml.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef __MESHLABDOC_XML_H -#define __MESHLABDOC_XML_H - -#include - -#include "ml_shared_data_context/ml_shared_data_context.h" -#include "ml_document/mesh_document.h" -#include - - -QDomDocument MeshDocumentToXML(MeshDocument &md, bool onlyVisibleLayers, bool saveViewState, bool binary, const std::map& rendOpt = std::map()); -bool MeshDocumentToXMLFile(MeshDocument &md, QString filename, bool onlyVisibleLayers, bool saveViewState, bool binary, const std::map& rendOpt = std::map()); -bool MeshDocumentFromXML(MeshDocument &md, QString filename, bool binary, std::map& rendOpt); -QDomElement RasterModelToXML(RasterModel *mp,QDomDocument &doc, bool binary); -QDomElement PlaneToXML(RasterPlane* pl,const QString& basePath,QDomDocument& doc); -#endif // __MESHLABDOC_XML_H diff --git a/src/common/ml_document/cmesh.cpp b/src/common/ml_document/cmesh.cpp index ac930027b..38ed7e522 100644 --- a/src/common/ml_document/cmesh.cpp +++ b/src/common/ml_document/cmesh.cpp @@ -35,18 +35,22 @@ CMeshO::CMeshO(const CMeshO& oth) : { enableOCFComponentsFromOtherMesh(oth); vcg::tri::Append::MeshAppendConst(*this, oth); + textures = oth.textures; + normalmaps = oth.normalmaps; } /// TODO: make a proper implementation of a move constructor. /// Even if almost never used, this is very inefficient. CMeshO::CMeshO(CMeshO&& oth): - vcgTriMesh(), sfn(oth.sfn), svn(oth.svn), + vcgTriMesh(), sfn(oth.sfn), svn(oth.svn), pvn(oth.pvn), pfn(oth.pfn), Tr(oth.Tr) { enableOCFComponentsFromOtherMesh(oth); //I could take everything from oth and place it in //this mesh vcg::tri::Append::Mesh(*this, oth); + textures = oth.textures; + normalmaps = oth.normalmaps; } /// TODO: change this and use the copy&swap idiom @@ -60,6 +64,8 @@ CMeshO& CMeshO::operator=(const CMeshO& oth) pvn = oth.pvn; pfn = oth.pfn; Tr = oth.Tr; + textures = oth.textures; + normalmaps = oth.normalmaps; return *this; } diff --git a/src/common/ml_document/helpers/mesh_document_state_data.cpp b/src/common/ml_document/helpers/mesh_document_state_data.cpp index 9a60edc0c..d12d34b67 100644 --- a/src/common/ml_document/helpers/mesh_document_state_data.cpp +++ b/src/common/ml_document/helpers/mesh_document_state_data.cpp @@ -16,9 +16,7 @@ MeshDocumentStateData::~MeshDocumentStateData() void MeshDocumentStateData::create(MeshDocument& md) { QWriteLocker locker(&_lock); - for (int ii = 0; ii < md.meshList.size(); ++ii) - { - MeshModel* mm = md.meshList[ii]; + for (MeshModel* mm : md.meshIterator()) { if (mm != NULL) insert(mm->id(), MeshModelStateData(mm->dataMask(), mm->cm.VN(), mm->cm.FN(), mm->cm.EN())); } diff --git a/src/common/ml_document/mesh_document.cpp b/src/common/ml_document/mesh_document.cpp index a923b49b9..5abff0951 100644 --- a/src/common/ml_document/mesh_document.cpp +++ b/src/common/ml_document/mesh_document.cpp @@ -2,7 +2,7 @@ * MeshLab o o * * Visual and Computer Graphics Library o o * * _ O _ * -* Copyright(C) 2004-2020 \/)\/ * +* Copyright(C) 2004-2021 \/)\/ * * Visual Computing Lab /\/| * * ISTI - Italian National Research Council | * * \ * @@ -24,11 +24,11 @@ #include "mesh_document.h" template -QString NameDisambiguator(QList &elemList, QString meshLabel ) +QString nameDisambiguator(std::list &elemList, QString meshLabel) { QString newName=std::move(meshLabel); - typename QList::iterator mmi; - + typename std::list::iterator mmi; + for(mmi=elemList.begin(); mmi!=elemList.end(); ++mmi) { if((*mmi)->label() == newName) // if duplicated name found @@ -37,38 +37,36 @@ QString NameDisambiguator(QList &elemList, QString meshLabel ) QString baseName = fi.baseName(); // all characters in the file up to the first '.' Eg "/tmp/archive.tar.gz" -> "archive" QString suffix = fi.suffix(); bool ok; - + // if name ends with a number between parenthesis (XXX), // it was himself a duplicated name, and we need to // just increase the number between parenthesis int numDisamb; int startDisamb; int endDisamb; - + startDisamb = baseName.lastIndexOf("("); endDisamb = baseName.lastIndexOf(")"); if((startDisamb!=-1)&&(endDisamb!=-1)) - numDisamb = (baseName.mid((startDisamb+1),(endDisamb-startDisamb-1))).toInt(&ok); + numDisamb = baseName.midRef((startDisamb+1),(endDisamb-startDisamb-1)).toInt(&ok); else numDisamb = 0; - + if(startDisamb!=-1) newName = baseName.left(startDisamb)+ "(" + QString::number(numDisamb+1) + ")"; else newName = baseName + "(" + QString::number(numDisamb+1) + ")"; - + if (suffix != QString("")) newName = newName + "." + suffix; - + // now recurse to see if the new name is free - newName = NameDisambiguator(elemList, newName); + newName = nameDisambiguator(elemList, newName); } } return newName; } - - MeshDocument::MeshDocument() { meshIdCounter=0; @@ -92,11 +90,11 @@ void MeshDocument::clear() for(MeshModel *mmp : meshList) delete mmp; meshList.clear(); - + for(RasterModel* rmp :rasterList) delete rmp; rasterList.clear(); - + meshIdCounter=0; rasterIdCounter=0; currentMesh = nullptr; @@ -108,7 +106,7 @@ void MeshDocument::clear() meshDocStateData().clear(); } -const MeshModel* MeshDocument::getMesh(int id) const +const MeshModel* MeshDocument::getMesh(unsigned int id) const { for (const MeshModel* m : meshList) if (m->id() == id) @@ -117,7 +115,7 @@ const MeshModel* MeshDocument::getMesh(int id) const } //returns the mesh ata given position in the list -MeshModel* MeshDocument::getMesh(int id) +MeshModel* MeshDocument::getMesh(unsigned int id) { for (MeshModel* m : meshList) if (m->id() == id) @@ -127,8 +125,7 @@ MeshModel* MeshDocument::getMesh(int id) void MeshDocument::setCurrentMesh(int new_curr_id) { - if(new_curr_id<0) - { + if(new_curr_id<0) { currentMesh=0; return; } @@ -137,30 +134,31 @@ void MeshDocument::setCurrentMesh(int new_curr_id) assert(currentMesh); } +void MeshDocument::setVisible(int meshId, bool val) +{ + getMesh(meshId)->visible=val; + emit meshSetChanged(); +} + //returns the raster at a given position in the list RasterModel *MeshDocument::getRaster(int i) { - foreach(RasterModel *rmp, rasterList) - { + for(RasterModel *rmp : rasterList) { if(rmp->id() == i) return rmp; } - //assert(0); return 0; } //if i is <0 it means that no currentRaster is set -void MeshDocument::setCurrentRaster( int new_curr_id) +void MeshDocument::setCurrentRaster(int new_curr_id) { - if(new_curr_id<0) - { + if(new_curr_id<0) { currentRaster=0; return; } - - foreach(RasterModel *rmp, rasterList) - { - if(rmp->id() == new_curr_id) - { + + for(RasterModel *rmp : rasterList) { + if(rmp->id() == new_curr_id) { currentRaster = rmp; return; } @@ -183,7 +181,7 @@ MeshModel* MeshDocument::nextVisibleMesh(MeshModel* _m) MeshModel *newM = nextMesh(_m); if(newM==0) return newM; - + if(newM->isVisible()) return newM; else @@ -193,26 +191,31 @@ MeshModel* MeshDocument::nextVisibleMesh(MeshModel* _m) MeshModel* MeshDocument::nextMesh(MeshModel* _m) { if(_m==0 && meshList.size()>0) - return meshList.at(0); - for (int i = 0; i < meshList.size(); ++i) { - if (meshList.at(i) == _m) { - if(i+1 < meshList.size()) - return meshList.at(i+1); + return meshList.front(); + for (auto it = meshList.begin(); it != meshList.end(); ++it) { + if (*it == _m) { + auto next = it; + next++; + if(next != meshList.end()) + return *next; } } - return 0; + return nullptr; } RasterModel* MeshDocument::nextRaster(RasterModel* _rm) { - for (int i = 0; i < rasterList.size(); ++i) { - if (rasterList.at(i) == _rm) - { - if(i+1 < rasterList.size()) - return rasterList.at(i+1); + if(_rm==0 && rasterList.size()>0) + return rasterList.front(); + for (auto it = rasterList.begin(); it != rasterList.end(); ++it) { + if (*it == _rm) { + auto next = it; + next++; + if(next != rasterList.end()) + return *next; } } - return 0; + return nullptr; } MeshModel* MeshDocument::mm() @@ -230,18 +233,13 @@ RasterModel* MeshDocument::rm() return currentRaster; } -unsigned int MeshDocument::newMeshId() +const RasterModel* MeshDocument::rm() const { - return meshIdCounter++; -} - -unsigned int MeshDocument::newRasterId() -{ - return rasterIdCounter++; + return currentRaster; } void MeshDocument::requestUpdatingPerMeshDecorators(int mesh_id) -{ +{ emit updateDecorators(mesh_id); } @@ -271,12 +269,12 @@ void MeshDocument::setFileName(const QString& newFileName) fullPathFilename = newFileName; } -int MeshDocument::size() const +unsigned int MeshDocument::meshNumber() const { return meshList.size(); } -int MeshDocument::sizeRasters() const +unsigned int MeshDocument::rasterNumber() const { return rasterList.size(); } @@ -295,36 +293,46 @@ void MeshDocument::setBusy(bool _busy) * @brief Adds a new mesh to the MeshDocument. The added mesh is a COPY of the mesh * passed as parameter. */ -MeshModel* MeshDocument::addNewMesh(const CMeshO& mesh, QString label, bool setAsCurrent) +MeshModel* MeshDocument::addNewMesh( + const CMeshO& mesh, + const QString& label, + bool setAsCurrent) { MeshModel* m = addNewMesh("", label, setAsCurrent); m->cm = mesh; - m->UpdateBoxAndNormals(); + m->updateBoxAndNormals(); + m->updateDataMask(); return m; } -MeshModel * MeshDocument::addNewMesh(QString fullPath, QString label, bool setAsCurrent) +MeshModel * MeshDocument::addNewMesh( + QString fullPath, + const QString& label, + bool setAsCurrent) { - QString newlabel = NameDisambiguator(this->meshList,std::move(label)); - + QString newlabel = nameDisambiguator(this->meshList, label); + if(!fullPath.isEmpty()) { QFileInfo fi(fullPath); fullPath = fi.absoluteFilePath(); } - - MeshModel *newMesh = new MeshModel(this, newMeshId(), fullPath,newlabel); + + MeshModel *newMesh = new MeshModel(newMeshId(), fullPath,newlabel); meshList.push_back(newMesh); - + if(setAsCurrent) this->setCurrentMesh(newMesh->id()); - + emit meshSetChanged(); emit meshAdded(newMesh->id()); return newMesh; } -MeshModel * MeshDocument::addOrGetMesh(QString fullPath, const QString& label, bool setAsCurrent) +MeshModel * MeshDocument::addOrGetMesh( + const QString& fullPath, + const QString& label, + bool setAsCurrent) { MeshModel *newMesh = nullptr; for (MeshModel* m : meshList) @@ -335,7 +343,7 @@ MeshModel * MeshDocument::addOrGetMesh(QString fullPath, const QString& label, b this->setCurrentMesh(newMesh->id()); return newMesh; } - return addNewMesh(std::move(fullPath),label,setAsCurrent); + return addNewMesh(fullPath,label,setAsCurrent); } /** @@ -361,16 +369,19 @@ std::list MeshDocument::getMeshesLoadedFromSameFile(MeshModel* mm) bool MeshDocument::delMesh(MeshModel *mmToDel) { - if(!meshList.removeOne(mmToDel)) + auto pos = std::find(meshList.begin(), meshList.end(), mmToDel); + if (pos == meshList.end()) return false; + meshList.erase(pos); + if((currentMesh == mmToDel) && (!meshList.empty())) - setCurrentMesh(this->meshList.at(0)->id()); + setCurrentMesh(this->meshList.front()->id()); else if (meshList.empty()) setCurrentMesh(-1); - + int index = mmToDel->id(); delete mmToDel; - + emit meshSetChanged(); emit meshRemoved(index); return true; @@ -380,45 +391,35 @@ RasterModel * MeshDocument::addNewRaster(/*QString fullPathFilename*/) { QFileInfo info(fullPathFilename); QString newLabel=info.fileName(); - QString newName = NameDisambiguator(this->rasterList, newLabel); - + RasterModel *newRaster=new RasterModel(this, newRasterId(), newLabel); rasterList.push_back(newRaster); - + //Add new plane //Plane *plane = new Plane(newRaster, fullPathFilename, QString()); //newRaster->addPlane(plane); - + this->setCurrentRaster(newRaster->id()); - + emit rasterSetChanged(); return newRaster; } bool MeshDocument::delRaster(RasterModel *rasterToDel) { - QMutableListIterator i(rasterList); - - while (i.hasNext()) - { - RasterModel *r = i.next(); - - if (r==rasterToDel) - { - i.remove(); - delete rasterToDel; - } - } - - if(currentRaster == rasterToDel) - { - if (!rasterList.empty()) - setCurrentRaster(rasterList.at(0)->id()); - else - setCurrentRaster(-1); - } + auto pos = std::find(rasterList.begin(), rasterList.end(), rasterToDel); + if (pos == rasterList.end()) + return false; + rasterList.erase(pos); + + if((currentRaster == rasterToDel) && (!rasterList.empty())) + setCurrentRaster(this->rasterList.front()->id()); + else if (rasterList.empty()) + setCurrentRaster(-1); + + delete rasterToDel; emit rasterSetChanged(); - + return true; } @@ -438,7 +439,7 @@ int MeshDocument::fn() return tot; } -Box3m MeshDocument::bbox() +Box3m MeshDocument::bbox() const { Box3m FullBBox; for(MeshModel * mp : meshList) @@ -453,8 +454,72 @@ bool MeshDocument::hasBeenModified() return false; } -MeshDocument::MeshRangeIterator MeshDocument::meshIterator() +MeshDocument::MeshIterator MeshDocument::meshBegin() { - return MeshRangeIterator(this); + return meshList.begin(); } +MeshDocument::MeshIterator MeshDocument::meshEnd() +{ + return meshList.end(); +} + +MeshDocument::RasterIterator MeshDocument::rasterBegin() +{ + return rasterList.begin(); +} + +MeshDocument::RasterIterator MeshDocument::rasterEnd() +{ + return rasterList.end(); +} + +MeshDocument::ConstMeshIterator MeshDocument::meshBegin() const +{ + return (reinterpret_cast* >(&meshList))->begin(); +} + +MeshDocument::ConstMeshIterator MeshDocument::meshEnd() const +{ + return (reinterpret_cast* >(&meshList))->end(); +} + +MeshDocument::ConstRasterIterator MeshDocument::rasterBegin() const +{ + return (reinterpret_cast* >(&rasterList))->begin(); +} + +MeshDocument::ConstRasterIterator MeshDocument::rasterEnd() const +{ + return (reinterpret_cast* >(&rasterList))->end(); +} + +MeshDocument::MeshRangeIterator MeshDocument::meshIterator() +{ + return MeshRangeIterator(*this); +} + +MeshDocument::ConstMeshRangeIterator MeshDocument::meshIterator() const +{ + return ConstMeshRangeIterator(*this); +} + +MeshDocument::RasterRangeIterator MeshDocument::rasterIterator() +{ + return RasterRangeIterator(*this); +} + +MeshDocument::ConstRasterRangeIterator MeshDocument::rasterIterator() const +{ + return ConstRasterRangeIterator(*this); +} + +unsigned int MeshDocument::newMeshId() +{ + return meshIdCounter++; +} + +unsigned int MeshDocument::newRasterId() +{ + return rasterIdCounter++; +} diff --git a/src/common/ml_document/mesh_document.h b/src/common/ml_document/mesh_document.h index f27511009..f3a88313e 100644 --- a/src/common/ml_document/mesh_document.h +++ b/src/common/ml_document/mesh_document.h @@ -2,7 +2,7 @@ * MeshLab o o * * Visual and Computer Graphics Library o o * * _ O _ * -* Copyright(C) 2004-2020 \/)\/ * +* Copyright(C) 2004-2021 \/)\/ * * Visual Computing Lab /\/| * * ISTI - Italian National Research Council | * * \ * @@ -32,150 +32,203 @@ class MeshDocument : public QObject { Q_OBJECT - + public: + + // Iterators + typedef std::list::iterator MeshIterator; + typedef std::list::const_iterator ConstMeshIterator; + typedef std::list::iterator RasterIterator; + typedef std::list::const_iterator ConstRasterIterator; + + class MeshRangeIterator + { + friend class MeshDocument; + public: + MeshIterator begin() {return md.meshBegin();} + MeshIterator end() {return md.meshEnd();} + private: + MeshRangeIterator(MeshDocument& md) : md(md){} + MeshDocument& md; + }; + + class ConstMeshRangeIterator + { + friend class MeshDocument; + public: + ConstMeshIterator begin() {return md.meshBegin();} + ConstMeshIterator end() {return md.meshEnd();} + private: + ConstMeshRangeIterator(const MeshDocument& md) : md(md){} + const MeshDocument& md; + }; + + class RasterRangeIterator + { + friend class MeshDocument; + public: + RasterIterator begin() {return md.rasterBegin();} + RasterIterator end() {return md.rasterEnd();} + private: + RasterRangeIterator(MeshDocument& md) : md(md){} + MeshDocument& md; + }; + + class ConstRasterRangeIterator + { + friend class MeshDocument; + public: + ConstRasterIterator begin() {return md.rasterBegin();} + ConstRasterIterator end() {return md.rasterEnd();} + private: + ConstRasterRangeIterator(const MeshDocument& md) : md(md){} + const MeshDocument& md; + }; + MeshDocument(); - + //deletes each meshModel ~MeshDocument(); - + void clear(); - + ///returns the mesh with the given unique id - const MeshModel* getMesh(int id) const; - MeshModel* getMesh(int id); - + const MeshModel* getMesh(unsigned int id) const; + MeshModel* getMesh(unsigned int id); + //set the current mesh to be the one with the given ID void setCurrentMesh( int new_curr_id ); void setVisible(int meshId, bool val); - + /// returns the raster with the given unique id RasterModel *getRaster(int i); - + //set the current raster to be the one with the given ID void setCurrentRaster( int new_curr_id ); void setCurrent(MeshModel *newCur); void setCurrent(RasterModel *newCur); - + /// methods to access the set of Meshes in a ordered fashion. MeshModel *nextVisibleMesh(MeshModel *_m = nullptr); - + MeshModel *nextMesh(MeshModel *_m = nullptr); /// methods to access the set of Meshes in a ordered fashion. RasterModel *nextRaster(RasterModel *_rm = nullptr); - + MeshModel* mm(); - + const MeshModel* mm() const; - + //Could return 0 if no raster has been selected RasterModel *rm(); + const RasterModel* rm() const; void requestUpdatingPerMeshDecorators(int mesh_id); - + MeshDocumentStateData& meshDocStateData(); void setDocLabel(const QString& docLb); QString docLabel() const; QString pathName() const; void setFileName(const QString& newFileName); - - - int size() const; - int sizeRasters() const; + + unsigned int meshNumber() const; + unsigned int rasterNumber() const; + bool isBusy(); // used in processing. To disable access to the mesh by the rendering thread void setBusy(bool _busy); ///add a new mesh with the given name - MeshModel* addNewMesh(const CMeshO& mesh, QString Label, bool setAsCurrent=true); - MeshModel *addNewMesh(QString fullPath, QString Label, bool setAsCurrent=true); - MeshModel *addOrGetMesh(QString fullPath, const QString& Label, bool setAsCurrent=true); + MeshModel* addNewMesh(const CMeshO& mesh, const QString& Label, bool setAsCurrent=true); + MeshModel *addNewMesh(QString fullPath, const QString& Label, bool setAsCurrent=true); + MeshModel *addOrGetMesh(const QString& fullPath, const QString& Label, bool setAsCurrent=true); std::list getMeshesLoadedFromSameFile(MeshModel* mm); - + ///remove the mesh from the list and delete it from memory bool delMesh(MeshModel *mmToDel); - + ///add a new raster model RasterModel *addNewRaster(/*QString rasterName*/); - + ///remove the raster from the list and delete it from memory bool delRaster(RasterModel *rasterToDel); - + int vn(); /// Sum of all the vertices of all the meshes int fn(); - - Box3m bbox(); - + + Box3m bbox() const; + bool hasBeenModified(); - - class MeshRangeIterator - { - friend class MeshDocument; - public: - QList::iterator begin() {return md->meshList.begin();} - QList::iterator end() {return md->meshList.end();} - private: - MeshRangeIterator(MeshDocument* md) : md(md){} - MeshDocument* md; - }; - + + //iterator member functions + MeshIterator meshBegin(); + MeshIterator meshEnd(); + RasterIterator rasterBegin(); + RasterIterator rasterEnd(); + ConstMeshIterator meshBegin() const; + ConstMeshIterator meshEnd() const; + ConstRasterIterator rasterBegin() const; + ConstRasterIterator rasterEnd() const; + MeshRangeIterator meshIterator(); - + ConstMeshRangeIterator meshIterator() const; + RasterRangeIterator rasterIterator(); + ConstRasterRangeIterator rasterIterator() const; + GLLogStream Log; FilterScript filterHistory; - + +private: /// The very important member: /// The list of MeshModels. - QList meshList; + std::list meshList; /// The list of the raster models of the project - QList rasterList; - -private: + std::list rasterList; + int meshIdCounter; int rasterIdCounter; - + /** All the files referred in a document are relative to the folder containing the project file. this is the full path to the document. */ QString fullPathFilename; - + //it is the label of the document. it should only be something like Project_n (a temporary name for a new empty document) or the fullPathFilename. QString documentLabel; - + MeshDocumentStateData mdstate; - + bool busy; - + MeshModel *currentMesh; //the current raster model RasterModel* currentRaster; - + unsigned int newMeshId(); unsigned int newRasterId(); - + signals: ///whenever the current mesh is changed (e.g. the user click on a different mesh) // this signal will send out with the index of the newest mesh void currentMeshChanged(int index); - + /// whenever the document (or even a single mesh) is modified by a filter void meshDocumentModified(); - + ///whenever the meshList is changed void meshSetChanged(); - + void meshAdded(int index); void meshRemoved(int index); - + ///whenever the rasterList is changed void rasterSetChanged(); - + //this signal is emitted when a filter request to update the mesh in the renderingState void documentUpdated(); void updateDecorators(int mesh_id); - };// end class MeshDocument diff --git a/src/common/ml_document/mesh_model.cpp b/src/common/ml_document/mesh_model.cpp index 8641dde4e..a16402852 100644 --- a/src/common/ml_document/mesh_model.cpp +++ b/src/common/ml_document/mesh_model.cpp @@ -2,7 +2,7 @@ * MeshLab o o * * Visual and Computer Graphics Library o o * * _ O _ * -* Copyright(C) 2004-2020 \/)\/ * +* Copyright(C) 2004-2021 \/)\/ * * Visual Computing Lab /\/| * * ISTI - Italian National Research Council | * * \ * @@ -21,13 +21,12 @@ * * ****************************************************************************/ - #include #include #include #include "mesh_model.h" -#include "mesh_document.h" +#include "../utilities/load_save.h" #include @@ -36,178 +35,311 @@ using namespace vcg; -MeshModel::MeshModel(MeshDocument *_parent, unsigned int id, const QString& fullFileName, const QString& labelName) : +MeshModel::MeshModel(unsigned int id, const QString& fullFileName, const QString& labelName) : idInsideFile(-1) { /*glw.m = &(cm);*/ - Clear(); - parent=_parent; + clear(); _id=id; if(!fullFileName.isEmpty()) this->fullPathFileName=fullFileName; - if(!labelName.isEmpty()) this->_label=labelName; + if(!labelName.isEmpty()) this->_label=labelName; } -void MeshModel::Clear() +void MeshModel::clear() { setMeshModified(false); - // These data are always active on the mesh - currentDataMask = MM_NONE; - currentDataMask |= MM_VERTCOORD | MM_VERTNORMAL | MM_VERTFLAG ; - currentDataMask |= MM_FACEVERT | MM_FACENORMAL | MM_FACEFLAG ; + // These data are always active on the mesh + currentDataMask = MM_NONE; + currentDataMask |= MM_VERTCOORD | MM_VERTNORMAL | MM_VERTFLAG ; + currentDataMask |= MM_FACEVERT | MM_FACENORMAL | MM_FACEFLAG ; - visible=true; - cm.Tr.SetIdentity(); - cm.sfn=0; - cm.svn=0; + visible=true; + cm.Tr.SetIdentity(); + cm.sfn=0; + cm.svn=0; } -void MeshModel::UpdateBoxAndNormals() +void MeshModel::updateBoxAndNormals() { - tri::UpdateBounding::Box(cm); - if(cm.fn>0) { - tri::UpdateNormal::PerFaceNormalized(cm); - tri::UpdateNormal::PerVertexAngleWeighted(cm); - } + tri::UpdateBounding::Box(cm); + if(cm.fn>0) { + tri::UpdateNormal::PerFaceNormalized(cm); + tri::UpdateNormal::PerVertexAngleWeighted(cm); + } } -QString MeshModel::relativePathName() const +QString MeshModel::relativePathName(const QString& path) const { - QDir documentDir (documentPathName()); - QString relPath=documentDir.relativeFilePath(this->fullPathFileName); + QDir documentDir (path); + QString relPath=documentDir.relativeFilePath(this->fullPathFileName); - if(relPath.size()>1 && relPath[0]=='.' && relPath[1]=='.') - qDebug("Error we have a mesh that is not in the same folder of the project: %s ", qUtf8Printable(relPath)); + //if(relPath.size()>1 && relPath[0]=='.' && relPath[1]=='.') + // qDebug("Error we have a mesh that is not in the same folder of the project: %s ", qUtf8Printable(relPath)); - return relPath; + return relPath; } -QString MeshModel::documentPathName() const +/** + * @brief Starting from the (still unloaded) textures contained in the contained + * CMeshO, loads the textures in the map of QImages contained in the MeshModel. + * + * The contained CMeshO will have a list of texture names like ":filename.png", + * and these names will be mapped with the actual loaded image in the map + * "textures". + * + * When a texture is not found, a dummy texture will be used (":dummy.png"). + * + * Returns the list of non-loaded textures that have been modified with + * ":dummy.png" in the contained mesh. + */ +std::list MeshModel::loadTextures( + GLLogStream* log, + vcg::CallBackPos* cb) { - return parent->pathName(); + std::list unloadedTextures; + for (std::string& textName : cm.textures){ + if (textures.find(textName) == textures.end()){ + QImage img(":/img/dummy.png"); + QFileInfo finfo(QString::fromStdString(textName)); + try { + img = meshlab::loadImage(finfo.absoluteFilePath(), log, cb); + textName = finfo.fileName().toStdString(); + } catch (const MLException& e) { + try { //could be relative to the meshmodel + QFileInfo mfi(fullName()); + QString fn2 = mfi.absolutePath() + "/" + finfo.fileName(); + img = meshlab::loadImage(fn2, log, cb); + textName = finfo.fileName().toStdString(); + } catch (const MLException& e) { + if (log){ + log->log( + GLLogStream::WARNING, "Failed loading " + textName + + "; using a dummy texture"); + } + else { + std::cerr << + "Failed loading " + textName + "; using a dummy texture\n"; + } + unloadedTextures.push_back(textName); + textName = "dummy.png"; + } + } + textures[textName] = img; + } + } + return unloadedTextures; +} + +void MeshModel::saveTextures( + const QString& basePath, + int quality, + GLLogStream* log, + CallBackPos* cb) +{ + for (const std::string& tname : cm.textures){ + meshlab::saveImage( + basePath + "/" + QString::fromStdString(tname), + textures.at(tname), quality, log, cb); + } +} + +QImage MeshModel::getTexture(const std::string& tn) const +{ + auto it = textures.find(tn); + if (it != textures.end()) + return it->second; + else + return QImage(); +} + +void MeshModel::clearTextures() +{ + textures.clear(); + cm.textures.clear(); +} + +void MeshModel::addTexture(std::string name, const QImage& txt) +{ + cm.textures.push_back(name); + textures[name]=txt; +} + +void MeshModel::setTexture(std::string name, const QImage& txt) +{ + auto it = textures.find(name); + if (it != textures.end()) + it->second = txt; +} + +void MeshModel::changeTextureName( + const std::string& oldName, + std::string newName) +{ + if (oldName != newName) { + auto mit = textures.find(oldName); + auto tit = std::find(cm.textures.begin(), cm.textures.end(), oldName); + if (mit != textures.end() && tit != cm.textures.end()){ + *tit = newName; + + textures[newName] = mit->second; + textures.erase(mit); + } + } } int MeshModel::io2mm(int single_iobit) { - switch(single_iobit) - { - case tri::io::Mask::IOM_NONE : return MM_NONE; - case tri::io::Mask::IOM_VERTCOORD : return MM_VERTCOORD; - case tri::io::Mask::IOM_VERTCOLOR : return MM_VERTCOLOR; - case tri::io::Mask::IOM_VERTFLAGS : return MM_VERTFLAG; - case tri::io::Mask::IOM_VERTQUALITY : return MM_VERTQUALITY; - case tri::io::Mask::IOM_VERTNORMAL : return MM_VERTNORMAL; - case tri::io::Mask::IOM_VERTTEXCOORD : return MM_VERTTEXCOORD; - case tri::io::Mask::IOM_VERTRADIUS : return MM_VERTRADIUS; + switch(single_iobit) + { + case tri::io::Mask::IOM_NONE : return MM_NONE; + case tri::io::Mask::IOM_VERTCOORD : return MM_VERTCOORD; + case tri::io::Mask::IOM_VERTCOLOR : return MM_VERTCOLOR; + case tri::io::Mask::IOM_VERTFLAGS : return MM_VERTFLAG; + case tri::io::Mask::IOM_VERTQUALITY : return MM_VERTQUALITY; + case tri::io::Mask::IOM_VERTNORMAL : return MM_VERTNORMAL; + case tri::io::Mask::IOM_VERTTEXCOORD : return MM_VERTTEXCOORD; + case tri::io::Mask::IOM_VERTRADIUS : return MM_VERTRADIUS; - case tri::io::Mask::IOM_FACEINDEX : return MM_FACEVERT ; - case tri::io::Mask::IOM_FACEFLAGS : return MM_FACEFLAG ; - case tri::io::Mask::IOM_FACECOLOR : return MM_FACECOLOR ; - case tri::io::Mask::IOM_FACEQUALITY : return MM_FACEQUALITY; - case tri::io::Mask::IOM_FACENORMAL : return MM_FACENORMAL ; + case tri::io::Mask::IOM_FACEINDEX : return MM_FACEVERT ; + case tri::io::Mask::IOM_FACEFLAGS : return MM_FACEFLAG ; + case tri::io::Mask::IOM_FACECOLOR : return MM_FACECOLOR ; + case tri::io::Mask::IOM_FACEQUALITY : return MM_FACEQUALITY; + case tri::io::Mask::IOM_FACENORMAL : return MM_FACENORMAL ; - case tri::io::Mask::IOM_WEDGTEXCOORD : return MM_WEDGTEXCOORD; - case tri::io::Mask::IOM_WEDGCOLOR : return MM_WEDGCOLOR; - case tri::io::Mask::IOM_WEDGNORMAL : return MM_WEDGNORMAL ; + case tri::io::Mask::IOM_WEDGTEXCOORD : return MM_WEDGTEXCOORD; + case tri::io::Mask::IOM_WEDGCOLOR : return MM_WEDGCOLOR; + case tri::io::Mask::IOM_WEDGNORMAL : return MM_WEDGNORMAL ; - case tri::io::Mask::IOM_BITPOLYGONAL : return MM_POLYGONAL ; + case tri::io::Mask::IOM_BITPOLYGONAL : return MM_POLYGONAL ; - default: - assert(0); - return MM_NONE; // FIXME: Returning this is not the best solution (!) - break; - } ; + default: + assert(0); + return MM_NONE; // FIXME: Returning this is not the best solution (!) + break; + } ; } /**** DATAMASK STUFF ****/ -void MeshDocument::setVisible(int meshId, bool val) -{ - getMesh(meshId)->visible=val; - emit meshSetChanged(); -} - bool MeshModel::hasDataMask(const int maskToBeTested) const { - return ((currentDataMask & maskToBeTested)!= 0); + return ((currentDataMask & maskToBeTested)!= 0); } -void MeshModel::updateDataMask(MeshModel *m) + +void MeshModel::updateDataMask() { - updateDataMask(m->currentDataMask); + currentDataMask = MM_NONE; + currentDataMask |= + MM_VERTCOORD | MM_VERTNORMAL | MM_VERTFLAG | + MM_VERTQUALITY | MM_VERTCOLOR; + currentDataMask |= + MM_FACEVERT | MM_FACENORMAL | MM_FACEFLAG ; + if (cm.vert.IsVFAdjacencyEnabled()) + currentDataMask |= MM_VERTFACETOPO; + if (cm.vert.IsMarkEnabled()) + currentDataMask |= MM_VERTMARK; + if (cm.vert.IsTexCoordEnabled()) + currentDataMask |= MM_VERTTEXCOORD; + if (cm.vert.IsCurvatureEnabled()) + currentDataMask |= MM_VERTCURV; + if (cm.vert.IsCurvatureDirEnabled()) + currentDataMask |= MM_VERTCURVDIR; + if (cm.vert.IsRadiusEnabled()) + currentDataMask |= MM_VERTRADIUS; + if (cm.face.IsQualityEnabled()) + currentDataMask |= MM_FACEQUALITY; + if (cm.face.IsMarkEnabled()) + currentDataMask |= MM_FACEMARK; + if (cm.face.IsColorEnabled()) + currentDataMask |= MM_FACECOLOR; + if (cm.face.IsFFAdjacencyEnabled()) + currentDataMask |= MM_FACEFACETOPO; + if (cm.face.IsVFAdjacencyEnabled()) + currentDataMask |= MM_VERTFACETOPO; + if (cm.face.IsCurvatureDirEnabled()) + currentDataMask |= MM_FACECURVDIR; + if (cm.face.IsWedgeTexCoordEnabled()) + currentDataMask |= MM_WEDGTEXCOORD; +} + +void MeshModel::updateDataMask(const MeshModel *m) +{ + updateDataMask(m->currentDataMask); } void MeshModel::updateDataMask(int neededDataMask) { - if((neededDataMask & MM_FACEFACETOPO)!=0) - { - cm.face.EnableFFAdjacency(); - tri::UpdateTopology::FaceFace(cm); - } - if((neededDataMask & MM_VERTFACETOPO)!=0) - { - cm.vert.EnableVFAdjacency(); - cm.face.EnableVFAdjacency(); - tri::UpdateTopology::VertexFace(cm); - } + if((neededDataMask & MM_FACEFACETOPO)!=0) + { + cm.face.EnableFFAdjacency(); + tri::UpdateTopology::FaceFace(cm); + } + if((neededDataMask & MM_VERTFACETOPO)!=0) + { + cm.vert.EnableVFAdjacency(); + cm.face.EnableVFAdjacency(); + tri::UpdateTopology::VertexFace(cm); + } - if((neededDataMask & MM_WEDGTEXCOORD)!=0) - cm.face.EnableWedgeTexCoord(); - if((neededDataMask & MM_FACECOLOR)!=0) - cm.face.EnableColor(); - if((neededDataMask & MM_FACEQUALITY)!=0) - cm.face.EnableQuality(); - if((neededDataMask & MM_FACECURVDIR)!=0) - cm.face.EnableCurvatureDir(); - if((neededDataMask & MM_FACEMARK)!=0) - cm.face.EnableMark(); - if((neededDataMask & MM_VERTMARK)!=0) - cm.vert.EnableMark(); - if((neededDataMask & MM_VERTCURV)!=0) - cm.vert.EnableCurvature(); - if((neededDataMask & MM_VERTCURVDIR)!=0) - cm.vert.EnableCurvatureDir(); - if((neededDataMask & MM_VERTRADIUS)!=0) - cm.vert.EnableRadius(); - if((neededDataMask & MM_VERTTEXCOORD)!=0) - cm.vert.EnableTexCoord(); + if((neededDataMask & MM_WEDGTEXCOORD)!=0) + cm.face.EnableWedgeTexCoord(); + if((neededDataMask & MM_FACECOLOR)!=0) + cm.face.EnableColor(); + if((neededDataMask & MM_FACEQUALITY)!=0) + cm.face.EnableQuality(); + if((neededDataMask & MM_FACECURVDIR)!=0) + cm.face.EnableCurvatureDir(); + if((neededDataMask & MM_FACEMARK)!=0) + cm.face.EnableMark(); + if((neededDataMask & MM_VERTMARK)!=0) + cm.vert.EnableMark(); + if((neededDataMask & MM_VERTCURV)!=0) + cm.vert.EnableCurvature(); + if((neededDataMask & MM_VERTCURVDIR)!=0) + cm.vert.EnableCurvatureDir(); + if((neededDataMask & MM_VERTRADIUS)!=0) + cm.vert.EnableRadius(); + if((neededDataMask & MM_VERTTEXCOORD)!=0) + cm.vert.EnableTexCoord(); - currentDataMask |= neededDataMask; + currentDataMask |= neededDataMask; } void MeshModel::clearDataMask(int unneededDataMask) { - if( ( (unneededDataMask & MM_VERTFACETOPO)!=0) && hasDataMask(MM_VERTFACETOPO)) {cm.face.DisableVFAdjacency(); - cm.vert.DisableVFAdjacency(); } - if( ( (unneededDataMask & MM_FACEFACETOPO)!=0) && hasDataMask(MM_FACEFACETOPO)) cm.face.DisableFFAdjacency(); + if( ( (unneededDataMask & MM_VERTFACETOPO)!=0) && hasDataMask(MM_VERTFACETOPO)) {cm.face.DisableVFAdjacency(); + cm.vert.DisableVFAdjacency(); } + if( ( (unneededDataMask & MM_FACEFACETOPO)!=0) && hasDataMask(MM_FACEFACETOPO)) cm.face.DisableFFAdjacency(); - if( ( (unneededDataMask & MM_WEDGTEXCOORD)!=0) && hasDataMask(MM_WEDGTEXCOORD)) cm.face.DisableWedgeTexCoord(); - if( ( (unneededDataMask & MM_FACECOLOR)!=0) && hasDataMask(MM_FACECOLOR)) cm.face.DisableColor(); - if( ( (unneededDataMask & MM_FACEQUALITY)!=0) && hasDataMask(MM_FACEQUALITY)) cm.face.DisableQuality(); - if( ( (unneededDataMask & MM_FACEMARK)!=0) && hasDataMask(MM_FACEMARK)) cm.face.DisableMark(); - if( ( (unneededDataMask & MM_VERTMARK)!=0) && hasDataMask(MM_VERTMARK)) cm.vert.DisableMark(); - if( ( (unneededDataMask & MM_VERTCURV)!=0) && hasDataMask(MM_VERTCURV)) cm.vert.DisableCurvature(); - if( ( (unneededDataMask & MM_VERTCURVDIR)!=0) && hasDataMask(MM_VERTCURVDIR)) cm.vert.DisableCurvatureDir(); - if( ( (unneededDataMask & MM_VERTRADIUS)!=0) && hasDataMask(MM_VERTRADIUS)) cm.vert.DisableRadius(); - if( ( (unneededDataMask & MM_VERTTEXCOORD)!=0) && hasDataMask(MM_VERTTEXCOORD)) cm.vert.DisableTexCoord(); + if( ( (unneededDataMask & MM_WEDGTEXCOORD)!=0) && hasDataMask(MM_WEDGTEXCOORD)) cm.face.DisableWedgeTexCoord(); + if( ( (unneededDataMask & MM_FACECOLOR)!=0) && hasDataMask(MM_FACECOLOR)) cm.face.DisableColor(); + if( ( (unneededDataMask & MM_FACEQUALITY)!=0) && hasDataMask(MM_FACEQUALITY)) cm.face.DisableQuality(); + if( ( (unneededDataMask & MM_FACEMARK)!=0) && hasDataMask(MM_FACEMARK)) cm.face.DisableMark(); + if( ( (unneededDataMask & MM_VERTMARK)!=0) && hasDataMask(MM_VERTMARK)) cm.vert.DisableMark(); + if( ( (unneededDataMask & MM_VERTCURV)!=0) && hasDataMask(MM_VERTCURV)) cm.vert.DisableCurvature(); + if( ( (unneededDataMask & MM_VERTCURVDIR)!=0) && hasDataMask(MM_VERTCURVDIR)) cm.vert.DisableCurvatureDir(); + if( ( (unneededDataMask & MM_VERTRADIUS)!=0) && hasDataMask(MM_VERTRADIUS)) cm.vert.DisableRadius(); + if( ( (unneededDataMask & MM_VERTTEXCOORD)!=0) && hasDataMask(MM_VERTTEXCOORD)) cm.vert.DisableTexCoord(); - currentDataMask = currentDataMask & (~unneededDataMask); + currentDataMask = currentDataMask & (~unneededDataMask); } -void MeshModel::Enable(int openingFileMask) +void MeshModel::enable(int openingFileMask) { - if( openingFileMask & tri::io::Mask::IOM_VERTTEXCOORD ) - updateDataMask(MM_VERTTEXCOORD); - if( openingFileMask & tri::io::Mask::IOM_WEDGTEXCOORD ) - updateDataMask(MM_WEDGTEXCOORD); - if( openingFileMask & tri::io::Mask::IOM_VERTCOLOR ) - updateDataMask(MM_VERTCOLOR); - if( openingFileMask & tri::io::Mask::IOM_FACECOLOR ) - updateDataMask(MM_FACECOLOR); - if( openingFileMask & tri::io::Mask::IOM_VERTRADIUS ) updateDataMask(MM_VERTRADIUS); - if( openingFileMask & tri::io::Mask::IOM_CAMERA ) updateDataMask(MM_CAMERA); - if( openingFileMask & tri::io::Mask::IOM_VERTQUALITY ) updateDataMask(MM_VERTQUALITY); - if( openingFileMask & tri::io::Mask::IOM_FACEQUALITY ) updateDataMask(MM_FACEQUALITY); - if( openingFileMask & tri::io::Mask::IOM_BITPOLYGONAL ) updateDataMask(MM_POLYGONAL); + if( openingFileMask & tri::io::Mask::IOM_VERTTEXCOORD ) + updateDataMask(MM_VERTTEXCOORD); + if( openingFileMask & tri::io::Mask::IOM_WEDGTEXCOORD ) + updateDataMask(MM_WEDGTEXCOORD); + if( openingFileMask & tri::io::Mask::IOM_VERTCOLOR ) + updateDataMask(MM_VERTCOLOR); + if( openingFileMask & tri::io::Mask::IOM_FACECOLOR ) + updateDataMask(MM_FACECOLOR); + if( openingFileMask & tri::io::Mask::IOM_VERTRADIUS ) updateDataMask(MM_VERTRADIUS); + if( openingFileMask & tri::io::Mask::IOM_CAMERA ) updateDataMask(MM_CAMERA); + if( openingFileMask & tri::io::Mask::IOM_VERTQUALITY ) updateDataMask(MM_VERTQUALITY); + if( openingFileMask & tri::io::Mask::IOM_FACEQUALITY ) updateDataMask(MM_FACEQUALITY); + if( openingFileMask & tri::io::Mask::IOM_BITPOLYGONAL ) updateDataMask(MM_POLYGONAL); } bool MeshModel::meshModified() const @@ -222,5 +354,5 @@ void MeshModel::setMeshModified(bool b) int MeshModel::dataMask() const { - return currentDataMask; + return currentDataMask; } diff --git a/src/common/ml_document/mesh_model.h b/src/common/ml_document/mesh_model.h index 4b223a613..d13c8f2e2 100644 --- a/src/common/ml_document/mesh_model.h +++ b/src/common/ml_document/mesh_model.h @@ -2,7 +2,7 @@ * MeshLab o o * * Visual and Computer Graphics Library o o * * _ O _ * -* Copyright(C) 2004-2020 \/)\/ * +* Copyright(C) 2004-2021 \/)\/ * * Visual Computing Lab /\/| * * ISTI - Italian National Research Council | * * \ * @@ -21,8 +21,8 @@ * * ****************************************************************************/ -#ifndef MESHMODEL_H -#define MESHMODEL_H +#ifndef MESH_MODEL_H +#define MESH_MODEL_H #include #include @@ -30,6 +30,9 @@ #include #include "cmesh.h" +#include "../GLLogStream.h" +#include "../filterscript.h" +#include "../ml_shared_data_context/ml_plugin_gl_context.h" #include #include @@ -40,11 +43,6 @@ #include #include - -//#include - - - #include #include #include @@ -56,10 +54,6 @@ #include #include #include -#include "../GLLogStream.h" -#include "../filterscript.h" -#include "../ml_shared_data_context/ml_plugin_gl_context.h" - /* MeshModel Class The base class for representing a single mesh. @@ -71,169 +65,149 @@ class MeshDocument; class MeshModel { public: - /* - This enum specify the various simplex components - It is used in various parts of the framework: - - to know what elements are currently active and therefore can be saved on a file - - to know what elements are required by a filter and therefore should be made ready before starting the filter (e.g. if a - - to know what elements are changed by a filter and therefore should be saved/restored in case of dynamic filters with a preview - */ - enum MeshElement{ - MM_NONE = 0x00000000, - MM_VERTCOORD = 0x00000001, - MM_VERTNORMAL = 0x00000002, - MM_VERTFLAG = 0x00000004, - MM_VERTCOLOR = 0x00000008, - MM_VERTQUALITY = 0x00000010, - MM_VERTMARK = 0x00000020, - MM_VERTFACETOPO = 0x00000040, - MM_VERTCURV = 0x00000080, - MM_VERTCURVDIR = 0x00000100, - MM_VERTRADIUS = 0x00000200, - MM_VERTTEXCOORD = 0x00000400, - MM_VERTNUMBER = 0x00000800, + /* + This enum specify the various simplex components + It is used in various parts of the framework: + - to know what elements are currently active and therefore can be saved on a file + - to know what elements are required by a filter and therefore should be made ready before starting the filter (e.g. if a + - to know what elements are changed by a filter and therefore should be saved/restored in case of dynamic filters with a preview + */ + enum MeshElement{ + MM_NONE = 0x00000000, + MM_VERTCOORD = 0x00000001, + MM_VERTNORMAL = 0x00000002, + MM_VERTFLAG = 0x00000004, + MM_VERTCOLOR = 0x00000008, + MM_VERTQUALITY = 0x00000010, + MM_VERTMARK = 0x00000020, + MM_VERTFACETOPO = 0x00000040, + MM_VERTCURV = 0x00000080, + MM_VERTCURVDIR = 0x00000100, + MM_VERTRADIUS = 0x00000200, + MM_VERTTEXCOORD = 0x00000400, + MM_VERTNUMBER = 0x00000800, - MM_FACEVERT = 0x00001000, - MM_FACENORMAL = 0x00002000, - MM_FACEFLAG = 0x00004000, - MM_FACECOLOR = 0x00008000, - MM_FACEQUALITY = 0x00010000, - MM_FACEMARK = 0x00020000, - MM_FACEFACETOPO = 0x00040000, - MM_FACENUMBER = 0x00080000, - MM_FACECURVDIR = 0x00100000, + MM_FACEVERT = 0x00001000, + MM_FACENORMAL = 0x00002000, + MM_FACEFLAG = 0x00004000, + MM_FACECOLOR = 0x00008000, + MM_FACEQUALITY = 0x00010000, + MM_FACEMARK = 0x00020000, + MM_FACEFACETOPO = 0x00040000, + MM_FACENUMBER = 0x00080000, + MM_FACECURVDIR = 0x00100000, - MM_WEDGTEXCOORD = 0x00200000, - MM_WEDGNORMAL = 0x00400000, - MM_WEDGCOLOR = 0x00800000, + MM_WEDGTEXCOORD = 0x00200000, + MM_WEDGNORMAL = 0x00400000, + MM_WEDGCOLOR = 0x00800000, - // Selection - MM_VERTFLAGSELECT = 0x01000000, - MM_FACEFLAGSELECT = 0x02000000, + // Selection + MM_VERTFLAGSELECT = 0x01000000, + MM_FACEFLAGSELECT = 0x02000000, - // Per Mesh Stuff.... - MM_CAMERA = 0x08000000, - MM_TRANSFMATRIX = 0x10000000, - MM_COLOR = 0x20000000, - MM_POLYGONAL = 0x40000000, + // Per Mesh Stuff.... + MM_CAMERA = 0x08000000, + MM_TRANSFMATRIX = 0x10000000, + MM_COLOR = 0x20000000, + MM_POLYGONAL = 0x40000000, // unknown - will raise exceptions, to be avoided, here just for compatibility - MM_UNKNOWN = 0x80000000, + MM_UNKNOWN = 0x80000000, // geometry change (for filters that remove stuff or modify geometry or topology, but not touch face/vertex color or face/vertex quality) - MM_GEOMETRY_AND_TOPOLOGY_CHANGE = 0x431e7be7, + MM_GEOMETRY_AND_TOPOLOGY_CHANGE = 0x431e7be7, // everything - dangerous, will add unwanted data to layer (e.g. if you use MM_ALL it could means that it could add even color or quality) - MM_ALL = 0xffffffff - }; + MM_ALL = 0xffffffff + }; - MeshModel(MeshDocument *parent, unsigned int id, const QString& fullFileName, const QString& labelName); - ~MeshModel() - { - } + MeshModel(unsigned int id, const QString& fullFileName, const QString& labelName); + ~MeshModel() + { + } - MeshDocument *parent; + void clear(); + void updateBoxAndNormals(); // This is the STANDARD method that you should call after changing coords. + inline unsigned int id() const {return _id;} - CMeshO cm; + int idInFile() const {return idInsideFile;} + void setIdInFile(int id) {idInsideFile = id;} + + // Some notes about the files and naming. + // Each mesh when shown in the layer dialog has a label. + // By default the label is just the name of the file, but the + + // in a future the path should be moved outside the meshmodel into the meshdocument (and assume that all the meshes resides in a common subtree) + // currently we just fix the interface and make the pathname private for avoiding future hassles. + + QString label() const { if(_label.isEmpty()) return shortName(); else return _label;} + + /// The whole full path name of the mesh + QString fullName() const {return fullPathFileName;} + + /// just the name of the file + QString shortName() const { return QFileInfo(fullPathFileName).fileName(); } + + /// the full path without the name of the file (e.g. the dir where the mesh and often its textures are) + QString pathName() const {QFileInfo fi(fullName()); return fi.absolutePath();} + + /// just the extension. + QString suffixName() const {QFileInfo fi(fullName()); return fi.suffix();} + + /// the relative path with respect to the current project + QString relativePathName(const QString& path) const; + + void setFileName(QString newFileName) { + QFileInfo fi(newFileName); + if(!fi.isAbsolute()) qWarning("Someone is trying to put a non relative filename"); + fullPathFileName = fi.absoluteFilePath(); + } + void setLabel(QString newName) {_label=newName;} + + bool visible; // used in rendering; Needed for toggling on and off the meshes + bool isVisible() const { return visible; } + + std::list loadTextures(GLLogStream* log = nullptr, vcg::CallBackPos* cb = nullptr); + void saveTextures(const QString& basePath, int quality = 66, GLLogStream* log = nullptr, vcg::CallBackPos* cb = nullptr); + + QImage getTexture(const std::string& tn) const; + void clearTextures(); + void addTexture(std::string name, const QImage& txt); + void setTexture(std::string name, const QImage& txt); + void changeTextureName(const std::string& oldName, std::string newName); + + // This function is roughly equivalent to the updateDataMask, + // but it takes in input a mask coming from a filetype instead of a filter requirement (like topology etc) + void enable(int openingFileMask); + + bool hasDataMask(const int maskToBeTested) const; + void updateDataMask(); + void updateDataMask(const MeshModel* m); + void updateDataMask(int neededDataMask); + void clearDataMask(int unneededDataMask); + int dataMask() const; + bool meshModified() const; + void setMeshModified(bool b = true); + static int io2mm(int single_iobit); - - /*vcg::GlTrimesh glw;*/ - - - - /* - Bitmask denoting what fields are currently used in the mesh - it is composed by MeshElement enums. - it should be changed by only mean the following functions: - - updateDataMask(neededStuff) - clearDataMask(no_needed_stuff) - hasDataMask(stuff) - - Note that if an element is active means that is also allocated - Some unactive elements (vertex color) are usually already allocated - other elements (FFAdj or curvature data) not necessarily. - - */ + CMeshO cm; private: - int currentDataMask; - QString fullPathFileName; - QString _label; - unsigned int _id; - bool modified; + int currentDataMask; + QString fullPathFileName; + QString _label; + unsigned int _id; + bool modified; //this is an id used for meshes that are loaded from files //that can store more than one mesh. For meshes loaded from //files containing just this mesh, this id will be -1. int idInsideFile; -public: - void Clear(); - void UpdateBoxAndNormals(); // This is the STANDARD method that you should call after changing coords. - inline int id() const {return _id;} - - int idInFile() const {return idInsideFile;} - void setIdInFile(int id) {idInsideFile = id;} - - - // Some notes about the files and naming. - // Each mesh when shown in the layer dialog has a label. - // By default the label is just the name of the file, but the - - // in a future the path should be moved outside the meshmodel into the meshdocument (and assume that all the meshes resides in a common subtree) - // currently we just fix the interface and make the pathname private for avoiding future hassles. - - QString label() const { if(_label.isEmpty()) return shortName(); else return _label;} - - /// The whole full path name of the mesh - QString fullName() const {return fullPathFileName;} - - /// just the name of the file - QString shortName() const { return QFileInfo(fullPathFileName).fileName(); } - - /// the full path without the name of the file (e.g. the dir where the mesh and often its textures are) - QString pathName() const {QFileInfo fi(fullName()); return fi.absolutePath();} - - /// just the extension. - QString suffixName() const {QFileInfo fi(fullName()); return fi.suffix();} - - /// the relative path with respect to the current project - QString relativePathName() const; - - /// the absolute path of the current project - QString documentPathName() const; - - void setFileName(QString newFileName) { - QFileInfo fi(newFileName); - if(!fi.isAbsolute()) qWarning("Someone is trying to put a non relative filename"); - fullPathFileName = fi.absoluteFilePath(); - } - void setLabel(QString newName) {_label=newName;} - - bool visible; // used in rendering; Needed for toggling on and off the meshes - bool isVisible() const { return visible; } - - // This function is roughly equivalent to the updateDataMask, - // but it takes in input a mask coming from a filetype instead of a filter requirement (like topology etc) - void Enable(int openingFileMask); - - bool hasDataMask(const int maskToBeTested) const; - void updateDataMask(MeshModel *m); - void updateDataMask(int neededDataMask); - void clearDataMask(int unneededDataMask); - int dataMask() const; - - - bool meshModified() const; - void setMeshModified(bool b = true); - static int io2mm(int single_iobit); + //textures associated to mesh + std::map textures; };// end class MeshModel - - - - #endif diff --git a/src/common/ml_document/render_raster.cpp b/src/common/ml_document/render_raster.cpp index 99de191f9..0f60ace4a 100644 --- a/src/common/ml_document/render_raster.cpp +++ b/src/common/ml_document/render_raster.cpp @@ -38,6 +38,16 @@ RasterPlane::RasterPlane(const QString& pathName, const int _semantic) image = QImage(pathName); } +RasterPlane::RasterPlane( + const QImage& img, + const QString& pathName, + const int _semantic) +{ + semantic =_semantic; + fullPathFileName = pathName; + image = img; +} + MeshLabRenderRaster::MeshLabRenderRaster() { diff --git a/src/common/ml_document/render_raster.h b/src/common/ml_document/render_raster.h index 9ab1cde26..a3a053ab6 100644 --- a/src/common/ml_document/render_raster.h +++ b/src/common/ml_document/render_raster.h @@ -58,7 +58,6 @@ public: int semantic; QString fullPathFileName; QImage image; - QImage thumb; float *buf; bool IsInCore() { return !image.isNull(); } @@ -72,6 +71,7 @@ public: RasterPlane(const RasterPlane& pl); RasterPlane(const QString& pathName, const int _semantic); + RasterPlane(const QImage& image, const QString& pathName, const int _semantic); }; //end class Plane diff --git a/src/common/ml_shared_data_context/ml_shared_data_context.cpp b/src/common/ml_shared_data_context/ml_shared_data_context.cpp index 23899066f..4710edc3f 100644 --- a/src/common/ml_shared_data_context/ml_shared_data_context.cpp +++ b/src/common/ml_shared_data_context/ml_shared_data_context.cpp @@ -134,11 +134,15 @@ void MLPoliciesStandAloneFunctions::maskMeaninglessAttributesPerPrimitiveModalit } } -void MLPoliciesStandAloneFunctions::updatedRendAttsAccordingToPriorities(const MLRenderingData::PRIMITIVE_MODALITY pm,const MLRenderingData::RendAtts& updated,const MLRenderingData::RendAtts& current,MLRenderingData::RendAtts& result) +void MLPoliciesStandAloneFunctions::updatedRendAttsAccordingToPriorities( + const MLRenderingData::PRIMITIVE_MODALITY pm, + const MLRenderingData::RendAtts& updated, //from the result of the filter + const MLRenderingData::RendAtts& current, //from the current model + MLRenderingData::RendAtts& result) //returned final result { - MLRenderingData::RendAtts filteredupdated = updated; - MLRenderingData::RendAtts tmp = current; - tmp[MLRenderingData::ATT_NAMES::ATT_VERTPOSITION] |= filteredupdated[MLRenderingData::ATT_NAMES::ATT_VERTPOSITION]; + MLRenderingData::RendAtts filteredupdated = updated; + MLRenderingData::RendAtts tmp = current; // tmp will be then saved in returned + tmp[MLRenderingData::ATT_NAMES::ATT_VERTPOSITION] |= filteredupdated[MLRenderingData::ATT_NAMES::ATT_VERTPOSITION]; if ((pm == MLRenderingData::PR_WIREFRAME_TRIANGLES) || (pm == MLRenderingData::PR_WIREFRAME_EDGES)) { tmp[MLRenderingData::ATT_NAMES::ATT_VERTNORMAL] = false; @@ -146,15 +150,17 @@ void MLPoliciesStandAloneFunctions::updatedRendAttsAccordingToPriorities(const M } else { + //vert normal shading if in current or in updated tmp[MLRenderingData::ATT_NAMES::ATT_VERTNORMAL] |= filteredupdated[MLRenderingData::ATT_NAMES::ATT_VERTNORMAL]; - tmp[MLRenderingData::ATT_NAMES::ATT_FACENORMAL] = (tmp[MLRenderingData::ATT_NAMES::ATT_FACENORMAL] || filteredupdated[MLRenderingData::ATT_NAMES::ATT_FACENORMAL]) && !(filteredupdated[MLRenderingData::ATT_NAMES::ATT_VERTNORMAL]); + //face normal shading if in current or in updated + tmp[MLRenderingData::ATT_NAMES::ATT_FACENORMAL] |= filteredupdated[MLRenderingData::ATT_NAMES::ATT_FACENORMAL]; } - + tmp[MLRenderingData::ATT_NAMES::ATT_VERTCOLOR] |= filteredupdated[MLRenderingData::ATT_NAMES::ATT_VERTCOLOR]; tmp[MLRenderingData::ATT_NAMES::ATT_FACECOLOR] = (tmp[MLRenderingData::ATT_NAMES::ATT_FACECOLOR] || filteredupdated[MLRenderingData::ATT_NAMES::ATT_FACECOLOR]) && !(filteredupdated[MLRenderingData::ATT_NAMES::ATT_VERTCOLOR]); - tmp[MLRenderingData::ATT_NAMES::ATT_WEDGETEXTURE] |= filteredupdated[MLRenderingData::ATT_NAMES::ATT_WEDGETEXTURE]; - tmp[MLRenderingData::ATT_NAMES::ATT_VERTTEXTURE] = (tmp[MLRenderingData::ATT_NAMES::ATT_VERTTEXTURE] || filteredupdated[MLRenderingData::ATT_NAMES::ATT_VERTTEXTURE]) && !(filteredupdated[MLRenderingData::ATT_NAMES::ATT_WEDGETEXTURE]); - result = tmp; + tmp[MLRenderingData::ATT_NAMES::ATT_WEDGETEXTURE] |= filteredupdated[MLRenderingData::ATT_NAMES::ATT_WEDGETEXTURE]; + tmp[MLRenderingData::ATT_NAMES::ATT_VERTTEXTURE] = (tmp[MLRenderingData::ATT_NAMES::ATT_VERTTEXTURE] || filteredupdated[MLRenderingData::ATT_NAMES::ATT_VERTTEXTURE]) && !(filteredupdated[MLRenderingData::ATT_NAMES::ATT_WEDGETEXTURE]); + result = tmp; } void MLPoliciesStandAloneFunctions::suggestedDefaultPerViewRenderingData(MeshModel* meshmodel,MLRenderingData& dtout, size_t minpolnumpersmoothshading) diff --git a/src/common/parameters/rich_parameter.cpp b/src/common/parameters/rich_parameter.cpp index 300fb6f35..0311d3d43 100644 --- a/src/common/parameters/rich_parameter.cpp +++ b/src/common/parameters/rich_parameter.cpp @@ -73,6 +73,11 @@ const QString& RichParameter::toolTip() const return tooltip; } +void RichParameter::setName(const QString& newName) +{ + pName = newName; +} + void RichParameter::setValue(const Value& ov) { assert(val->typeName() == ov.typeName()); @@ -572,39 +577,17 @@ bool RichSaveFile::operator==( const RichParameter& rb ) RichMesh::RichMesh( const QString& nm, - MeshModel* defval, - MeshDocument* doc, + unsigned int meshind, + const MeshDocument* doc, const QString& desc, const QString& tltip ): - RichParameter(nm, MeshValue(defval), desc, tltip), meshdoc(doc) + RichParameter(nm,MeshValue(meshind), desc, tltip), meshdoc(doc) { - meshindex = -1; - if (meshdoc != nullptr) - meshindex = meshdoc->meshList.indexOf(defval); - assert((meshindex != -1) || (meshdoc == nullptr)); } -RichMesh::RichMesh( - const QString& nm, - int meshind, - MeshDocument* doc, - const QString& desc, - const QString& tltip ): - RichParameter(nm,MeshValue(doc, meshind), desc, tltip), meshdoc(doc) +RichMesh::RichMesh(const QString& nm, unsigned int meshind, const QString& desc, const QString& tltip): + RichParameter(nm, MeshValue(meshind), desc, tltip), meshdoc(nullptr) { - assert(meshind < meshdoc->size() && meshind >= 0); - meshindex = meshind; - if (meshdoc != nullptr) - val = new MeshValue(meshdoc->meshList.at(meshindex)); - else - val = nullptr; -} - -RichMesh::RichMesh(const QString& nm, int meshind, const QString& desc, const QString& tltip): - RichParameter(nm, MeshValue(nullptr), desc, tltip) -{ - meshdoc = nullptr; - meshindex = meshind; } RichMesh::~RichMesh() @@ -619,7 +602,7 @@ QString RichMesh::stringType() const QDomElement RichMesh::fillToXMLDocument(QDomDocument& doc, bool saveDescriptionAndTooltip) const { QDomElement parElem = RichParameter::fillToXMLDocument(doc, saveDescriptionAndTooltip); - parElem.setAttribute("value", QString::number(meshindex)); + parElem.setAttribute("value", QString::number(val->getMeshId())); return parElem; } @@ -630,7 +613,7 @@ RichMesh* RichMesh::clone() const bool RichMesh::operator==( const RichParameter& rb ) { - return (rb.value().isMesh() &&(pName == rb.name()) && (value().getMesh() == rb.value().getMesh())); + return (rb.value().isMesh() &&(pName == rb.name()) && (value().getMeshId() == rb.value().getMeshId())); } /**** RichParameterAdapter Class ****/ diff --git a/src/common/parameters/rich_parameter.h b/src/common/parameters/rich_parameter.h index 82c2a5c79..f7daae81d 100644 --- a/src/common/parameters/rich_parameter.h +++ b/src/common/parameters/rich_parameter.h @@ -59,6 +59,7 @@ public: virtual QString stringType() const = 0; + void setName(const QString& newName); void setValue(const Value& ov); virtual QDomElement fillToXMLDocument(QDomDocument& doc, bool saveDescriptionAndTooltip = true) const; @@ -251,10 +252,9 @@ public: class RichMesh : public RichParameter { public: - RichMesh(const QString& nm, MeshModel* defval, MeshDocument* doc, const QString& desc = QString(), const QString& tltip = QString()); - RichMesh(const QString& nm, int meshindex, MeshDocument* doc, const QString& desc = QString(), const QString& tltip = QString()); + RichMesh(const QString& nm, unsigned int meshindex, const MeshDocument* doc, const QString& desc = QString(), const QString& tltip = QString()); //WARNING: IT SHOULD BE USED ONLY BY MESHLABSERVER!!!!!!! - RichMesh(const QString& nm, int meshind, const QString& desc = QString(), const QString& tltip = QString()); + RichMesh(const QString& nm, unsigned int meshind, const QString& desc = QString(), const QString& tltip = QString()); ~RichMesh(); QString stringType() const; @@ -262,8 +262,7 @@ public: RichMesh* clone() const; bool operator==(const RichParameter& rb); - MeshDocument* meshdoc; - int meshindex; + const MeshDocument* meshdoc; }; class RichParameterAdapter diff --git a/src/common/parameters/rich_parameter_list.cpp b/src/common/parameters/rich_parameter_list.cpp index 6535ef00e..9f13ae2f2 100644 --- a/src/common/parameters/rich_parameter_list.cpp +++ b/src/common/parameters/rich_parameter_list.cpp @@ -24,6 +24,7 @@ #include "rich_parameter_list.h" #include "../mlexception.h" +#include "../ml_document/mesh_document.h" #include #include @@ -194,9 +195,9 @@ int RichParameterList::getEnum(const QString& name) const * @return the mesh of the RichParameter having the given name. * @throws an MLException if the name is not found in the list */ -MeshModel * RichParameterList::getMesh(const QString& name) const +unsigned int RichParameterList::getMeshId(const QString& name) const { - return getParameterByName(name).value().getMesh(); + return getParameterByName(name).value().getMeshId(); } /** diff --git a/src/common/parameters/rich_parameter_list.h b/src/common/parameters/rich_parameter_list.h index 5c5763e83..7b49f21d3 100644 --- a/src/common/parameters/rich_parameter_list.h +++ b/src/common/parameters/rich_parameter_list.h @@ -108,7 +108,7 @@ public: vcg::Color4b getColor4b(const QString& name) const; Scalarm getAbsPerc(const QString& name) const; int getEnum(const QString& name) const; - MeshModel* getMesh(const QString& name) const; + unsigned int getMeshId(const QString& name) const; Scalarm getDynamicFloat(const QString& name) const; QString getOpenFileName(const QString& name) const; QString getSaveFileName(const QString& name) const; diff --git a/src/common/parameters/value.cpp b/src/common/parameters/value.cpp index 5becc2381..efaeeaee5 100644 --- a/src/common/parameters/value.cpp +++ b/src/common/parameters/value.cpp @@ -31,14 +31,6 @@ void BoolValue::fillToXMLElement(QDomElement& element) const element.setAttribute("value", v); } -MeshValue::MeshValue(MeshDocument* doc, int meshind) -{ - if (doc != nullptr) - pval = doc->meshList.at(meshind); - else - pval = nullptr; -} - void IntValue::fillToXMLElement(QDomElement& element) const { element.setAttribute("value", QString::number(pval)); diff --git a/src/common/parameters/value.h b/src/common/parameters/value.h index 03cc65fad..23acb0296 100644 --- a/src/common/parameters/value.h +++ b/src/common/parameters/value.h @@ -53,7 +53,7 @@ public: virtual QColor getColor() const { assert(0); return QColor(); } virtual Scalarm getAbsPerc() const { assert(0); return Scalarm(); } virtual int getEnum() const { assert(0); return int(); } - virtual MeshModel* getMesh() const { assert(0); return NULL; } + virtual unsigned int getMeshId() const { assert(0); return 0; } virtual Scalarm getDynamicFloat() const { assert(0); return Scalarm(); } virtual QString getFileName() const { assert(0); return QString(); } @@ -275,19 +275,18 @@ private: class MeshValue : public Value { public: - MeshValue(MeshModel* mesh) : pval(mesh) {} - MeshValue(MeshDocument* doc, int meshind); + MeshValue(unsigned int meshind) : pval(meshind) {}; ~MeshValue() {} - inline MeshModel* getMesh() const { return pval; } + inline unsigned int getMeshId() const { return pval; } inline bool isMesh() const { return true; } inline QString typeName() const { return QString("Mesh"); } - inline void set(const Value& p) { pval = p.getMesh(); } + inline void set(const Value& p) { pval = p.getMeshId(); } inline MeshValue* clone() const {return new MeshValue(*this);} void fillToXMLElement(QDomElement& element) const; private: - MeshModel* pval; + unsigned int pval; }; #endif //MESHLAB_VALUE_H diff --git a/src/common/plugins/containers/decorate_plugin_container.cpp b/src/common/plugins/containers/decorate_plugin_container.cpp index bd4fffe90..2689ef77c 100644 --- a/src/common/plugins/containers/decorate_plugin_container.cpp +++ b/src/common/plugins/containers/decorate_plugin_container.cpp @@ -35,9 +35,6 @@ void DecoratePluginContainer::clear() void DecoratePluginContainer::pushDecoratePlugin(DecoratePlugin* iDecorate) { decoratePlugins.push_back(iDecorate); - for(QAction *decoratorAction : iDecorate->actions()) { - iDecorate->initGlobalParameterList(decoratorAction, meshlab::defaultGlobalParameterList()); - } } void DecoratePluginContainer::eraseDecoratePlugin(DecoratePlugin* iDecorate) diff --git a/src/common/plugins/containers/io_plugin_container.cpp b/src/common/plugins/containers/io_plugin_container.cpp index b62aaff11..f320b7181 100644 --- a/src/common/plugins/containers/io_plugin_container.cpp +++ b/src/common/plugins/containers/io_plugin_container.cpp @@ -14,7 +14,7 @@ void IOPluginContainer::clear() ioPlugins.clear(); inputMeshFormatToPluginMap.clear(); outputMeshFormatToPluginMap.clear(); - inputRasterFormatToPluginMap.clear(); + inputImageFormatToPluginMap.clear(); } void IOPluginContainer::pushIOPlugin(IOPlugin* iIO) @@ -39,11 +39,38 @@ void IOPluginContainer::pushIOPlugin(IOPlugin* iIO) } } - //add input raster formats to inputFormatMap - for (const FileFormat& ff : iIO->importRasterFormats()){ + //add input image formats to inputFormatMap + for (const FileFormat& ff : iIO->importImageFormats()){ for (const QString& currentExtension : ff.extensions) { - if (! inputRasterFormatToPluginMap.contains(currentExtension.toLower())) { - inputRasterFormatToPluginMap.insert(currentExtension.toLower(), iIO); + if (! inputImageFormatToPluginMap.contains(currentExtension.toLower())) { + inputImageFormatToPluginMap.insert(currentExtension.toLower(), iIO); + } + } + } + + //add output image formats to inputFormatMap + for (const FileFormat& ff : iIO->exportImageFormats()){ + for (const QString& currentExtension : ff.extensions) { + if (! outputImageFormatToPluginMap.contains(currentExtension.toLower())) { + outputImageFormatToPluginMap.insert(currentExtension.toLower(), iIO); + } + } + } + + //add input project formats to inputFormatMap + for (const FileFormat& ff : iIO->importProjectFormats()){ + for (const QString& currentExtension : ff.extensions) { + if (! inputProjectFormatToPluginMap.contains(currentExtension.toLower())) { + inputProjectFormatToPluginMap.insert(currentExtension.toLower(), iIO); + } + } + } + + //add output project formats to inputFormatMap + for (const FileFormat& ff : iIO->exportProjectFormats()){ + for (const QString& currentExtension : ff.extensions) { + if (! outputProjectFormatToPluginMap.contains(currentExtension.toLower())) { + outputProjectFormatToPluginMap.insert(currentExtension.toLower(), iIO); } } } @@ -62,9 +89,9 @@ void IOPluginContainer::eraseIOPlugin(IOPlugin* iIO) outputMeshFormatToPluginMap.remove(currentExtension.toLower()); } } - for (const FileFormat& ff : iIO->importRasterFormats()){ + for (const FileFormat& ff : iIO->importImageFormats()){ for (const QString& currentExtension : ff.extensions) { - inputRasterFormatToPluginMap.remove(currentExtension.toLower()); + inputImageFormatToPluginMap.remove(currentExtension.toLower()); } } } @@ -79,9 +106,24 @@ bool IOPluginContainer::isOutputMeshFormatSupported(const QString& outputFormat) return outputMeshFormatToPluginMap.find(outputFormat.toLower()) != outputMeshFormatToPluginMap.end(); } -bool IOPluginContainer::isInputRasterFormatSupported(const QString& inputFormat) const +bool IOPluginContainer::isInputImageFormatSupported(const QString& inputFormat) const { - return inputRasterFormatToPluginMap.find(inputFormat.toLower()) != inputRasterFormatToPluginMap.end(); + return inputImageFormatToPluginMap.find(inputFormat.toLower()) != inputImageFormatToPluginMap.end(); +} + +bool IOPluginContainer::isOutputImageFormatSupported(const QString& outputFormat) const +{ + return outputImageFormatToPluginMap.find(outputFormat.toLower()) != outputImageFormatToPluginMap.end(); +} + +bool IOPluginContainer::isInputProjectFormatSupported(const QString& inputFormat) const +{ + return inputProjectFormatToPluginMap.find(inputFormat.toLower()) != inputProjectFormatToPluginMap.end(); +} + +bool IOPluginContainer::isOutputProjectFormatSupported(const QString& outputFormat) const +{ + return outputImageFormatToPluginMap.find(outputFormat.toLower()) != outputProjectFormatToPluginMap.end(); } IOPlugin* IOPluginContainer::inputMeshPlugin(const QString& inputFormat) const @@ -100,10 +142,34 @@ IOPlugin* IOPluginContainer::outputMeshPlugin(const QString& outputFormat) const return nullptr; } -IOPlugin* IOPluginContainer::inputRasterPlugin(const QString& inputFormat) const +IOPlugin* IOPluginContainer::inputImagePlugin(const QString& inputFormat) const { - auto it = inputRasterFormatToPluginMap.find(inputFormat.toLower()); - if (it != inputRasterFormatToPluginMap.end()) + auto it = inputImageFormatToPluginMap.find(inputFormat.toLower()); + if (it != inputImageFormatToPluginMap.end()) + return *it; + return nullptr; +} + +IOPlugin* IOPluginContainer::outputImagePlugin(const QString& outputFormat) const +{ + auto it = outputImageFormatToPluginMap.find(outputFormat.toLower()); + if (it != outputImageFormatToPluginMap.end()) + return *it; + return nullptr; +} + +IOPlugin* IOPluginContainer::inputProjectPlugin(const QString& inputFormat) const +{ + auto it = inputProjectFormatToPluginMap.find(inputFormat.toLower()); + if (it != inputProjectFormatToPluginMap.end()) + return *it; + return nullptr; +} + +IOPlugin* IOPluginContainer::outputProjectPlugin(const QString& outputFormat) const +{ + auto it = outputProjectFormatToPluginMap.find(outputFormat.toLower()); + if (it != outputProjectFormatToPluginMap.end()) return *it; return nullptr; } @@ -118,9 +184,24 @@ QStringList IOPluginContainer::outputMeshFormatList() const return outputMeshFormatToPluginMap.keys(); } -QStringList IOPluginContainer::inputRasterFormatList() const +QStringList IOPluginContainer::inputImageFormatList() const { - return inputRasterFormatToPluginMap.keys(); + return inputImageFormatToPluginMap.keys(); +} + +QStringList IOPluginContainer::outputImageFormatList() const +{ + return outputImageFormatToPluginMap.keys(); +} + +QStringList IOPluginContainer::inputProjectFormatList() const +{ + return inputProjectFormatToPluginMap.keys(); +} + +QStringList IOPluginContainer::outputProjectFormatList() const +{ + return outputProjectFormatToPluginMap.keys(); } IOPluginContainer::IOPluginRangeIterator IOPluginContainer::ioPluginIterator(bool iterateAlsoDisabledPlugins) const diff --git a/src/common/plugins/containers/io_plugin_container.h b/src/common/plugins/containers/io_plugin_container.h index 8c6ee71fe..d9266a429 100644 --- a/src/common/plugins/containers/io_plugin_container.h +++ b/src/common/plugins/containers/io_plugin_container.h @@ -47,14 +47,24 @@ public: bool isInputMeshFormatSupported(const QString& inputFormat) const; bool isOutputMeshFormatSupported(const QString& outputFormat) const; - bool isInputRasterFormatSupported(const QString& inputFormat) const; + bool isInputImageFormatSupported(const QString& inputFormat) const; + bool isOutputImageFormatSupported(const QString& outputFormat) const; + bool isInputProjectFormatSupported(const QString& inputFormat) const; + bool isOutputProjectFormatSupported(const QString& outputFormat) const; IOPlugin* inputMeshPlugin(const QString& inputFormat) const; IOPlugin* outputMeshPlugin(const QString& outputFormat) const; - IOPlugin* inputRasterPlugin(const QString& inputFormat) const; + IOPlugin* inputImagePlugin(const QString& inputFormat) const; + IOPlugin* outputImagePlugin(const QString& outputFormat) const; + IOPlugin* inputProjectPlugin(const QString& inputFormat) const; + IOPlugin* outputProjectPlugin(const QString& outputFormat) const; + QStringList inputMeshFormatList() const; QStringList outputMeshFormatList() const; - QStringList inputRasterFormatList() const; + QStringList inputImageFormatList() const; + QStringList outputImageFormatList() const; + QStringList inputProjectFormatList() const; + QStringList outputProjectFormatList() const; IOPluginRangeIterator ioPluginIterator(bool iterateAlsoDisabledPlugins = false) const; @@ -62,7 +72,10 @@ private: std::vector ioPlugins; QMap inputMeshFormatToPluginMap; QMap outputMeshFormatToPluginMap; - QMap inputRasterFormatToPluginMap; + QMap inputImageFormatToPluginMap; + QMap outputImageFormatToPluginMap; + QMap inputProjectFormatToPluginMap; + QMap outputProjectFormatToPluginMap; }; class IOPluginContainer::IOPluginRangeIterator diff --git a/src/common/plugins/interfaces/filter_plugin.h b/src/common/plugins/interfaces/filter_plugin.h index 6e99b4d71..7adfe92f5 100644 --- a/src/common/plugins/interfaces/filter_plugin.h +++ b/src/common/plugins/interfaces/filter_plugin.h @@ -98,7 +98,8 @@ public: * This string is printed in the top of the parameter window * so it should be at least one or two paragraphs long. The more the better. * you can use simple html formatting tags (like "
" "" and "") to improve readability. - * This string is used in the 'About plugin' dialog and by meshlabserver to create the filter list wiki page and the doxygen documentation of the filters. + * This string is used in the 'About plugin' dialog and by pymeshlab to create + * the filter list documentation page of the filters. * Here is the place where you should put you bibliographic references in a form like this: *
* See:
@@ -128,7 +129,7 @@ public: * to MeshModel::updateDataMask(...) */ virtual int getRequirements(const QAction*) { return MeshModel::MM_NONE; } - + /** * @brief This function should require true if the glContext is used by the * filter. Without this, the glContext will remain set to nullptr on non-GUI @@ -156,6 +157,23 @@ public: */ virtual int postCondition(const QAction*) const { return MeshModel::MM_ALL; } + /** + * @brief This function is called to initialized the list of parameters. + * If a filter does not need parameters, do not implement this function and + * the framework will not create a dialog (unless for previewing). + * You can implement the one which takes the MeshModel or the one that + * takes the MeshDocument, depending of your needings, but do not re-implement + * both the functions. + */ + virtual RichParameterList initParameterList(const QAction*, const MeshModel &/*m*/) + { + return RichParameterList(); + } + virtual RichParameterList initParameterList(const QAction* filter, const MeshDocument &md) + { + return initParameterList(filter, *(md.mm())); + } + /** * @brief applies the selected filter with the already stabilished parameters * This function is called by the framework after getting values for the parameters specified in the \ref initParameterList @@ -198,17 +216,6 @@ public: */ virtual FilterArity filterArity(const QAction *act) const = 0; - /** - * @brief This function is called to initialized the list of parameters. - * it is always called. If a filter does not need parameter it leave it empty and the framework - * will not create a dialog (unless for previewing) - */ - virtual void initParameterList(const QAction*, MeshModel &/*m*/, RichParameterList & /*par*/) {} - virtual void initParameterList(const QAction* filter, MeshDocument &md, RichParameterList &par) - { - initParameterList(filter, *(md.mm()), par); - } - virtual QString filterInfo(const QAction* a) const { return this->filterInfo(ID(a)); } virtual QString filterName(const QAction* a) const { return this->filterName(ID(a)); } virtual QString pythonFilterName(const QAction* a) const {return this->pythonFilterName(ID(a)); } diff --git a/src/common/plugins/interfaces/io_plugin.cpp b/src/common/plugins/interfaces/io_plugin.cpp index 6782b0baf..416d9e951 100644 --- a/src/common/plugins/interfaces/io_plugin.cpp +++ b/src/common/plugins/interfaces/io_plugin.cpp @@ -3,21 +3,12 @@ unsigned int IOPlugin::numberMeshesContainedInFile( const QString&, - const QString&) const + const QString&, + const RichParameterList&) const { return 1; } -void IOPlugin::initOpenParameter(const QString& format, const std::list& ml, RichParameterList& params) -{ - initOpenParameter(format, *ml.front(), params); -} - -void IOPlugin::applyOpenParameter(const QString& format, const std::list& ml, const RichParameterList& params) -{ - applyOpenParameter(format, *ml.front(), params); -} - void IOPlugin::open( const QString& format, const QString& fileName, diff --git a/src/common/plugins/interfaces/io_plugin.h b/src/common/plugins/interfaces/io_plugin.h index 974582ccf..695544306 100644 --- a/src/common/plugins/interfaces/io_plugin.h +++ b/src/common/plugins/interfaces/io_plugin.h @@ -31,8 +31,27 @@ #include "../../utilities/file_format.h" #include "../../ml_document/raster_model.h" +class MLRenderingData; + /** - * @brief The IOPlugin is the base class for all the single mesh loading plugins. + * @brief The IOPlugin is the base class for meshes, images and projects loading + * and saving. + * + * Provides the base functions to open: + * - a mesh file (open); + * - a project file (openProject); + * - an image file (openImage); + * + * and the base functions to save: + * - a mesh file (save); + * - a project file (saveProject); + * - an image file (saveImage); + * + * You can tell which formats your plugin will be able to open or save by + * re-implementing the following functions + * - importFormats() + * - exportFormats() + * where can be [todo] Mesh, Image or Project. */ class IOPlugin : virtual public MeshLabPlugin, virtual public MeshLabPluginLogger { @@ -40,6 +59,10 @@ public: IOPlugin() : MeshLabPluginLogger() { } virtual ~IOPlugin() { } + /*********************** + * Open Mesh Functions * + ***********************/ + /** * @brief The importFormats function returns a list of all the * input file formats supported by the plugin. @@ -49,28 +72,9 @@ public: */ virtual std::list importFormats() const = 0; - /** - * @brief The exportFormats function returns a list of all the - * output file formats supported by the plugin. - * This function must be implemented on any IO plugin. - * If yout plugin does not export any mesh format, just return an - * empty list. - */ - virtual std::list exportFormats() const = 0; - - /** - * @brief If yout plugin supports loading also raster formats, re-implement - * this function, returning the list of raster formats supported by - * your openRaster function. - */ - virtual std::list importRasterFormats() const - { - return std::list(); - } - /** * @brief The initPreOpenParameter function is called to initialize the list - * of additional parameters that a OPENING filter could require. It is + * of additional parameters that opening a mesh format could require. It is * called by the framework BEFORE the actual mesh loading to determine how * to parse the input file. The instanced parameters are then passed to the * open at the loading time. @@ -78,78 +82,12 @@ public: * load. If you do not need any additional processing simply do not override * this and ignore the parameterList in the open member function */ - virtual void initPreOpenParameter( - const QString& /*format*/, - RichParameterList& /*parameters*/) + virtual RichParameterList initPreOpenParameter( + const QString& /*format*/) const { + return RichParameterList(); } - virtual void initOpenParameter( - const QString& /*format*/, - const std::list& /*m*/, - RichParameterList& /*parameters*/); - - /** - * @brief The initOpenParameter function is called to initialize the list - * of additional parameters that a OPENING filter could require. - * It is called by the framework AFTER the mesh is already loaded to - * perform more or less standard processing on the mesh. - * typical example: unifying vertices in stl models. - * If you do not need any additional processing do nothing. - */ - virtual void initOpenParameter( - const QString& /*format*/, - MeshModel& /*m*/, - RichParameterList& /*parameters*/) - { - } - - virtual void applyOpenParameter( - const QString& /*format*/, - const std::list& /*m*/, - const RichParameterList& /*parameters*/); - - /** - * @brief The applyOpenParameter function is the corrispondent function to - * the initOpenParameter. It is called after the mesh is loaded, - * and it should apply the given parameters to the loaded mesh. - * If you haven't implemented the initOpenParameter member function, - * you do not need to implement this. - */ - virtual void applyOpenParameter( - const QString& /*format*/, - MeshModel& /*m*/, - const RichParameterList& /*parameters*/) - { - } - - /** - * @brief The initSaveParameter function is called to initialize the list - * of additional parameters that a SAVING filter could require. It is called - * by the framework after the output format is selected by the user. - * typical example: ascii or binary format for ply or stl - * If you do not need any additional parameters, simply do not implement - * this function. - */ - virtual void initSaveParameter( - const QString& /*format*/, - const MeshModel& /*m*/, - RichParameterList& /*par*/) - { - } - - /** - * @brief The exportMaskCapability function tells to the framework which - * export capabilities are supported by the given format (e.g. if the format - * supports saving face colors, vertex quality...). - * It also tells to the framework which of these export capabilities are - * set by default. - */ - virtual void exportMaskCapability( - const QString &format, - int& capability, - int& defaultBits) const = 0; - /** * @brief this function returns the number of meshes that the open function * is going to load from the file given as parameter. Default value is 1. @@ -171,7 +109,8 @@ public: */ virtual unsigned int numberMeshesContainedInFile( const QString& format, - const QString& fileName) const; + const QString& fileName, + const RichParameterList& preParams) const; /** * @brief The open function is called by the framework everytime a mesh is @@ -195,12 +134,12 @@ public: * @param cb: standard callback for reporting progress in the loading */ virtual void open( - const QString &format, - const QString &fileName, - const std::list& meshModelList, - std::list& maskList, - const RichParameterList & par, - vcg::CallBackPos *cb = nullptr); + const QString &format, + const QString &fileName, + const std::list& meshModelList, + std::list& maskList, + const RichParameterList & par, + vcg::CallBackPos *cb = nullptr); /** * @brief The open function is called by the framework everytime a mesh is @@ -218,12 +157,52 @@ public: * @param cb: standard callback for reporting progress in the loading */ virtual void open( - const QString &format, - const QString &fileName, - MeshModel &m, - int &mask, - const RichParameterList & par, - vcg::CallBackPos *cb = nullptr) = 0; + const QString &format, + const QString &fileName, + MeshModel &m, + int &mask, + const RichParameterList & par, + vcg::CallBackPos *cb = nullptr) = 0; + + /*********************** + * Save Mesh Functions * + ***********************/ + + /** + * @brief The exportFormats function returns a list of all the + * output file formats supported by the plugin. + * This function must be implemented on any IO plugin. + * If yout plugin does not export any mesh format, just return an + * empty list. + */ + virtual std::list exportFormats() const = 0; + + /** + * @brief The exportMaskCapability function tells to the framework which + * export capabilities are supported by the given format (e.g. if the format + * supports saving face colors, vertex quality...). + * It also tells to the framework which of these export capabilities are + * set by default. + */ + virtual void exportMaskCapability( + const QString &format, + int& capability, + int& defaultBits) const = 0; + + /** + * @brief The initSaveParameter function is called to initialize the list + * of additional parameters that saving a mesh could require. It is called + * by the framework after the output format is selected by the user. + * typical example: ascii or binary format for ply or stl + * If you do not need any additional parameters, simply do not implement + * this function. + */ + virtual RichParameterList initSaveParameter( + const QString& /*format*/, + const MeshModel& /*m*/) const + { + return RichParameterList(); + } /** * @brief The save function is called by the framework everytime a mesh is @@ -239,27 +218,188 @@ public: * @param cb: standard callback for reporting progress in the saving */ virtual void save( - const QString &format, - const QString &fileName, - MeshModel &m, /** NOTE: this is going to be const MeshModel&: try to use only const functions!! **/ - const int mask, - const RichParameterList & par, - vcg::CallBackPos *cb) = 0; + const QString &format, + const QString &fileName, + MeshModel &m, /** NOTE: this is going to be const MeshModel&: try to use only const functions!! **/ + const int mask, + const RichParameterList & par, + vcg::CallBackPos* cb = nullptr) = 0; + + /************************ + * Open Image Functions * + ************************/ /** - * @brief If your plugin supports raster formats, re-implement this - * function. - * @param format: the extension of the format e.g. "JPG" - * @param filename: the name of the file to be opened (including its path) - * @param rm: the raster model on which save the loaded raster - * @param cb: standard callback for reporting progress while opening + * @brief If your plugin supports loading also images, re-implement + * this function, returning the list of image formats supported by + * your openImage function. */ - virtual void openRaster( - const QString& /*format*/, + virtual std::list importImageFormats() const + { + return std::list(); + } + + /** + * @brief The openImage function is called by the framework everytime an image + * needs to be loaded. Could be called when loading textures or rasters. + * @param format: the extension of the format, e.g. "PNG" + * @param fileName: the name of the file from which load the image (including its path) + * @param cb: standard callback for reporting progresso in the loading + * @return the loaded QImage + */ + virtual QImage openImage( + const QString& format, const QString& /*fileName*/, - RasterModel& /*rm*/, vcg::CallBackPos* /*cb*/ = nullptr) - {}; + { + wrongOpenFormat(format); + return QImage(); + }; + + /************************ + * Save Image Functions * + ************************/ + + /** + * @brief If your plugin supports saving also images, re-implement + * this function, returning the list of image formats supported by + * your saveImage function. + */ + virtual std::list exportImageFormats() const + { + return std::list(); + } + + /** + * @brief The saveImage function is called by the framework everytime an image + * needs to be saved (e.g. when saving a texture). + * @param format: the extension of the format, e.g. "PNG" + * @param fileName: the name of the file on which save the image (including its path) + * @param image: the image to save in the given fileName + * @param cb: standard callback for reporting progresso in the loading + */ + virtual void saveImage( + const QString& format, + const QString& /*fileName*/, + const QImage& /*image*/, + int /*quality*/ = 66, + vcg::CallBackPos* /*cb*/ = nullptr) + { + wrongSaveFormat(format); + } + + /************************** + * Open Project Functions * + **************************/ + + /** + * @brief If your plugin supports loading also projects, re-implement + * this function, returning the list of project formats supported by + * your openProject function. + */ + virtual std::list importProjectFormats() const + { + return std::list(); + } + + /** + * @brief some project file formats require the load of more than one file + * (e.g. bundler.out requires also a txt containing raster infos). + * + * If this is your case, you should implement this returning a list of + * *FileFormats* for each additional file that should be loaded. + * Then, the framework will ask the user to select the additional required + * files. Leaving the returned list empty means that the format of the + * project does not need additional files to be loaded. + * + * The list of files will then passed to the user in the openProject. + * + * @return + */ + virtual std::list projectFileRequiresAdditionalFiles( + const QString& /*format*/, + const QString& /*filename*/) + { + return std::list(); + }; + + /** + * @brief The openProject function is called by the framework everytime a + * project needs to be loaded. + * + * The function takes an list of filenames because some project files + * are composed by more than one file. In this specific case, you should + * re-implement the function projectFileRequiresAdditionalFiles. + * The number of filenames contained in the input list will be + * 1 + number of elements in the list returned by the function + * projectFileRequiresAdditionalFiles (default: 0). + * + * If the meshes contained in the project are saved in separate files and not + * into the project, you should use the functions provided into the file + * "common/utilities/load_save.h". These functions will take care to load + * a mesh with any of the formats supported by meshlab. + * + * @param format: the extension of the format, e.g. "MLP" + * @param fileName: the name of the file from which load the project (including its path) + * @param md: MeshDocument on which store the content of the loaded project + * note: the document could not be empty! + * @param rendOpt: rendering options that may be loaded from the project file, + * if it supports them. They are not required. If you can support + * rendering options, the rendOpt vector must have the same size of + * the MeshModel vector returned by the openProject function. + * @param cb: standard callback for reporting progresso in the loading + * @return the list of MeshModel that have been loaded from the given project + */ + virtual std::vector openProject( + const QString& format, + const QStringList& /*filenames*/, + MeshDocument& /*md*/, + std::vector& /*rendOpt*/, + vcg::CallBackPos* /*cb*/ = nullptr) + { + wrongOpenFormat(format); + return std::vector(); + } + + /************************** + * Save Project Functions * + **************************/ + + /** + * @brief If your plugin supports saving also projects, re-implement + * this function, returning the list of project formats supported by + * your saveProject function. + */ + virtual std::list exportProjectFormats() const + { + return std::list(); + } + + /** + * @brief The saveProject function is called by the framework everytime a + * project is saved. + * @param format: the extension of the format e.g. "MLP" + * @param fileName: the name of the file on which save the project md + * (including its path) + * @param md: the MeshDocument to be saved in the file + * @param onlyVisibleMesh: if this parameter is set to true, only the meshes + * marked visible should be saved into the project + * @param cb: standard callback for reporting progress in the saving + */ + virtual void saveProject( + const QString& format, + const QString& /*fileName*/, + const MeshDocument& /*md*/, + bool /*onlyVisibleMeshes*/, + const std::vector& /*rendOpt*/, + vcg::CallBackPos* /*cb*/ = nullptr) + { + wrongSaveFormat(format); + } + + /*************************** + * Other utility Functions * + ***************************/ /** * @brief The reportWarning function should be used everytime that a @@ -287,14 +427,13 @@ public: /** * @brief The warningMessageString is invoked by the framework after the - * execution of load/save function. It returns the warning string containing + * execution of load/save functions. It returns the warning string containing * all the warinings produced by the function, and it clears the string. */ QString warningMessageString() const; private: mutable QString warnString; - }; #define IO_PLUGIN_IID "vcg.meshlab.IOPlugin/1.0" diff --git a/src/common/plugins/plugin_manager.cpp b/src/common/plugins/plugin_manager.cpp index 9d5fc9a6c..3d2aa08c5 100644 --- a/src/common/plugins/plugin_manager.cpp +++ b/src/common/plugins/plugin_manager.cpp @@ -29,7 +29,6 @@ #include -#include "meshlab_plugin_type.h" #include "../mlexception.h" #include "../globals.h" @@ -68,7 +67,7 @@ PluginManager::~PluginManager() * * Throws a MLException if the file is not a valid MeshLab plugin. */ -void PluginManager::checkPlugin(const QString& filename) +MeshLabPluginType PluginManager::checkPlugin(const QString& filename) { QFileInfo fin(filename); if (!fin.exists()){ @@ -126,6 +125,7 @@ void PluginManager::checkPlugin(const QString& filename) } loader.unload(); + return type; } /** @@ -184,7 +184,7 @@ void PluginManager::loadPlugins(QDir pluginsDirectory) * * Throws a MLException if the load of the plugin fails. */ -void PluginManager::loadPlugin(const QString& fileName) +MeshLabPlugin* PluginManager::loadPlugin(const QString& fileName) { QFileInfo fin(fileName); if (pluginFiles.find(fin.absoluteFilePath()) != pluginFiles.end()) @@ -220,6 +220,7 @@ void PluginManager::loadPlugin(const QString& fileName) allPlugins.push_back(ifp); allPluginLoaders.push_back(loader); pluginFiles.insert(fin.absoluteFilePath()); + return ifp; } void PluginManager::unloadPlugin(MeshLabPlugin* ifp) @@ -300,9 +301,24 @@ IOPlugin* PluginManager::outputMeshPlugin(const QString& outputFormat) const return ioPlugins.outputMeshPlugin(outputFormat); } -IOPlugin* PluginManager::inputRasterPlugin(const QString inputFormat) const +IOPlugin* PluginManager::inputImagePlugin(const QString inputFormat) const { - return ioPlugins.inputRasterPlugin(inputFormat); + return ioPlugins.inputImagePlugin(inputFormat); +} + +IOPlugin* PluginManager::outputImagePlugin(const QString& outputFormat) const +{ + return ioPlugins.outputImagePlugin(outputFormat); +} + +IOPlugin* PluginManager::inputProjectPlugin(const QString& inputFormat) const +{ + return ioPlugins.inputProjectPlugin(inputFormat); +} + +IOPlugin* PluginManager::outputProjectPlugin(const QString& outputFormat) const +{ + return ioPlugins.outputProjectPlugin(outputFormat); } bool PluginManager::isInputMeshFormatSupported(const QString inputFormat) const @@ -315,9 +331,24 @@ bool PluginManager::isOutputMeshFormatSupported(const QString outputFormat) cons return ioPlugins.isOutputMeshFormatSupported(outputFormat); } -bool PluginManager::isInputRasterFormatSupported(const QString inputFormat) const +bool PluginManager::isInputImageFormatSupported(const QString inputFormat) const { - return ioPlugins.isInputRasterFormatSupported(inputFormat); + return ioPlugins.isInputImageFormatSupported(inputFormat); +} + +bool PluginManager::isOutputImageFormatSupported(const QString outputFormat) const +{ + return ioPlugins.isOutputImageFormatSupported(outputFormat); +} + +bool PluginManager::isInputProjectFormatSupported(const QString inputFormat) const +{ + return ioPlugins.isInputProjectFormatSupported(inputFormat); +} + +bool PluginManager::isOutputProjectFormatSupported(const QString outputFormat) const +{ + return ioPlugins.isOutputProjectFormatSupported(outputFormat); } QStringList PluginManager::inputMeshFormatList() const @@ -330,9 +361,24 @@ QStringList PluginManager::outputMeshFormatList() const return ioPlugins.outputMeshFormatList(); } -QStringList PluginManager::inputRasterFormatList() const +QStringList PluginManager::inputImageFormatList() const { - return ioPlugins.inputRasterFormatList(); + return ioPlugins.inputImageFormatList(); +} + +QStringList PluginManager::outputImageFormatList() const +{ + return ioPlugins.outputImageFormatList(); +} + +QStringList PluginManager::inputProjectFormatList() const +{ + return ioPlugins.inputProjectFormatList(); +} + +QStringList PluginManager::outputProjectFormatList() const +{ + return ioPlugins.outputProjectFormatList(); } QStringList PluginManager::inputMeshFormatListDialog() const @@ -345,9 +391,19 @@ QStringList PluginManager::outputMeshFormatListDialog() const return outputFormatListDialog(ioPluginIterator()); } -QStringList PluginManager::inputRasterFormatListDialog() const +QStringList PluginManager::inputImageFormatListDialog() const { - return inputRasterFormatListDialog(ioPluginIterator()); + return inputImageFormatListDialog(ioPluginIterator()); +} + +QStringList PluginManager::inputProjectFormatListDialog() const +{ + return inputProjectFormatListDialog(ioPluginIterator()); +} + +QStringList PluginManager::outputProjectFormatListDialog() const +{ + return outputProjectFormatListDialog(ioPluginIterator()); } MeshLabPlugin* PluginManager::operator[](unsigned int i) const @@ -410,7 +466,7 @@ template QStringList PluginManager::inputFormatListDialog(RangeIterator iterator) { QString allKnownFormats = QObject::tr("All known formats ("); - QStringList inputRasterFormatsDialogStringList; + QStringList inputFormatsDialogStringList; for (auto io : iterator){ QString allKnownFormatsFilter; for (const FileFormat& currentFormat : io->importFormats()){ @@ -423,19 +479,19 @@ QStringList PluginManager::inputFormatListDialog(RangeIterator iterator) currentFilterEntry.append(currentExtension); } currentFilterEntry.append(')'); - inputRasterFormatsDialogStringList.append(currentFilterEntry); + inputFormatsDialogStringList.append(currentFilterEntry); } allKnownFormats += allKnownFormatsFilter; } allKnownFormats.append(')'); - inputRasterFormatsDialogStringList.push_front(allKnownFormats); - return inputRasterFormatsDialogStringList; + inputFormatsDialogStringList.push_front(allKnownFormats); + return inputFormatsDialogStringList; } template QStringList PluginManager::outputFormatListDialog(RangeIterator iterator) { - QStringList inputRasterFormatsDialogStringList; + QStringList outputFormatsDialogStringList; for (auto io : iterator){ for (const FileFormat& currentFormat : io->exportFormats()){ QString currentFilterEntry = currentFormat.description + " ("; @@ -445,20 +501,20 @@ QStringList PluginManager::outputFormatListDialog(RangeIterator iterator) currentFilterEntry.append(currentExtension); } currentFilterEntry.append(')'); - inputRasterFormatsDialogStringList.append(currentFilterEntry); + outputFormatsDialogStringList.append(currentFilterEntry); } } - return inputRasterFormatsDialogStringList; + return outputFormatsDialogStringList; } template -QStringList PluginManager::inputRasterFormatListDialog(RangeIterator iterator) +QStringList PluginManager::inputImageFormatListDialog(RangeIterator iterator) { QString allKnownFormats = QObject::tr("All known formats ("); - QStringList inputRasterFormatsDialogStringList; + QStringList inputImageFormatsDialogStringList; for (auto io : iterator){ QString allKnownFormatsFilter; - for (const FileFormat& currentFormat : io->importRasterFormats()){ + for (const FileFormat& currentFormat : io->importImageFormats()){ QString currentFilterEntry = currentFormat.description + " ("; for (QString currentExtension : currentFormat.extensions) { currentExtension = currentExtension.toLower(); @@ -468,13 +524,58 @@ QStringList PluginManager::inputRasterFormatListDialog(RangeIterator iterator) currentFilterEntry.append(currentExtension); } currentFilterEntry.append(')'); - inputRasterFormatsDialogStringList.append(currentFilterEntry); + inputImageFormatsDialogStringList.append(currentFilterEntry); } allKnownFormats += allKnownFormatsFilter; } allKnownFormats.append(')'); - inputRasterFormatsDialogStringList.push_front(allKnownFormats); - return inputRasterFormatsDialogStringList; + inputImageFormatsDialogStringList.push_front(allKnownFormats); + return inputImageFormatsDialogStringList; +} + +template +QStringList PluginManager::inputProjectFormatListDialog(RangeIterator iterator) +{ + QString allKnownFormats = QObject::tr("All known formats ("); + QStringList inputProjectFormatsDialogStringList; + for (auto io : iterator){ + QString allKnownFormatsFilter; + for (const FileFormat& currentFormat : io->importProjectFormats()){ + QString currentFilterEntry = currentFormat.description + " ("; + for (QString currentExtension : currentFormat.extensions) { + currentExtension = currentExtension.toLower(); + allKnownFormatsFilter.append(QObject::tr(" *.")); + allKnownFormatsFilter.append(currentExtension); + currentFilterEntry.append(QObject::tr(" *.")); + currentFilterEntry.append(currentExtension); + } + currentFilterEntry.append(')'); + inputProjectFormatsDialogStringList.append(currentFilterEntry); + } + allKnownFormats += allKnownFormatsFilter; + } + allKnownFormats.append(')'); + inputProjectFormatsDialogStringList.push_front(allKnownFormats); + return inputProjectFormatsDialogStringList; +} + +template +QStringList PluginManager::outputProjectFormatListDialog(RangeIterator iterator) +{ + QStringList outputProjectFormatsDialogStringList; + for (auto io : iterator){ + for (const FileFormat& currentFormat : io->exportProjectFormats()){ + QString currentFilterEntry = currentFormat.description + " ("; + for (QString currentExtension : currentFormat.extensions) { + currentExtension = currentExtension.toLower(); + currentFilterEntry.append(QObject::tr(" *.")); + currentFilterEntry.append(currentExtension); + } + currentFilterEntry.append(')'); + outputProjectFormatsDialogStringList.append(currentFilterEntry); + } + } + return outputProjectFormatsDialogStringList; } ConstPluginIterator PluginManager::PluginRangeIterator::begin() diff --git a/src/common/plugins/plugin_manager.h b/src/common/plugins/plugin_manager.h index 65156931b..ed44098b3 100644 --- a/src/common/plugins/plugin_manager.h +++ b/src/common/plugins/plugin_manager.h @@ -29,6 +29,7 @@ #include "containers/filter_plugin_container.h" #include "containers/io_plugin_container.h" #include "containers/render_plugin_container.h" +#include "meshlab_plugin_type.h" #include #include @@ -45,11 +46,11 @@ public: class PluginRangeIterator; /** Member functions **/ - static void checkPlugin(const QString& filename); + static MeshLabPluginType checkPlugin(const QString& filename); void loadPlugins(); void loadPlugins(QDir pluginsDirectory); - void loadPlugin(const QString& filename); + MeshLabPlugin* loadPlugin(const QString& filename); void unloadPlugin(MeshLabPlugin* ifp); void enablePlugin(MeshLabPlugin* ifp); @@ -64,16 +65,27 @@ public: IOPlugin* inputMeshPlugin(const QString& inputFormat) const; IOPlugin* outputMeshPlugin(const QString& outputFormat) const; - IOPlugin* inputRasterPlugin(const QString inputFormat) const; + IOPlugin* inputImagePlugin(const QString inputFormat) const; + IOPlugin* outputImagePlugin(const QString& outputFormat) const; + IOPlugin* inputProjectPlugin(const QString& inputFormat) const; + IOPlugin* outputProjectPlugin(const QString& outputFormat) const; bool isInputMeshFormatSupported(const QString inputFormat) const; bool isOutputMeshFormatSupported(const QString outputFormat) const; - bool isInputRasterFormatSupported(const QString inputFormat) const; + bool isInputImageFormatSupported(const QString inputFormat) const; + bool isOutputImageFormatSupported(const QString outputFormat) const; + bool isInputProjectFormatSupported(const QString inputFormat) const; + bool isOutputProjectFormatSupported(const QString outputFormat) const; QStringList inputMeshFormatList() const; QStringList outputMeshFormatList() const; - QStringList inputRasterFormatList() const; + QStringList inputImageFormatList() const; + QStringList outputImageFormatList() const; + QStringList inputProjectFormatList() const; + QStringList outputProjectFormatList() const; QStringList inputMeshFormatListDialog() const; QStringList outputMeshFormatListDialog() const; - QStringList inputRasterFormatListDialog() const; + QStringList inputImageFormatListDialog() const; + QStringList inputProjectFormatListDialog() const; + QStringList outputProjectFormatListDialog() const; MeshLabPlugin* operator [](unsigned int i) const; @@ -108,7 +120,13 @@ private: static QStringList outputFormatListDialog(RangeIterator iterator); template - static QStringList inputRasterFormatListDialog(RangeIterator iterator); + static QStringList inputImageFormatListDialog(RangeIterator iterator); + + template + static QStringList inputProjectFormatListDialog(RangeIterator iterator); + + template + static QStringList outputProjectFormatListDialog(RangeIterator iterator); }; class PluginManager::PluginRangeIterator diff --git a/src/common/python/function_parameter.cpp b/src/common/python/function_parameter.cpp index cad07799f..5f83c0ebc 100644 --- a/src/common/python/function_parameter.cpp +++ b/src/common/python/function_parameter.cpp @@ -160,7 +160,7 @@ void pymeshlab::FunctionParameter::printDefaultValue(std::ostream& o) const } if (parameter->value().isMesh()){ const RichMesh* rm = dynamic_cast(parameter); - o << rm->meshindex; + o << rm->value().getMeshId(); return; } if (parameter->value().isFileName()){ diff --git a/src/common/python/function_set.cpp b/src/common/python/function_set.cpp index 3a70b9668..b6a7d76c2 100644 --- a/src/common/python/function_set.cpp +++ b/src/common/python/function_set.cpp @@ -36,94 +36,98 @@ pymeshlab::FunctionSet::FunctionSet(const PluginManager& pm) { //dummy MeshDocument use to compute default value parameters //the mesh used is a 1x1x1 cube (with extremes [-0.5; 0.5]) - MeshDocument dummyMeshDocument; - Box3m b(Point3m(-0.5,-0.5,-0.5),Point3m(0.5,0.5,0.5)); - CMeshO dummyMesh; - vcg::tri::Box(dummyMesh,b); - dummyMeshDocument.addNewMesh(dummyMesh, "cube"); - int mask = 0; - mask |= vcg::tri::io::Mask::IOM_VERTQUALITY; - mask |= vcg::tri::io::Mask::IOM_FACEQUALITY; - dummyMeshDocument.mm()->Enable(mask); + initDummyMeshDocument(); - for (auto inputFormat : pm.inputMeshFormatList()){ - QString originalFilterName = inputFormat; - QString pythonFilterName = inputFormat.toLower(); - Function f(pythonFilterName, originalFilterName, "Load " + inputFormat + " format."); - IOPlugin* plugin = pm.inputMeshPlugin(inputFormat); - RichParameterList rps; - plugin->initPreOpenParameter(inputFormat, rps); - plugin->initOpenParameter(inputFormat, *dummyMeshDocument.mm(), rps); - - //filename parameter - QString sv = "file_name." + inputFormat; - QStringList sl(inputFormat); - RichOpenFile of("file_name", sv, sl, "File Name", "The name of the file to load"); - FunctionParameter par(of); - f.addParameter(par); - - for (const RichParameter& rp : rps){ - FunctionParameter par(rp); - f.addParameter(par); - } - loadMeshSet.insert(f); - } - - for (auto outputFormat : pm.outputMeshFormatList()){ - QString originalFilterName = outputFormat; - QString pythonFilterName = outputFormat.toLower(); - Function f(pythonFilterName, originalFilterName, "Save " + outputFormat + " format."); - IOPlugin* plugin = pm.outputMeshPlugin(outputFormat); - RichParameterList rps; - plugin->initSaveParameter(outputFormat, *dummyMeshDocument.mm(), rps); - - //filename parameter - QString sv = "file_name." + outputFormat; - RichSaveFile of("file_name", sv, outputFormat, "File Name", "The name of the file to save"); - FunctionParameter par(of); - f.addParameter(par); - - for (const RichParameter& rp : rps){ - FunctionParameter par(rp); - f.addParameter(par); - } - - //data to save - updateSaveParameters(plugin, outputFormat, f); - - saveMeshSet.insert(f); - } - - for (auto inputRasterFormat : pm.inputRasterFormatList()){ - QString originalFilterName = inputRasterFormat; - QString pythonFilterName = inputRasterFormat.toLower(); - Function f(pythonFilterName, originalFilterName, "Load " + inputRasterFormat + " format."); - - //filename parameter - QString sv = "file_name." + inputRasterFormat; - QStringList sl(inputRasterFormat); - RichOpenFile of("file_name", sv, sl, "File Name", "The name of the file to load"); - FunctionParameter par(of); - f.addParameter(par); - - loadRasterSet.insert(f); + for (IOPlugin* iop : pm.ioPluginIterator()){ + loadIOPlugin(iop); } for (FilterPlugin* fp : pm.filterPluginIterator()){ - for (QAction* act : fp->actions()) { - QString originalFilterName = fp->filterName(act); - QString description = fp->filterInfo(act); - QString pythonFilterName = fp->pythonFilterName(act); - Function f(pythonFilterName, originalFilterName, description); + loadFilterPlugin(fp); + } +} - RichParameterList rps; - fp->initParameterList(act, dummyMeshDocument, rps); +void pymeshlab::FunctionSet::loadFilterPlugin(FilterPlugin* fp) +{ + for (QAction* act : fp->actions()) { + QString originalFilterName = fp->filterName(act); + QString description = fp->filterInfo(act); + QString pythonFilterName = fp->pythonFilterName(act); + Function f(pythonFilterName, originalFilterName, description); + + RichParameterList rps = fp->initParameterList(act, dummyMeshDocument); + + for (const RichParameter& rp : rps){ + FunctionParameter par(rp); + f.addParameter(par); + } + filterSet.insert(f); + } +} + +void pymeshlab::FunctionSet::loadIOPlugin(IOPlugin* iop) +{ + for (const FileFormat& ff : iop->importFormats()){ + for (const QString& inputFormat : ff.extensions){ + QString originalFilterName = inputFormat.toLower(); + QString pythonFilterName = inputFormat.toLower(); + Function f(pythonFilterName, originalFilterName, "Load " + inputFormat + " format."); + RichParameterList rps = iop->initPreOpenParameter(inputFormat); + + //filename parameter + QString sv = "file_name." + inputFormat; + QStringList sl(inputFormat); + RichOpenFile of("file_name", sv, sl, "File Name", "The name of the file to load"); + FunctionParameter par(of); + f.addParameter(par); for (const RichParameter& rp : rps){ FunctionParameter par(rp); f.addParameter(par); } - filterSet.insert(f); + loadMeshSet.insert(f); + } + } + + for (const FileFormat& ff : iop->exportFormats()){ + for (const QString& outputFormat : ff.extensions){ + QString originalFilterName = outputFormat.toLower(); + QString pythonFilterName = outputFormat.toLower(); + Function f(pythonFilterName, originalFilterName, "Save " + outputFormat + " format."); + RichParameterList rps = iop->initSaveParameter(outputFormat, *dummyMeshDocument.mm()); + + //filename parameter + QString sv = "file_name." + outputFormat; + RichSaveFile of("file_name", sv, outputFormat, "File Name", "The name of the file to save"); + FunctionParameter par(of); + f.addParameter(par); + + for (const RichParameter& rp : rps){ + FunctionParameter par(rp); + f.addParameter(par); + } + + //data to save + updateSaveParameters(iop, outputFormat, f); + + saveMeshSet.insert(f); + } + } + + for (const FileFormat& ff : iop->importImageFormats()){ + for (const QString& inputImageFormat : ff.extensions){ + QString originalFilterName = inputImageFormat; + QString pythonFilterName = inputImageFormat.toLower(); + Function f(pythonFilterName, originalFilterName, "Load " + inputImageFormat + " format."); + + //filename parameter + QString sv = "file_name." + inputImageFormat; + QStringList sl(inputImageFormat); + RichOpenFile of("file_name", sv, sl, "File Name", "The name of the file to load"); + FunctionParameter par(of); + f.addParameter(par); + + loadImageSet.insert(f); } } } @@ -178,15 +182,15 @@ bool pymeshlab::FunctionSet::containsSaveMeshFunction(const QString& pythonFunct const pymeshlab::Function& pymeshlab::FunctionSet::loadRasterFunction(const QString& pythonFunctionName) const { - auto it = loadRasterSet.find(Function(pythonFunctionName, "", "")); - if (it == loadRasterSet.end()) + auto it = loadImageSet.find(Function(pythonFunctionName, "", "")); + if (it == loadImageSet.end()) throw MLException(pythonFunctionName + " format for loading raster not found."); return *it; } bool pymeshlab::FunctionSet::containsLoadRasterFunction(const QString& pythonFunctionName) const { - return loadRasterSet.find(Function(pythonFunctionName, "", "")) != loadRasterSet.end(); + return loadImageSet.find(Function(pythonFunctionName, "", "")) != loadImageSet.end(); } pymeshlab::FunctionSet::FunctionRangeIterator pymeshlab::FunctionSet::filterFunctionIterator() const @@ -206,7 +210,7 @@ pymeshlab::FunctionSet::FunctionRangeIterator pymeshlab::FunctionSet::saveMeshFu pymeshlab::FunctionSet::FunctionRangeIterator pymeshlab::FunctionSet::loadRasterFunctionIterator() const { - return FunctionRangeIterator(loadRasterSet); + return FunctionRangeIterator(loadImageSet); } void pymeshlab::FunctionSet::updateSaveParameters(IOPlugin* plugin, @@ -230,3 +234,16 @@ void pymeshlab::FunctionSet::updateSaveParameters(IOPlugin* plugin, } + +void pymeshlab::FunctionSet::initDummyMeshDocument() +{ + dummyMeshDocument.clear(); + Box3m b(Point3m(-0.5,-0.5,-0.5),Point3m(0.5,0.5,0.5)); + CMeshO dummyMesh; + vcg::tri::Box(dummyMesh,b); + dummyMeshDocument.addNewMesh(dummyMesh, "cube"); + int mask = 0; + mask |= vcg::tri::io::Mask::IOM_VERTQUALITY; + mask |= vcg::tri::io::Mask::IOM_FACEQUALITY; + dummyMeshDocument.mm()->enable(mask); +} diff --git a/src/common/python/function_set.h b/src/common/python/function_set.h index 128a3d07a..94390d00d 100644 --- a/src/common/python/function_set.h +++ b/src/common/python/function_set.h @@ -50,6 +50,10 @@ public: FunctionSet(); FunctionSet(const PluginManager& pm); + //load plugins + void loadFilterPlugin(FilterPlugin* fp); + void loadIOPlugin(IOPlugin* iop); + std::list pythonFilterFunctionNames() const; const Function& filterFunction(const QString& pythonFunctionName) const; @@ -87,10 +91,14 @@ private: const QString& outputFormat, Function& f); + void initDummyMeshDocument(); + + MeshDocument dummyMeshDocument; + std::set filterSet; std::set loadMeshSet; std::set saveMeshSet; - std::set loadRasterSet; + std::set loadImageSet; }; } diff --git a/src/common/utilities/load_save.cpp b/src/common/utilities/load_save.cpp index ef238215b..bcaf33c28 100644 --- a/src/common/utilities/load_save.cpp +++ b/src/common/utilities/load_save.cpp @@ -29,10 +29,38 @@ #include "../globals.h" #include "../plugins/plugin_manager.h" +#include + namespace meshlab { -void loadMesh(const QString& fileName, IOPlugin* ioPlugin, const RichParameterList& prePar, const std::list& meshList, std::list& maskList, vcg::CallBackPos *cb) +/** + * @brief This function assumes that you already have the followind data: + * - the plugin that is needed to load the mesh + * - the number of meshes that will be loaded from the file + * - the list of MeshModel(s) that will contain the loaded mesh(es) + * - the open parameters that will be used to load the mesh(es) + * + * The function will take care to loat the mesh, load textures if needed + * and make all the clean operations after loading the meshes. + * If load fails, throws a MLException. + * + * @param[i] fileName: the filename + * @param[i] ioPlugin: the plugin that supports the file format to load + * @param[i] prePar: the pre open parameters + * @param[i/o] meshList: the list of meshes that will be loaded from the file + * @param[o] maskList: masks of loaded components for each loaded mesh + * @param cb: callback + * @return the list of texture names that could not be loaded + */ +std::list loadMesh( + const QString& fileName, + IOPlugin* ioPlugin, + const RichParameterList& prePar, + const std::list& meshList, + std::list& maskList, + vcg::CallBackPos *cb) { + std::list unloadedTextures; QFileInfo fi(fileName); QString extension = fi.suffix(); @@ -46,7 +74,7 @@ void loadMesh(const QString& fileName, IOPlugin* ioPlugin, const RichParameterLi QString fileNameSansDir = fi.fileName(); try { - ioPlugin->open(extension, fileNameSansDir, meshList ,maskList, prePar, cb); + ioPlugin->open(extension, fileNameSansDir, meshList, maskList, prePar, cb); } catch(const MLException& e) { QDir::setCurrent(origDir); // undo the change of directory before leaving @@ -59,6 +87,9 @@ void loadMesh(const QString& fileName, IOPlugin* ioPlugin, const RichParameterLi MeshModel* mm = *itmesh; int mask = *itmask; + std::list tmp = mm->loadTextures(nullptr, cb); + unloadedTextures.insert(unloadedTextures.end(), tmp.begin(), tmp.end()); + // In case of polygonal meshes the normal should be updated accordingly if( mask & vcg::tri::io::Mask::IOM_BITPOLYGONAL) { mm->updateDataMask(MeshModel::MM_POLYGONAL); // just to be sure. Hopefully it should be done in the plugin... @@ -98,28 +129,56 @@ void loadMesh(const QString& fileName, IOPlugin* ioPlugin, const RichParameterLi ++itmask; } QDir::setCurrent(origDir); // undo the change of directory before leaving + return unloadedTextures; } - -void loadMeshWithStandardParameters(const QString& filename, MeshDocument& md, vcg::CallBackPos *cb) +/** + * @brief loads the given filename and puts the loaded mesh(es) into the + * given MeshDocument. Returns the list of loaded meshes. + * + * If you already know the open parameters that could be used to load the mesh, + * you can pass a RichParameterList containing them. + * Note: only parameters of your RPL that are actually required by the plugin + * will be given as input to the load function. + * If you don't know any parameter, leave the RichParameterList parameter empty. + * + * The function takes care to: + * - find the plugin that loads the format of the file + * - create the required MeshModels into the MeshDocument + * - load the meshes and their textures, with standard parameters + * + * if an error occurs, an exception will be thrown, and MeshDocument won't + * contain new meshes. + */ +std::list loadMeshWithStandardParameters( + const QString& filename, + MeshDocument& md, + vcg::CallBackPos *cb, + RichParameterList prePar) { QFileInfo fi(filename); QString extension = fi.suffix(); PluginManager& pm = meshlab::pluginManagerInstance(); - IOPlugin *ioPlugin = pm.inputMeshPlugin(extension); + IOPlugin* ioPlugin = pm.inputMeshPlugin(extension); if (ioPlugin == nullptr) throw MLException( "Mesh " + filename + " cannot be opened. Your MeshLab version " "has not plugin to read " + extension + " file format"); + ioPlugin->setLog(&md.Log); + RichParameterList openParams =ioPlugin->initPreOpenParameter(extension); - RichParameterList prePar; - ioPlugin->initPreOpenParameter(extension, prePar); + for (RichParameter& rp : prePar){ + auto it = openParams.findParameter(rp.name()); + if (it != openParams.end()){ + it->setValue(rp.value()); + } + } prePar.join(meshlab::defaultGlobalParameterList()); - unsigned int nMeshes = ioPlugin->numberMeshesContainedInFile(extension, filename); + unsigned int nMeshes = ioPlugin->numberMeshesContainedInFile(extension, filename, prePar); std::list meshList; for (unsigned int i = 0; i < nMeshes; i++) { MeshModel *mm = md.addNewMesh(filename, fi.fileName()); @@ -135,28 +194,27 @@ void loadMeshWithStandardParameters(const QString& filename, MeshDocument& md, v try{ loadMesh(fi.fileName(), ioPlugin, prePar, meshList, masks, cb); - RichParameterList par; - ioPlugin->initOpenParameter(extension, meshList, par); - ioPlugin->applyOpenParameter(extension, meshList, par); } catch(const MLException& e){ for (MeshModel* mm : meshList) md.delMesh(mm); throw e; } + + return meshList; } void reloadMesh( const QString& filename, const std::list& meshList, + GLLogStream* log, vcg::CallBackPos* cb) { - QFileInfo fi(filename); QString extension = fi.suffix(); PluginManager& pm = meshlab::pluginManagerInstance(); - IOPlugin *ioPlugin = pm.inputMeshPlugin(extension); + IOPlugin* ioPlugin = pm.inputMeshPlugin(extension); if (ioPlugin == nullptr) { throw MLException( @@ -165,11 +223,12 @@ void reloadMesh( " file format"); } - RichParameterList prePar; - ioPlugin->initPreOpenParameter(extension, prePar); + + ioPlugin->setLog(log); + RichParameterList prePar = ioPlugin->initPreOpenParameter(extension); prePar.join(meshlab::defaultGlobalParameterList()); - unsigned int nMeshes = ioPlugin->numberMeshesContainedInFile(extension, filename); + unsigned int nMeshes = ioPlugin->numberMeshesContainedInFile(extension, filename, prePar); if (meshList.size() != nMeshes){ throw MLException( @@ -179,35 +238,254 @@ void reloadMesh( std::list masks; for (MeshModel* mm : meshList){ - mm->Clear(); + mm->clear(); } loadMesh(filename, ioPlugin, prePar, meshList, masks, cb); - RichParameterList par; - ioPlugin->initOpenParameter(extension, meshList, par); - ioPlugin->applyOpenParameter(extension, meshList, par); } -void loadRaster(const QString& filename, MeshDocument& md, vcg::CallBackPos* cb) +void saveMeshWithStandardParameters( + const QString& fileName, + MeshModel& m, + GLLogStream* log, + vcg::CallBackPos* cb) +{ + QFileInfo fi(fileName); + QString extension = fi.suffix().toLower(); + + PluginManager& pm = meshlab::pluginManagerInstance(); + IOPlugin* ioPlugin = pm.outputMeshPlugin(extension); + if (ioPlugin == nullptr) { + throw MLException( + "Mesh " + fileName + " cannot be saved. Your MeshLab " + "version has not plugin to save " + extension + + " file format"); + } + ioPlugin->setLog(log); + int capability=0,defaultBits=0; + ioPlugin->exportMaskCapability(extension, capability, defaultBits); + RichParameterList saveParams = ioPlugin->initSaveParameter(extension, m); + + ioPlugin->save(extension, fileName, m ,capability, saveParams, cb); + m.setFileName(fileName); + m.saveTextures(fi.absolutePath(), 66, log, cb); +} + +void saveAllMeshes( + const QString& basePath, + MeshDocument& md, + bool onlyVisible, + GLLogStream* log, + vcg::CallBackPos* cb) +{ + PluginManager& pm = meshlab::pluginManagerInstance(); + + for (MeshModel* m : md.meshIterator()){ + if (m->isVisible() || !onlyVisible) { + QString filename, extension; + if (m->fullName().isEmpty()){ + if (m->label().contains('.')){ + extension = QFileInfo(m->label()).suffix(); + filename = QFileInfo(m->label()).baseName(); + } + else { + extension = "ply"; + filename = m->label(); + } + } + else { + QFileInfo fi(m->fullName()); + extension = fi.suffix(); + filename = fi.baseName(); + } + filename.replace(QRegExp("[" + QRegExp::escape( "\\/:*?\"<>|" ) + "]"),QString("_")); + IOPlugin* ioPlugin = pm.outputMeshPlugin(extension); + if (ioPlugin == nullptr){ + std::cerr << "Warning: extension " + extension.toStdString() + + " not supported. Saving " + filename.toStdString() + ".ply."; + filename += ".ply"; + } + else { + filename += ("." + extension.toLower()); + } + filename = basePath + "/" + filename; + saveMeshWithStandardParameters(filename, *m, log, cb); + } + } +} + +QImage loadImage( + const QString& filename, + GLLogStream* log, + vcg::CallBackPos* cb) { QFileInfo fi(filename); QString extension = fi.suffix(); PluginManager& pm = meshlab::pluginManagerInstance(); - IOPlugin *ioPlugin = pm.inputRasterPlugin(extension); + IOPlugin *ioPlugin = pm.inputImagePlugin(extension); if (ioPlugin == nullptr) throw MLException( - "Raster " + filename + " cannot be opened. Your MeshLab version " + "Image " + filename + " cannot be opened. Your MeshLab version " "has not plugin to read " + extension + " file format."); - RasterModel *rm = md.addNewRaster(); - try { - ioPlugin->openRaster(extension, filename, *rm, cb); + ioPlugin->setLog(log); + return ioPlugin->openImage(extension, filename, cb); +} + +void saveImage( + const QString& filename, + const QImage& image, + int quality, + GLLogStream* log, + vcg::CallBackPos* cb) +{ + QFileInfo fi(filename); + QString extension = fi.suffix(); + PluginManager& pm = meshlab::pluginManagerInstance(); + IOPlugin *ioPlugin = pm.outputImagePlugin(extension); + + if (ioPlugin == nullptr) + throw MLException( + "Image " + filename + " cannot be saved. Your MeshLab version " + "has not plugin to save " + extension + " file format."); + + ioPlugin->setLog(log); + ioPlugin->saveImage(extension, filename, image, quality, cb); +} + +void loadRaster(const QString& filename, RasterModel& rm, GLLogStream* log, vcg::CallBackPos* cb) +{ + QImage loadedImage = loadImage(filename, log, cb); + rm.setLabel(filename); + rm.addPlane(new RasterPlane(loadedImage, filename, RasterPlane::RGBA)); + + // Read the file into a buffer + FILE *fp = fopen(qUtf8Printable(filename), "rb"); + if (!fp) { + QString errorMsgFormat = "Exif Parsing: Unable to open file:\n\"%1\"\n\nError details: file %1 is not readable."; + throw MLException(errorMsgFormat.arg(filename)); } - catch(const MLException& e){ - md.delRaster(rm); - throw e; + fseek(fp, 0, SEEK_END); + unsigned long fsize = ftell(fp); + rewind(fp); + unsigned char *buf = new unsigned char[fsize]; + if (fread(buf, 1, fsize, fp) != fsize) { + QString errorMsgFormat = "Exif Parsing: Unable to read the content of the opened file:\n\"%1\"\n\nError details: file %1 is not readable."; + delete[] buf; + fclose(fp); + throw MLException(errorMsgFormat.arg(filename)); + } + fclose(fp); + + // Parse EXIF + easyexif::EXIFInfo ImageInfo; + int code = ImageInfo.parseFrom(buf, fsize); + delete[] buf; + if (!code) { + log->log(GLLogStream::FILTER, "Warning: unable to parse exif for file " + filename); } + if (code && ImageInfo.FocalLengthIn35mm==0.0f) + { + rm.shot.Intrinsics.ViewportPx = vcg::Point2i(rm.currentPlane->image.width(), rm.currentPlane->image.height()); + rm.shot.Intrinsics.CenterPx = Point2m(float(rm.currentPlane->image.width()/2.0), float(rm.currentPlane->image.width()/2.0)); + rm.shot.Intrinsics.PixelSizeMm[0]=36.0f/(float)rm.currentPlane->image.width(); + rm.shot.Intrinsics.PixelSizeMm[1]=rm.shot.Intrinsics.PixelSizeMm[0]; + rm.shot.Intrinsics.FocalMm = 50.0f; + } + else + { + rm.shot.Intrinsics.ViewportPx = vcg::Point2i(ImageInfo.ImageWidth, ImageInfo.ImageHeight); + rm.shot.Intrinsics.CenterPx = Point2m(float(ImageInfo.ImageWidth/2.0), float(ImageInfo.ImageHeight/2.0)); + float ratioFocal=ImageInfo.FocalLength/ImageInfo.FocalLengthIn35mm; + rm.shot.Intrinsics.PixelSizeMm[0]=(36.0f*ratioFocal)/(float)ImageInfo.ImageWidth; + rm.shot.Intrinsics.PixelSizeMm[1]=(24.0f*ratioFocal)/(float)ImageInfo.ImageHeight; + rm.shot.Intrinsics.FocalMm = ImageInfo.FocalLength; + } + // End of EXIF reading +} + +std::vector loadProject( + const QStringList& filenames, + IOPlugin* ioPlugin, + MeshDocument& md, + std::vector& rendOpt, + GLLogStream* log, + vcg::CallBackPos* cb) +{ + QFileInfo fi(filenames.first()); + QString extension = fi.suffix(); + + ioPlugin->setLog(log); + return ioPlugin->openProject(extension, filenames, md, rendOpt, cb); +} + +std::vector loadProject( + const QStringList& filenames, + MeshDocument& md, + GLLogStream* log, + vcg::CallBackPos* cb) +{ + QFileInfo fi(filenames.first()); + QString extension = fi.suffix(); + PluginManager& pm = meshlab::pluginManagerInstance(); + IOPlugin *ioPlugin = pm.inputProjectPlugin(extension); + + if (ioPlugin == nullptr) + throw MLException( + "Project " + filenames.first() + " cannot be loaded. Your MeshLab version " + "has not plugin to load " + extension + " file format."); + + std::list additionalFiles = + ioPlugin->projectFileRequiresAdditionalFiles(extension, filenames.first()); + + if (additionalFiles.size() +1 != (unsigned int)filenames.size()){ + throw MLException( + "The number of input files given (" + QString::number(filenames.size()) + + ") is different from the expected one (" + + QString::number(additionalFiles.size() +1)); + } + std::vector rendOpt; + return loadProject(filenames, ioPlugin, md, rendOpt, log, cb); +} + +std::vector loadProject( + const QString& filename, + MeshDocument& md, + GLLogStream* log, + vcg::CallBackPos* cb) +{ + QStringList fnms; + fnms.push_back(filename); + return loadProject(fnms, md, log, cb); +} + +void saveProject( + const QString& filename, + const MeshDocument& md, + bool onlyVisibleMeshes, + std::vector renderData) +{ + QFileInfo fi(filename); + QString extension = fi.suffix(); + + PluginManager& pm = meshlab::pluginManagerInstance(); + IOPlugin *ioPlugin = pm.outputProjectPlugin(extension); + + if (ioPlugin == nullptr) + throw MLException( + "Project " + filename + " cannot be loaded. Your MeshLab version " + "has not plugin to load " + extension + " file format."); + + if (renderData.size() != 0 && md.meshNumber() != renderData.size()){ + std::cerr << "Warning: renderData vector has different size from " + "MeshDocument number meshes. Ignoring render data when saving " + + filename.toStdString() << " project."; + renderData.clear(); + } + + RichParameterList rpl; + ioPlugin->saveProject(extension, filename, md, onlyVisibleMeshes, renderData); } } diff --git a/src/common/utilities/load_save.h b/src/common/utilities/load_save.h index 61e96cebb..2c2bfc066 100644 --- a/src/common/utilities/load_save.h +++ b/src/common/utilities/load_save.h @@ -34,7 +34,7 @@ namespace meshlab { -void loadMesh( +std::list loadMesh( const QString& fileName, IOPlugin* ioPlugin, const RichParameterList& prePar, @@ -42,20 +42,75 @@ void loadMesh( std::list& maskList, vcg::CallBackPos *cb); -void loadMeshWithStandardParameters( +std::list loadMeshWithStandardParameters( const QString& filename, MeshDocument& md, - vcg::CallBackPos *cb); + vcg::CallBackPos *cb = nullptr, + RichParameterList prePar = RichParameterList()); void reloadMesh( const QString& filename, const std::list& meshList, - vcg::CallBackPos* cb); + GLLogStream* log = nullptr, + vcg::CallBackPos* cb = nullptr); + +void saveMeshWithStandardParameters( + const QString& fileName, + MeshModel& m, + GLLogStream* log = nullptr, + vcg::CallBackPos* cb = nullptr); + +void saveAllMeshes( + const QString& basePath, + MeshDocument& md, + bool onlyVisible = false, + GLLogStream* log = nullptr, + vcg::CallBackPos* cb = nullptr); + +QImage loadImage( + const QString& filename, + GLLogStream* log = nullptr, + vcg::CallBackPos *cb = nullptr); + +void saveImage( + const QString& filename, + const QImage& image, + int quality = 66, + GLLogStream* log = nullptr, + vcg::CallBackPos* cb = nullptr); void loadRaster( const QString& filename, + RasterModel& rm, + GLLogStream* log = nullptr, + vcg::CallBackPos *cb = nullptr); + +std::vector loadProject( + const QStringList& filenames, + IOPlugin* ioPlugin, MeshDocument& md, - vcg::CallBackPos *cb); + std::vector& rendOpt, + GLLogStream* log = nullptr, + vcg::CallBackPos *cb = nullptr); + +std::vector loadProject( + const QStringList& filenames, + MeshDocument& md, + GLLogStream* log = nullptr, + vcg::CallBackPos *cb = nullptr); + +std::vector loadProject( + const QString& filename, + MeshDocument& md, + GLLogStream* log = nullptr, + vcg::CallBackPos *cb = nullptr); + +void saveProject( + const QString& filename, + const MeshDocument& md, + bool onlyVisibleMeshes, + std::vector renderData = std::vector()); + } #endif // MESHLAB_LOAD_SAVE_H diff --git a/src/external/CMakeLists.txt b/src/external/CMakeLists.txt index 970b890be..ecfb697ba 100644 --- a/src/external/CMakeLists.txt +++ b/src/external/CMakeLists.txt @@ -2,5 +2,77 @@ # Copyright 2019, 2020, Visual Computing Lab, ISTI - Italian National Research Council # SPDX-License-Identifier: BSL-1.0 -message(STATUS "Searching for optional components") -include(${EXTERNAL_DIR}/external.cmake) +option( + ALLOW_OPTIONAL_EXTERNAL_MESHLAB_LIBRARIES + "Allow to use/build optional external libraries" + ON) + +option( + BUILD_BUNDLED_SOURCES_WITHOUT_WARNINGS + "Should warnings be disabled on bundled source code?" + ON) + +add_library(external-disable-warnings INTERFACE) +if(BUILD_BUNDLED_SOURCES_WITHOUT_WARNINGS) + if(MSVC) + # TODO + elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") + target_compile_options(external-disable-warnings INTERFACE -w) + endif() +endif() + +## REQUIRED EXTERNAL LIBS ## + +# GLEW - required +include(${CMAKE_CURRENT_SOURCE_DIR}/glew.cmake) + +# EasyExif - required +include(${CMAKE_CURRENT_SOURCE_DIR}/easyexif.cmake) + + +## OPTIONAL EXTERNAL LIBS ## + +if ((NOT BUILD_MINI) AND ALLOW_OPTIONAL_EXTERNAL_MESHLAB_LIBRARIES) + + message(STATUS "Searching for optional components") + + # boost - optional for filter_mesh_booleans + include(${CMAKE_CURRENT_SOURCE_DIR}/boost.cmake) + + # cgal - optional for filter_mesh_booleans + include(${CMAKE_CURRENT_SOURCE_DIR}/cgal.cmake) + + # levmar - optional, for several plugins + include(${CMAKE_CURRENT_SOURCE_DIR}/levmar.cmake) + + # lib3ds - optional, for io_3ds + include(${CMAKE_CURRENT_SOURCE_DIR}/lib3ds.cmake) + + # libigl - optional for filter_mesh_booleans + include(${CMAKE_CURRENT_SOURCE_DIR}/libigl.cmake) + + # muparser - optional, for filter_func + include(${CMAKE_CURRENT_SOURCE_DIR}/muparser.cmake) + + # newuoa - optional and header-only, for several plugins including all that use levmar + include(${CMAKE_CURRENT_SOURCE_DIR}/newuoa.cmake) + + # OpenCTM - optional, for io_ctm + include(${CMAKE_CURRENT_SOURCE_DIR}/openctm.cmake) + + # qhull - optional, for filter_qhull + include(${CMAKE_CURRENT_SOURCE_DIR}/qhull.cmake) + + # structure-synth - optional, for filter_ssynth + include(${CMAKE_CURRENT_SOURCE_DIR}/ssynth.cmake) + + # u3d - optional, for io_u3d + include(${CMAKE_CURRENT_SOURCE_DIR}/u3d.cmake) + + # xerces library - optional, needed by libe57 + include(${CMAKE_CURRENT_SOURCE_DIR}/xerces.cmake) + + # libe57Format - optional, for io_e57 + include(${CMAKE_CURRENT_SOURCE_DIR}/e57.cmake) + +endif() diff --git a/src/external/README.md b/src/external/README.md new file mode 100644 index 000000000..93b69415f --- /dev/null +++ b/src/external/README.md @@ -0,0 +1,14 @@ +# External libraries for MeshLab + +Notes about external libraries: + +## Required libraries + +- GLEW +- easyexif + +Without these two libraries (or their relative system provided libraries), MeshLab cannot be compiled. + +## Optional libraries + +Boost and CGAL directories contain only a portion of the libraries, that is the code necessary to build the `mesh_booleans` plugin. diff --git a/src/external/boost.cmake b/src/external/boost.cmake new file mode 100644 index 000000000..02b49d215 --- /dev/null +++ b/src/external/boost.cmake @@ -0,0 +1,22 @@ +# Copyright 2019, 2021, Collabora, Ltd. +# Copyright 2019, 2021, Visual Computing Lab, ISTI - Italian National Research Council +# SPDX-License-Identifier: BSL-1.0 + +option(ALLOW_BUNDLED_BOOST "Allow use of bundled boost source" ON) +option(ALLOW_SYSTEM_BOOST "Allow use of system-provided boost" ON) + +find_package(Boost COMPONENTS thread) +set(BOOST_DIR ${CMAKE_CURRENT_LIST_DIR}/boost_1_75_0) + +if(ALLOW_SYSTEM_BOOST AND TARGET Boost::boost) + message(STATUS "- Boost - using system-provided library") + add_library(external-boost INTERFACE) + target_link_libraries(external-boost INTERFACE Boost::boost) + if (TARGET Boost::thread) + target_link_libraries(external-boost INTERFACE Boost::thread) + endif() +elseif(ALLOW_BUNDLED_BOOST AND EXISTS "${BOOST_DIR}/boost/version.hpp") + message(STATUS "- Boost - using bundled source") + add_library(external-boost INTERFACE) + target_include_directories(external-boost INTERFACE "${BOOST_DIR}") +endif() diff --git a/src/external/cgal.cmake b/src/external/cgal.cmake new file mode 100644 index 000000000..78ae9dda7 --- /dev/null +++ b/src/external/cgal.cmake @@ -0,0 +1,57 @@ +# Copyright 2019, 2021, Collabora, Ltd. +# Copyright 2019, 2021, Visual Computing Lab, ISTI - Italian National Research Council +# SPDX-License-Identifier: BSL-1.0 +option(ALLOW_BUNDLED_CGAL "Allow use of bundled CGAL source" ON) +option(ALLOW_SYSTEM_CGAL "Allow use of system-provided CGAL" ON) + +find_package(Threads REQUIRED) +find_package(CGAL) +set(CGAL_DIR "${CMAKE_CURRENT_LIST_DIR}/CGAL-5.2.1") + +if(ALLOW_SYSTEM_CGAL AND TARGET CGAL::CGAL) + message(STATUS "- CGAL - using system-provided library") + add_library(external-cgal INTERFACE) + target_link_libraries(external-cgal INTERFACE CGAL::CGAL Threads::Threads) +elseif(ALLOW_BUNDLED_CGAL AND EXISTS "${CGAL_DIR}/include/CGAL/version.h") + message(STATUS "- CGAL - using bundled source") + add_library(external-cgal INTERFACE) + target_include_directories(external-cgal INTERFACE "${CGAL_DIR}/include/") + + if (WIN32) + add_library(mpfr SHARED IMPORTED GLOBAL) + set_property(TARGET mpfr PROPERTY IMPORTED_IMPLIB "${CGAL_DIR}/auxiliary/gmp/lib/libmpfr-4.lib") + set_property(TARGET mpfr PROPERTY IMPORTED_LOCATION "${CGAL_DIR}/auxiliary/gmp/lib/libmpfr-4.dll") + target_include_directories(mpfr INTERFACE "${CGAL_DIR}/auxiliary/gmp/include") + + add_library(gmp SHARED IMPORTED GLOBAL) + set_property(TARGET gmp PROPERTY IMPORTED_IMPLIB "${CGAL_DIR}/auxiliary/gmp/lib/libgmp-10.lib") + set_property(TARGET gmp PROPERTY IMPORTED_LOCATION "${CGAL_DIR}/auxiliary/gmp/lib/libgmp-10.dll") + endif() + + target_link_libraries(external-cgal INTERFACE mpfr gmp Threads::Threads) + + if (WIN32) + if (DEFINED MESHLAB_BUILD_DISTRIB_DIR) + file( + COPY + ${CGAL_DIR}/auxiliary/gmp/lib/libmpfr-4.lib + ${CGAL_DIR}/auxiliary/gmp/lib/libmpfr-4.dll + ${CGAL_DIR}/auxiliary/gmp/lib/libgmp-10.lib + ${CGAL_DIR}/auxiliary/gmp/lib/libgmp-10.dll + DESTINATION + ${MESHLAB_BUILD_DISTRIB_DIR}) + endif() + if (DEFINED MESHLAB_LIB_INSTALL_DIR) + install( + FILES + ${CGAL_DIR}/auxiliary/gmp/lib/libmpfr-4.lib + ${CGAL_DIR}/auxiliary/gmp/lib/libmpfr-4.dll + ${CGAL_DIR}/auxiliary/gmp/lib/libgmp-10.lib + ${CGAL_DIR}/auxiliary/gmp/lib/libgmp-10.dll + DESTINATION + ${MESHLAB_LIB_INSTALL_DIR}) + endif() + endif() +else() + message(STATUS "- CGAL - skipping CGAL library") +endif() diff --git a/src/external/easyexif.cmake b/src/external/easyexif.cmake new file mode 100644 index 000000000..1ba86b040 --- /dev/null +++ b/src/external/easyexif.cmake @@ -0,0 +1,17 @@ +# Copyright 2019, 2020, Collabora, Ltd. +# Copyright 2019, 2020, Visual Computing Lab, ISTI - Italian National Research Council +# SPDX-License-Identifier: BSL-1.0 + +option(ALLOW_BUNDLED_EXIF "Allow use of bundled EasyExif source" ON) + +set(EXIF_DIR ${CMAKE_CURRENT_LIST_DIR}/easyexif) + +if(ALLOW_BUNDLED_EXIF AND EXISTS "${EXIF_DIR}/exif.h") + message(STATUS "- exif - using bundled source") + add_library(external-exif STATIC ${EXIF_DIR}/exif.h ${EXIF_DIR}/exif.cpp) + target_include_directories(external-exif PUBLIC ${EXIF_DIR}) +else() + message( + FATAL_ERROR + "Exif is required - ALLOW_BUNDLED_EXIF must be enabled and found.") +endif() diff --git a/src/external/external.cmake b/src/external/external.cmake deleted file mode 100644 index ed587d758..000000000 --- a/src/external/external.cmake +++ /dev/null @@ -1,36 +0,0 @@ -# Copyright 2019, 2020, Collabora, Ltd. -# Copyright 2019, 2020, Visual Computing Lab, ISTI - Italian National Research Council -# SPDX-License-Identifier: BSL-1.0 - -# newuoa - optional and header-only, for several plugins including all that use levmar -include(${EXTERNAL_DIR}/newuoa.cmake) - -# levmar - optional, for several plugins -include(${EXTERNAL_DIR}/levmar.cmake) - -# lib3ds - optional, for io_3ds -include(${EXTERNAL_DIR}/lib3ds.cmake) - -# gmp or mpir - optional, for filter_csg -include(${EXTERNAL_DIR}/gmp-mpir.cmake) - -# muparser - optional, for filter_func -include(${EXTERNAL_DIR}/muparser.cmake) - -# OpenCTM - optional, for io_ctm -include(${EXTERNAL_DIR}/openctm.cmake) - -# structure-synth - optional, for filter_ssynth -include(${EXTERNAL_DIR}/ssynth.cmake) - -# qhull - optional, for filter_qhull -include(${EXTERNAL_DIR}/qhull.cmake) - -# u3d - optional, for io_u3d -include(${EXTERNAL_DIR}/u3d.cmake) - -# xerces library - optional, needed by libe57 -include(${EXTERNAL_DIR}/xerces.cmake) - -# libe57Format - optional, for io_e57 -include(${EXTERNAL_DIR}/e57.cmake) diff --git a/src/external/external_common.cmake b/src/external/external_common.cmake deleted file mode 100644 index eae693393..000000000 --- a/src/external/external_common.cmake +++ /dev/null @@ -1,16 +0,0 @@ -# Copyright 2019, 2020, Collabora, Ltd. -# Copyright 2019, 2020, Visual Computing Lab, ISTI - Italian National Research Council -# SPDX-License-Identifier: BSL-1.0 - -option(BUILD_BUNDLED_SOURCES_WITHOUT_WARNINGS "Should warnings be disabled on bundled source code?" ON) -add_library(external-disable-warnings INTERFACE) -if(BUILD_BUNDLED_SOURCES_WITHOUT_WARNINGS) - if(MSVC) - # TODO - elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") - target_compile_options(external-disable-warnings INTERFACE -w) - endif() -endif() - -# GLEW - required -include(${EXTERNAL_DIR}/glew.cmake) diff --git a/src/external/glew.cmake b/src/external/glew.cmake index de4a9c745..3173da046 100644 --- a/src/external/glew.cmake +++ b/src/external/glew.cmake @@ -5,7 +5,7 @@ option(ALLOW_BUNDLED_GLEW "Allow use of bundled GLEW source" ON) option(ALLOW_SYSTEM_GLEW "Allow use of system-provided GLEW" ON) -set(GLEW_DIR ${EXTERNAL_DIR}/glew-2.1.0) +set(GLEW_DIR ${CMAKE_CURRENT_LIST_DIR}/glew-2.1.0) unset(HAVE_SYSTEM_GLEW) if(DEFINED GLEW_VERSION) diff --git a/src/external/gmp-mpir.cmake b/src/external/gmp-mpir.cmake deleted file mode 100644 index 26e7a256c..000000000 --- a/src/external/gmp-mpir.cmake +++ /dev/null @@ -1,44 +0,0 @@ -# Copyright 2019, 2020, Collabora, Ltd. -# Copyright 2019, 2020, Visual Computing Lab, ISTI - Italian National Research Council -# SPDX-License-Identifier: BSL-1.0 - -option(ALLOW_SYSTEM_GMP "Allow use of system-provided GMP" ON) -option(ALLOW_BUNDLED_MPIR "Allow use of bundled MPIR binaries" ON) - -find_package(GMP) -set(MPIR_DIR ${EXTERNAL_DIR}/mpir) - -unset(HAVE_BUNDLED_MPIR) -if (APPLE AND EXISTS "${MPIR_DIR}/macx64/libmpir.a" AND CMAKE_SIZEOF_VOID_P EQUAL 8) - # We have mac binaries for x64 - # TODO check target processor architecture, not just pointer size - set(HAVE_BUNDLED_MPIR APPLE-x64) -elseif(WIN32 AND MSVC AND EXISTS "${MPIR_DIR}/win32-msvc/mpir.lib" AND CMAKE_SIZEOF_VOID_P EQUAL 8) - # We have windows binaries for x64 - # TODO check target processor architecture, not just pointer size - set(HAVE_BUNDLED_MPIR WIN-x64) -endif() - -# gmp or mpir - optional, for filter_csg -if(ALLOW_SYSTEM_GMP AND GMP_FOUND) - message(STATUS "- GMP/MPIR - using system-provided GMP library") - add_library(external-gmp INTERFACE) - target_include_directories(external-gmp SYSTEM INTERFACE ${GMP_INCLUDE_DIRS}) - target_link_libraries(external-gmp INTERFACE ${GMP_LIBRARIES}) - -elseif(ALLOW_BUNDLED_MPIR AND HAVE_BUNDLED_MPIR) - message(STATUS "- GMP/MPIR - using already built MPIR library") - add_library(mpir STATIC IMPORTED GLOBAL) - add_library(mpirxx STATIC IMPORTED GLOBAL) - if (HAVE_BUNDLED_MPIR STREQUAL "WIN-x64") - set_property(TARGET mpir PROPERTY IMPORTED_LOCATION "${MPIR_DIR}/win32-msvc/mpir.lib") - set_property(TARGET mpirxx PROPERTY IMPORTED_LOCATION "${MPIR_DIR}/win32-msvc/mpirxx.lib") - target_include_directories(mpir INTERFACE ${EXTERNAL_DIR}/inc/win32-msvc/mpir-2.2.1_x64) - elseif(HAVE_BUNDLED_MPIR STREQUAL "APPLE-x64") - set_property(TARGET mpir PROPERTY IMPORTED_LOCATION "${MPIR_DIR}/macx64/libmpir.a") - set_property(TARGET mpirxx PROPERTY IMPORTED_LOCATION "${MPIR_DIR}/macx64/libmpirxx.a") - target_include_directories(mpir INTERFACE ${EXTERNAL_DIR}/inc/macx64/mpir-2.4.0) - endif() - add_library(external-mpir INTERFACE) - target_link_libraries(external-mpir INTERFACE mpir mpirxx) -endif() diff --git a/src/external/inc/macx/gmp-5.0.1/gmp.h b/src/external/inc/macx/gmp-5.0.1/gmp.h deleted file mode 100644 index e4ed56b47..000000000 --- a/src/external/inc/macx/gmp-5.0.1/gmp.h +++ /dev/null @@ -1,2280 +0,0 @@ -/* Definitions for GNU multiple precision functions. -*- mode: c -*- - -Copyright 1991, 1993, 1994, 1995, 1996, 1997, 1999, 2000, 2001, 2002, 2003, -2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc. - -This file is part of the GNU MP Library. - -The GNU MP Library is free software; you can redistribute it and/or modify -it under the terms of the GNU Lesser General Public License as published by -the Free Software Foundation; either version 3 of the License, or (at your -option) any later version. - -The GNU MP Library is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public -License for more details. - -You should have received a copy of the GNU Lesser General Public License -along with the GNU MP Library. If not, see http://www.gnu.org/licenses/. */ - -#ifndef __GMP_H__ - -#if defined (__cplusplus) -#include /* for std::istream, std::ostream, std::string */ -#include -#endif - - -/* Instantiated by configure. */ -#if ! defined (__GMP_WITHIN_CONFIGURE) -#define __GMP_HAVE_HOST_CPU_FAMILY_power 0 -#define __GMP_HAVE_HOST_CPU_FAMILY_powerpc 0 -#define GMP_LIMB_BITS 32 -#define GMP_NAIL_BITS 0 -#endif -#define GMP_NUMB_BITS (GMP_LIMB_BITS - GMP_NAIL_BITS) -#define GMP_NUMB_MASK ((~ __GMP_CAST (mp_limb_t, 0)) >> GMP_NAIL_BITS) -#define GMP_NUMB_MAX GMP_NUMB_MASK -#define GMP_NAIL_MASK (~ GMP_NUMB_MASK) - - -/* The following (everything under ifndef __GNU_MP__) must be identical in - gmp.h and mp.h to allow both to be included in an application or during - the library build. */ -#ifndef __GNU_MP__ -#define __GNU_MP__ 5 - -#define __need_size_t /* tell gcc stddef.h we only want size_t */ -#if defined (__cplusplus) -#include /* for size_t */ -#else -#include /* for size_t */ -#endif -#undef __need_size_t - -/* Instantiated by configure. */ -#if ! defined (__GMP_WITHIN_CONFIGURE) -/* #undef _LONG_LONG_LIMB */ -#define __GMP_LIBGMP_DLL 0 -#endif - - -/* __STDC__ - some ANSI compilers define this only to 0, hence the use of - "defined" and not "__STDC__-0". In particular Sun workshop C 5.0 - sets __STDC__ to 0, but requires "##" for token pasting. - - _AIX - gnu ansidecl.h asserts that all known AIX compilers are ANSI but - don't always define __STDC__. - - __DECC - current versions of DEC C (5.9 for instance) for alpha are ANSI, - but don't define __STDC__ in their default mode. Don't know if old - versions might have been K&R, but let's not worry about that unless - someone is still using one. - - _mips - gnu ansidecl.h says the RISC/OS MIPS compiler is ANSI in SVR4 - mode, but doesn't define __STDC__. - - _MSC_VER - Microsoft C is ANSI, but __STDC__ is undefined unless the /Za - option is given (in which case it's 1). - - _WIN32 - tested for by gnu ansidecl.h, no doubt on the assumption that - all w32 compilers are ansi. - - Note: This same set of tests is used by gen-psqr.c and - demos/expr/expr-impl.h, so if anything needs adding, then be sure to - update those too. */ - -#if defined (__STDC__) \ - || defined (__cplusplus) \ - || defined (_AIX) \ - || defined (__DECC) \ - || (defined (__mips) && defined (_SYSTYPE_SVR4)) \ - || defined (_MSC_VER) \ - || defined (_WIN32) -#define __GMP_HAVE_CONST 1 -#define __GMP_HAVE_PROTOTYPES 1 -#define __GMP_HAVE_TOKEN_PASTE 1 -#else -#define __GMP_HAVE_CONST 0 -#define __GMP_HAVE_PROTOTYPES 0 -#define __GMP_HAVE_TOKEN_PASTE 0 -#endif - - -#if __GMP_HAVE_CONST -#define __gmp_const const -#define __gmp_signed signed -#else -#define __gmp_const -#define __gmp_signed -#endif - - -/* __GMP_DECLSPEC supports Windows DLL versions of libgmp, and is empty in - all other circumstances. - - When compiling objects for libgmp, __GMP_DECLSPEC is an export directive, - or when compiling for an application it's an import directive. The two - cases are differentiated by __GMP_WITHIN_GMP defined by the GMP Makefiles - (and not defined from an application). - - __GMP_DECLSPEC_XX is similarly used for libgmpxx. __GMP_WITHIN_GMPXX - indicates when building libgmpxx, and in that case libgmpxx functions are - exports, but libgmp functions which might get called are imports. - - libmp.la uses __GMP_DECLSPEC, just as if it were libgmp.la. libgmp and - libmp don't call each other, so there's no conflict or confusion. - - Libtool DLL_EXPORT define is not used. - - There's no attempt to support GMP built both static and DLL. Doing so - would mean applications would have to tell us which of the two is going - to be used when linking, and that seems very tedious and error prone if - using GMP by hand, and equally tedious from a package since autoconf and - automake don't give much help. - - __GMP_DECLSPEC is required on all documented global functions and - variables, the various internals in gmp-impl.h etc can be left unadorned. - But internals used by the test programs or speed measuring programs - should have __GMP_DECLSPEC, and certainly constants or variables must - have it or the wrong address will be resolved. - - In gcc __declspec can go at either the start or end of a prototype. - - In Microsoft C __declspec must go at the start, or after the type like - void __declspec(...) *foo()". There's no __dllexport or anything to - guard against someone foolish #defining dllexport. _export used to be - available, but no longer. - - In Borland C _export still exists, but needs to go after the type, like - "void _export foo();". Would have to change the __GMP_DECLSPEC syntax to - make use of that. Probably more trouble than it's worth. */ - -#if defined (__GNUC__) -#define __GMP_DECLSPEC_EXPORT __declspec(__dllexport__) -#define __GMP_DECLSPEC_IMPORT __declspec(__dllimport__) -#endif -#if defined (_MSC_VER) || defined (__BORLANDC__) -#define __GMP_DECLSPEC_EXPORT __declspec(dllexport) -#define __GMP_DECLSPEC_IMPORT __declspec(dllimport) -#endif -#ifdef __WATCOMC__ -#define __GMP_DECLSPEC_EXPORT __export -#define __GMP_DECLSPEC_IMPORT __import -#endif -#ifdef __IBMC__ -#define __GMP_DECLSPEC_EXPORT _Export -#define __GMP_DECLSPEC_IMPORT _Import -#endif - -#if __GMP_LIBGMP_DLL -#if __GMP_WITHIN_GMP -/* compiling to go into a DLL libgmp */ -#define __GMP_DECLSPEC __GMP_DECLSPEC_EXPORT -#else -/* compiling to go into an application which will link to a DLL libgmp */ -#define __GMP_DECLSPEC __GMP_DECLSPEC_IMPORT -#endif -#else -/* all other cases */ -#define __GMP_DECLSPEC -#endif - - -#ifdef __GMP_SHORT_LIMB -typedef unsigned int mp_limb_t; -typedef int mp_limb_signed_t; -#else -#ifdef _LONG_LONG_LIMB -typedef unsigned long long int mp_limb_t; -typedef long long int mp_limb_signed_t; -#else -typedef unsigned long int mp_limb_t; -typedef long int mp_limb_signed_t; -#endif -#endif -typedef unsigned long int mp_bitcnt_t; - -/* For reference, note that the name __mpz_struct gets into C++ mangled - function names, which means although the "__" suggests an internal, we - must leave this name for binary compatibility. */ -typedef struct -{ - int _mp_alloc; /* Number of *limbs* allocated and pointed - to by the _mp_d field. */ - int _mp_size; /* abs(_mp_size) is the number of limbs the - last field points to. If _mp_size is - negative this is a negative number. */ - mp_limb_t *_mp_d; /* Pointer to the limbs. */ -} __mpz_struct; - -#endif /* __GNU_MP__ */ - - -typedef __mpz_struct MP_INT; /* gmp 1 source compatibility */ -typedef __mpz_struct mpz_t[1]; - -typedef mp_limb_t * mp_ptr; -typedef __gmp_const mp_limb_t * mp_srcptr; -#if defined (_CRAY) && ! defined (_CRAYMPP) -/* plain `int' is much faster (48 bits) */ -#define __GMP_MP_SIZE_T_INT 1 -typedef int mp_size_t; -typedef int mp_exp_t; -#else -#define __GMP_MP_SIZE_T_INT 0 -typedef long int mp_size_t; -typedef long int mp_exp_t; -#endif - -typedef struct -{ - __mpz_struct _mp_num; - __mpz_struct _mp_den; -} __mpq_struct; - -typedef __mpq_struct MP_RAT; /* gmp 1 source compatibility */ -typedef __mpq_struct mpq_t[1]; - -typedef struct -{ - int _mp_prec; /* Max precision, in number of `mp_limb_t's. - Set by mpf_init and modified by - mpf_set_prec. The area pointed to by the - _mp_d field contains `prec' + 1 limbs. */ - int _mp_size; /* abs(_mp_size) is the number of limbs the - last field points to. If _mp_size is - negative this is a negative number. */ - mp_exp_t _mp_exp; /* Exponent, in the base of `mp_limb_t'. */ - mp_limb_t *_mp_d; /* Pointer to the limbs. */ -} __mpf_struct; - -/* typedef __mpf_struct MP_FLOAT; */ -typedef __mpf_struct mpf_t[1]; - -/* Available random number generation algorithms. */ -typedef enum -{ - GMP_RAND_ALG_DEFAULT = 0, - GMP_RAND_ALG_LC = GMP_RAND_ALG_DEFAULT /* Linear congruential. */ -} gmp_randalg_t; - -/* Random state struct. */ -typedef struct -{ - mpz_t _mp_seed; /* _mp_d member points to state of the generator. */ - gmp_randalg_t _mp_alg; /* Currently unused. */ - union { - void *_mp_lc; /* Pointer to function pointers structure. */ - } _mp_algdata; -} __gmp_randstate_struct; -typedef __gmp_randstate_struct gmp_randstate_t[1]; - -/* Types for function declarations in gmp files. */ -/* ??? Should not pollute user name space with these ??? */ -typedef __gmp_const __mpz_struct *mpz_srcptr; -typedef __mpz_struct *mpz_ptr; -typedef __gmp_const __mpf_struct *mpf_srcptr; -typedef __mpf_struct *mpf_ptr; -typedef __gmp_const __mpq_struct *mpq_srcptr; -typedef __mpq_struct *mpq_ptr; - - -/* This is not wanted in mp.h, so put it outside the __GNU_MP__ common - section. */ -#if __GMP_LIBGMP_DLL -#if __GMP_WITHIN_GMPXX -/* compiling to go into a DLL libgmpxx */ -#define __GMP_DECLSPEC_XX __GMP_DECLSPEC_EXPORT -#else -/* compiling to go into a application which will link to a DLL libgmpxx */ -#define __GMP_DECLSPEC_XX __GMP_DECLSPEC_IMPORT -#endif -#else -/* all other cases */ -#define __GMP_DECLSPEC_XX -#endif - - -#if __GMP_HAVE_PROTOTYPES -#define __GMP_PROTO(x) x -#else -#define __GMP_PROTO(x) () -#endif - -#ifndef __MPN -#if __GMP_HAVE_TOKEN_PASTE -#define __MPN(x) __gmpn_##x -#else -#define __MPN(x) __gmpn_/**/x -#endif -#endif - -/* For reference, "defined(EOF)" cannot be used here. In g++ 2.95.4, - defines EOF but not FILE. */ -#if defined (FILE) \ - || defined (H_STDIO) \ - || defined (_H_STDIO) /* AIX */ \ - || defined (_STDIO_H) /* glibc, Sun, SCO */ \ - || defined (_STDIO_H_) /* BSD, OSF */ \ - || defined (__STDIO_H) /* Borland */ \ - || defined (__STDIO_H__) /* IRIX */ \ - || defined (_STDIO_INCLUDED) /* HPUX */ \ - || defined (__dj_include_stdio_h_) /* DJGPP */ \ - || defined (_FILE_DEFINED) /* Microsoft */ \ - || defined (__STDIO__) /* Apple MPW MrC */ \ - || defined (_MSL_STDIO_H) /* Metrowerks */ \ - || defined (_STDIO_H_INCLUDED) /* QNX4 */ \ - || defined (_ISO_STDIO_ISO_H) /* Sun C++ */ -#define _GMP_H_HAVE_FILE 1 -#endif - -/* In ISO C, if a prototype involving "struct obstack *" is given without - that structure defined, then the struct is scoped down to just the - prototype, causing a conflict if it's subsequently defined for real. So - only give prototypes if we've got obstack.h. */ -#if defined (_OBSTACK_H) /* glibc */ -#define _GMP_H_HAVE_OBSTACK 1 -#endif - -/* The prototypes for gmp_vprintf etc are provided only if va_list is - available, via an application having included or . - Usually va_list is a typedef so can't be tested directly, but C99 - specifies that va_start is a macro (and it was normally a macro on past - systems too), so look for that. - - will define some sort of va_list for vprintf and vfprintf, but - let's not bother trying to use that since it's not standard and since - application uses for gmp_vprintf etc will almost certainly require the - whole or anyway. */ - -#ifdef va_start -#define _GMP_H_HAVE_VA_LIST 1 -#endif - -/* Test for gcc >= maj.min, as per __GNUC_PREREQ in glibc */ -#if defined (__GNUC__) && defined (__GNUC_MINOR__) -#define __GMP_GNUC_PREREQ(maj, min) \ - ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min)) -#else -#define __GMP_GNUC_PREREQ(maj, min) 0 -#endif - -/* "pure" is in gcc 2.96 and up, see "(gcc)Function Attributes". Basically - it means a function does nothing but examine its arguments and memory - (global or via arguments) to generate a return value, but changes nothing - and has no side-effects. __GMP_NO_ATTRIBUTE_CONST_PURE lets - tune/common.c etc turn this off when trying to write timing loops. */ -#if __GMP_GNUC_PREREQ (2,96) && ! defined (__GMP_NO_ATTRIBUTE_CONST_PURE) -#define __GMP_ATTRIBUTE_PURE __attribute__ ((__pure__)) -#else -#define __GMP_ATTRIBUTE_PURE -#endif - - -/* __GMP_CAST allows us to use static_cast in C++, so our macros are clean - to "g++ -Wold-style-cast". - - Casts in "extern inline" code within an extern "C" block don't induce - these warnings, so __GMP_CAST only needs to be used on documented - macros. */ - -#ifdef __cplusplus -#define __GMP_CAST(type, expr) (static_cast (expr)) -#else -#define __GMP_CAST(type, expr) ((type) (expr)) -#endif - - -/* An empty "throw ()" means the function doesn't throw any C++ exceptions, - this can save some stack frame info in applications. - - Currently it's given only on functions which never divide-by-zero etc, - don't allocate memory, and are expected to never need to allocate memory. - This leaves open the possibility of a C++ throw from a future GMP - exceptions scheme. - - mpz_set_ui etc are omitted to leave open the lazy allocation scheme - described in doc/tasks.html. mpz_get_d etc are omitted to leave open - exceptions for float overflows. - - Note that __GMP_NOTHROW must be given on any inlines the same as on their - prototypes (for g++ at least, where they're used together). Note also - that g++ 3.0 demands that __GMP_NOTHROW is before other attributes like - __GMP_ATTRIBUTE_PURE. */ - -#if defined (__cplusplus) -#define __GMP_NOTHROW throw () -#else -#define __GMP_NOTHROW -#endif - - -/* PORTME: What other compilers have a useful "extern inline"? "static - inline" would be an acceptable substitute if the compiler (or linker) - discards unused statics. */ - - /* gcc has __inline__ in all modes, including strict ansi. Give a prototype - for an inline too, so as to correctly specify "dllimport" on windows, in - case the function is called rather than inlined. - GCC 4.3 and above with -std=c99 or -std=gnu99 implements ISO C99 - inline semantics, unless -fgnu89-inline is used. */ -#ifdef __GNUC__ -#if (defined __GNUC_STDC_INLINE__) || (__GNUC__ == 4 && __GNUC_MINOR__ == 2) -#define __GMP_EXTERN_INLINE extern __inline__ __attribute__ ((__gnu_inline__)) -#else -#define __GMP_EXTERN_INLINE extern __inline__ -#endif -#define __GMP_INLINE_PROTOTYPES 1 -#endif - -/* DEC C (eg. version 5.9) supports "static __inline foo()", even in -std1 - strict ANSI mode. Inlining is done even when not optimizing (ie. -O0 - mode, which is the default), but an unnecessary local copy of foo is - emitted unless -O is used. "extern __inline" is accepted, but the - "extern" appears to be ignored, ie. it becomes a plain global function - but which is inlined within its file. Don't know if all old versions of - DEC C supported __inline, but as a start let's do the right thing for - current versions. */ -#ifdef __DECC -#define __GMP_EXTERN_INLINE static __inline -#endif - -/* SCO OpenUNIX 8 cc supports "static inline foo()" but not in -Xc strict - ANSI mode (__STDC__ is 1 in that mode). Inlining only actually takes - place under -O. Without -O "foo" seems to be emitted whether it's used - or not, which is wasteful. "extern inline foo()" isn't useful, the - "extern" is apparently ignored, so foo is inlined if possible but also - emitted as a global, which causes multiple definition errors when - building a shared libgmp. */ -#ifdef __SCO_VERSION__ -#if __SCO_VERSION__ > 400000000 && __STDC__ != 1 \ - && ! defined (__GMP_EXTERN_INLINE) -#define __GMP_EXTERN_INLINE static inline -#endif -#endif - -/* Microsoft's C compiler accepts __inline */ -#ifdef _MSC_VER -#define __GMP_EXTERN_INLINE __inline -#endif - -/* Recent enough Sun C compilers want "inline" */ -#if defined (__SUNPRO_C) && __SUNPRO_C >= 0x560 \ - && ! defined (__GMP_EXTERN_INLINE) -#define __GMP_EXTERN_INLINE inline -#endif - -/* Somewhat older Sun C compilers want "static inline" */ -#if defined (__SUNPRO_C) && __SUNPRO_C >= 0x540 \ - && ! defined (__GMP_EXTERN_INLINE) -#define __GMP_EXTERN_INLINE static inline -#endif - - -/* C++ always has "inline" and since it's a normal feature the linker should - discard duplicate non-inlined copies, or if it doesn't then that's a - problem for everyone, not just GMP. */ -#if defined (__cplusplus) && ! defined (__GMP_EXTERN_INLINE) -#define __GMP_EXTERN_INLINE inline -#endif - -/* Don't do any inlining within a configure run, since if the compiler ends - up emitting copies of the code into the object file it can end up - demanding the various support routines (like mpn_popcount) for linking, - making the "alloca" test and perhaps others fail. And on hppa ia64 a - pre-release gcc 3.2 was seen not respecting the "extern" in "extern - __inline__", triggering this problem too. */ -#if defined (__GMP_WITHIN_CONFIGURE) && ! __GMP_WITHIN_CONFIGURE_INLINE -#undef __GMP_EXTERN_INLINE -#endif - -/* By default, don't give a prototype when there's going to be an inline - version. Note in particular that Cray C++ objects to the combination of - prototype and inline. */ -#ifdef __GMP_EXTERN_INLINE -#ifndef __GMP_INLINE_PROTOTYPES -#define __GMP_INLINE_PROTOTYPES 0 -#endif -#else -#define __GMP_INLINE_PROTOTYPES 1 -#endif - - -#define __GMP_ABS(x) ((x) >= 0 ? (x) : -(x)) -#define __GMP_MAX(h,i) ((h) > (i) ? (h) : (i)) - -/* __GMP_USHRT_MAX is not "~ (unsigned short) 0" because short is promoted - to int by "~". */ -#define __GMP_UINT_MAX (~ (unsigned) 0) -#define __GMP_ULONG_MAX (~ (unsigned long) 0) -#define __GMP_USHRT_MAX ((unsigned short) ~0) - - -/* __builtin_expect is in gcc 3.0, and not in 2.95. */ -#if __GMP_GNUC_PREREQ (3,0) -#define __GMP_LIKELY(cond) __builtin_expect ((cond) != 0, 1) -#define __GMP_UNLIKELY(cond) __builtin_expect ((cond) != 0, 0) -#else -#define __GMP_LIKELY(cond) (cond) -#define __GMP_UNLIKELY(cond) (cond) -#endif - -#ifdef _CRAY -#define __GMP_CRAY_Pragma(str) _Pragma (str) -#else -#define __GMP_CRAY_Pragma(str) -#endif - - -/* Allow direct user access to numerator and denominator of a mpq_t object. */ -#define mpq_numref(Q) (&((Q)->_mp_num)) -#define mpq_denref(Q) (&((Q)->_mp_den)) - - -#if defined (__cplusplus) -extern "C" { -using std::FILE; -#endif - -#define mp_set_memory_functions __gmp_set_memory_functions -__GMP_DECLSPEC void mp_set_memory_functions __GMP_PROTO ((void *(*) (size_t), - void *(*) (void *, size_t, size_t), - void (*) (void *, size_t))) __GMP_NOTHROW; - -#define mp_get_memory_functions __gmp_get_memory_functions -__GMP_DECLSPEC void mp_get_memory_functions __GMP_PROTO ((void *(**) (size_t), - void *(**) (void *, size_t, size_t), - void (**) (void *, size_t))) __GMP_NOTHROW; - -#define mp_bits_per_limb __gmp_bits_per_limb -__GMP_DECLSPEC extern __gmp_const int mp_bits_per_limb; - -#define gmp_errno __gmp_errno -__GMP_DECLSPEC extern int gmp_errno; - -#define gmp_version __gmp_version -__GMP_DECLSPEC extern __gmp_const char * __gmp_const gmp_version; - - -/**************** Random number routines. ****************/ - -/* obsolete */ -#define gmp_randinit __gmp_randinit -__GMP_DECLSPEC void gmp_randinit __GMP_PROTO ((gmp_randstate_t, gmp_randalg_t, ...)); - -#define gmp_randinit_default __gmp_randinit_default -__GMP_DECLSPEC void gmp_randinit_default __GMP_PROTO ((gmp_randstate_t)); - -#define gmp_randinit_lc_2exp __gmp_randinit_lc_2exp -__GMP_DECLSPEC void gmp_randinit_lc_2exp __GMP_PROTO ((gmp_randstate_t, - mpz_srcptr, unsigned long int, - mp_bitcnt_t)); - -#define gmp_randinit_lc_2exp_size __gmp_randinit_lc_2exp_size -__GMP_DECLSPEC int gmp_randinit_lc_2exp_size __GMP_PROTO ((gmp_randstate_t, mp_bitcnt_t)); - -#define gmp_randinit_mt __gmp_randinit_mt -__GMP_DECLSPEC void gmp_randinit_mt __GMP_PROTO ((gmp_randstate_t)); - -#define gmp_randinit_set __gmp_randinit_set -__GMP_DECLSPEC void gmp_randinit_set __GMP_PROTO ((gmp_randstate_t, __gmp_const __gmp_randstate_struct *)); - -#define gmp_randseed __gmp_randseed -__GMP_DECLSPEC void gmp_randseed __GMP_PROTO ((gmp_randstate_t, mpz_srcptr)); - -#define gmp_randseed_ui __gmp_randseed_ui -__GMP_DECLSPEC void gmp_randseed_ui __GMP_PROTO ((gmp_randstate_t, unsigned long int)); - -#define gmp_randclear __gmp_randclear -__GMP_DECLSPEC void gmp_randclear __GMP_PROTO ((gmp_randstate_t)); - -#define gmp_urandomb_ui __gmp_urandomb_ui -__GMP_DECLSPEC unsigned long gmp_urandomb_ui __GMP_PROTO ((gmp_randstate_t, unsigned long)); - -#define gmp_urandomm_ui __gmp_urandomm_ui -__GMP_DECLSPEC unsigned long gmp_urandomm_ui __GMP_PROTO ((gmp_randstate_t, unsigned long)); - - -/**************** Formatted output routines. ****************/ - -#define gmp_asprintf __gmp_asprintf -__GMP_DECLSPEC int gmp_asprintf __GMP_PROTO ((char **, __gmp_const char *, ...)); - -#define gmp_fprintf __gmp_fprintf -#ifdef _GMP_H_HAVE_FILE -__GMP_DECLSPEC int gmp_fprintf __GMP_PROTO ((FILE *, __gmp_const char *, ...)); -#endif - -#define gmp_obstack_printf __gmp_obstack_printf -#if defined (_GMP_H_HAVE_OBSTACK) -__GMP_DECLSPEC int gmp_obstack_printf __GMP_PROTO ((struct obstack *, __gmp_const char *, ...)); -#endif - -#define gmp_obstack_vprintf __gmp_obstack_vprintf -#if defined (_GMP_H_HAVE_OBSTACK) && defined (_GMP_H_HAVE_VA_LIST) -__GMP_DECLSPEC int gmp_obstack_vprintf __GMP_PROTO ((struct obstack *, __gmp_const char *, va_list)); -#endif - -#define gmp_printf __gmp_printf -__GMP_DECLSPEC int gmp_printf __GMP_PROTO ((__gmp_const char *, ...)); - -#define gmp_snprintf __gmp_snprintf -__GMP_DECLSPEC int gmp_snprintf __GMP_PROTO ((char *, size_t, __gmp_const char *, ...)); - -#define gmp_sprintf __gmp_sprintf -__GMP_DECLSPEC int gmp_sprintf __GMP_PROTO ((char *, __gmp_const char *, ...)); - -#define gmp_vasprintf __gmp_vasprintf -#if defined (_GMP_H_HAVE_VA_LIST) -__GMP_DECLSPEC int gmp_vasprintf __GMP_PROTO ((char **, __gmp_const char *, va_list)); -#endif - -#define gmp_vfprintf __gmp_vfprintf -#if defined (_GMP_H_HAVE_FILE) && defined (_GMP_H_HAVE_VA_LIST) -__GMP_DECLSPEC int gmp_vfprintf __GMP_PROTO ((FILE *, __gmp_const char *, va_list)); -#endif - -#define gmp_vprintf __gmp_vprintf -#if defined (_GMP_H_HAVE_VA_LIST) -__GMP_DECLSPEC int gmp_vprintf __GMP_PROTO ((__gmp_const char *, va_list)); -#endif - -#define gmp_vsnprintf __gmp_vsnprintf -#if defined (_GMP_H_HAVE_VA_LIST) -__GMP_DECLSPEC int gmp_vsnprintf __GMP_PROTO ((char *, size_t, __gmp_const char *, va_list)); -#endif - -#define gmp_vsprintf __gmp_vsprintf -#if defined (_GMP_H_HAVE_VA_LIST) -__GMP_DECLSPEC int gmp_vsprintf __GMP_PROTO ((char *, __gmp_const char *, va_list)); -#endif - - -/**************** Formatted input routines. ****************/ - -#define gmp_fscanf __gmp_fscanf -#ifdef _GMP_H_HAVE_FILE -__GMP_DECLSPEC int gmp_fscanf __GMP_PROTO ((FILE *, __gmp_const char *, ...)); -#endif - -#define gmp_scanf __gmp_scanf -__GMP_DECLSPEC int gmp_scanf __GMP_PROTO ((__gmp_const char *, ...)); - -#define gmp_sscanf __gmp_sscanf -__GMP_DECLSPEC int gmp_sscanf __GMP_PROTO ((__gmp_const char *, __gmp_const char *, ...)); - -#define gmp_vfscanf __gmp_vfscanf -#if defined (_GMP_H_HAVE_FILE) && defined (_GMP_H_HAVE_VA_LIST) -__GMP_DECLSPEC int gmp_vfscanf __GMP_PROTO ((FILE *, __gmp_const char *, va_list)); -#endif - -#define gmp_vscanf __gmp_vscanf -#if defined (_GMP_H_HAVE_VA_LIST) -__GMP_DECLSPEC int gmp_vscanf __GMP_PROTO ((__gmp_const char *, va_list)); -#endif - -#define gmp_vsscanf __gmp_vsscanf -#if defined (_GMP_H_HAVE_VA_LIST) -__GMP_DECLSPEC int gmp_vsscanf __GMP_PROTO ((__gmp_const char *, __gmp_const char *, va_list)); -#endif - - -/**************** Integer (i.e. Z) routines. ****************/ - -#define _mpz_realloc __gmpz_realloc -#define mpz_realloc __gmpz_realloc -__GMP_DECLSPEC void *_mpz_realloc __GMP_PROTO ((mpz_ptr, mp_size_t)); - -#define mpz_abs __gmpz_abs -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_abs) -__GMP_DECLSPEC void mpz_abs __GMP_PROTO ((mpz_ptr, mpz_srcptr)); -#endif - -#define mpz_add __gmpz_add -__GMP_DECLSPEC void mpz_add __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_add_ui __gmpz_add_ui -__GMP_DECLSPEC void mpz_add_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_addmul __gmpz_addmul -__GMP_DECLSPEC void mpz_addmul __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_addmul_ui __gmpz_addmul_ui -__GMP_DECLSPEC void mpz_addmul_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_and __gmpz_and -__GMP_DECLSPEC void mpz_and __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_array_init __gmpz_array_init -__GMP_DECLSPEC void mpz_array_init __GMP_PROTO ((mpz_ptr, mp_size_t, mp_size_t)); - -#define mpz_bin_ui __gmpz_bin_ui -__GMP_DECLSPEC void mpz_bin_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_bin_uiui __gmpz_bin_uiui -__GMP_DECLSPEC void mpz_bin_uiui __GMP_PROTO ((mpz_ptr, unsigned long int, unsigned long int)); - -#define mpz_cdiv_q __gmpz_cdiv_q -__GMP_DECLSPEC void mpz_cdiv_q __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_cdiv_q_2exp __gmpz_cdiv_q_2exp -__GMP_DECLSPEC void mpz_cdiv_q_2exp __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long)); - -#define mpz_cdiv_q_ui __gmpz_cdiv_q_ui -__GMP_DECLSPEC unsigned long int mpz_cdiv_q_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_cdiv_qr __gmpz_cdiv_qr -__GMP_DECLSPEC void mpz_cdiv_qr __GMP_PROTO ((mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_cdiv_qr_ui __gmpz_cdiv_qr_ui -__GMP_DECLSPEC unsigned long int mpz_cdiv_qr_ui __GMP_PROTO ((mpz_ptr, mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_cdiv_r __gmpz_cdiv_r -__GMP_DECLSPEC void mpz_cdiv_r __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_cdiv_r_2exp __gmpz_cdiv_r_2exp -__GMP_DECLSPEC void mpz_cdiv_r_2exp __GMP_PROTO ((mpz_ptr, mpz_srcptr, mp_bitcnt_t)); - -#define mpz_cdiv_r_ui __gmpz_cdiv_r_ui -__GMP_DECLSPEC unsigned long int mpz_cdiv_r_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_cdiv_ui __gmpz_cdiv_ui -__GMP_DECLSPEC unsigned long int mpz_cdiv_ui __GMP_PROTO ((mpz_srcptr, unsigned long int)) __GMP_ATTRIBUTE_PURE; - -#define mpz_clear __gmpz_clear -__GMP_DECLSPEC void mpz_clear __GMP_PROTO ((mpz_ptr)); - -#define mpz_clears __gmpz_clears -__GMP_DECLSPEC void mpz_clears __GMP_PROTO ((mpz_ptr, ...)); - -#define mpz_clrbit __gmpz_clrbit -__GMP_DECLSPEC void mpz_clrbit __GMP_PROTO ((mpz_ptr, mp_bitcnt_t)); - -#define mpz_cmp __gmpz_cmp -__GMP_DECLSPEC int mpz_cmp __GMP_PROTO ((mpz_srcptr, mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpz_cmp_d __gmpz_cmp_d -__GMP_DECLSPEC int mpz_cmp_d __GMP_PROTO ((mpz_srcptr, double)) __GMP_ATTRIBUTE_PURE; - -#define _mpz_cmp_si __gmpz_cmp_si -__GMP_DECLSPEC int _mpz_cmp_si __GMP_PROTO ((mpz_srcptr, signed long int)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define _mpz_cmp_ui __gmpz_cmp_ui -__GMP_DECLSPEC int _mpz_cmp_ui __GMP_PROTO ((mpz_srcptr, unsigned long int)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpz_cmpabs __gmpz_cmpabs -__GMP_DECLSPEC int mpz_cmpabs __GMP_PROTO ((mpz_srcptr, mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpz_cmpabs_d __gmpz_cmpabs_d -__GMP_DECLSPEC int mpz_cmpabs_d __GMP_PROTO ((mpz_srcptr, double)) __GMP_ATTRIBUTE_PURE; - -#define mpz_cmpabs_ui __gmpz_cmpabs_ui -__GMP_DECLSPEC int mpz_cmpabs_ui __GMP_PROTO ((mpz_srcptr, unsigned long int)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpz_com __gmpz_com -__GMP_DECLSPEC void mpz_com __GMP_PROTO ((mpz_ptr, mpz_srcptr)); - -#define mpz_combit __gmpz_combit -__GMP_DECLSPEC void mpz_combit __GMP_PROTO ((mpz_ptr, mp_bitcnt_t)); - -#define mpz_congruent_p __gmpz_congruent_p -__GMP_DECLSPEC int mpz_congruent_p __GMP_PROTO ((mpz_srcptr, mpz_srcptr, mpz_srcptr)) __GMP_ATTRIBUTE_PURE; - -#define mpz_congruent_2exp_p __gmpz_congruent_2exp_p -__GMP_DECLSPEC int mpz_congruent_2exp_p __GMP_PROTO ((mpz_srcptr, mpz_srcptr, mp_bitcnt_t)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpz_congruent_ui_p __gmpz_congruent_ui_p -__GMP_DECLSPEC int mpz_congruent_ui_p __GMP_PROTO ((mpz_srcptr, unsigned long, unsigned long)) __GMP_ATTRIBUTE_PURE; - -#define mpz_divexact __gmpz_divexact -__GMP_DECLSPEC void mpz_divexact __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_divexact_ui __gmpz_divexact_ui -__GMP_DECLSPEC void mpz_divexact_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long)); - -#define mpz_divisible_p __gmpz_divisible_p -__GMP_DECLSPEC int mpz_divisible_p __GMP_PROTO ((mpz_srcptr, mpz_srcptr)) __GMP_ATTRIBUTE_PURE; - -#define mpz_divisible_ui_p __gmpz_divisible_ui_p -__GMP_DECLSPEC int mpz_divisible_ui_p __GMP_PROTO ((mpz_srcptr, unsigned long)) __GMP_ATTRIBUTE_PURE; - -#define mpz_divisible_2exp_p __gmpz_divisible_2exp_p -__GMP_DECLSPEC int mpz_divisible_2exp_p __GMP_PROTO ((mpz_srcptr, mp_bitcnt_t)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpz_dump __gmpz_dump -__GMP_DECLSPEC void mpz_dump __GMP_PROTO ((mpz_srcptr)); - -#define mpz_export __gmpz_export -__GMP_DECLSPEC void *mpz_export __GMP_PROTO ((void *, size_t *, int, size_t, int, size_t, mpz_srcptr)); - -#define mpz_fac_ui __gmpz_fac_ui -__GMP_DECLSPEC void mpz_fac_ui __GMP_PROTO ((mpz_ptr, unsigned long int)); - -#define mpz_fdiv_q __gmpz_fdiv_q -__GMP_DECLSPEC void mpz_fdiv_q __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_fdiv_q_2exp __gmpz_fdiv_q_2exp -__GMP_DECLSPEC void mpz_fdiv_q_2exp __GMP_PROTO ((mpz_ptr, mpz_srcptr, mp_bitcnt_t)); - -#define mpz_fdiv_q_ui __gmpz_fdiv_q_ui -__GMP_DECLSPEC unsigned long int mpz_fdiv_q_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_fdiv_qr __gmpz_fdiv_qr -__GMP_DECLSPEC void mpz_fdiv_qr __GMP_PROTO ((mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_fdiv_qr_ui __gmpz_fdiv_qr_ui -__GMP_DECLSPEC unsigned long int mpz_fdiv_qr_ui __GMP_PROTO ((mpz_ptr, mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_fdiv_r __gmpz_fdiv_r -__GMP_DECLSPEC void mpz_fdiv_r __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_fdiv_r_2exp __gmpz_fdiv_r_2exp -__GMP_DECLSPEC void mpz_fdiv_r_2exp __GMP_PROTO ((mpz_ptr, mpz_srcptr, mp_bitcnt_t)); - -#define mpz_fdiv_r_ui __gmpz_fdiv_r_ui -__GMP_DECLSPEC unsigned long int mpz_fdiv_r_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_fdiv_ui __gmpz_fdiv_ui -__GMP_DECLSPEC unsigned long int mpz_fdiv_ui __GMP_PROTO ((mpz_srcptr, unsigned long int)) __GMP_ATTRIBUTE_PURE; - -#define mpz_fib_ui __gmpz_fib_ui -__GMP_DECLSPEC void mpz_fib_ui __GMP_PROTO ((mpz_ptr, unsigned long int)); - -#define mpz_fib2_ui __gmpz_fib2_ui -__GMP_DECLSPEC void mpz_fib2_ui __GMP_PROTO ((mpz_ptr, mpz_ptr, unsigned long int)); - -#define mpz_fits_sint_p __gmpz_fits_sint_p -__GMP_DECLSPEC int mpz_fits_sint_p __GMP_PROTO ((mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpz_fits_slong_p __gmpz_fits_slong_p -__GMP_DECLSPEC int mpz_fits_slong_p __GMP_PROTO ((mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpz_fits_sshort_p __gmpz_fits_sshort_p -__GMP_DECLSPEC int mpz_fits_sshort_p __GMP_PROTO ((mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpz_fits_uint_p __gmpz_fits_uint_p -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_fits_uint_p) -__GMP_DECLSPEC int mpz_fits_uint_p __GMP_PROTO ((mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#endif - -#define mpz_fits_ulong_p __gmpz_fits_ulong_p -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_fits_ulong_p) -__GMP_DECLSPEC int mpz_fits_ulong_p __GMP_PROTO ((mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#endif - -#define mpz_fits_ushort_p __gmpz_fits_ushort_p -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_fits_ushort_p) -__GMP_DECLSPEC int mpz_fits_ushort_p __GMP_PROTO ((mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#endif - -#define mpz_gcd __gmpz_gcd -__GMP_DECLSPEC void mpz_gcd __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_gcd_ui __gmpz_gcd_ui -__GMP_DECLSPEC unsigned long int mpz_gcd_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_gcdext __gmpz_gcdext -__GMP_DECLSPEC void mpz_gcdext __GMP_PROTO ((mpz_ptr, mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_get_d __gmpz_get_d -__GMP_DECLSPEC double mpz_get_d __GMP_PROTO ((mpz_srcptr)) __GMP_ATTRIBUTE_PURE; - -#define mpz_get_d_2exp __gmpz_get_d_2exp -__GMP_DECLSPEC double mpz_get_d_2exp __GMP_PROTO ((signed long int *, mpz_srcptr)); - -#define mpz_get_si __gmpz_get_si -__GMP_DECLSPEC /* signed */ long int mpz_get_si __GMP_PROTO ((mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpz_get_str __gmpz_get_str -__GMP_DECLSPEC char *mpz_get_str __GMP_PROTO ((char *, int, mpz_srcptr)); - -#define mpz_get_ui __gmpz_get_ui -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_get_ui) -__GMP_DECLSPEC unsigned long int mpz_get_ui __GMP_PROTO ((mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#endif - -#define mpz_getlimbn __gmpz_getlimbn -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_getlimbn) -__GMP_DECLSPEC mp_limb_t mpz_getlimbn __GMP_PROTO ((mpz_srcptr, mp_size_t)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#endif - -#define mpz_hamdist __gmpz_hamdist -__GMP_DECLSPEC mp_bitcnt_t mpz_hamdist __GMP_PROTO ((mpz_srcptr, mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpz_import __gmpz_import -__GMP_DECLSPEC void mpz_import __GMP_PROTO ((mpz_ptr, size_t, int, size_t, int, size_t, __gmp_const void *)); - -#define mpz_init __gmpz_init -__GMP_DECLSPEC void mpz_init __GMP_PROTO ((mpz_ptr)); - -#define mpz_init2 __gmpz_init2 -__GMP_DECLSPEC void mpz_init2 __GMP_PROTO ((mpz_ptr, mp_bitcnt_t)); - -#define mpz_inits __gmpz_inits -__GMP_DECLSPEC void mpz_inits __GMP_PROTO ((mpz_ptr, ...)); - -#define mpz_init_set __gmpz_init_set -__GMP_DECLSPEC void mpz_init_set __GMP_PROTO ((mpz_ptr, mpz_srcptr)); - -#define mpz_init_set_d __gmpz_init_set_d -__GMP_DECLSPEC void mpz_init_set_d __GMP_PROTO ((mpz_ptr, double)); - -#define mpz_init_set_si __gmpz_init_set_si -__GMP_DECLSPEC void mpz_init_set_si __GMP_PROTO ((mpz_ptr, signed long int)); - -#define mpz_init_set_str __gmpz_init_set_str -__GMP_DECLSPEC int mpz_init_set_str __GMP_PROTO ((mpz_ptr, __gmp_const char *, int)); - -#define mpz_init_set_ui __gmpz_init_set_ui -__GMP_DECLSPEC void mpz_init_set_ui __GMP_PROTO ((mpz_ptr, unsigned long int)); - -#define mpz_inp_raw __gmpz_inp_raw -#ifdef _GMP_H_HAVE_FILE -__GMP_DECLSPEC size_t mpz_inp_raw __GMP_PROTO ((mpz_ptr, FILE *)); -#endif - -#define mpz_inp_str __gmpz_inp_str -#ifdef _GMP_H_HAVE_FILE -__GMP_DECLSPEC size_t mpz_inp_str __GMP_PROTO ((mpz_ptr, FILE *, int)); -#endif - -#define mpz_invert __gmpz_invert -__GMP_DECLSPEC int mpz_invert __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_ior __gmpz_ior -__GMP_DECLSPEC void mpz_ior __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_jacobi __gmpz_jacobi -__GMP_DECLSPEC int mpz_jacobi __GMP_PROTO ((mpz_srcptr, mpz_srcptr)) __GMP_ATTRIBUTE_PURE; - -#define mpz_kronecker mpz_jacobi /* alias */ - -#define mpz_kronecker_si __gmpz_kronecker_si -__GMP_DECLSPEC int mpz_kronecker_si __GMP_PROTO ((mpz_srcptr, long)) __GMP_ATTRIBUTE_PURE; - -#define mpz_kronecker_ui __gmpz_kronecker_ui -__GMP_DECLSPEC int mpz_kronecker_ui __GMP_PROTO ((mpz_srcptr, unsigned long)) __GMP_ATTRIBUTE_PURE; - -#define mpz_si_kronecker __gmpz_si_kronecker -__GMP_DECLSPEC int mpz_si_kronecker __GMP_PROTO ((long, mpz_srcptr)) __GMP_ATTRIBUTE_PURE; - -#define mpz_ui_kronecker __gmpz_ui_kronecker -__GMP_DECLSPEC int mpz_ui_kronecker __GMP_PROTO ((unsigned long, mpz_srcptr)) __GMP_ATTRIBUTE_PURE; - -#define mpz_lcm __gmpz_lcm -__GMP_DECLSPEC void mpz_lcm __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_lcm_ui __gmpz_lcm_ui -__GMP_DECLSPEC void mpz_lcm_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long)); - -#define mpz_legendre mpz_jacobi /* alias */ - -#define mpz_lucnum_ui __gmpz_lucnum_ui -__GMP_DECLSPEC void mpz_lucnum_ui __GMP_PROTO ((mpz_ptr, unsigned long int)); - -#define mpz_lucnum2_ui __gmpz_lucnum2_ui -__GMP_DECLSPEC void mpz_lucnum2_ui __GMP_PROTO ((mpz_ptr, mpz_ptr, unsigned long int)); - -#define mpz_millerrabin __gmpz_millerrabin -__GMP_DECLSPEC int mpz_millerrabin __GMP_PROTO ((mpz_srcptr, int)) __GMP_ATTRIBUTE_PURE; - -#define mpz_mod __gmpz_mod -__GMP_DECLSPEC void mpz_mod __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_mod_ui mpz_fdiv_r_ui /* same as fdiv_r because divisor unsigned */ - -#define mpz_mul __gmpz_mul -__GMP_DECLSPEC void mpz_mul __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_mul_2exp __gmpz_mul_2exp -__GMP_DECLSPEC void mpz_mul_2exp __GMP_PROTO ((mpz_ptr, mpz_srcptr, mp_bitcnt_t)); - -#define mpz_mul_si __gmpz_mul_si -__GMP_DECLSPEC void mpz_mul_si __GMP_PROTO ((mpz_ptr, mpz_srcptr, long int)); - -#define mpz_mul_ui __gmpz_mul_ui -__GMP_DECLSPEC void mpz_mul_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_neg __gmpz_neg -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_neg) -__GMP_DECLSPEC void mpz_neg __GMP_PROTO ((mpz_ptr, mpz_srcptr)); -#endif - -#define mpz_nextprime __gmpz_nextprime -__GMP_DECLSPEC void mpz_nextprime __GMP_PROTO ((mpz_ptr, mpz_srcptr)); - -#define mpz_out_raw __gmpz_out_raw -#ifdef _GMP_H_HAVE_FILE -__GMP_DECLSPEC size_t mpz_out_raw __GMP_PROTO ((FILE *, mpz_srcptr)); -#endif - -#define mpz_out_str __gmpz_out_str -#ifdef _GMP_H_HAVE_FILE -__GMP_DECLSPEC size_t mpz_out_str __GMP_PROTO ((FILE *, int, mpz_srcptr)); -#endif - -#define mpz_perfect_power_p __gmpz_perfect_power_p -__GMP_DECLSPEC int mpz_perfect_power_p __GMP_PROTO ((mpz_srcptr)) __GMP_ATTRIBUTE_PURE; - -#define mpz_perfect_square_p __gmpz_perfect_square_p -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_perfect_square_p) -__GMP_DECLSPEC int mpz_perfect_square_p __GMP_PROTO ((mpz_srcptr)) __GMP_ATTRIBUTE_PURE; -#endif - -#define mpz_popcount __gmpz_popcount -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_popcount) -__GMP_DECLSPEC mp_bitcnt_t mpz_popcount __GMP_PROTO ((mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#endif - -#define mpz_pow_ui __gmpz_pow_ui -__GMP_DECLSPEC void mpz_pow_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_powm __gmpz_powm -__GMP_DECLSPEC void mpz_powm __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_powm_sec __gmpz_powm_sec -__GMP_DECLSPEC void mpz_powm_sec __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_powm_ui __gmpz_powm_ui -__GMP_DECLSPEC void mpz_powm_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int, mpz_srcptr)); - -#define mpz_probab_prime_p __gmpz_probab_prime_p -__GMP_DECLSPEC int mpz_probab_prime_p __GMP_PROTO ((mpz_srcptr, int)) __GMP_ATTRIBUTE_PURE; - -#define mpz_random __gmpz_random -__GMP_DECLSPEC void mpz_random __GMP_PROTO ((mpz_ptr, mp_size_t)); - -#define mpz_random2 __gmpz_random2 -__GMP_DECLSPEC void mpz_random2 __GMP_PROTO ((mpz_ptr, mp_size_t)); - -#define mpz_realloc2 __gmpz_realloc2 -__GMP_DECLSPEC void mpz_realloc2 __GMP_PROTO ((mpz_ptr, mp_bitcnt_t)); - -#define mpz_remove __gmpz_remove -__GMP_DECLSPEC unsigned long int mpz_remove __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_root __gmpz_root -__GMP_DECLSPEC int mpz_root __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_rootrem __gmpz_rootrem -__GMP_DECLSPEC void mpz_rootrem __GMP_PROTO ((mpz_ptr,mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_rrandomb __gmpz_rrandomb -__GMP_DECLSPEC void mpz_rrandomb __GMP_PROTO ((mpz_ptr, gmp_randstate_t, mp_bitcnt_t)); - -#define mpz_scan0 __gmpz_scan0 -__GMP_DECLSPEC mp_bitcnt_t mpz_scan0 __GMP_PROTO ((mpz_srcptr, mp_bitcnt_t)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpz_scan1 __gmpz_scan1 -__GMP_DECLSPEC mp_bitcnt_t mpz_scan1 __GMP_PROTO ((mpz_srcptr, mp_bitcnt_t)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpz_set __gmpz_set -__GMP_DECLSPEC void mpz_set __GMP_PROTO ((mpz_ptr, mpz_srcptr)); - -#define mpz_set_d __gmpz_set_d -__GMP_DECLSPEC void mpz_set_d __GMP_PROTO ((mpz_ptr, double)); - -#define mpz_set_f __gmpz_set_f -__GMP_DECLSPEC void mpz_set_f __GMP_PROTO ((mpz_ptr, mpf_srcptr)); - -#define mpz_set_q __gmpz_set_q -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_set_q) -__GMP_DECLSPEC void mpz_set_q __GMP_PROTO ((mpz_ptr, mpq_srcptr)); -#endif - -#define mpz_set_si __gmpz_set_si -__GMP_DECLSPEC void mpz_set_si __GMP_PROTO ((mpz_ptr, signed long int)); - -#define mpz_set_str __gmpz_set_str -__GMP_DECLSPEC int mpz_set_str __GMP_PROTO ((mpz_ptr, __gmp_const char *, int)); - -#define mpz_set_ui __gmpz_set_ui -__GMP_DECLSPEC void mpz_set_ui __GMP_PROTO ((mpz_ptr, unsigned long int)); - -#define mpz_setbit __gmpz_setbit -__GMP_DECLSPEC void mpz_setbit __GMP_PROTO ((mpz_ptr, mp_bitcnt_t)); - -#define mpz_size __gmpz_size -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_size) -__GMP_DECLSPEC size_t mpz_size __GMP_PROTO ((mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#endif - -#define mpz_sizeinbase __gmpz_sizeinbase -__GMP_DECLSPEC size_t mpz_sizeinbase __GMP_PROTO ((mpz_srcptr, int)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpz_sqrt __gmpz_sqrt -__GMP_DECLSPEC void mpz_sqrt __GMP_PROTO ((mpz_ptr, mpz_srcptr)); - -#define mpz_sqrtrem __gmpz_sqrtrem -__GMP_DECLSPEC void mpz_sqrtrem __GMP_PROTO ((mpz_ptr, mpz_ptr, mpz_srcptr)); - -#define mpz_sub __gmpz_sub -__GMP_DECLSPEC void mpz_sub __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_sub_ui __gmpz_sub_ui -__GMP_DECLSPEC void mpz_sub_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_ui_sub __gmpz_ui_sub -__GMP_DECLSPEC void mpz_ui_sub __GMP_PROTO ((mpz_ptr, unsigned long int, mpz_srcptr)); - -#define mpz_submul __gmpz_submul -__GMP_DECLSPEC void mpz_submul __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_submul_ui __gmpz_submul_ui -__GMP_DECLSPEC void mpz_submul_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_swap __gmpz_swap -__GMP_DECLSPEC void mpz_swap __GMP_PROTO ((mpz_ptr, mpz_ptr)) __GMP_NOTHROW; - -#define mpz_tdiv_ui __gmpz_tdiv_ui -__GMP_DECLSPEC unsigned long int mpz_tdiv_ui __GMP_PROTO ((mpz_srcptr, unsigned long int)) __GMP_ATTRIBUTE_PURE; - -#define mpz_tdiv_q __gmpz_tdiv_q -__GMP_DECLSPEC void mpz_tdiv_q __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_tdiv_q_2exp __gmpz_tdiv_q_2exp -__GMP_DECLSPEC void mpz_tdiv_q_2exp __GMP_PROTO ((mpz_ptr, mpz_srcptr, mp_bitcnt_t)); - -#define mpz_tdiv_q_ui __gmpz_tdiv_q_ui -__GMP_DECLSPEC unsigned long int mpz_tdiv_q_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_tdiv_qr __gmpz_tdiv_qr -__GMP_DECLSPEC void mpz_tdiv_qr __GMP_PROTO ((mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_tdiv_qr_ui __gmpz_tdiv_qr_ui -__GMP_DECLSPEC unsigned long int mpz_tdiv_qr_ui __GMP_PROTO ((mpz_ptr, mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_tdiv_r __gmpz_tdiv_r -__GMP_DECLSPEC void mpz_tdiv_r __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_tdiv_r_2exp __gmpz_tdiv_r_2exp -__GMP_DECLSPEC void mpz_tdiv_r_2exp __GMP_PROTO ((mpz_ptr, mpz_srcptr, mp_bitcnt_t)); - -#define mpz_tdiv_r_ui __gmpz_tdiv_r_ui -__GMP_DECLSPEC unsigned long int mpz_tdiv_r_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_tstbit __gmpz_tstbit -__GMP_DECLSPEC int mpz_tstbit __GMP_PROTO ((mpz_srcptr, mp_bitcnt_t)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpz_ui_pow_ui __gmpz_ui_pow_ui -__GMP_DECLSPEC void mpz_ui_pow_ui __GMP_PROTO ((mpz_ptr, unsigned long int, unsigned long int)); - -#define mpz_urandomb __gmpz_urandomb -__GMP_DECLSPEC void mpz_urandomb __GMP_PROTO ((mpz_ptr, gmp_randstate_t, mp_bitcnt_t)); - -#define mpz_urandomm __gmpz_urandomm -__GMP_DECLSPEC void mpz_urandomm __GMP_PROTO ((mpz_ptr, gmp_randstate_t, mpz_srcptr)); - -#define mpz_xor __gmpz_xor -#define mpz_eor __gmpz_xor -__GMP_DECLSPEC void mpz_xor __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - - -/**************** Rational (i.e. Q) routines. ****************/ - -#define mpq_abs __gmpq_abs -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpq_abs) -__GMP_DECLSPEC void mpq_abs __GMP_PROTO ((mpq_ptr, mpq_srcptr)); -#endif - -#define mpq_add __gmpq_add -__GMP_DECLSPEC void mpq_add __GMP_PROTO ((mpq_ptr, mpq_srcptr, mpq_srcptr)); - -#define mpq_canonicalize __gmpq_canonicalize -__GMP_DECLSPEC void mpq_canonicalize __GMP_PROTO ((mpq_ptr)); - -#define mpq_clear __gmpq_clear -__GMP_DECLSPEC void mpq_clear __GMP_PROTO ((mpq_ptr)); - -#define mpq_clears __gmpq_clears -__GMP_DECLSPEC void mpq_clears __GMP_PROTO ((mpq_ptr, ...)); - -#define mpq_cmp __gmpq_cmp -__GMP_DECLSPEC int mpq_cmp __GMP_PROTO ((mpq_srcptr, mpq_srcptr)) __GMP_ATTRIBUTE_PURE; - -#define _mpq_cmp_si __gmpq_cmp_si -__GMP_DECLSPEC int _mpq_cmp_si __GMP_PROTO ((mpq_srcptr, long, unsigned long)) __GMP_ATTRIBUTE_PURE; - -#define _mpq_cmp_ui __gmpq_cmp_ui -__GMP_DECLSPEC int _mpq_cmp_ui __GMP_PROTO ((mpq_srcptr, unsigned long int, unsigned long int)) __GMP_ATTRIBUTE_PURE; - -#define mpq_div __gmpq_div -__GMP_DECLSPEC void mpq_div __GMP_PROTO ((mpq_ptr, mpq_srcptr, mpq_srcptr)); - -#define mpq_div_2exp __gmpq_div_2exp -__GMP_DECLSPEC void mpq_div_2exp __GMP_PROTO ((mpq_ptr, mpq_srcptr, mp_bitcnt_t)); - -#define mpq_equal __gmpq_equal -__GMP_DECLSPEC int mpq_equal __GMP_PROTO ((mpq_srcptr, mpq_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpq_get_num __gmpq_get_num -__GMP_DECLSPEC void mpq_get_num __GMP_PROTO ((mpz_ptr, mpq_srcptr)); - -#define mpq_get_den __gmpq_get_den -__GMP_DECLSPEC void mpq_get_den __GMP_PROTO ((mpz_ptr, mpq_srcptr)); - -#define mpq_get_d __gmpq_get_d -__GMP_DECLSPEC double mpq_get_d __GMP_PROTO ((mpq_srcptr)) __GMP_ATTRIBUTE_PURE; - -#define mpq_get_str __gmpq_get_str -__GMP_DECLSPEC char *mpq_get_str __GMP_PROTO ((char *, int, mpq_srcptr)); - -#define mpq_init __gmpq_init -__GMP_DECLSPEC void mpq_init __GMP_PROTO ((mpq_ptr)); - -#define mpq_inits __gmpq_inits -__GMP_DECLSPEC void mpq_inits __GMP_PROTO ((mpq_ptr, ...)); - -#define mpq_inp_str __gmpq_inp_str -#ifdef _GMP_H_HAVE_FILE -__GMP_DECLSPEC size_t mpq_inp_str __GMP_PROTO ((mpq_ptr, FILE *, int)); -#endif - -#define mpq_inv __gmpq_inv -__GMP_DECLSPEC void mpq_inv __GMP_PROTO ((mpq_ptr, mpq_srcptr)); - -#define mpq_mul __gmpq_mul -__GMP_DECLSPEC void mpq_mul __GMP_PROTO ((mpq_ptr, mpq_srcptr, mpq_srcptr)); - -#define mpq_mul_2exp __gmpq_mul_2exp -__GMP_DECLSPEC void mpq_mul_2exp __GMP_PROTO ((mpq_ptr, mpq_srcptr, mp_bitcnt_t)); - -#define mpq_neg __gmpq_neg -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpq_neg) -__GMP_DECLSPEC void mpq_neg __GMP_PROTO ((mpq_ptr, mpq_srcptr)); -#endif - -#define mpq_out_str __gmpq_out_str -#ifdef _GMP_H_HAVE_FILE -__GMP_DECLSPEC size_t mpq_out_str __GMP_PROTO ((FILE *, int, mpq_srcptr)); -#endif - -#define mpq_set __gmpq_set -__GMP_DECLSPEC void mpq_set __GMP_PROTO ((mpq_ptr, mpq_srcptr)); - -#define mpq_set_d __gmpq_set_d -__GMP_DECLSPEC void mpq_set_d __GMP_PROTO ((mpq_ptr, double)); - -#define mpq_set_den __gmpq_set_den -__GMP_DECLSPEC void mpq_set_den __GMP_PROTO ((mpq_ptr, mpz_srcptr)); - -#define mpq_set_f __gmpq_set_f -__GMP_DECLSPEC void mpq_set_f __GMP_PROTO ((mpq_ptr, mpf_srcptr)); - -#define mpq_set_num __gmpq_set_num -__GMP_DECLSPEC void mpq_set_num __GMP_PROTO ((mpq_ptr, mpz_srcptr)); - -#define mpq_set_si __gmpq_set_si -__GMP_DECLSPEC void mpq_set_si __GMP_PROTO ((mpq_ptr, signed long int, unsigned long int)); - -#define mpq_set_str __gmpq_set_str -__GMP_DECLSPEC int mpq_set_str __GMP_PROTO ((mpq_ptr, __gmp_const char *, int)); - -#define mpq_set_ui __gmpq_set_ui -__GMP_DECLSPEC void mpq_set_ui __GMP_PROTO ((mpq_ptr, unsigned long int, unsigned long int)); - -#define mpq_set_z __gmpq_set_z -__GMP_DECLSPEC void mpq_set_z __GMP_PROTO ((mpq_ptr, mpz_srcptr)); - -#define mpq_sub __gmpq_sub -__GMP_DECLSPEC void mpq_sub __GMP_PROTO ((mpq_ptr, mpq_srcptr, mpq_srcptr)); - -#define mpq_swap __gmpq_swap -__GMP_DECLSPEC void mpq_swap __GMP_PROTO ((mpq_ptr, mpq_ptr)) __GMP_NOTHROW; - - -/**************** Float (i.e. F) routines. ****************/ - -#define mpf_abs __gmpf_abs -__GMP_DECLSPEC void mpf_abs __GMP_PROTO ((mpf_ptr, mpf_srcptr)); - -#define mpf_add __gmpf_add -__GMP_DECLSPEC void mpf_add __GMP_PROTO ((mpf_ptr, mpf_srcptr, mpf_srcptr)); - -#define mpf_add_ui __gmpf_add_ui -__GMP_DECLSPEC void mpf_add_ui __GMP_PROTO ((mpf_ptr, mpf_srcptr, unsigned long int)); -#define mpf_ceil __gmpf_ceil -__GMP_DECLSPEC void mpf_ceil __GMP_PROTO ((mpf_ptr, mpf_srcptr)); - -#define mpf_clear __gmpf_clear -__GMP_DECLSPEC void mpf_clear __GMP_PROTO ((mpf_ptr)); - -#define mpf_clears __gmpf_clears -__GMP_DECLSPEC void mpf_clears __GMP_PROTO ((mpf_ptr, ...)); - -#define mpf_cmp __gmpf_cmp -__GMP_DECLSPEC int mpf_cmp __GMP_PROTO ((mpf_srcptr, mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpf_cmp_d __gmpf_cmp_d -__GMP_DECLSPEC int mpf_cmp_d __GMP_PROTO ((mpf_srcptr, double)) __GMP_ATTRIBUTE_PURE; - -#define mpf_cmp_si __gmpf_cmp_si -__GMP_DECLSPEC int mpf_cmp_si __GMP_PROTO ((mpf_srcptr, signed long int)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpf_cmp_ui __gmpf_cmp_ui -__GMP_DECLSPEC int mpf_cmp_ui __GMP_PROTO ((mpf_srcptr, unsigned long int)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpf_div __gmpf_div -__GMP_DECLSPEC void mpf_div __GMP_PROTO ((mpf_ptr, mpf_srcptr, mpf_srcptr)); - -#define mpf_div_2exp __gmpf_div_2exp -__GMP_DECLSPEC void mpf_div_2exp __GMP_PROTO ((mpf_ptr, mpf_srcptr, mp_bitcnt_t)); - -#define mpf_div_ui __gmpf_div_ui -__GMP_DECLSPEC void mpf_div_ui __GMP_PROTO ((mpf_ptr, mpf_srcptr, unsigned long int)); - -#define mpf_dump __gmpf_dump -__GMP_DECLSPEC void mpf_dump __GMP_PROTO ((mpf_srcptr)); - -#define mpf_eq __gmpf_eq -__GMP_DECLSPEC int mpf_eq __GMP_PROTO ((mpf_srcptr, mpf_srcptr, unsigned long int)) __GMP_ATTRIBUTE_PURE; - -#define mpf_fits_sint_p __gmpf_fits_sint_p -__GMP_DECLSPEC int mpf_fits_sint_p __GMP_PROTO ((mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpf_fits_slong_p __gmpf_fits_slong_p -__GMP_DECLSPEC int mpf_fits_slong_p __GMP_PROTO ((mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpf_fits_sshort_p __gmpf_fits_sshort_p -__GMP_DECLSPEC int mpf_fits_sshort_p __GMP_PROTO ((mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpf_fits_uint_p __gmpf_fits_uint_p -__GMP_DECLSPEC int mpf_fits_uint_p __GMP_PROTO ((mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpf_fits_ulong_p __gmpf_fits_ulong_p -__GMP_DECLSPEC int mpf_fits_ulong_p __GMP_PROTO ((mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpf_fits_ushort_p __gmpf_fits_ushort_p -__GMP_DECLSPEC int mpf_fits_ushort_p __GMP_PROTO ((mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpf_floor __gmpf_floor -__GMP_DECLSPEC void mpf_floor __GMP_PROTO ((mpf_ptr, mpf_srcptr)); - -#define mpf_get_d __gmpf_get_d -__GMP_DECLSPEC double mpf_get_d __GMP_PROTO ((mpf_srcptr)) __GMP_ATTRIBUTE_PURE; - -#define mpf_get_d_2exp __gmpf_get_d_2exp -__GMP_DECLSPEC double mpf_get_d_2exp __GMP_PROTO ((signed long int *, mpf_srcptr)); - -#define mpf_get_default_prec __gmpf_get_default_prec -__GMP_DECLSPEC mp_bitcnt_t mpf_get_default_prec __GMP_PROTO ((void)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpf_get_prec __gmpf_get_prec -__GMP_DECLSPEC mp_bitcnt_t mpf_get_prec __GMP_PROTO ((mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpf_get_si __gmpf_get_si -__GMP_DECLSPEC long mpf_get_si __GMP_PROTO ((mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpf_get_str __gmpf_get_str -__GMP_DECLSPEC char *mpf_get_str __GMP_PROTO ((char *, mp_exp_t *, int, size_t, mpf_srcptr)); - -#define mpf_get_ui __gmpf_get_ui -__GMP_DECLSPEC unsigned long mpf_get_ui __GMP_PROTO ((mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpf_init __gmpf_init -__GMP_DECLSPEC void mpf_init __GMP_PROTO ((mpf_ptr)); - -#define mpf_init2 __gmpf_init2 -__GMP_DECLSPEC void mpf_init2 __GMP_PROTO ((mpf_ptr, mp_bitcnt_t)); - -#define mpf_inits __gmpf_inits -__GMP_DECLSPEC void mpf_inits __GMP_PROTO ((mpf_ptr, ...)); - -#define mpf_init_set __gmpf_init_set -__GMP_DECLSPEC void mpf_init_set __GMP_PROTO ((mpf_ptr, mpf_srcptr)); - -#define mpf_init_set_d __gmpf_init_set_d -__GMP_DECLSPEC void mpf_init_set_d __GMP_PROTO ((mpf_ptr, double)); - -#define mpf_init_set_si __gmpf_init_set_si -__GMP_DECLSPEC void mpf_init_set_si __GMP_PROTO ((mpf_ptr, signed long int)); - -#define mpf_init_set_str __gmpf_init_set_str -__GMP_DECLSPEC int mpf_init_set_str __GMP_PROTO ((mpf_ptr, __gmp_const char *, int)); - -#define mpf_init_set_ui __gmpf_init_set_ui -__GMP_DECLSPEC void mpf_init_set_ui __GMP_PROTO ((mpf_ptr, unsigned long int)); - -#define mpf_inp_str __gmpf_inp_str -#ifdef _GMP_H_HAVE_FILE -__GMP_DECLSPEC size_t mpf_inp_str __GMP_PROTO ((mpf_ptr, FILE *, int)); -#endif - -#define mpf_integer_p __gmpf_integer_p -__GMP_DECLSPEC int mpf_integer_p __GMP_PROTO ((mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpf_mul __gmpf_mul -__GMP_DECLSPEC void mpf_mul __GMP_PROTO ((mpf_ptr, mpf_srcptr, mpf_srcptr)); - -#define mpf_mul_2exp __gmpf_mul_2exp -__GMP_DECLSPEC void mpf_mul_2exp __GMP_PROTO ((mpf_ptr, mpf_srcptr, mp_bitcnt_t)); - -#define mpf_mul_ui __gmpf_mul_ui -__GMP_DECLSPEC void mpf_mul_ui __GMP_PROTO ((mpf_ptr, mpf_srcptr, unsigned long int)); - -#define mpf_neg __gmpf_neg -__GMP_DECLSPEC void mpf_neg __GMP_PROTO ((mpf_ptr, mpf_srcptr)); - -#define mpf_out_str __gmpf_out_str -#ifdef _GMP_H_HAVE_FILE -__GMP_DECLSPEC size_t mpf_out_str __GMP_PROTO ((FILE *, int, size_t, mpf_srcptr)); -#endif - -#define mpf_pow_ui __gmpf_pow_ui -__GMP_DECLSPEC void mpf_pow_ui __GMP_PROTO ((mpf_ptr, mpf_srcptr, unsigned long int)); - -#define mpf_random2 __gmpf_random2 -__GMP_DECLSPEC void mpf_random2 __GMP_PROTO ((mpf_ptr, mp_size_t, mp_exp_t)); - -#define mpf_reldiff __gmpf_reldiff -__GMP_DECLSPEC void mpf_reldiff __GMP_PROTO ((mpf_ptr, mpf_srcptr, mpf_srcptr)); - -#define mpf_set __gmpf_set -__GMP_DECLSPEC void mpf_set __GMP_PROTO ((mpf_ptr, mpf_srcptr)); - -#define mpf_set_d __gmpf_set_d -__GMP_DECLSPEC void mpf_set_d __GMP_PROTO ((mpf_ptr, double)); - -#define mpf_set_default_prec __gmpf_set_default_prec -__GMP_DECLSPEC void mpf_set_default_prec __GMP_PROTO ((mp_bitcnt_t)) __GMP_NOTHROW; - -#define mpf_set_prec __gmpf_set_prec -__GMP_DECLSPEC void mpf_set_prec __GMP_PROTO ((mpf_ptr, mp_bitcnt_t)); - -#define mpf_set_prec_raw __gmpf_set_prec_raw -__GMP_DECLSPEC void mpf_set_prec_raw __GMP_PROTO ((mpf_ptr, mp_bitcnt_t)) __GMP_NOTHROW; - -#define mpf_set_q __gmpf_set_q -__GMP_DECLSPEC void mpf_set_q __GMP_PROTO ((mpf_ptr, mpq_srcptr)); - -#define mpf_set_si __gmpf_set_si -__GMP_DECLSPEC void mpf_set_si __GMP_PROTO ((mpf_ptr, signed long int)); - -#define mpf_set_str __gmpf_set_str -__GMP_DECLSPEC int mpf_set_str __GMP_PROTO ((mpf_ptr, __gmp_const char *, int)); - -#define mpf_set_ui __gmpf_set_ui -__GMP_DECLSPEC void mpf_set_ui __GMP_PROTO ((mpf_ptr, unsigned long int)); - -#define mpf_set_z __gmpf_set_z -__GMP_DECLSPEC void mpf_set_z __GMP_PROTO ((mpf_ptr, mpz_srcptr)); - -#define mpf_size __gmpf_size -__GMP_DECLSPEC size_t mpf_size __GMP_PROTO ((mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpf_sqrt __gmpf_sqrt -__GMP_DECLSPEC void mpf_sqrt __GMP_PROTO ((mpf_ptr, mpf_srcptr)); - -#define mpf_sqrt_ui __gmpf_sqrt_ui -__GMP_DECLSPEC void mpf_sqrt_ui __GMP_PROTO ((mpf_ptr, unsigned long int)); - -#define mpf_sub __gmpf_sub -__GMP_DECLSPEC void mpf_sub __GMP_PROTO ((mpf_ptr, mpf_srcptr, mpf_srcptr)); - -#define mpf_sub_ui __gmpf_sub_ui -__GMP_DECLSPEC void mpf_sub_ui __GMP_PROTO ((mpf_ptr, mpf_srcptr, unsigned long int)); - -#define mpf_swap __gmpf_swap -__GMP_DECLSPEC void mpf_swap __GMP_PROTO ((mpf_ptr, mpf_ptr)) __GMP_NOTHROW; - -#define mpf_trunc __gmpf_trunc -__GMP_DECLSPEC void mpf_trunc __GMP_PROTO ((mpf_ptr, mpf_srcptr)); - -#define mpf_ui_div __gmpf_ui_div -__GMP_DECLSPEC void mpf_ui_div __GMP_PROTO ((mpf_ptr, unsigned long int, mpf_srcptr)); - -#define mpf_ui_sub __gmpf_ui_sub -__GMP_DECLSPEC void mpf_ui_sub __GMP_PROTO ((mpf_ptr, unsigned long int, mpf_srcptr)); - -#define mpf_urandomb __gmpf_urandomb -__GMP_DECLSPEC void mpf_urandomb __GMP_PROTO ((mpf_t, gmp_randstate_t, mp_bitcnt_t)); - - -/************ Low level positive-integer (i.e. N) routines. ************/ - -/* This is ugly, but we need to make user calls reach the prefixed function. */ - -#define mpn_add __MPN(add) -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpn_add) -__GMP_DECLSPEC mp_limb_t mpn_add __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_srcptr,mp_size_t)); -#endif - -#define mpn_add_1 __MPN(add_1) -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpn_add_1) -__GMP_DECLSPEC mp_limb_t mpn_add_1 __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_limb_t)) __GMP_NOTHROW; -#endif - -#define mpn_add_n __MPN(add_n) -__GMP_DECLSPEC mp_limb_t mpn_add_n __GMP_PROTO ((mp_ptr, mp_srcptr, mp_srcptr, mp_size_t)); - -#define mpn_addmul_1 __MPN(addmul_1) -__GMP_DECLSPEC mp_limb_t mpn_addmul_1 __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_limb_t)); - -#define mpn_cmp __MPN(cmp) -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpn_cmp) -__GMP_DECLSPEC int mpn_cmp __GMP_PROTO ((mp_srcptr, mp_srcptr, mp_size_t)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#endif - -#define mpn_divexact_by3(dst,src,size) \ - mpn_divexact_by3c (dst, src, size, __GMP_CAST (mp_limb_t, 0)) - -#define mpn_divexact_by3c __MPN(divexact_by3c) -__GMP_DECLSPEC mp_limb_t mpn_divexact_by3c __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_limb_t)); - -#define mpn_divmod_1(qp,np,nsize,dlimb) \ - mpn_divrem_1 (qp, __GMP_CAST (mp_size_t, 0), np, nsize, dlimb) - -#define mpn_divrem __MPN(divrem) -__GMP_DECLSPEC mp_limb_t mpn_divrem __GMP_PROTO ((mp_ptr, mp_size_t, mp_ptr, mp_size_t, mp_srcptr, mp_size_t)); - -#define mpn_divrem_1 __MPN(divrem_1) -__GMP_DECLSPEC mp_limb_t mpn_divrem_1 __GMP_PROTO ((mp_ptr, mp_size_t, mp_srcptr, mp_size_t, mp_limb_t)); - -#define mpn_divrem_2 __MPN(divrem_2) -__GMP_DECLSPEC mp_limb_t mpn_divrem_2 __GMP_PROTO ((mp_ptr, mp_size_t, mp_ptr, mp_size_t, mp_srcptr)); - -#define mpn_gcd __MPN(gcd) -__GMP_DECLSPEC mp_size_t mpn_gcd __GMP_PROTO ((mp_ptr, mp_ptr, mp_size_t, mp_ptr, mp_size_t)); - -#define mpn_gcd_1 __MPN(gcd_1) -__GMP_DECLSPEC mp_limb_t mpn_gcd_1 __GMP_PROTO ((mp_srcptr, mp_size_t, mp_limb_t)) __GMP_ATTRIBUTE_PURE; - -#define mpn_gcdext_1 __MPN(gcdext_1) -__GMP_DECLSPEC mp_limb_t mpn_gcdext_1 __GMP_PROTO ((mp_limb_signed_t *, mp_limb_signed_t *, mp_limb_t, mp_limb_t)); - -#define mpn_gcdext __MPN(gcdext) -__GMP_DECLSPEC mp_size_t mpn_gcdext __GMP_PROTO ((mp_ptr, mp_ptr, mp_size_t *, mp_ptr, mp_size_t, mp_ptr, mp_size_t)); - -#define mpn_get_str __MPN(get_str) -__GMP_DECLSPEC size_t mpn_get_str __GMP_PROTO ((unsigned char *, int, mp_ptr, mp_size_t)); - -#define mpn_hamdist __MPN(hamdist) -__GMP_DECLSPEC mp_bitcnt_t mpn_hamdist __GMP_PROTO ((mp_srcptr, mp_srcptr, mp_size_t)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpn_lshift __MPN(lshift) -__GMP_DECLSPEC mp_limb_t mpn_lshift __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, unsigned int)); - -#define mpn_mod_1 __MPN(mod_1) -__GMP_DECLSPEC mp_limb_t mpn_mod_1 __GMP_PROTO ((mp_srcptr, mp_size_t, mp_limb_t)) __GMP_ATTRIBUTE_PURE; - -#define mpn_mul __MPN(mul) -__GMP_DECLSPEC mp_limb_t mpn_mul __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t)); - -#define mpn_mul_1 __MPN(mul_1) -__GMP_DECLSPEC mp_limb_t mpn_mul_1 __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_limb_t)); - -#define mpn_mul_n __MPN(mul_n) -__GMP_DECLSPEC void mpn_mul_n __GMP_PROTO ((mp_ptr, mp_srcptr, mp_srcptr, mp_size_t)); - -#define mpn_sqr __MPN(sqr) -__GMP_DECLSPEC void mpn_sqr __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t)); - -#define mpn_neg __MPN(neg) -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpn_neg) -__GMP_DECLSPEC mp_limb_t mpn_neg __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t)); -#endif - -#define mpn_com __MPN(com) -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpn_com) -__GMP_DECLSPEC void mpn_com __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t)); -#endif - -#define mpn_perfect_square_p __MPN(perfect_square_p) -__GMP_DECLSPEC int mpn_perfect_square_p __GMP_PROTO ((mp_srcptr, mp_size_t)) __GMP_ATTRIBUTE_PURE; - -#define mpn_perfect_power_p __MPN(perfect_power_p) -__GMP_DECLSPEC int mpn_perfect_power_p __GMP_PROTO ((mp_srcptr, mp_size_t)) __GMP_ATTRIBUTE_PURE; - -#define mpn_popcount __MPN(popcount) -__GMP_DECLSPEC mp_bitcnt_t mpn_popcount __GMP_PROTO ((mp_srcptr, mp_size_t)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpn_pow_1 __MPN(pow_1) -__GMP_DECLSPEC mp_size_t mpn_pow_1 __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_limb_t, mp_ptr)); - -/* undocumented now, but retained here for upward compatibility */ -#define mpn_preinv_mod_1 __MPN(preinv_mod_1) -__GMP_DECLSPEC mp_limb_t mpn_preinv_mod_1 __GMP_PROTO ((mp_srcptr, mp_size_t, mp_limb_t, mp_limb_t)) __GMP_ATTRIBUTE_PURE; - -#define mpn_random __MPN(random) -__GMP_DECLSPEC void mpn_random __GMP_PROTO ((mp_ptr, mp_size_t)); - -#define mpn_random2 __MPN(random2) -__GMP_DECLSPEC void mpn_random2 __GMP_PROTO ((mp_ptr, mp_size_t)); - -#define mpn_rshift __MPN(rshift) -__GMP_DECLSPEC mp_limb_t mpn_rshift __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, unsigned int)); - -#define mpn_scan0 __MPN(scan0) -__GMP_DECLSPEC mp_bitcnt_t mpn_scan0 __GMP_PROTO ((mp_srcptr, mp_bitcnt_t)) __GMP_ATTRIBUTE_PURE; - -#define mpn_scan1 __MPN(scan1) -__GMP_DECLSPEC mp_bitcnt_t mpn_scan1 __GMP_PROTO ((mp_srcptr, mp_bitcnt_t)) __GMP_ATTRIBUTE_PURE; - -#define mpn_set_str __MPN(set_str) -__GMP_DECLSPEC mp_size_t mpn_set_str __GMP_PROTO ((mp_ptr, __gmp_const unsigned char *, size_t, int)); - -#define mpn_sqrtrem __MPN(sqrtrem) -__GMP_DECLSPEC mp_size_t mpn_sqrtrem __GMP_PROTO ((mp_ptr, mp_ptr, mp_srcptr, mp_size_t)); - -#define mpn_sub __MPN(sub) -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpn_sub) -__GMP_DECLSPEC mp_limb_t mpn_sub __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_srcptr,mp_size_t)); -#endif - -#define mpn_sub_1 __MPN(sub_1) -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpn_sub_1) -__GMP_DECLSPEC mp_limb_t mpn_sub_1 __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_limb_t)) __GMP_NOTHROW; -#endif - -#define mpn_sub_n __MPN(sub_n) -__GMP_DECLSPEC mp_limb_t mpn_sub_n __GMP_PROTO ((mp_ptr, mp_srcptr, mp_srcptr, mp_size_t)); - -#define mpn_submul_1 __MPN(submul_1) -__GMP_DECLSPEC mp_limb_t mpn_submul_1 __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_limb_t)); - -#define mpn_tdiv_qr __MPN(tdiv_qr) -__GMP_DECLSPEC void mpn_tdiv_qr __GMP_PROTO ((mp_ptr, mp_ptr, mp_size_t, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t)); - -#define mpn_and_n __MPN(and_n) -__GMP_DECLSPEC void mpn_and_n __GMP_PROTO ((mp_ptr, mp_srcptr, mp_srcptr, mp_size_t)); -#define mpn_andn_n __MPN(andn_n) -__GMP_DECLSPEC void mpn_andn_n __GMP_PROTO ((mp_ptr, mp_srcptr, mp_srcptr, mp_size_t)); -#define mpn_nand_n __MPN(nand_n) -__GMP_DECLSPEC void mpn_nand_n __GMP_PROTO ((mp_ptr, mp_srcptr, mp_srcptr, mp_size_t)); -#define mpn_ior_n __MPN(ior_n) -__GMP_DECLSPEC void mpn_ior_n __GMP_PROTO ((mp_ptr, mp_srcptr, mp_srcptr, mp_size_t)); -#define mpn_iorn_n __MPN(iorn_n) -__GMP_DECLSPEC void mpn_iorn_n __GMP_PROTO ((mp_ptr, mp_srcptr, mp_srcptr, mp_size_t)); -#define mpn_nior_n __MPN(nior_n) -__GMP_DECLSPEC void mpn_nior_n __GMP_PROTO ((mp_ptr, mp_srcptr, mp_srcptr, mp_size_t)); -#define mpn_xor_n __MPN(xor_n) -__GMP_DECLSPEC void mpn_xor_n __GMP_PROTO ((mp_ptr, mp_srcptr, mp_srcptr, mp_size_t)); -#define mpn_xnor_n __MPN(xnor_n) -__GMP_DECLSPEC void mpn_xnor_n __GMP_PROTO ((mp_ptr, mp_srcptr, mp_srcptr, mp_size_t)); - -#define mpn_copyi __MPN(copyi) -__GMP_DECLSPEC void mpn_copyi __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t)); -#define mpn_copyd __MPN(copyd) -__GMP_DECLSPEC void mpn_copyd __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t)); -#define mpn_zero __MPN(zero) -__GMP_DECLSPEC void mpn_zero __GMP_PROTO ((mp_ptr, mp_size_t)); - -/**************** mpz inlines ****************/ - -/* The following are provided as inlines where possible, but always exist as - library functions too, for binary compatibility. - - Within gmp itself this inlining generally isn't relied on, since it - doesn't get done for all compilers, whereas if something is worth - inlining then it's worth arranging always. - - There are two styles of inlining here. When the same bit of code is - wanted for the inline as for the library version, then __GMP_FORCE_foo - arranges for that code to be emitted and the __GMP_EXTERN_INLINE - directive suppressed, eg. mpz_fits_uint_p. When a different bit of code - is wanted for the inline than for the library version, then - __GMP_FORCE_foo arranges the inline to be suppressed, eg. mpz_abs. */ - -#if defined (__GMP_EXTERN_INLINE) && ! defined (__GMP_FORCE_mpz_abs) -__GMP_EXTERN_INLINE void -mpz_abs (mpz_ptr __gmp_w, mpz_srcptr __gmp_u) -{ - if (__gmp_w != __gmp_u) - mpz_set (__gmp_w, __gmp_u); - __gmp_w->_mp_size = __GMP_ABS (__gmp_w->_mp_size); -} -#endif - -#if GMP_NAIL_BITS == 0 -#define __GMPZ_FITS_UTYPE_P(z,maxval) \ - mp_size_t __gmp_n = z->_mp_size; \ - mp_ptr __gmp_p = z->_mp_d; \ - return (__gmp_n == 0 || (__gmp_n == 1 && __gmp_p[0] <= maxval)); -#else -#define __GMPZ_FITS_UTYPE_P(z,maxval) \ - mp_size_t __gmp_n = z->_mp_size; \ - mp_ptr __gmp_p = z->_mp_d; \ - return (__gmp_n == 0 || (__gmp_n == 1 && __gmp_p[0] <= maxval) \ - || (__gmp_n == 2 && __gmp_p[1] <= ((mp_limb_t) maxval >> GMP_NUMB_BITS))); -#endif - -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_fits_uint_p) -#if ! defined (__GMP_FORCE_mpz_fits_uint_p) -__GMP_EXTERN_INLINE -#endif -int -mpz_fits_uint_p (mpz_srcptr __gmp_z) __GMP_NOTHROW -{ - __GMPZ_FITS_UTYPE_P (__gmp_z, __GMP_UINT_MAX); -} -#endif - -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_fits_ulong_p) -#if ! defined (__GMP_FORCE_mpz_fits_ulong_p) -__GMP_EXTERN_INLINE -#endif -int -mpz_fits_ulong_p (mpz_srcptr __gmp_z) __GMP_NOTHROW -{ - __GMPZ_FITS_UTYPE_P (__gmp_z, __GMP_ULONG_MAX); -} -#endif - -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_fits_ushort_p) -#if ! defined (__GMP_FORCE_mpz_fits_ushort_p) -__GMP_EXTERN_INLINE -#endif -int -mpz_fits_ushort_p (mpz_srcptr __gmp_z) __GMP_NOTHROW -{ - __GMPZ_FITS_UTYPE_P (__gmp_z, __GMP_USHRT_MAX); -} -#endif - -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_get_ui) -#if ! defined (__GMP_FORCE_mpz_get_ui) -__GMP_EXTERN_INLINE -#endif -unsigned long -mpz_get_ui (mpz_srcptr __gmp_z) __GMP_NOTHROW -{ - mp_ptr __gmp_p = __gmp_z->_mp_d; - mp_size_t __gmp_n = __gmp_z->_mp_size; - mp_limb_t __gmp_l = __gmp_p[0]; - /* This is a "#if" rather than a plain "if" so as to avoid gcc warnings - about "<< GMP_NUMB_BITS" exceeding the type size, and to avoid Borland - C++ 6.0 warnings about condition always true for something like - "__GMP_ULONG_MAX < GMP_NUMB_MASK". */ -#if GMP_NAIL_BITS == 0 || defined (_LONG_LONG_LIMB) - /* limb==long and no nails, or limb==longlong, one limb is enough */ - return (__gmp_n != 0 ? __gmp_l : 0); -#else - /* limb==long and nails, need two limbs when available */ - __gmp_n = __GMP_ABS (__gmp_n); - if (__gmp_n <= 1) - return (__gmp_n != 0 ? __gmp_l : 0); - else - return __gmp_l + (__gmp_p[1] << GMP_NUMB_BITS); -#endif -} -#endif - -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_getlimbn) -#if ! defined (__GMP_FORCE_mpz_getlimbn) -__GMP_EXTERN_INLINE -#endif -mp_limb_t -mpz_getlimbn (mpz_srcptr __gmp_z, mp_size_t __gmp_n) __GMP_NOTHROW -{ - mp_limb_t __gmp_result = 0; - if (__GMP_LIKELY (__gmp_n >= 0 && __gmp_n < __GMP_ABS (__gmp_z->_mp_size))) - __gmp_result = __gmp_z->_mp_d[__gmp_n]; - return __gmp_result; -} -#endif - -#if defined (__GMP_EXTERN_INLINE) && ! defined (__GMP_FORCE_mpz_neg) -__GMP_EXTERN_INLINE void -mpz_neg (mpz_ptr __gmp_w, mpz_srcptr __gmp_u) -{ - if (__gmp_w != __gmp_u) - mpz_set (__gmp_w, __gmp_u); - __gmp_w->_mp_size = - __gmp_w->_mp_size; -} -#endif - -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_perfect_square_p) -#if ! defined (__GMP_FORCE_mpz_perfect_square_p) -__GMP_EXTERN_INLINE -#endif -int -mpz_perfect_square_p (mpz_srcptr __gmp_a) -{ - mp_size_t __gmp_asize; - int __gmp_result; - - __gmp_asize = __gmp_a->_mp_size; - __gmp_result = (__gmp_asize >= 0); /* zero is a square, negatives are not */ - if (__GMP_LIKELY (__gmp_asize > 0)) - __gmp_result = mpn_perfect_square_p (__gmp_a->_mp_d, __gmp_asize); - return __gmp_result; -} -#endif - -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_popcount) -#if ! defined (__GMP_FORCE_mpz_popcount) -__GMP_EXTERN_INLINE -#endif -mp_bitcnt_t -mpz_popcount (mpz_srcptr __gmp_u) __GMP_NOTHROW -{ - mp_size_t __gmp_usize; - mp_bitcnt_t __gmp_result; - - __gmp_usize = __gmp_u->_mp_size; - __gmp_result = (__gmp_usize < 0 ? __GMP_ULONG_MAX : 0); - if (__GMP_LIKELY (__gmp_usize > 0)) - __gmp_result = mpn_popcount (__gmp_u->_mp_d, __gmp_usize); - return __gmp_result; -} -#endif - -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_set_q) -#if ! defined (__GMP_FORCE_mpz_set_q) -__GMP_EXTERN_INLINE -#endif -void -mpz_set_q (mpz_ptr __gmp_w, mpq_srcptr __gmp_u) -{ - mpz_tdiv_q (__gmp_w, mpq_numref (__gmp_u), mpq_denref (__gmp_u)); -} -#endif - -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_size) -#if ! defined (__GMP_FORCE_mpz_size) -__GMP_EXTERN_INLINE -#endif -size_t -mpz_size (mpz_srcptr __gmp_z) __GMP_NOTHROW -{ - return __GMP_ABS (__gmp_z->_mp_size); -} -#endif - - -/**************** mpq inlines ****************/ - -#if defined (__GMP_EXTERN_INLINE) && ! defined (__GMP_FORCE_mpq_abs) -__GMP_EXTERN_INLINE void -mpq_abs (mpq_ptr __gmp_w, mpq_srcptr __gmp_u) -{ - if (__gmp_w != __gmp_u) - mpq_set (__gmp_w, __gmp_u); - __gmp_w->_mp_num._mp_size = __GMP_ABS (__gmp_w->_mp_num._mp_size); -} -#endif - -#if defined (__GMP_EXTERN_INLINE) && ! defined (__GMP_FORCE_mpq_neg) -__GMP_EXTERN_INLINE void -mpq_neg (mpq_ptr __gmp_w, mpq_srcptr __gmp_u) -{ - if (__gmp_w != __gmp_u) - mpq_set (__gmp_w, __gmp_u); - __gmp_w->_mp_num._mp_size = - __gmp_w->_mp_num._mp_size; -} -#endif - - -/**************** mpn inlines ****************/ - -/* The comments with __GMPN_ADD_1 below apply here too. - - The test for FUNCTION returning 0 should predict well. If it's assumed - {yp,ysize} will usually have a random number of bits then the high limb - won't be full and a carry out will occur a good deal less than 50% of the - time. - - ysize==0 isn't a documented feature, but is used internally in a few - places. - - Producing cout last stops it using up a register during the main part of - the calculation, though gcc (as of 3.0) on an "if (mpn_add (...))" - doesn't seem able to move the true and false legs of the conditional up - to the two places cout is generated. */ - -#define __GMPN_AORS(cout, wp, xp, xsize, yp, ysize, FUNCTION, TEST) \ - do { \ - mp_size_t __gmp_i; \ - mp_limb_t __gmp_x; \ - \ - /* ASSERT ((ysize) >= 0); */ \ - /* ASSERT ((xsize) >= (ysize)); */ \ - /* ASSERT (MPN_SAME_OR_SEPARATE2_P (wp, xsize, xp, xsize)); */ \ - /* ASSERT (MPN_SAME_OR_SEPARATE2_P (wp, xsize, yp, ysize)); */ \ - \ - __gmp_i = (ysize); \ - if (__gmp_i != 0) \ - { \ - if (FUNCTION (wp, xp, yp, __gmp_i)) \ - { \ - do \ - { \ - if (__gmp_i >= (xsize)) \ - { \ - (cout) = 1; \ - goto __gmp_done; \ - } \ - __gmp_x = (xp)[__gmp_i]; \ - } \ - while (TEST); \ - } \ - } \ - if ((wp) != (xp)) \ - __GMPN_COPY_REST (wp, xp, xsize, __gmp_i); \ - (cout) = 0; \ - __gmp_done: \ - ; \ - } while (0) - -#define __GMPN_ADD(cout, wp, xp, xsize, yp, ysize) \ - __GMPN_AORS (cout, wp, xp, xsize, yp, ysize, mpn_add_n, \ - (((wp)[__gmp_i++] = (__gmp_x + 1) & GMP_NUMB_MASK) == 0)) -#define __GMPN_SUB(cout, wp, xp, xsize, yp, ysize) \ - __GMPN_AORS (cout, wp, xp, xsize, yp, ysize, mpn_sub_n, \ - (((wp)[__gmp_i++] = (__gmp_x - 1) & GMP_NUMB_MASK), __gmp_x == 0)) - - -/* The use of __gmp_i indexing is designed to ensure a compile time src==dst - remains nice and clear to the compiler, so that __GMPN_COPY_REST can - disappear, and the load/add/store gets a chance to become a - read-modify-write on CISC CPUs. - - Alternatives: - - Using a pair of pointers instead of indexing would be possible, but gcc - isn't able to recognise compile-time src==dst in that case, even when the - pointers are incremented more or less together. Other compilers would - very likely have similar difficulty. - - gcc could use "if (__builtin_constant_p(src==dst) && src==dst)" or - similar to detect a compile-time src==dst. This works nicely on gcc - 2.95.x, it's not good on gcc 3.0 where __builtin_constant_p(p==p) seems - to be always false, for a pointer p. But the current code form seems - good enough for src==dst anyway. - - gcc on x86 as usual doesn't give particularly good flags handling for the - carry/borrow detection. It's tempting to want some multi instruction asm - blocks to help it, and this was tried, but in truth there's only a few - instructions to save and any gain is all too easily lost by register - juggling setting up for the asm. */ - -#if GMP_NAIL_BITS == 0 -#define __GMPN_AORS_1(cout, dst, src, n, v, OP, CB) \ - do { \ - mp_size_t __gmp_i; \ - mp_limb_t __gmp_x, __gmp_r; \ - \ - /* ASSERT ((n) >= 1); */ \ - /* ASSERT (MPN_SAME_OR_SEPARATE_P (dst, src, n)); */ \ - \ - __gmp_x = (src)[0]; \ - __gmp_r = __gmp_x OP (v); \ - (dst)[0] = __gmp_r; \ - if (CB (__gmp_r, __gmp_x, (v))) \ - { \ - (cout) = 1; \ - for (__gmp_i = 1; __gmp_i < (n);) \ - { \ - __gmp_x = (src)[__gmp_i]; \ - __gmp_r = __gmp_x OP 1; \ - (dst)[__gmp_i] = __gmp_r; \ - ++__gmp_i; \ - if (!CB (__gmp_r, __gmp_x, 1)) \ - { \ - if ((src) != (dst)) \ - __GMPN_COPY_REST (dst, src, n, __gmp_i); \ - (cout) = 0; \ - break; \ - } \ - } \ - } \ - else \ - { \ - if ((src) != (dst)) \ - __GMPN_COPY_REST (dst, src, n, 1); \ - (cout) = 0; \ - } \ - } while (0) -#endif - -#if GMP_NAIL_BITS >= 1 -#define __GMPN_AORS_1(cout, dst, src, n, v, OP, CB) \ - do { \ - mp_size_t __gmp_i; \ - mp_limb_t __gmp_x, __gmp_r; \ - \ - /* ASSERT ((n) >= 1); */ \ - /* ASSERT (MPN_SAME_OR_SEPARATE_P (dst, src, n)); */ \ - \ - __gmp_x = (src)[0]; \ - __gmp_r = __gmp_x OP (v); \ - (dst)[0] = __gmp_r & GMP_NUMB_MASK; \ - if (__gmp_r >> GMP_NUMB_BITS != 0) \ - { \ - (cout) = 1; \ - for (__gmp_i = 1; __gmp_i < (n);) \ - { \ - __gmp_x = (src)[__gmp_i]; \ - __gmp_r = __gmp_x OP 1; \ - (dst)[__gmp_i] = __gmp_r & GMP_NUMB_MASK; \ - ++__gmp_i; \ - if (__gmp_r >> GMP_NUMB_BITS == 0) \ - { \ - if ((src) != (dst)) \ - __GMPN_COPY_REST (dst, src, n, __gmp_i); \ - (cout) = 0; \ - break; \ - } \ - } \ - } \ - else \ - { \ - if ((src) != (dst)) \ - __GMPN_COPY_REST (dst, src, n, 1); \ - (cout) = 0; \ - } \ - } while (0) -#endif - -#define __GMPN_ADDCB(r,x,y) ((r) < (y)) -#define __GMPN_SUBCB(r,x,y) ((x) < (y)) - -#define __GMPN_ADD_1(cout, dst, src, n, v) \ - __GMPN_AORS_1(cout, dst, src, n, v, +, __GMPN_ADDCB) -#define __GMPN_SUB_1(cout, dst, src, n, v) \ - __GMPN_AORS_1(cout, dst, src, n, v, -, __GMPN_SUBCB) - - -/* Compare {xp,size} and {yp,size}, setting "result" to positive, zero or - negative. size==0 is allowed. On random data usually only one limb will - need to be examined to get a result, so it's worth having it inline. */ -#define __GMPN_CMP(result, xp, yp, size) \ - do { \ - mp_size_t __gmp_i; \ - mp_limb_t __gmp_x, __gmp_y; \ - \ - /* ASSERT ((size) >= 0); */ \ - \ - (result) = 0; \ - __gmp_i = (size); \ - while (--__gmp_i >= 0) \ - { \ - __gmp_x = (xp)[__gmp_i]; \ - __gmp_y = (yp)[__gmp_i]; \ - if (__gmp_x != __gmp_y) \ - { \ - /* Cannot use __gmp_x - __gmp_y, may overflow an "int" */ \ - (result) = (__gmp_x > __gmp_y ? 1 : -1); \ - break; \ - } \ - } \ - } while (0) - - -#if defined (__GMPN_COPY) && ! defined (__GMPN_COPY_REST) -#define __GMPN_COPY_REST(dst, src, size, start) \ - do { \ - /* ASSERT ((start) >= 0); */ \ - /* ASSERT ((start) <= (size)); */ \ - __GMPN_COPY ((dst)+(start), (src)+(start), (size)-(start)); \ - } while (0) -#endif - -/* Copy {src,size} to {dst,size}, starting at "start". This is designed to - keep the indexing dst[j] and src[j] nice and simple for __GMPN_ADD_1, - __GMPN_ADD, etc. */ -#if ! defined (__GMPN_COPY_REST) -#define __GMPN_COPY_REST(dst, src, size, start) \ - do { \ - mp_size_t __gmp_j; \ - /* ASSERT ((size) >= 0); */ \ - /* ASSERT ((start) >= 0); */ \ - /* ASSERT ((start) <= (size)); */ \ - /* ASSERT (MPN_SAME_OR_SEPARATE_P (dst, src, size)); */ \ - __GMP_CRAY_Pragma ("_CRI ivdep"); \ - for (__gmp_j = (start); __gmp_j < (size); __gmp_j++) \ - (dst)[__gmp_j] = (src)[__gmp_j]; \ - } while (0) -#endif - -/* Enhancement: Use some of the smarter code from gmp-impl.h. Maybe use - mpn_copyi if there's a native version, and if we don't mind demanding - binary compatibility for it (on targets which use it). */ - -#if ! defined (__GMPN_COPY) -#define __GMPN_COPY(dst, src, size) __GMPN_COPY_REST (dst, src, size, 0) -#endif - - -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpn_add) -#if ! defined (__GMP_FORCE_mpn_add) -__GMP_EXTERN_INLINE -#endif -mp_limb_t -mpn_add (mp_ptr __gmp_wp, mp_srcptr __gmp_xp, mp_size_t __gmp_xsize, mp_srcptr __gmp_yp, mp_size_t __gmp_ysize) -{ - mp_limb_t __gmp_c; - __GMPN_ADD (__gmp_c, __gmp_wp, __gmp_xp, __gmp_xsize, __gmp_yp, __gmp_ysize); - return __gmp_c; -} -#endif - -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpn_add_1) -#if ! defined (__GMP_FORCE_mpn_add_1) -__GMP_EXTERN_INLINE -#endif -mp_limb_t -mpn_add_1 (mp_ptr __gmp_dst, mp_srcptr __gmp_src, mp_size_t __gmp_size, mp_limb_t __gmp_n) __GMP_NOTHROW -{ - mp_limb_t __gmp_c; - __GMPN_ADD_1 (__gmp_c, __gmp_dst, __gmp_src, __gmp_size, __gmp_n); - return __gmp_c; -} -#endif - -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpn_cmp) -#if ! defined (__GMP_FORCE_mpn_cmp) -__GMP_EXTERN_INLINE -#endif -int -mpn_cmp (mp_srcptr __gmp_xp, mp_srcptr __gmp_yp, mp_size_t __gmp_size) __GMP_NOTHROW -{ - int __gmp_result; - __GMPN_CMP (__gmp_result, __gmp_xp, __gmp_yp, __gmp_size); - return __gmp_result; -} -#endif - -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpn_sub) -#if ! defined (__GMP_FORCE_mpn_sub) -__GMP_EXTERN_INLINE -#endif -mp_limb_t -mpn_sub (mp_ptr __gmp_wp, mp_srcptr __gmp_xp, mp_size_t __gmp_xsize, mp_srcptr __gmp_yp, mp_size_t __gmp_ysize) -{ - mp_limb_t __gmp_c; - __GMPN_SUB (__gmp_c, __gmp_wp, __gmp_xp, __gmp_xsize, __gmp_yp, __gmp_ysize); - return __gmp_c; -} -#endif - -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpn_sub_1) -#if ! defined (__GMP_FORCE_mpn_sub_1) -__GMP_EXTERN_INLINE -#endif -mp_limb_t -mpn_sub_1 (mp_ptr __gmp_dst, mp_srcptr __gmp_src, mp_size_t __gmp_size, mp_limb_t __gmp_n) __GMP_NOTHROW -{ - mp_limb_t __gmp_c; - __GMPN_SUB_1 (__gmp_c, __gmp_dst, __gmp_src, __gmp_size, __gmp_n); - return __gmp_c; -} -#endif - -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpn_neg) -#if ! defined (__GMP_FORCE_mpn_neg) -__GMP_EXTERN_INLINE -#endif -mp_limb_t -mpn_neg (mp_ptr __gmp_rp, mp_srcptr __gmp_up, mp_size_t __gmp_n) -{ - mp_limb_t __gmp_ul, __gmp_cy; - __gmp_cy = 0; - do { - __gmp_ul = *__gmp_up++; - *__gmp_rp++ = -__gmp_ul - __gmp_cy; - __gmp_cy |= __gmp_ul != 0; - } while (--__gmp_n != 0); - return __gmp_cy; -} -#endif - -#if defined (__cplusplus) -} -#endif - - -/* Allow faster testing for negative, zero, and positive. */ -#define mpz_sgn(Z) ((Z)->_mp_size < 0 ? -1 : (Z)->_mp_size > 0) -#define mpf_sgn(F) ((F)->_mp_size < 0 ? -1 : (F)->_mp_size > 0) -#define mpq_sgn(Q) ((Q)->_mp_num._mp_size < 0 ? -1 : (Q)->_mp_num._mp_size > 0) - -/* When using GCC, optimize certain common comparisons. */ -#if defined (__GNUC__) && __GNUC__ >= 2 -#define mpz_cmp_ui(Z,UI) \ - (__builtin_constant_p (UI) && (UI) == 0 \ - ? mpz_sgn (Z) : _mpz_cmp_ui (Z,UI)) -#define mpz_cmp_si(Z,SI) \ - (__builtin_constant_p (SI) && (SI) == 0 ? mpz_sgn (Z) \ - : __builtin_constant_p (SI) && (SI) > 0 \ - ? _mpz_cmp_ui (Z, __GMP_CAST (unsigned long int, SI)) \ - : _mpz_cmp_si (Z,SI)) -#define mpq_cmp_ui(Q,NUI,DUI) \ - (__builtin_constant_p (NUI) && (NUI) == 0 \ - ? mpq_sgn (Q) : _mpq_cmp_ui (Q,NUI,DUI)) -#define mpq_cmp_si(q,n,d) \ - (__builtin_constant_p ((n) >= 0) && (n) >= 0 \ - ? mpq_cmp_ui (q, __GMP_CAST (unsigned long, n), d) \ - : _mpq_cmp_si (q, n, d)) -#else -#define mpz_cmp_ui(Z,UI) _mpz_cmp_ui (Z,UI) -#define mpz_cmp_si(Z,UI) _mpz_cmp_si (Z,UI) -#define mpq_cmp_ui(Q,NUI,DUI) _mpq_cmp_ui (Q,NUI,DUI) -#define mpq_cmp_si(q,n,d) _mpq_cmp_si(q,n,d) -#endif - - -/* Using "&" rather than "&&" means these can come out branch-free. Every - mpz_t has at least one limb allocated, so fetching the low limb is always - allowed. */ -#define mpz_odd_p(z) (((z)->_mp_size != 0) & __GMP_CAST (int, (z)->_mp_d[0])) -#define mpz_even_p(z) (! mpz_odd_p (z)) - - -/**************** C++ routines ****************/ - -#ifdef __cplusplus -__GMP_DECLSPEC_XX std::ostream& operator<< (std::ostream &, mpz_srcptr); -__GMP_DECLSPEC_XX std::ostream& operator<< (std::ostream &, mpq_srcptr); -__GMP_DECLSPEC_XX std::ostream& operator<< (std::ostream &, mpf_srcptr); -__GMP_DECLSPEC_XX std::istream& operator>> (std::istream &, mpz_ptr); -__GMP_DECLSPEC_XX std::istream& operator>> (std::istream &, mpq_ptr); -__GMP_DECLSPEC_XX std::istream& operator>> (std::istream &, mpf_ptr); -#endif - - -/* Source-level compatibility with GMP 2 and earlier. */ -#define mpn_divmod(qp,np,nsize,dp,dsize) \ - mpn_divrem (qp, __GMP_CAST (mp_size_t, 0), np, nsize, dp, dsize) - -/* Source-level compatibility with GMP 1. */ -#define mpz_mdiv mpz_fdiv_q -#define mpz_mdivmod mpz_fdiv_qr -#define mpz_mmod mpz_fdiv_r -#define mpz_mdiv_ui mpz_fdiv_q_ui -#define mpz_mdivmod_ui(q,r,n,d) \ - (((r) == 0) ? mpz_fdiv_q_ui (q,n,d) : mpz_fdiv_qr_ui (q,r,n,d)) -#define mpz_mmod_ui(r,n,d) \ - (((r) == 0) ? mpz_fdiv_ui (n,d) : mpz_fdiv_r_ui (r,n,d)) - -/* Useful synonyms, but not quite compatible with GMP 1. */ -#define mpz_div mpz_fdiv_q -#define mpz_divmod mpz_fdiv_qr -#define mpz_div_ui mpz_fdiv_q_ui -#define mpz_divmod_ui mpz_fdiv_qr_ui -#define mpz_div_2exp mpz_fdiv_q_2exp -#define mpz_mod_2exp mpz_fdiv_r_2exp - -enum -{ - GMP_ERROR_NONE = 0, - GMP_ERROR_UNSUPPORTED_ARGUMENT = 1, - GMP_ERROR_DIVISION_BY_ZERO = 2, - GMP_ERROR_SQRT_OF_NEGATIVE = 4, - GMP_ERROR_INVALID_ARGUMENT = 8 -}; - -/* Define CC and CFLAGS which were used to build this version of GMP */ -#define __GMP_CC "gcc -std=gnu99" -#define __GMP_CFLAGS "-mmacosx-version-min=10.5 -arch i386" - -/* Major version number is the value of __GNU_MP__ too, above and in mp.h. */ -#define __GNU_MP_VERSION 5 -#define __GNU_MP_VERSION_MINOR 0 -#define __GNU_MP_VERSION_PATCHLEVEL 1 -#define __GMP_MP_RELEASE (__GNU_MP_VERSION * 10000 + __GNU_MP_VERSION_MINOR * 100 + __GNU_MP_VERSION_PATCHLEVEL) - -#define __GMP_H__ -#endif /* __GMP_H__ */ diff --git a/src/external/inc/macx/gmp-5.0.1/gmpxx.h b/src/external/inc/macx/gmp-5.0.1/gmpxx.h deleted file mode 100644 index 7490312d3..000000000 --- a/src/external/inc/macx/gmp-5.0.1/gmpxx.h +++ /dev/null @@ -1,3388 +0,0 @@ -/* gmpxx.h -- C++ class wrapper for GMP types. -*- C++ -*- - -Copyright 2001, 2002, 2003, 2006, 2008 Free Software Foundation, Inc. - -This file is part of the GNU MP Library. - -The GNU MP Library is free software; you can redistribute it and/or modify -it under the terms of the GNU Lesser General Public License as published by -the Free Software Foundation; either version 3 of the License, or (at your -option) any later version. - -The GNU MP Library is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public -License for more details. - -You should have received a copy of the GNU Lesser General Public License -along with the GNU MP Library. If not, see http://www.gnu.org/licenses/. */ - -/* the C++ compiler must implement the following features: - - member templates - - partial specialization of templates - - namespace support - for g++, this means version 2.91 or higher - for other compilers, I don't know */ -#ifdef __GNUC__ -#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 91) -#error gmpxx.h requires g++ version 2.91 (egcs 1.1.2) or higher -#endif -#endif - -#ifndef __GMP_PLUSPLUS__ -#define __GMP_PLUSPLUS__ - -#include - -#include /* for strlen */ -#include -#include -#include -#include - - -/**************** Function objects ****************/ -/* Any evaluation of a __gmp_expr ends up calling one of these functions - all intermediate functions being inline, the evaluation should optimize - to a direct call to the relevant function, thus yielding no overhead - over the C interface. */ - -struct __gmp_unary_plus -{ - static void eval(mpz_ptr z, mpz_srcptr w) { mpz_set(z, w); } - static void eval(mpq_ptr q, mpq_srcptr r) { mpq_set(q, r); } - static void eval(mpf_ptr f, mpf_srcptr g) { mpf_set(f, g); } -}; - -struct __gmp_unary_minus -{ - static void eval(mpz_ptr z, mpz_srcptr w) { mpz_neg(z, w); } - static void eval(mpq_ptr q, mpq_srcptr r) { mpq_neg(q, r); } - static void eval(mpf_ptr f, mpf_srcptr g) { mpf_neg(f, g); } -}; - -struct __gmp_unary_com -{ - static void eval(mpz_ptr z, mpz_srcptr w) { mpz_com(z, w); } -}; - -struct __gmp_binary_plus -{ - static void eval(mpz_ptr z, mpz_srcptr w, mpz_srcptr v) - { mpz_add(z, w, v); } - - static void eval(mpz_ptr z, mpz_srcptr w, unsigned long int l) - { mpz_add_ui(z, w, l); } - static void eval(mpz_ptr z, unsigned long int l, mpz_srcptr w) - { mpz_add_ui(z, w, l); } - static void eval(mpz_ptr z, mpz_srcptr w, signed long int l) - { - if (l >= 0) - mpz_add_ui(z, w, l); - else - mpz_sub_ui(z, w, -l); - } - static void eval(mpz_ptr z, signed long int l, mpz_srcptr w) - { - if (l >= 0) - mpz_add_ui(z, w, l); - else - mpz_sub_ui(z, w, -l); - } - static void eval(mpz_ptr z, mpz_srcptr w, double d) - { - mpz_t temp; - mpz_init_set_d(temp, d); - mpz_add(z, w, temp); - mpz_clear(temp); - } - static void eval(mpz_ptr z, double d, mpz_srcptr w) - { - mpz_t temp; - mpz_init_set_d(temp, d); - mpz_add(z, temp, w); - mpz_clear(temp); - } - - static void eval(mpq_ptr q, mpq_srcptr r, mpq_srcptr s) - { mpq_add(q, r, s); } - - static void eval(mpq_ptr q, mpq_srcptr r, unsigned long int l) - { mpq_set(q, r); mpz_addmul_ui(mpq_numref(q), mpq_denref(q), l); } - static void eval(mpq_ptr q, unsigned long int l, mpq_srcptr r) - { mpq_set(q, r); mpz_addmul_ui(mpq_numref(q), mpq_denref(q), l); } - static void eval(mpq_ptr q, mpq_srcptr r, signed long int l) - { - mpq_set(q, r); - if (l >= 0) - mpz_addmul_ui(mpq_numref(q), mpq_denref(q), l); - else - mpz_submul_ui(mpq_numref(q), mpq_denref(q), -l); - } - static void eval(mpq_ptr q, signed long int l, mpq_srcptr r) - { - mpq_set(q, r); - if (l >= 0) - mpz_addmul_ui(mpq_numref(q), mpq_denref(q), l); - else - mpz_submul_ui(mpq_numref(q), mpq_denref(q), -l); - } - static void eval(mpq_ptr q, mpq_srcptr r, double d) - { - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - mpq_add(q, r, temp); - mpq_clear(temp); - } - static void eval(mpq_ptr q, double d, mpq_srcptr r) - { - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - mpq_add(q, temp, r); - mpq_clear(temp); - } - - static void eval(mpq_ptr q, mpq_srcptr r, mpz_srcptr z) - { mpq_set(q, r); mpz_addmul(mpq_numref(q), mpq_denref(q), z); } - static void eval(mpq_ptr q, mpz_srcptr z, mpq_srcptr r) - { mpq_set(q, r); mpz_addmul(mpq_numref(q), mpq_denref(q), z); } - - static void eval(mpf_ptr f, mpf_srcptr g, mpf_srcptr h) - { mpf_add(f, g, h); } - - static void eval(mpf_ptr f, mpf_srcptr g, unsigned long int l) - { mpf_add_ui(f, g, l); } - static void eval(mpf_ptr f, unsigned long int l, mpf_srcptr g) - { mpf_add_ui(f, g, l); } - static void eval(mpf_ptr f, mpf_srcptr g, signed long int l) - { - if (l >= 0) - mpf_add_ui(f, g, l); - else - mpf_sub_ui(f, g, -l); - } - static void eval(mpf_ptr f, signed long int l, mpf_srcptr g) - { - if (l >= 0) - mpf_add_ui(f, g, l); - else - mpf_sub_ui(f, g, -l); - } - static void eval(mpf_ptr f, mpf_srcptr g, double d) - { - mpf_t temp; - mpf_init2(temp, 8*sizeof(double)); - mpf_set_d(temp, d); - mpf_add(f, g, temp); - mpf_clear(temp); - } - static void eval(mpf_ptr f, double d, mpf_srcptr g) - { - mpf_t temp; - mpf_init2(temp, 8*sizeof(double)); - mpf_set_d(temp, d); - mpf_add(f, temp, g); - mpf_clear(temp); - } -}; - -struct __gmp_binary_minus -{ - static void eval(mpz_ptr z, mpz_srcptr w, mpz_srcptr v) - { mpz_sub(z, w, v); } - - static void eval(mpz_ptr z, mpz_srcptr w, unsigned long int l) - { mpz_sub_ui(z, w, l); } - static void eval(mpz_ptr z, unsigned long int l, mpz_srcptr w) - { mpz_ui_sub(z, l, w); } - static void eval(mpz_ptr z, mpz_srcptr w, signed long int l) - { - if (l >= 0) - mpz_sub_ui(z, w, l); - else - mpz_add_ui(z, w, -l); - } - static void eval(mpz_ptr z, signed long int l, mpz_srcptr w) - { - if (l >= 0) - mpz_ui_sub(z, l, w); - else - { - mpz_add_ui(z, w, -l); - mpz_neg(z, z); - } - } - static void eval(mpz_ptr z, mpz_srcptr w, double d) - { - mpz_t temp; - mpz_init_set_d(temp, d); - mpz_sub(z, w, temp); - mpz_clear(temp); - } - static void eval(mpz_ptr z, double d, mpz_srcptr w) - { - mpz_t temp; - mpz_init_set_d(temp, d); - mpz_sub(z, temp, w); - mpz_clear(temp); - } - - static void eval(mpq_ptr q, mpq_srcptr r, mpq_srcptr s) - { mpq_sub(q, r, s); } - - static void eval(mpq_ptr q, mpq_srcptr r, unsigned long int l) - { mpq_set(q, r); mpz_submul_ui(mpq_numref(q), mpq_denref(q), l); } - static void eval(mpq_ptr q, unsigned long int l, mpq_srcptr r) - { mpq_neg(q, r); mpz_addmul_ui(mpq_numref(q), mpq_denref(q), l); } - static void eval(mpq_ptr q, mpq_srcptr r, signed long int l) - { - mpq_set(q, r); - if (l >= 0) - mpz_submul_ui(mpq_numref(q), mpq_denref(q), l); - else - mpz_addmul_ui(mpq_numref(q), mpq_denref(q), -l); - } - static void eval(mpq_ptr q, signed long int l, mpq_srcptr r) - { - mpq_neg(q, r); - if (l >= 0) - mpz_addmul_ui(mpq_numref(q), mpq_denref(q), l); - else - mpz_submul_ui(mpq_numref(q), mpq_denref(q), -l); - } - static void eval(mpq_ptr q, mpq_srcptr r, double d) - { - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - mpq_sub(q, r, temp); - mpq_clear(temp); - } - static void eval(mpq_ptr q, double d, mpq_srcptr r) - { - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - mpq_sub(q, temp, r); - mpq_clear(temp); - } - - static void eval(mpq_ptr q, mpq_srcptr r, mpz_srcptr z) - { mpq_set(q, r); mpz_submul(mpq_numref(q), mpq_denref(q), z); } - static void eval(mpq_ptr q, mpz_srcptr z, mpq_srcptr r) - { mpq_neg(q, r); mpz_addmul(mpq_numref(q), mpq_denref(q), z); } - - static void eval(mpf_ptr f, mpf_srcptr g, mpf_srcptr h) - { mpf_sub(f, g, h); } - - static void eval(mpf_ptr f, mpf_srcptr g, unsigned long int l) - { mpf_sub_ui(f, g, l); } - static void eval(mpf_ptr f, unsigned long int l, mpf_srcptr g) - { mpf_ui_sub(f, l, g); } - static void eval(mpf_ptr f, mpf_srcptr g, signed long int l) - { - if (l >= 0) - mpf_sub_ui(f, g, l); - else - mpf_add_ui(f, g, -l); - } - static void eval(mpf_ptr f, signed long int l, mpf_srcptr g) - { - if (l >= 0) - mpf_sub_ui(f, g, l); - else - mpf_add_ui(f, g, -l); - mpf_neg(f, f); - } - static void eval(mpf_ptr f, mpf_srcptr g, double d) - { - mpf_t temp; - mpf_init2(temp, 8*sizeof(double)); - mpf_set_d(temp, d); - mpf_sub(f, g, temp); - mpf_clear(temp); - } - static void eval(mpf_ptr f, double d, mpf_srcptr g) - { - mpf_t temp; - mpf_init2(temp, 8*sizeof(double)); - mpf_set_d(temp, d); - mpf_sub(f, temp, g); - mpf_clear(temp); - } -}; - -struct __gmp_binary_multiplies -{ - static void eval(mpz_ptr z, mpz_srcptr w, mpz_srcptr v) - { mpz_mul(z, w, v); } - - static void eval(mpz_ptr z, mpz_srcptr w, unsigned long int l) - { mpz_mul_ui(z, w, l); } - static void eval(mpz_ptr z, unsigned long int l, mpz_srcptr w) - { mpz_mul_ui(z, w, l); } - static void eval(mpz_ptr z, mpz_srcptr w, signed long int l) - { mpz_mul_si (z, w, l); } - static void eval(mpz_ptr z, signed long int l, mpz_srcptr w) - { mpz_mul_si (z, w, l); } - static void eval(mpz_ptr z, mpz_srcptr w, double d) - { - mpz_t temp; - mpz_init_set_d(temp, d); - mpz_mul(z, w, temp); - mpz_clear(temp); - } - static void eval(mpz_ptr z, double d, mpz_srcptr w) - { - mpz_t temp; - mpz_init_set_d(temp, d); - mpz_mul(z, temp, w); - mpz_clear(temp); - } - - static void eval(mpq_ptr q, mpq_srcptr r, mpq_srcptr s) - { mpq_mul(q, r, s); } - - static void eval(mpq_ptr q, mpq_srcptr r, unsigned long int l) - { - mpq_t temp; - mpq_init(temp); - mpq_set_ui(temp, l, 1); - mpq_mul(q, r, temp); - mpq_clear(temp); - } - static void eval(mpq_ptr q, unsigned long int l, mpq_srcptr r) - { - mpq_t temp; - mpq_init(temp); - mpq_set_ui(temp, l, 1); - mpq_mul(q, temp, r); - mpq_clear(temp); - } - static void eval(mpq_ptr q, mpq_srcptr r, signed long int l) - { - mpq_t temp; - mpq_init(temp); - mpq_set_si(temp, l, 1); - mpq_mul(q, r, temp); - mpq_clear(temp); - } - static void eval(mpq_ptr q, signed long int l, mpq_srcptr r) - { - mpq_t temp; - mpq_init(temp); - mpq_set_si(temp, l, 1); - mpq_mul(q, temp, r); - mpq_clear(temp); - } - static void eval(mpq_ptr q, mpq_srcptr r, double d) - { - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - mpq_mul(q, r, temp); - mpq_clear(temp); - } - static void eval(mpq_ptr q, double d, mpq_srcptr r) - { - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - mpq_mul(q, temp, r); - mpq_clear(temp); - } - - static void eval(mpf_ptr f, mpf_srcptr g, mpf_srcptr h) - { mpf_mul(f, g, h); } - - static void eval(mpf_ptr f, mpf_srcptr g, unsigned long int l) - { mpf_mul_ui(f, g, l); } - static void eval(mpf_ptr f, unsigned long int l, mpf_srcptr g) - { mpf_mul_ui(f, g, l); } - static void eval(mpf_ptr f, mpf_srcptr g, signed long int l) - { - if (l >= 0) - mpf_mul_ui(f, g, l); - else - { - mpf_mul_ui(f, g, -l); - mpf_neg(f, f); - } - } - static void eval(mpf_ptr f, signed long int l, mpf_srcptr g) - { - if (l >= 0) - mpf_mul_ui(f, g, l); - else - { - mpf_mul_ui(f, g, -l); - mpf_neg(f, f); - } - } - static void eval(mpf_ptr f, mpf_srcptr g, double d) - { - mpf_t temp; - mpf_init2(temp, 8*sizeof(double)); - mpf_set_d(temp, d); - mpf_mul(f, g, temp); - mpf_clear(temp); - } - static void eval(mpf_ptr f, double d, mpf_srcptr g) - { - mpf_t temp; - mpf_init2(temp, 8*sizeof(double)); - mpf_set_d(temp, d); - mpf_mul(f, temp, g); - mpf_clear(temp); - } -}; - -struct __gmp_binary_divides -{ - static void eval(mpz_ptr z, mpz_srcptr w, mpz_srcptr v) - { mpz_tdiv_q(z, w, v); } - - static void eval(mpz_ptr z, mpz_srcptr w, unsigned long int l) - { mpz_tdiv_q_ui(z, w, l); } - static void eval(mpz_ptr z, unsigned long int l, mpz_srcptr w) - { - if (mpz_sgn(w) >= 0) - { - if (mpz_fits_ulong_p(w)) - mpz_set_ui(z, l / mpz_get_ui(w)); - else - mpz_set_ui(z, 0); - } - else - { - mpz_neg(z, w); - if (mpz_fits_ulong_p(z)) - { - mpz_set_ui(z, l / mpz_get_ui(z)); - mpz_neg(z, z); - } - else - mpz_set_ui(z, 0); - } - } - static void eval(mpz_ptr z, mpz_srcptr w, signed long int l) - { - if (l >= 0) - mpz_tdiv_q_ui(z, w, l); - else - { - mpz_tdiv_q_ui(z, w, -l); - mpz_neg(z, z); - } - } - static void eval(mpz_ptr z, signed long int l, mpz_srcptr w) - { - if (mpz_fits_slong_p(w)) - mpz_set_si(z, l / mpz_get_si(w)); - else - { - /* if w is bigger than a long then the quotient must be zero, unless - l==LONG_MIN and w==-LONG_MIN in which case the quotient is -1 */ - mpz_set_si (z, (mpz_cmpabs_ui (w, (l >= 0 ? l : -l)) == 0 ? -1 : 0)); - } - } - static void eval(mpz_ptr z, mpz_srcptr w, double d) - { - mpz_t temp; - mpz_init_set_d(temp, d); - mpz_tdiv_q(z, w, temp); - mpz_clear(temp); - } - static void eval(mpz_ptr z, double d, mpz_srcptr w) - { - mpz_t temp; - mpz_init_set_d(temp, d); - mpz_tdiv_q(z, temp, w); - mpz_clear(temp); - } - - static void eval(mpq_ptr q, mpq_srcptr r, mpq_srcptr s) - { mpq_div(q, r, s); } - - static void eval(mpq_ptr q, mpq_srcptr r, unsigned long int l) - { - mpq_t temp; - mpq_init(temp); - mpq_set_ui(temp, l, 1); - mpq_div(q, r, temp); - mpq_clear(temp); - } - static void eval(mpq_ptr q, unsigned long int l, mpq_srcptr r) - { - mpq_t temp; - mpq_init(temp); - mpq_set_ui(temp, l, 1); - mpq_div(q, temp, r); - mpq_clear(temp); - } - static void eval(mpq_ptr q, mpq_srcptr r, signed long int l) - { - mpq_t temp; - mpq_init(temp); - mpq_set_si(temp, l, 1); - mpq_div(q, r, temp); - mpq_clear(temp); - } - static void eval(mpq_ptr q, signed long int l, mpq_srcptr r) - { - mpq_t temp; - mpq_init(temp); - mpq_set_si(temp, l, 1); - mpq_div(q, temp, r); - mpq_clear(temp); - } - static void eval(mpq_ptr q, mpq_srcptr r, double d) - { - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - mpq_div(q, r, temp); - mpq_clear(temp); - } - static void eval(mpq_ptr q, double d, mpq_srcptr r) - { - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - mpq_div(q, temp, r); - mpq_clear(temp); - } - - static void eval(mpf_ptr f, mpf_srcptr g, mpf_srcptr h) - { mpf_div(f, g, h); } - - static void eval(mpf_ptr f, mpf_srcptr g, unsigned long int l) - { mpf_div_ui(f, g, l); } - static void eval(mpf_ptr f, unsigned long int l, mpf_srcptr g) - { mpf_ui_div(f, l, g); } - static void eval(mpf_ptr f, mpf_srcptr g, signed long int l) - { - if (l >= 0) - mpf_div_ui(f, g, l); - else - { - mpf_div_ui(f, g, -l); - mpf_neg(f, f); - } - } - static void eval(mpf_ptr f, signed long int l, mpf_srcptr g) - { - if (l >= 0) - mpf_ui_div(f, l, g); - else - { - mpf_ui_div(f, -l, g); - mpf_neg(f, f); - } - } - static void eval(mpf_ptr f, mpf_srcptr g, double d) - { - mpf_t temp; - mpf_init2(temp, 8*sizeof(double)); - mpf_set_d(temp, d); - mpf_div(f, g, temp); - mpf_clear(temp); - } - static void eval(mpf_ptr f, double d, mpf_srcptr g) - { - mpf_t temp; - mpf_init2(temp, 8*sizeof(double)); - mpf_set_d(temp, d); - mpf_div(f, temp, g); - mpf_clear(temp); - } -}; - -struct __gmp_binary_modulus -{ - static void eval(mpz_ptr z, mpz_srcptr w, mpz_srcptr v) - { mpz_tdiv_r(z, w, v); } - - static void eval(mpz_ptr z, mpz_srcptr w, unsigned long int l) - { mpz_tdiv_r_ui(z, w, l); } - static void eval(mpz_ptr z, unsigned long int l, mpz_srcptr w) - { - if (mpz_sgn(w) >= 0) - { - if (mpz_fits_ulong_p(w)) - mpz_set_ui(z, l % mpz_get_ui(w)); - else - mpz_set_ui(z, l); - } - else - { - mpz_neg(z, w); - if (mpz_fits_ulong_p(z)) - mpz_set_ui(z, l % mpz_get_ui(z)); - else - mpz_set_ui(z, l); - } - } - static void eval(mpz_ptr z, mpz_srcptr w, signed long int l) - { - mpz_tdiv_r_ui (z, w, (l >= 0 ? l : -l)); - } - static void eval(mpz_ptr z, signed long int l, mpz_srcptr w) - { - if (mpz_fits_slong_p(w)) - mpz_set_si(z, l % mpz_get_si(w)); - else - { - /* if w is bigger than a long then the remainder is l unchanged, - unless l==LONG_MIN and w==-LONG_MIN in which case it's 0 */ - mpz_set_si (z, mpz_cmpabs_ui (w, (l >= 0 ? l : -l)) == 0 ? 0 : l); - } - } - static void eval(mpz_ptr z, mpz_srcptr w, double d) - { - mpz_t temp; - mpz_init_set_d(temp, d); - mpz_tdiv_r(z, w, temp); - mpz_clear(temp); - } - static void eval(mpz_ptr z, double d, mpz_srcptr w) - { - mpz_t temp; - mpz_init_set_d(temp, d); - mpz_tdiv_r(z, temp, w); - mpz_clear(temp); - } -}; - -// Max allocations for plain types when converted to mpz_t -#define __GMP_DBL_LIMBS (2 + DBL_MAX_EXP / GMP_NUMB_BITS) -#define __GMP_ULI_LIMBS (1 + (8 * sizeof (long) - 1) / GMP_NUMB_BITS) - -#define __GMPXX_TMP_UI \ - mpz_t temp; \ - mp_limb_t limbs[__GMP_ULI_LIMBS]; \ - temp->_mp_d = limbs; \ - temp->_mp_alloc = __GMP_ULI_LIMBS; \ - mpz_set_ui (temp, l) -#define __GMPXX_TMP_SI \ - mpz_t temp; \ - mp_limb_t limbs[__GMP_ULI_LIMBS]; \ - temp->_mp_d = limbs; \ - temp->_mp_alloc = __GMP_ULI_LIMBS; \ - mpz_set_si (temp, l) -#define __GMPXX_TMP_D \ - mpz_t temp; \ - mp_limb_t limbs[__GMP_DBL_LIMBS]; \ - temp->_mp_d = limbs; \ - temp->_mp_alloc = __GMP_DBL_LIMBS; \ - mpz_set_d (temp, d) - -struct __gmp_binary_and -{ - static void eval(mpz_ptr z, mpz_srcptr w, mpz_srcptr v) - { mpz_and(z, w, v); } - - static void eval(mpz_ptr z, mpz_srcptr w, unsigned long int l) - { __GMPXX_TMP_UI; mpz_and (z, w, temp); } - static void eval(mpz_ptr z, unsigned long int l, mpz_srcptr w) - { __GMPXX_TMP_UI; mpz_and (z, w, temp); } - static void eval(mpz_ptr z, mpz_srcptr w, signed long int l) - { __GMPXX_TMP_SI; mpz_and (z, w, temp); } - static void eval(mpz_ptr z, signed long int l, mpz_srcptr w) - { __GMPXX_TMP_SI; mpz_and (z, w, temp); } - static void eval(mpz_ptr z, mpz_srcptr w, double d) - { __GMPXX_TMP_D; mpz_and (z, w, temp); } - static void eval(mpz_ptr z, double d, mpz_srcptr w) - { __GMPXX_TMP_D; mpz_and (z, w, temp); } -}; - -struct __gmp_binary_ior -{ - static void eval(mpz_ptr z, mpz_srcptr w, mpz_srcptr v) - { mpz_ior(z, w, v); } - static void eval(mpz_ptr z, mpz_srcptr w, unsigned long int l) - { __GMPXX_TMP_UI; mpz_ior (z, w, temp); } - static void eval(mpz_ptr z, unsigned long int l, mpz_srcptr w) - { __GMPXX_TMP_UI; mpz_ior (z, w, temp); } - static void eval(mpz_ptr z, mpz_srcptr w, signed long int l) - { __GMPXX_TMP_SI; mpz_ior (z, w, temp); } - static void eval(mpz_ptr z, signed long int l, mpz_srcptr w) - { __GMPXX_TMP_SI; mpz_ior (z, w, temp); } - static void eval(mpz_ptr z, mpz_srcptr w, double d) - { __GMPXX_TMP_D; mpz_ior (z, w, temp); } - static void eval(mpz_ptr z, double d, mpz_srcptr w) - { __GMPXX_TMP_D; mpz_ior (z, w, temp); } -}; - -struct __gmp_binary_xor -{ - static void eval(mpz_ptr z, mpz_srcptr w, mpz_srcptr v) - { mpz_xor(z, w, v); } - static void eval(mpz_ptr z, mpz_srcptr w, unsigned long int l) - { __GMPXX_TMP_UI; mpz_xor (z, w, temp); } - static void eval(mpz_ptr z, unsigned long int l, mpz_srcptr w) - { __GMPXX_TMP_UI; mpz_xor (z, w, temp); } - static void eval(mpz_ptr z, mpz_srcptr w, signed long int l) - { __GMPXX_TMP_SI; mpz_xor (z, w, temp); } - static void eval(mpz_ptr z, signed long int l, mpz_srcptr w) - { __GMPXX_TMP_SI; mpz_xor (z, w, temp); } - static void eval(mpz_ptr z, mpz_srcptr w, double d) - { __GMPXX_TMP_D; mpz_xor (z, w, temp); } - static void eval(mpz_ptr z, double d, mpz_srcptr w) - { __GMPXX_TMP_D; mpz_xor (z, w, temp); } -}; - -struct __gmp_binary_lshift -{ - static void eval(mpz_ptr z, mpz_srcptr w, unsigned long int l) - { mpz_mul_2exp(z, w, l); } - static void eval(mpq_ptr q, mpq_srcptr r, unsigned long int l) - { mpq_mul_2exp(q, r, l); } - static void eval(mpf_ptr f, mpf_srcptr g, unsigned long int l) - { mpf_mul_2exp(f, g, l); } -}; - -struct __gmp_binary_rshift -{ - static void eval(mpz_ptr z, mpz_srcptr w, unsigned long int l) - { mpz_fdiv_q_2exp(z, w, l); } - static void eval(mpq_ptr q, mpq_srcptr r, unsigned long int l) - { mpq_div_2exp(q, r, l); } - static void eval(mpf_ptr f, mpf_srcptr g, unsigned long int l) - { mpf_div_2exp(f, g, l); } -}; - -struct __gmp_binary_equal -{ - static bool eval(mpz_srcptr z, mpz_srcptr w) { return mpz_cmp(z, w) == 0; } - - static bool eval(mpz_srcptr z, unsigned long int l) - { return mpz_cmp_ui(z, l) == 0; } - static bool eval(unsigned long int l, mpz_srcptr z) - { return mpz_cmp_ui(z, l) == 0; } - static bool eval(mpz_srcptr z, signed long int l) - { return mpz_cmp_si(z, l) == 0; } - static bool eval(signed long int l, mpz_srcptr z) - { return mpz_cmp_si(z, l) == 0; } - static bool eval(mpz_srcptr z, double d) - { return mpz_cmp_d(z, d) == 0; } - static bool eval(double d, mpz_srcptr z) - { return mpz_cmp_d(z, d) == 0; } - - static bool eval(mpq_srcptr q, mpq_srcptr r) - { return mpq_equal(q, r) != 0; } - - static bool eval(mpq_srcptr q, unsigned long int l) - { return mpq_cmp_ui(q, l, 1) == 0; } - static bool eval(unsigned long int l, mpq_srcptr q) - { return mpq_cmp_ui(q, l, 1) == 0; } - static bool eval(mpq_srcptr q, signed long int l) - { return mpq_cmp_si(q, l, 1) == 0; } - static bool eval(signed long int l, mpq_srcptr q) - { return mpq_cmp_si(q, l, 1) == 0; } - static bool eval(mpq_srcptr q, double d) - { - bool b; - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - b = (mpq_equal(q, temp) != 0); - mpq_clear(temp); - return b; - } - static bool eval(double d, mpq_srcptr q) - { - bool b; - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - b = (mpq_equal(temp, q) != 0); - mpq_clear(temp); - return b; - } - - static bool eval(mpf_srcptr f, mpf_srcptr g) { return mpf_cmp(f, g) == 0; } - - static bool eval(mpf_srcptr f, unsigned long int l) - { return mpf_cmp_ui(f, l) == 0; } - static bool eval(unsigned long int l, mpf_srcptr f) - { return mpf_cmp_ui(f, l) == 0; } - static bool eval(mpf_srcptr f, signed long int l) - { return mpf_cmp_si(f, l) == 0; } - static bool eval(signed long int l, mpf_srcptr f) - { return mpf_cmp_si(f, l) == 0; } - static bool eval(mpf_srcptr f, double d) - { return mpf_cmp_d(f, d) == 0; } - static bool eval(double d, mpf_srcptr f) - { return mpf_cmp_d(f, d) == 0; } -}; - -struct __gmp_binary_not_equal -{ - static bool eval(mpz_srcptr z, mpz_srcptr w) { return mpz_cmp(z, w) != 0; } - - static bool eval(mpz_srcptr z, unsigned long int l) - { return mpz_cmp_ui(z, l) != 0; } - static bool eval(unsigned long int l, mpz_srcptr z) - { return mpz_cmp_ui(z, l) != 0; } - static bool eval(mpz_srcptr z, signed long int l) - { return mpz_cmp_si(z, l) != 0; } - static bool eval(signed long int l, mpz_srcptr z) - { return mpz_cmp_si(z, l) != 0; } - static bool eval(mpz_srcptr z, double d) - { return mpz_cmp_d(z, d) != 0; } - static bool eval(double d, mpz_srcptr z) - { return mpz_cmp_d(z, d) != 0; } - - static bool eval(mpq_srcptr q, mpq_srcptr r) - { return mpq_equal(q, r) == 0; } - - static bool eval(mpq_srcptr q, unsigned long int l) - { return mpq_cmp_ui(q, l, 1) != 0; } - static bool eval(unsigned long int l, mpq_srcptr q) - { return mpq_cmp_ui(q, l, 1) != 0; } - static bool eval(mpq_srcptr q, signed long int l) - { return mpq_cmp_si(q, l, 1) != 0; } - static bool eval(signed long int l, mpq_srcptr q) - { return mpq_cmp_si(q, l, 1) != 0; } - static bool eval(mpq_srcptr q, double d) - { - bool b; - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - b = (mpq_equal(q, temp) == 0); - mpq_clear(temp); - return b; - } - static bool eval(double d, mpq_srcptr q) - { - bool b; - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - b = (mpq_equal(temp, q) == 0); - mpq_clear(temp); - return b; - } - - static bool eval(mpf_srcptr f, mpf_srcptr g) { return mpf_cmp(f, g) != 0; } - - static bool eval(mpf_srcptr f, unsigned long int l) - { return mpf_cmp_ui(f, l) != 0; } - static bool eval(unsigned long int l, mpf_srcptr f) - { return mpf_cmp_ui(f, l) != 0; } - static bool eval(mpf_srcptr f, signed long int l) - { return mpf_cmp_si(f, l) != 0; } - static bool eval(signed long int l, mpf_srcptr f) - { return mpf_cmp_si(f, l) != 0; } - static bool eval(mpf_srcptr f, double d) - { return mpf_cmp_d(f, d) != 0; } - static bool eval(double d, mpf_srcptr f) - { return mpf_cmp_d(f, d) != 0; } -}; - -struct __gmp_binary_less -{ - static bool eval(mpz_srcptr z, mpz_srcptr w) { return mpz_cmp(z, w) < 0; } - - static bool eval(mpz_srcptr z, unsigned long int l) - { return mpz_cmp_ui(z, l) < 0; } - static bool eval(unsigned long int l, mpz_srcptr z) - { return mpz_cmp_ui(z, l) > 0; } - static bool eval(mpz_srcptr z, signed long int l) - { return mpz_cmp_si(z, l) < 0; } - static bool eval(signed long int l, mpz_srcptr z) - { return mpz_cmp_si(z, l) > 0; } - static bool eval(mpz_srcptr z, double d) - { return mpz_cmp_d(z, d) < 0; } - static bool eval(double d, mpz_srcptr z) - { return mpz_cmp_d(z, d) > 0; } - - static bool eval(mpq_srcptr q, mpq_srcptr r) { return mpq_cmp(q, r) < 0; } - - static bool eval(mpq_srcptr q, unsigned long int l) - { return mpq_cmp_ui(q, l, 1) < 0; } - static bool eval(unsigned long int l, mpq_srcptr q) - { return mpq_cmp_ui(q, l, 1) > 0; } - static bool eval(mpq_srcptr q, signed long int l) - { return mpq_cmp_si(q, l, 1) < 0; } - static bool eval(signed long int l, mpq_srcptr q) - { return mpq_cmp_si(q, l, 1) > 0; } - static bool eval(mpq_srcptr q, double d) - { - bool b; - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - b = (mpq_cmp(q, temp) < 0); - mpq_clear(temp); - return b; - } - static bool eval(double d, mpq_srcptr q) - { - bool b; - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - b = (mpq_cmp(temp, q) < 0); - mpq_clear(temp); - return b; - } - - static bool eval(mpf_srcptr f, mpf_srcptr g) { return mpf_cmp(f, g) < 0; } - - static bool eval(mpf_srcptr f, unsigned long int l) - { return mpf_cmp_ui(f, l) < 0; } - static bool eval(unsigned long int l, mpf_srcptr f) - { return mpf_cmp_ui(f, l) > 0; } - static bool eval(mpf_srcptr f, signed long int l) - { return mpf_cmp_si(f, l) < 0; } - static bool eval(signed long int l, mpf_srcptr f) - { return mpf_cmp_si(f, l) > 0; } - static bool eval(mpf_srcptr f, double d) - { return mpf_cmp_d(f, d) < 0; } - static bool eval(double d, mpf_srcptr f) - { return mpf_cmp_d(f, d) > 0; } -}; - -struct __gmp_binary_less_equal -{ - static bool eval(mpz_srcptr z, mpz_srcptr w) { return mpz_cmp(z, w) <= 0; } - - static bool eval(mpz_srcptr z, unsigned long int l) - { return mpz_cmp_ui(z, l) <= 0; } - static bool eval(unsigned long int l, mpz_srcptr z) - { return mpz_cmp_ui(z, l) >= 0; } - static bool eval(mpz_srcptr z, signed long int l) - { return mpz_cmp_si(z, l) <= 0; } - static bool eval(signed long int l, mpz_srcptr z) - { return mpz_cmp_si(z, l) >= 0; } - static bool eval(mpz_srcptr z, double d) - { return mpz_cmp_d(z, d) <= 0; } - static bool eval(double d, mpz_srcptr z) - { return mpz_cmp_d(z, d) >= 0; } - - static bool eval(mpq_srcptr q, mpq_srcptr r) { return mpq_cmp(q, r) <= 0; } - - static bool eval(mpq_srcptr q, unsigned long int l) - { return mpq_cmp_ui(q, l, 1) <= 0; } - static bool eval(unsigned long int l, mpq_srcptr q) - { return mpq_cmp_ui(q, l, 1) >= 0; } - static bool eval(mpq_srcptr q, signed long int l) - { return mpq_cmp_si(q, l, 1) <= 0; } - static bool eval(signed long int l, mpq_srcptr q) - { return mpq_cmp_si(q, l, 1) >= 0; } - static bool eval(mpq_srcptr q, double d) - { - bool b; - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - b = (mpq_cmp(q, temp) <= 0); - mpq_clear(temp); - return b; - } - static bool eval(double d, mpq_srcptr q) - { - bool b; - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - b = (mpq_cmp(temp, q) <= 0); - mpq_clear(temp); - return b; - } - - static bool eval(mpf_srcptr f, mpf_srcptr g) { return mpf_cmp(f, g) <= 0; } - - static bool eval(mpf_srcptr f, unsigned long int l) - { return mpf_cmp_ui(f, l) <= 0; } - static bool eval(unsigned long int l, mpf_srcptr f) - { return mpf_cmp_ui(f, l) >= 0; } - static bool eval(mpf_srcptr f, signed long int l) - { return mpf_cmp_si(f, l) <= 0; } - static bool eval(signed long int l, mpf_srcptr f) - { return mpf_cmp_si(f, l) >= 0; } - static bool eval(mpf_srcptr f, double d) - { return mpf_cmp_d(f, d) <= 0; } - static bool eval(double d, mpf_srcptr f) - { return mpf_cmp_d(f, d) >= 0; } -}; - -struct __gmp_binary_greater -{ - static bool eval(mpz_srcptr z, mpz_srcptr w) { return mpz_cmp(z, w) > 0; } - - static bool eval(mpz_srcptr z, unsigned long int l) - { return mpz_cmp_ui(z, l) > 0; } - static bool eval(unsigned long int l, mpz_srcptr z) - { return mpz_cmp_ui(z, l) < 0; } - static bool eval(mpz_srcptr z, signed long int l) - { return mpz_cmp_si(z, l) > 0; } - static bool eval(signed long int l, mpz_srcptr z) - { return mpz_cmp_si(z, l) < 0; } - static bool eval(mpz_srcptr z, double d) - { return mpz_cmp_d(z, d) > 0; } - static bool eval(double d, mpz_srcptr z) - { return mpz_cmp_d(z, d) < 0; } - - static bool eval(mpq_srcptr q, mpq_srcptr r) { return mpq_cmp(q, r) > 0; } - - static bool eval(mpq_srcptr q, unsigned long int l) - { return mpq_cmp_ui(q, l, 1) > 0; } - static bool eval(unsigned long int l, mpq_srcptr q) - { return mpq_cmp_ui(q, l, 1) < 0; } - static bool eval(mpq_srcptr q, signed long int l) - { return mpq_cmp_si(q, l, 1) > 0; } - static bool eval(signed long int l, mpq_srcptr q) - { return mpq_cmp_si(q, l, 1) < 0; } - static bool eval(mpq_srcptr q, double d) - { - bool b; - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - b = (mpq_cmp(q, temp) > 0); - mpq_clear(temp); - return b; - } - static bool eval(double d, mpq_srcptr q) - { - bool b; - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - b = (mpq_cmp(temp, q) > 0); - mpq_clear(temp); - return b; - } - - static bool eval(mpf_srcptr f, mpf_srcptr g) { return mpf_cmp(f, g) > 0; } - - static bool eval(mpf_srcptr f, unsigned long int l) - { return mpf_cmp_ui(f, l) > 0; } - static bool eval(unsigned long int l, mpf_srcptr f) - { return mpf_cmp_ui(f, l) < 0; } - static bool eval(mpf_srcptr f, signed long int l) - { return mpf_cmp_si(f, l) > 0; } - static bool eval(signed long int l, mpf_srcptr f) - { return mpf_cmp_si(f, l) < 0; } - static bool eval(mpf_srcptr f, double d) - { return mpf_cmp_d(f, d) > 0; } - static bool eval(double d, mpf_srcptr f) - { return mpf_cmp_d(f, d) < 0; } -}; - -struct __gmp_binary_greater_equal -{ - static bool eval(mpz_srcptr z, mpz_srcptr w) { return mpz_cmp(z, w) >= 0; } - - static bool eval(mpz_srcptr z, unsigned long int l) - { return mpz_cmp_ui(z, l) >= 0; } - static bool eval(unsigned long int l, mpz_srcptr z) - { return mpz_cmp_ui(z, l) <= 0; } - static bool eval(mpz_srcptr z, signed long int l) - { return mpz_cmp_si(z, l) >= 0; } - static bool eval(signed long int l, mpz_srcptr z) - { return mpz_cmp_si(z, l) <= 0; } - static bool eval(mpz_srcptr z, double d) - { return mpz_cmp_d(z, d) >= 0; } - static bool eval(double d, mpz_srcptr z) - { return mpz_cmp_d(z, d) <= 0; } - - static bool eval(mpq_srcptr q, mpq_srcptr r) { return mpq_cmp(q, r) >= 0; } - - static bool eval(mpq_srcptr q, unsigned long int l) - { return mpq_cmp_ui(q, l, 1) >= 0; } - static bool eval(unsigned long int l, mpq_srcptr q) - { return mpq_cmp_ui(q, l, 1) <= 0; } - static bool eval(mpq_srcptr q, signed long int l) - { return mpq_cmp_si(q, l, 1) >= 0; } - static bool eval(signed long int l, mpq_srcptr q) - { return mpq_cmp_si(q, l, 1) <= 0; } - static bool eval(mpq_srcptr q, double d) - { - bool b; - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - b = (mpq_cmp(q, temp) >= 0); - mpq_clear(temp); - return b; - } - static bool eval(double d, mpq_srcptr q) - { - bool b; - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - b = (mpq_cmp(temp, q) >= 0); - mpq_clear(temp); - return b; - } - - static bool eval(mpf_srcptr f, mpf_srcptr g) { return mpf_cmp(f, g) >= 0; } - - static bool eval(mpf_srcptr f, unsigned long int l) - { return mpf_cmp_ui(f, l) >= 0; } - static bool eval(unsigned long int l, mpf_srcptr f) - { return mpf_cmp_ui(f, l) <= 0; } - static bool eval(mpf_srcptr f, signed long int l) - { return mpf_cmp_si(f, l) >= 0; } - static bool eval(signed long int l, mpf_srcptr f) - { return mpf_cmp_si(f, l) <= 0; } - static bool eval(mpf_srcptr f, double d) - { return mpf_cmp_d(f, d) >= 0; } - static bool eval(double d, mpf_srcptr f) - { return mpf_cmp_d(f, d) <= 0; } -}; - -struct __gmp_unary_increment -{ - static void eval(mpz_ptr z) { mpz_add_ui(z, z, 1); } - static void eval(mpq_ptr q) - { mpz_add(mpq_numref(q), mpq_numref(q), mpq_denref(q)); } - static void eval(mpf_ptr f) { mpf_add_ui(f, f, 1); } -}; - -struct __gmp_unary_decrement -{ - static void eval(mpz_ptr z) { mpz_sub_ui(z, z, 1); } - static void eval(mpq_ptr q) - { mpz_sub(mpq_numref(q), mpq_numref(q), mpq_denref(q)); } - static void eval(mpf_ptr f) { mpf_sub_ui(f, f, 1); } -}; - -struct __gmp_abs_function -{ - static void eval(mpz_ptr z, mpz_srcptr w) { mpz_abs(z, w); } - static void eval(mpq_ptr q, mpq_srcptr r) { mpq_abs(q, r); } - static void eval(mpf_ptr f, mpf_srcptr g) { mpf_abs(f, g); } -}; - -struct __gmp_trunc_function -{ - static void eval(mpf_ptr f, mpf_srcptr g) { mpf_trunc(f, g); } -}; - -struct __gmp_floor_function -{ - static void eval(mpf_ptr f, mpf_srcptr g) { mpf_floor(f, g); } -}; - -struct __gmp_ceil_function -{ - static void eval(mpf_ptr f, mpf_srcptr g) { mpf_ceil(f, g); } -}; - -struct __gmp_sqrt_function -{ - static void eval(mpz_ptr z, mpz_srcptr w) { mpz_sqrt(z, w); } - static void eval(mpf_ptr f, mpf_srcptr g) { mpf_sqrt(f, g); } -}; - -struct __gmp_hypot_function -{ - static void eval(mpf_ptr f, mpf_srcptr g, mpf_srcptr h) - { - mpf_t temp; - mpf_init2(temp, mpf_get_prec(f)); - mpf_mul(temp, g, g); - mpf_mul(f, h, h); - mpf_add(f, f, temp); - mpf_sqrt(f, f); - mpf_clear(temp); - } - - static void eval(mpf_ptr f, mpf_srcptr g, unsigned long int l) - { - mpf_t temp; - mpf_init2(temp, mpf_get_prec(f)); - mpf_mul(temp, g, g); - mpf_set_ui(f, l); - mpf_mul(f, f, f); - mpf_add(f, f, temp); - mpf_sqrt(f, f); - mpf_clear(temp); - } - static void eval(mpf_ptr f, unsigned long int l, mpf_srcptr g) - { - mpf_t temp; - mpf_init2(temp, mpf_get_prec(f)); - mpf_mul(temp, g, g); - mpf_set_ui(f, l); - mpf_mul(f, f, f); - mpf_add(f, f, temp); - mpf_sqrt(f, f); - mpf_clear(temp); - } - static void eval(mpf_ptr f, mpf_srcptr g, signed long int l) - { - mpf_t temp; - mpf_init2(temp, mpf_get_prec(f)); - mpf_mul(temp, g, g); - mpf_set_si(f, l); - mpf_mul(f, f, f); - mpf_add(f, f, temp); - mpf_sqrt(f, f); - mpf_clear(temp); - } - static void eval(mpf_ptr f, signed long int l, mpf_srcptr g) - { - mpf_t temp; - mpf_init2(temp, mpf_get_prec(f)); - mpf_mul(temp, g, g); - mpf_set_si(f, l); - mpf_mul(f, f, f); - mpf_add(f, f, temp); - mpf_sqrt(f, f); - mpf_clear(temp); - } - static void eval(mpf_ptr f, mpf_srcptr g, double d) - { - mpf_t temp; - mpf_init2(temp, mpf_get_prec(f)); - mpf_mul(temp, g, g); - mpf_set_d(f, d); - mpf_mul(f, f, f); - mpf_add(f, f, temp); - mpf_sqrt(f, f); - mpf_clear(temp); - } - static void eval(mpf_ptr f, double d, mpf_srcptr g) - { - mpf_t temp; - mpf_init2(temp, mpf_get_prec(f)); - mpf_mul(temp, g, g); - mpf_set_d(f, d); - mpf_mul(f, f, f); - mpf_add(f, f, temp); - mpf_sqrt(f, f); - mpf_clear(temp); - } -}; - -struct __gmp_sgn_function -{ - static int eval(mpz_srcptr z) { return mpz_sgn(z); } - static int eval(mpq_srcptr q) { return mpq_sgn(q); } - static int eval(mpf_srcptr f) { return mpf_sgn(f); } -}; - -struct __gmp_cmp_function -{ - static int eval(mpz_srcptr z, mpz_srcptr w) { return mpz_cmp(z, w); } - - static int eval(mpz_srcptr z, unsigned long int l) - { return mpz_cmp_ui(z, l); } - static int eval(unsigned long int l, mpz_srcptr z) - { return -mpz_cmp_ui(z, l); } - static int eval(mpz_srcptr z, signed long int l) - { return mpz_cmp_si(z, l); } - static int eval(signed long int l, mpz_srcptr z) - { return -mpz_cmp_si(z, l); } - static int eval(mpz_srcptr z, double d) - { return mpz_cmp_d(z, d); } - static int eval(double d, mpz_srcptr z) - { return -mpz_cmp_d(z, d); } - - static int eval(mpq_srcptr q, mpq_srcptr r) { return mpq_cmp(q, r); } - - static int eval(mpq_srcptr q, unsigned long int l) - { return mpq_cmp_ui(q, l, 1); } - static int eval(unsigned long int l, mpq_srcptr q) - { return -mpq_cmp_ui(q, l, 1); } - static int eval(mpq_srcptr q, signed long int l) - { return mpq_cmp_si(q, l, 1); } - static int eval(signed long int l, mpq_srcptr q) - { return -mpq_cmp_si(q, l, 1); } - static int eval(mpq_srcptr q, double d) - { - int i; - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - i = mpq_cmp(q, temp); - mpq_clear(temp); - return i; - } - static int eval(double d, mpq_srcptr q) - { - int i; - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - i = mpq_cmp(temp, q); - mpq_clear(temp); - return i; - } - - static int eval(mpf_srcptr f, mpf_srcptr g) { return mpf_cmp(f, g); } - - static int eval(mpf_srcptr f, unsigned long int l) - { return mpf_cmp_ui(f, l); } - static int eval(unsigned long int l, mpf_srcptr f) - { return -mpf_cmp_ui(f, l); } - static int eval(mpf_srcptr f, signed long int l) - { return mpf_cmp_si(f, l); } - static int eval(signed long int l, mpf_srcptr f) - { return -mpf_cmp_si(f, l); } - static int eval(mpf_srcptr f, double d) - { return mpf_cmp_d(f, d); } - static int eval(double d, mpf_srcptr f) - { return -mpf_cmp_d(f, d); } -}; - -struct __gmp_rand_function -{ - static void eval(mpz_ptr z, gmp_randstate_t s, unsigned long int l) - { mpz_urandomb(z, s, l); } - static void eval(mpz_ptr z, gmp_randstate_t s, mpz_srcptr w) - { mpz_urandomm(z, s, w); } - static void eval(mpf_ptr f, gmp_randstate_t s, mp_bitcnt_t prec) - { mpf_urandomb(f, s, prec); } -}; - - -/**************** Auxiliary classes ****************/ - -/* this is much the same as gmp_allocated_string in gmp-impl.h - since gmp-impl.h is not publicly available, I redefine it here - I use a different name to avoid possible clashes */ - -extern "C" { - typedef void (*__gmp_freefunc_t) (void *, size_t); -} -struct __gmp_alloc_cstring -{ - char *str; - __gmp_alloc_cstring(char *s) { str = s; } - ~__gmp_alloc_cstring() - { - __gmp_freefunc_t freefunc; - mp_get_memory_functions (NULL, NULL, &freefunc); - (*freefunc) (str, std::strlen(str)+1); - } -}; - - -// general expression template class -template -class __gmp_expr; - - -// templates for resolving expression types -template -struct __gmp_resolve_ref -{ - typedef T ref_type; -}; - -template -struct __gmp_resolve_ref<__gmp_expr > -{ - typedef const __gmp_expr & ref_type; -}; - - -template -struct __gmp_resolve_expr; - -template <> -struct __gmp_resolve_expr -{ - typedef mpz_t value_type; - typedef mpz_ptr ptr_type; -}; - -template <> -struct __gmp_resolve_expr -{ - typedef mpq_t value_type; - typedef mpq_ptr ptr_type; -}; - -template <> -struct __gmp_resolve_expr -{ - typedef mpf_t value_type; - typedef mpf_ptr ptr_type; -}; - -template <> -struct __gmp_resolve_expr -{ - typedef mpq_t value_type; -}; - -template <> -struct __gmp_resolve_expr -{ - typedef mpq_t value_type; -}; - -template <> -struct __gmp_resolve_expr -{ - typedef mpf_t value_type; -}; - -template <> -struct __gmp_resolve_expr -{ - typedef mpf_t value_type; -}; - -template <> -struct __gmp_resolve_expr -{ - typedef mpf_t value_type; -}; - -template <> -struct __gmp_resolve_expr -{ - typedef mpf_t value_type; -}; - - - -template -struct __gmp_resolve_temp -{ - typedef __gmp_expr temp_type; -}; - -template -struct __gmp_resolve_temp -{ - typedef const __gmp_expr & temp_type; -}; - - -// classes for evaluating unary and binary expressions -template -struct __gmp_unary_expr -{ - const T &val; - - __gmp_unary_expr(const T &v) : val(v) { } -private: - __gmp_unary_expr(); -}; - -template -struct __gmp_binary_expr -{ - typename __gmp_resolve_ref::ref_type val1; - typename __gmp_resolve_ref::ref_type val2; - - __gmp_binary_expr(const T &v1, const U &v2) : val1(v1), val2(v2) { } -private: - __gmp_binary_expr(); -}; - - -// functions for evaluating expressions -template -void __gmp_set_expr(mpz_ptr, const __gmp_expr &); -template -void __gmp_set_expr(mpq_ptr, const __gmp_expr &); -template -void __gmp_set_expr(mpf_ptr, const __gmp_expr &); - - -/**************** Macros for in-class declarations ****************/ -/* This is just repetitive code that is easier to maintain if it's written - only once */ - -#define __GMPP_DECLARE_COMPOUND_OPERATOR(fun) \ - template \ - __gmp_expr & fun(const __gmp_expr &); - -#define __GMPN_DECLARE_COMPOUND_OPERATOR(fun) \ - __gmp_expr & fun(signed char); \ - __gmp_expr & fun(unsigned char); \ - __gmp_expr & fun(signed int); \ - __gmp_expr & fun(unsigned int); \ - __gmp_expr & fun(signed short int); \ - __gmp_expr & fun(unsigned short int); \ - __gmp_expr & fun(signed long int); \ - __gmp_expr & fun(unsigned long int); \ - __gmp_expr & fun(float); \ - __gmp_expr & fun(double); \ - __gmp_expr & fun(long double); - -#define __GMP_DECLARE_COMPOUND_OPERATOR(fun) \ -__GMPP_DECLARE_COMPOUND_OPERATOR(fun) \ -__GMPN_DECLARE_COMPOUND_OPERATOR(fun) - -#define __GMP_DECLARE_COMPOUND_OPERATOR_UI(fun) \ - __gmp_expr & fun(unsigned long int); - -#define __GMP_DECLARE_INCREMENT_OPERATOR(fun) \ - inline __gmp_expr & fun(); \ - inline __gmp_expr fun(int); - - -/**************** mpz_class -- wrapper for mpz_t ****************/ - -template <> -class __gmp_expr -{ -private: - typedef mpz_t value_type; - value_type mp; -public: - mp_bitcnt_t get_prec() const { return mpf_get_default_prec(); } - - // constructors and destructor - __gmp_expr() { mpz_init(mp); } - - __gmp_expr(const __gmp_expr &z) { mpz_init_set(mp, z.mp); } - template - __gmp_expr(const __gmp_expr &expr) - { mpz_init(mp); __gmp_set_expr(mp, expr); } - - __gmp_expr(signed char c) { mpz_init_set_si(mp, c); } - __gmp_expr(unsigned char c) { mpz_init_set_ui(mp, c); } - - __gmp_expr(signed int i) { mpz_init_set_si(mp, i); } - __gmp_expr(unsigned int i) { mpz_init_set_ui(mp, i); } - - __gmp_expr(signed short int s) { mpz_init_set_si(mp, s); } - __gmp_expr(unsigned short int s) { mpz_init_set_ui(mp, s); } - - __gmp_expr(signed long int l) { mpz_init_set_si(mp, l); } - __gmp_expr(unsigned long int l) { mpz_init_set_ui(mp, l); } - - __gmp_expr(float f) { mpz_init_set_d(mp, f); } - __gmp_expr(double d) { mpz_init_set_d(mp, d); } - // __gmp_expr(long double ld) { mpz_init_set_d(mp, ld); } - - explicit __gmp_expr(const char *s) - { - if (mpz_init_set_str (mp, s, 0) != 0) - { - mpz_clear (mp); - throw std::invalid_argument ("mpz_set_str"); - } - } - __gmp_expr(const char *s, int base) - { - if (mpz_init_set_str (mp, s, base) != 0) - { - mpz_clear (mp); - throw std::invalid_argument ("mpz_set_str"); - } - } - explicit __gmp_expr(const std::string &s) - { - if (mpz_init_set_str (mp, s.c_str(), 0) != 0) - { - mpz_clear (mp); - throw std::invalid_argument ("mpz_set_str"); - } - } - __gmp_expr(const std::string &s, int base) - { - if (mpz_init_set_str(mp, s.c_str(), base) != 0) - { - mpz_clear (mp); - throw std::invalid_argument ("mpz_set_str"); - } - } - - explicit __gmp_expr(mpz_srcptr z) { mpz_init_set(mp, z); } - - ~__gmp_expr() { mpz_clear(mp); } - - // assignment operators - __gmp_expr & operator=(const __gmp_expr &z) - { mpz_set(mp, z.mp); return *this; } - template - __gmp_expr & operator=(const __gmp_expr &expr) - { __gmp_set_expr(mp, expr); return *this; } - - __gmp_expr & operator=(signed char c) { mpz_set_si(mp, c); return *this; } - __gmp_expr & operator=(unsigned char c) { mpz_set_ui(mp, c); return *this; } - - __gmp_expr & operator=(signed int i) { mpz_set_si(mp, i); return *this; } - __gmp_expr & operator=(unsigned int i) { mpz_set_ui(mp, i); return *this; } - - __gmp_expr & operator=(signed short int s) - { mpz_set_si(mp, s); return *this; } - __gmp_expr & operator=(unsigned short int s) - { mpz_set_ui(mp, s); return *this; } - - __gmp_expr & operator=(signed long int l) - { mpz_set_si(mp, l); return *this; } - __gmp_expr & operator=(unsigned long int l) - { mpz_set_ui(mp, l); return *this; } - - __gmp_expr & operator=(float f) { mpz_set_d(mp, f); return *this; } - __gmp_expr & operator=(double d) { mpz_set_d(mp, d); return *this; } - // __gmp_expr & operator=(long double ld) - // { mpz_set_ld(mp, ld); return *this; } - - __gmp_expr & operator=(const char *s) - { - if (mpz_set_str (mp, s, 0) != 0) - throw std::invalid_argument ("mpz_set_str"); - return *this; - } - __gmp_expr & operator=(const std::string &s) - { - if (mpz_set_str(mp, s.c_str(), 0) != 0) - throw std::invalid_argument ("mpz_set_str"); - return *this; - } - - // string input/output functions - int set_str(const char *s, int base) - { return mpz_set_str(mp, s, base); } - int set_str(const std::string &s, int base) - { return mpz_set_str(mp, s.c_str(), base); } - std::string get_str(int base = 10) const - { - __gmp_alloc_cstring temp(mpz_get_str(0, base, mp)); - return std::string(temp.str); - } - - // conversion functions - mpz_srcptr __get_mp() const { return mp; } - mpz_ptr __get_mp() { return mp; } - mpz_srcptr get_mpz_t() const { return mp; } - mpz_ptr get_mpz_t() { return mp; } - - signed long int get_si() const { return mpz_get_si(mp); } - unsigned long int get_ui() const { return mpz_get_ui(mp); } - double get_d() const { return mpz_get_d(mp); } - - // bool fits_schar_p() const { return mpz_fits_schar_p(mp); } - // bool fits_uchar_p() const { return mpz_fits_uchar_p(mp); } - bool fits_sint_p() const { return mpz_fits_sint_p(mp); } - bool fits_uint_p() const { return mpz_fits_uint_p(mp); } - bool fits_sshort_p() const { return mpz_fits_sshort_p(mp); } - bool fits_ushort_p() const { return mpz_fits_ushort_p(mp); } - bool fits_slong_p() const { return mpz_fits_slong_p(mp); } - bool fits_ulong_p() const { return mpz_fits_ulong_p(mp); } - // bool fits_float_p() const { return mpz_fits_float_p(mp); } - // bool fits_double_p() const { return mpz_fits_double_p(mp); } - // bool fits_ldouble_p() const { return mpz_fits_ldouble_p(mp); } - - // member operators - __GMP_DECLARE_COMPOUND_OPERATOR(operator+=) - __GMP_DECLARE_COMPOUND_OPERATOR(operator-=) - __GMP_DECLARE_COMPOUND_OPERATOR(operator*=) - __GMP_DECLARE_COMPOUND_OPERATOR(operator/=) - __GMP_DECLARE_COMPOUND_OPERATOR(operator%=) - - __GMP_DECLARE_COMPOUND_OPERATOR(operator&=) - __GMP_DECLARE_COMPOUND_OPERATOR(operator|=) - __GMP_DECLARE_COMPOUND_OPERATOR(operator^=) - - __GMP_DECLARE_COMPOUND_OPERATOR_UI(operator<<=) - __GMP_DECLARE_COMPOUND_OPERATOR_UI(operator>>=) - - __GMP_DECLARE_INCREMENT_OPERATOR(operator++) - __GMP_DECLARE_INCREMENT_OPERATOR(operator--) -}; - -typedef __gmp_expr mpz_class; - - -/**************** mpq_class -- wrapper for mpq_t ****************/ - -template <> -class __gmp_expr -{ -private: - typedef mpq_t value_type; - value_type mp; -public: - mp_bitcnt_t get_prec() const { return mpf_get_default_prec(); } - void canonicalize() { mpq_canonicalize(mp); } - - // constructors and destructor - __gmp_expr() { mpq_init(mp); } - - __gmp_expr(const __gmp_expr &q) { mpq_init(mp); mpq_set(mp, q.mp); } - template - __gmp_expr(const __gmp_expr &expr) - { mpq_init(mp); __gmp_set_expr(mp, expr); } - - __gmp_expr(signed char c) { mpq_init(mp); mpq_set_si(mp, c, 1); } - __gmp_expr(unsigned char c) { mpq_init(mp); mpq_set_ui(mp, c, 1); } - - __gmp_expr(signed int i) { mpq_init(mp); mpq_set_si(mp, i, 1); } - __gmp_expr(unsigned int i) { mpq_init(mp); mpq_set_ui(mp, i, 1); } - - __gmp_expr(signed short int s) { mpq_init(mp); mpq_set_si(mp, s, 1); } - __gmp_expr(unsigned short int s) { mpq_init(mp); mpq_set_ui(mp, s, 1); } - - __gmp_expr(signed long int l) { mpq_init(mp); mpq_set_si(mp, l, 1); } - __gmp_expr(unsigned long int l) { mpq_init(mp); mpq_set_ui(mp, l, 1); } - - __gmp_expr(float f) { mpq_init(mp); mpq_set_d(mp, f); } - __gmp_expr(double d) { mpq_init(mp); mpq_set_d(mp, d); } - // __gmp_expr(long double ld) { mpq_init(mp); mpq_set_ld(mp, ld); } - - explicit __gmp_expr(const char *s) - { - mpq_init (mp); - if (mpq_set_str (mp, s, 0) != 0) - { - mpq_clear (mp); - throw std::invalid_argument ("mpq_set_str"); - } - } - __gmp_expr(const char *s, int base) - { - mpq_init (mp); - if (mpq_set_str(mp, s, base) != 0) - { - mpq_clear (mp); - throw std::invalid_argument ("mpq_set_str"); - } - } - explicit __gmp_expr(const std::string &s) - { - mpq_init (mp); - if (mpq_set_str (mp, s.c_str(), 0) != 0) - { - mpq_clear (mp); - throw std::invalid_argument ("mpq_set_str"); - } - } - __gmp_expr(const std::string &s, int base) - { - mpq_init(mp); - if (mpq_set_str (mp, s.c_str(), base) != 0) - { - mpq_clear (mp); - throw std::invalid_argument ("mpq_set_str"); - } - } - explicit __gmp_expr(mpq_srcptr q) { mpq_init(mp); mpq_set(mp, q); } - - __gmp_expr(const mpz_class &num, const mpz_class &den) - { - mpq_init(mp); - mpz_set(mpq_numref(mp), num.get_mpz_t()); - mpz_set(mpq_denref(mp), den.get_mpz_t()); - } - - ~__gmp_expr() { mpq_clear(mp); } - - // assignment operators - __gmp_expr & operator=(const __gmp_expr &q) - { mpq_set(mp, q.mp); return *this; } - template - __gmp_expr & operator=(const __gmp_expr &expr) - { __gmp_set_expr(mp, expr); return *this; } - - __gmp_expr & operator=(signed char c) - { mpq_set_si(mp, c, 1); return *this; } - __gmp_expr & operator=(unsigned char c) - { mpq_set_ui(mp, c, 1); return *this; } - - __gmp_expr & operator=(signed int i) { mpq_set_si(mp, i, 1); return *this; } - __gmp_expr & operator=(unsigned int i) - { mpq_set_ui(mp, i, 1); return *this; } - - __gmp_expr & operator=(signed short int s) - { mpq_set_si(mp, s, 1); return *this; } - __gmp_expr & operator=(unsigned short int s) - { mpq_set_ui(mp, s, 1); return *this; } - - __gmp_expr & operator=(signed long int l) - { mpq_set_si(mp, l, 1); return *this; } - __gmp_expr & operator=(unsigned long int l) - { mpq_set_ui(mp, l, 1); return *this; } - - __gmp_expr & operator=(float f) { mpq_set_d(mp, f); return *this; } - __gmp_expr & operator=(double d) { mpq_set_d(mp, d); return *this; } - // __gmp_expr & operator=(long double ld) - // { mpq_set_ld(mp, ld); return *this; } - - __gmp_expr & operator=(const char *s) - { - if (mpq_set_str (mp, s, 0) != 0) - throw std::invalid_argument ("mpq_set_str"); - return *this; - } - __gmp_expr & operator=(const std::string &s) - { - if (mpq_set_str(mp, s.c_str(), 0) != 0) - throw std::invalid_argument ("mpq_set_str"); - return *this; - } - - // string input/output functions - int set_str(const char *s, int base) - { return mpq_set_str(mp, s, base); } - int set_str(const std::string &s, int base) - { return mpq_set_str(mp, s.c_str(), base); } - std::string get_str(int base = 10) const - { - __gmp_alloc_cstring temp(mpq_get_str(0, base, mp)); - return std::string(temp.str); - } - - // conversion functions - - // casting a reference to an mpz_t to mpz_class & is a dirty hack, - // but works because the internal representation of mpz_class is - // exactly an mpz_t - const mpz_class & get_num() const - { return reinterpret_cast(*mpq_numref(mp)); } - mpz_class & get_num() - { return reinterpret_cast(*mpq_numref(mp)); } - const mpz_class & get_den() const - { return reinterpret_cast(*mpq_denref(mp)); } - mpz_class & get_den() - { return reinterpret_cast(*mpq_denref(mp)); } - - mpq_srcptr __get_mp() const { return mp; } - mpq_ptr __get_mp() { return mp; } - mpq_srcptr get_mpq_t() const { return mp; } - mpq_ptr get_mpq_t() { return mp; } - - mpz_srcptr get_num_mpz_t() const { return mpq_numref(mp); } - mpz_ptr get_num_mpz_t() { return mpq_numref(mp); } - mpz_srcptr get_den_mpz_t() const { return mpq_denref(mp); } - mpz_ptr get_den_mpz_t() { return mpq_denref(mp); } - - double get_d() const { return mpq_get_d(mp); } - - // compound assignments - __GMP_DECLARE_COMPOUND_OPERATOR(operator+=) - __GMP_DECLARE_COMPOUND_OPERATOR(operator-=) - __GMP_DECLARE_COMPOUND_OPERATOR(operator*=) - __GMP_DECLARE_COMPOUND_OPERATOR(operator/=) - - __GMP_DECLARE_COMPOUND_OPERATOR_UI(operator<<=) - __GMP_DECLARE_COMPOUND_OPERATOR_UI(operator>>=) - - __GMP_DECLARE_INCREMENT_OPERATOR(operator++) - __GMP_DECLARE_INCREMENT_OPERATOR(operator--) -}; - -typedef __gmp_expr mpq_class; - - -/**************** mpf_class -- wrapper for mpf_t ****************/ - -template <> -class __gmp_expr -{ -private: - typedef mpf_t value_type; - value_type mp; -public: - mp_bitcnt_t get_prec() const { return mpf_get_prec(mp); } - - void set_prec(mp_bitcnt_t prec) { mpf_set_prec(mp, prec); } - void set_prec_raw(mp_bitcnt_t prec) { mpf_set_prec_raw(mp, prec); } - - // constructors and destructor - __gmp_expr() { mpf_init(mp); } - - __gmp_expr(const __gmp_expr &f) - { mpf_init2(mp, f.get_prec()); mpf_set(mp, f.mp); } - __gmp_expr(const __gmp_expr &f, mp_bitcnt_t prec) - { mpf_init2(mp, prec); mpf_set(mp, f.mp); } - template - __gmp_expr(const __gmp_expr &expr) - { mpf_init2(mp, expr.get_prec()); __gmp_set_expr(mp, expr); } - template - __gmp_expr(const __gmp_expr &expr, mp_bitcnt_t prec) - { mpf_init2(mp, prec); __gmp_set_expr(mp, expr); } - - __gmp_expr(signed char c) { mpf_init_set_si(mp, c); } - __gmp_expr(signed char c, mp_bitcnt_t prec) - { mpf_init2(mp, prec); mpf_set_si(mp, c); } - __gmp_expr(unsigned char c) { mpf_init_set_ui(mp, c); } - __gmp_expr(unsigned char c, mp_bitcnt_t prec) - { mpf_init2(mp, prec); mpf_set_ui(mp, c); } - - __gmp_expr(signed int i) { mpf_init_set_si(mp, i); } - __gmp_expr(signed int i, mp_bitcnt_t prec) - { mpf_init2(mp, prec); mpf_set_si(mp, i); } - __gmp_expr(unsigned int i) { mpf_init_set_ui(mp, i); } - __gmp_expr(unsigned int i, mp_bitcnt_t prec) - { mpf_init2(mp, prec); mpf_set_ui(mp, i); } - - __gmp_expr(signed short int s) { mpf_init_set_si(mp, s); } - __gmp_expr(signed short int s, mp_bitcnt_t prec) - { mpf_init2(mp, prec); mpf_set_si(mp, s); } - __gmp_expr(unsigned short int s) { mpf_init_set_ui(mp, s); } - __gmp_expr(unsigned short int s, mp_bitcnt_t prec) - { mpf_init2(mp, prec); mpf_set_ui(mp, s); } - - __gmp_expr(signed long int l) { mpf_init_set_si(mp, l); } - __gmp_expr(signed long int l, mp_bitcnt_t prec) - { mpf_init2(mp, prec); mpf_set_si(mp, l); } - __gmp_expr(unsigned long int l) { mpf_init_set_ui(mp, l); } - __gmp_expr(unsigned long int l, mp_bitcnt_t prec) - { mpf_init2(mp, prec); mpf_set_ui(mp, l); } - - __gmp_expr(float f) { mpf_init_set_d(mp, f); } - __gmp_expr(float f, mp_bitcnt_t prec) - { mpf_init2(mp, prec); mpf_set_d(mp, f); } - __gmp_expr(double d) { mpf_init_set_d(mp, d); } - __gmp_expr(double d, mp_bitcnt_t prec) - { mpf_init2(mp, prec); mpf_set_d(mp, d); } - // __gmp_expr(long double ld) { mpf_init_set_d(mp, ld); } - // __gmp_expr(long double ld, mp_bitcnt_t prec) - // { mpf_init2(mp, prec); mpf_set_d(mp, ld); } - - explicit __gmp_expr(const char *s) - { - if (mpf_init_set_str (mp, s, 0) != 0) - { - mpf_clear (mp); - throw std::invalid_argument ("mpf_set_str"); - } - } - __gmp_expr(const char *s, mp_bitcnt_t prec, int base = 0) - { - mpf_init2(mp, prec); - if (mpf_set_str(mp, s, base) != 0) - { - mpf_clear (mp); - throw std::invalid_argument ("mpf_set_str"); - } - } - explicit __gmp_expr(const std::string &s) - { - if (mpf_init_set_str(mp, s.c_str(), 0) != 0) - { - mpf_clear (mp); - throw std::invalid_argument ("mpf_set_str"); - } - } - __gmp_expr(const std::string &s, mp_bitcnt_t prec, int base = 0) - { - mpf_init2(mp, prec); - if (mpf_set_str(mp, s.c_str(), base) != 0) - { - mpf_clear (mp); - throw std::invalid_argument ("mpf_set_str"); - } - } - - explicit __gmp_expr(mpf_srcptr f) - { mpf_init2(mp, mpf_get_prec(f)); mpf_set(mp, f); } - __gmp_expr(mpf_srcptr f, mp_bitcnt_t prec) - { mpf_init2(mp, prec); mpf_set(mp, f); } - - ~__gmp_expr() { mpf_clear(mp); } - - // assignment operators - __gmp_expr & operator=(const __gmp_expr &f) - { mpf_set(mp, f.mp); return *this; } - template - __gmp_expr & operator=(const __gmp_expr &expr) - { __gmp_set_expr(mp, expr); return *this; } - - __gmp_expr & operator=(signed char c) { mpf_set_si(mp, c); return *this; } - __gmp_expr & operator=(unsigned char c) { mpf_set_ui(mp, c); return *this; } - - __gmp_expr & operator=(signed int i) { mpf_set_si(mp, i); return *this; } - __gmp_expr & operator=(unsigned int i) { mpf_set_ui(mp, i); return *this; } - - __gmp_expr & operator=(signed short int s) - { mpf_set_si(mp, s); return *this; } - __gmp_expr & operator=(unsigned short int s) - { mpf_set_ui(mp, s); return *this; } - - __gmp_expr & operator=(signed long int l) - { mpf_set_si(mp, l); return *this; } - __gmp_expr & operator=(unsigned long int l) - { mpf_set_ui(mp, l); return *this; } - - __gmp_expr & operator=(float f) { mpf_set_d(mp, f); return *this; } - __gmp_expr & operator=(double d) { mpf_set_d(mp, d); return *this; } - // __gmp_expr & operator=(long double ld) - // { mpf_set_ld(mp, ld); return *this; } - - __gmp_expr & operator=(const char *s) - { - if (mpf_set_str (mp, s, 0) != 0) - throw std::invalid_argument ("mpf_set_str"); - return *this; - } - __gmp_expr & operator=(const std::string &s) - { - if (mpf_set_str(mp, s.c_str(), 0) != 0) - throw std::invalid_argument ("mpf_set_str"); - return *this; - } - - // string input/output functions - int set_str(const char *s, int base) - { return mpf_set_str(mp, s, base); } - int set_str(const std::string &s, int base) - { return mpf_set_str(mp, s.c_str(), base); } - std::string get_str(mp_exp_t &expo, int base = 10, size_t size = 0) const - { - __gmp_alloc_cstring temp(mpf_get_str(0, &expo, base, size, mp)); - return std::string(temp.str); - } - - // conversion functions - mpf_srcptr __get_mp() const { return mp; } - mpf_ptr __get_mp() { return mp; } - mpf_srcptr get_mpf_t() const { return mp; } - mpf_ptr get_mpf_t() { return mp; } - - signed long int get_si() const { return mpf_get_si(mp); } - unsigned long int get_ui() const { return mpf_get_ui(mp); } - double get_d() const { return mpf_get_d(mp); } - - // bool fits_schar_p() const { return mpf_fits_schar_p(mp); } - // bool fits_uchar_p() const { return mpf_fits_uchar_p(mp); } - bool fits_sint_p() const { return mpf_fits_sint_p(mp); } - bool fits_uint_p() const { return mpf_fits_uint_p(mp); } - bool fits_sshort_p() const { return mpf_fits_sshort_p(mp); } - bool fits_ushort_p() const { return mpf_fits_ushort_p(mp); } - bool fits_slong_p() const { return mpf_fits_slong_p(mp); } - bool fits_ulong_p() const { return mpf_fits_ulong_p(mp); } - // bool fits_float_p() const { return mpf_fits_float_p(mp); } - // bool fits_double_p() const { return mpf_fits_double_p(mp); } - // bool fits_ldouble_p() const { return mpf_fits_ldouble_p(mp); } - - // compound assignments - __GMP_DECLARE_COMPOUND_OPERATOR(operator+=) - __GMP_DECLARE_COMPOUND_OPERATOR(operator-=) - __GMP_DECLARE_COMPOUND_OPERATOR(operator*=) - __GMP_DECLARE_COMPOUND_OPERATOR(operator/=) - - __GMP_DECLARE_COMPOUND_OPERATOR_UI(operator<<=) - __GMP_DECLARE_COMPOUND_OPERATOR_UI(operator>>=) - - __GMP_DECLARE_INCREMENT_OPERATOR(operator++) - __GMP_DECLARE_INCREMENT_OPERATOR(operator--) -}; - -typedef __gmp_expr mpf_class; - - - -/**************** I/O operators ****************/ - -// these should (and will) be provided separately - -template -inline std::ostream & operator<< -(std::ostream &o, const __gmp_expr &expr) -{ - return o << expr.__get_mp(); -} - -template -inline std::ostream & operator<< -(std::ostream &o, const __gmp_expr &expr) -{ - __gmp_expr temp(expr); - return o << temp.__get_mp(); -} - - -template -inline std::istream & operator>>(std::istream &i, __gmp_expr &expr) -{ - return i >> expr.__get_mp(); -} - -inline std::istream & operator>>(std::istream &i, mpq_class &q) -{ - i >> q.get_mpq_t(); - // q.canonicalize(); // you might want to uncomment this - return i; -} - - -/**************** Functions for type conversion ****************/ - -template <> -inline void __gmp_set_expr(mpz_ptr z, const mpz_class &w) -{ - mpz_set(z, w.get_mpz_t()); -} - -template -inline void __gmp_set_expr(mpz_ptr z, const __gmp_expr &expr) -{ - expr.eval(z); -} - -template <> -inline void __gmp_set_expr(mpz_ptr z, const mpq_class &q) -{ - mpz_set_q(z, q.get_mpq_t()); -} - -template -inline void __gmp_set_expr(mpz_ptr z, const __gmp_expr &expr) -{ - mpq_class temp(expr); - mpz_set_q(z, temp.get_mpq_t()); -} - -template -inline void __gmp_set_expr(mpz_ptr z, const mpf_class &f) -{ - mpz_set_f(z, f.get_mpf_t()); -} - -template -inline void __gmp_set_expr(mpz_ptr z, const __gmp_expr &expr) -{ - mpf_class temp(expr); - mpz_set_f(z, temp.get_mpf_t()); -} - -template <> -inline void __gmp_set_expr(mpq_ptr q, const mpz_class &z) -{ - mpq_set_z(q, z.get_mpz_t()); -} - -template -inline void __gmp_set_expr(mpq_ptr q, const __gmp_expr &expr) -{ - mpz_class temp(expr); - mpq_set_z(q, temp.get_mpz_t()); -} - -template <> -inline void __gmp_set_expr(mpq_ptr q, const mpq_class &r) -{ - mpq_set(q, r.get_mpq_t()); -} - -template -inline void __gmp_set_expr(mpq_ptr q, const __gmp_expr &expr) -{ - expr.eval(q); -} - -template -inline void __gmp_set_expr(mpq_ptr q, const mpf_class &f) -{ - mpq_set_f(q, f.get_mpf_t()); -} - -template -inline void __gmp_set_expr(mpq_ptr q, const __gmp_expr &expr) -{ - mpf_class temp(expr); - mpq_set_f(q, temp.get_mpf_t()); -} - -template -inline void __gmp_set_expr(mpf_ptr f, const mpz_class &z) -{ - mpf_set_z(f, z.get_mpz_t()); -} - -template -inline void __gmp_set_expr(mpf_ptr f, const __gmp_expr &expr) -{ - mpz_class temp(expr); - mpf_set_z(f, temp.get_mpz_t()); -} - -template -inline void __gmp_set_expr(mpf_ptr f, const mpq_class &q) -{ - mpf_set_q(f, q.get_mpq_t()); -} - -template -inline void __gmp_set_expr(mpf_ptr f, const __gmp_expr &expr) -{ - mpq_class temp(expr); - mpf_set_q(f, temp.get_mpq_t()); -} - -template <> -inline void __gmp_set_expr(mpf_ptr f, const mpf_class &g) -{ - mpf_set(f, g.get_mpf_t()); -} - -template -inline void __gmp_set_expr(mpf_ptr f, const __gmp_expr &expr) -{ - expr.eval(f, mpf_get_prec(f)); -} - - -/**************** Specializations of __gmp_expr ****************/ -/* The eval() method of __gmp_expr evaluates the corresponding - expression and assigns the result to its argument, which is either an - mpz_t, mpq_t, or mpf_t as specified by the T argument. - Compound expressions are evaluated recursively (temporaries are created - to hold intermediate values), while for simple expressions the eval() - method of the appropriate function object (available as the Op argument - of either __gmp_unary_expr or __gmp_binary_expr) is - called. */ - - -/**************** Unary expressions ****************/ -/* cases: - - simple: argument is mp*_class, that is, __gmp_expr - - compound: argument is __gmp_expr (with U not equal to T) */ - - -// simple expressions - -template -class __gmp_expr, Op> > -{ -private: - typedef __gmp_expr val_type; - - __gmp_unary_expr expr; -public: - __gmp_expr(const val_type &val) : expr(val) { } - void eval(typename __gmp_resolve_expr::ptr_type p, - unsigned long int = 0) const - { Op::eval(p, expr.val.__get_mp()); } - const val_type & get_val() const { return expr.val; } - unsigned long int get_prec() const { return expr.val.get_prec(); } -}; - - -// compound expressions - -template -class __gmp_expr, Op> > -{ -private: - typedef __gmp_expr val_type; - - __gmp_unary_expr expr; -public: - __gmp_expr(const val_type &val) : expr(val) { } - void eval(typename __gmp_resolve_expr::ptr_type p) const - { __gmp_expr temp(expr.val); Op::eval(p, temp.__get_mp()); } - void eval(typename __gmp_resolve_expr::ptr_type p, - mp_bitcnt_t prec) const - { __gmp_expr temp(expr.val, prec); Op::eval(p, temp.__get_mp()); } - const val_type & get_val() const { return expr.val; } - unsigned long int get_prec() const { return expr.val.get_prec(); } -}; - - -/**************** Binary expressions ****************/ -/* simple: - - arguments are both mp*_class - - one argument is mp*_class, one is a built-in type - compound: - - one is mp*_class, one is __gmp_expr - - one is __gmp_expr, one is built-in - - both arguments are __gmp_expr<...> */ - - -// simple expressions - -template -class __gmp_expr -, __gmp_expr, Op> > -{ -private: - typedef __gmp_expr val1_type; - typedef __gmp_expr val2_type; - - __gmp_binary_expr expr; -public: - __gmp_expr(const val1_type &val1, const val2_type &val2) - : expr(val1, val2) { } - void eval(typename __gmp_resolve_expr::ptr_type p, - unsigned long int = 0) const - { Op::eval(p, expr.val1.__get_mp(), expr.val2.__get_mp()); } - const val1_type & get_val1() const { return expr.val1; } - const val2_type & get_val2() const { return expr.val2; } - unsigned long int get_prec() const - { - mp_bitcnt_t prec1 = expr.val1.get_prec(), - prec2 = expr.val2.get_prec(); - return (prec1 > prec2) ? prec1 : prec2; - } -}; - - -// simple expressions, T is a built-in numerical type - -template -class __gmp_expr, U, Op> > -{ -private: - typedef __gmp_expr val1_type; - typedef U val2_type; - - __gmp_binary_expr expr; -public: - __gmp_expr(const val1_type &val1, const val2_type &val2) - : expr(val1, val2) { } - void eval(typename __gmp_resolve_expr::ptr_type p, - unsigned long int = 0) const - { Op::eval(p, expr.val1.__get_mp(), expr.val2); } - const val1_type & get_val1() const { return expr.val1; } - const val2_type & get_val2() const { return expr.val2; } - unsigned long int get_prec() const { return expr.val1.get_prec(); } -}; - -template -class __gmp_expr, Op> > -{ -private: - typedef U val1_type; - typedef __gmp_expr val2_type; - - __gmp_binary_expr expr; -public: - __gmp_expr(const val1_type &val1, const val2_type &val2) - : expr(val1, val2) { } - void eval(typename __gmp_resolve_expr::ptr_type p, - unsigned long int = 0) const - { Op::eval(p, expr.val1, expr.val2.__get_mp()); } - const val1_type & get_val1() const { return expr.val1; } - const val2_type & get_val2() const { return expr.val2; } - unsigned long int get_prec() const { return expr.val2.get_prec(); } -}; - - -// compound expressions, one argument is a subexpression - -template -class __gmp_expr -, __gmp_expr, Op> > -{ -private: - typedef __gmp_expr val1_type; - typedef __gmp_expr val2_type; - - __gmp_binary_expr expr; -public: - __gmp_expr(const val1_type &val1, const val2_type &val2) - : expr(val1, val2) { } - void eval(typename __gmp_resolve_expr::ptr_type p) const - { - __gmp_expr temp(expr.val2); - Op::eval(p, expr.val1.__get_mp(), temp.__get_mp()); - } - void eval(typename __gmp_resolve_expr::ptr_type p, - mp_bitcnt_t prec) const - { - __gmp_expr temp(expr.val2, prec); - Op::eval(p, expr.val1.__get_mp(), temp.__get_mp()); - } - const val1_type & get_val1() const { return expr.val1; } - const val2_type & get_val2() const { return expr.val2; } - unsigned long int get_prec() const - { - mp_bitcnt_t prec1 = expr.val1.get_prec(), - prec2 = expr.val2.get_prec(); - return (prec1 > prec2) ? prec1 : prec2; - } -}; - -template -class __gmp_expr -, __gmp_expr, Op> > -{ -private: - typedef __gmp_expr val1_type; - typedef __gmp_expr val2_type; - - __gmp_binary_expr expr; -public: - __gmp_expr(const val1_type &val1, const val2_type &val2) - : expr(val1, val2) { } - void eval(typename __gmp_resolve_expr::ptr_type p) const - { - __gmp_expr temp(expr.val1); - Op::eval(p, temp.__get_mp(), expr.val2.__get_mp()); - } - void eval(typename __gmp_resolve_expr::ptr_type p, - mp_bitcnt_t prec) const - { - __gmp_expr temp(expr.val1, prec); - Op::eval(p, temp.__get_mp(), expr.val2.__get_mp()); - } - const val1_type & get_val1() const { return expr.val1; } - const val2_type & get_val2() const { return expr.val2; } - unsigned long int get_prec() const - { - mp_bitcnt_t prec1 = expr.val1.get_prec(), - prec2 = expr.val2.get_prec(); - return (prec1 > prec2) ? prec1 : prec2; - } -}; - -template -class __gmp_expr -, __gmp_expr, Op> > -{ -private: - typedef __gmp_expr val1_type; - typedef __gmp_expr val2_type; - - __gmp_binary_expr expr; -public: - __gmp_expr(const val1_type &val1, const val2_type &val2) - : expr(val1, val2) { } - void eval(typename __gmp_resolve_expr::ptr_type p) const - { - __gmp_expr temp(expr.val2); - Op::eval(p, expr.val1.__get_mp(), temp.__get_mp()); - } - void eval(typename __gmp_resolve_expr::ptr_type p, - mp_bitcnt_t prec) const - { - __gmp_expr temp(expr.val2, prec); - Op::eval(p, expr.val1.__get_mp(), temp.__get_mp()); - } - const val1_type & get_val1() const { return expr.val1; } - const val2_type & get_val2() const { return expr.val2; } - unsigned long int get_prec() const - { - mp_bitcnt_t prec1 = expr.val1.get_prec(), - prec2 = expr.val2.get_prec(); - return (prec1 > prec2) ? prec1 : prec2; - } -}; - -template -class __gmp_expr -, __gmp_expr, Op> > -{ -private: - typedef __gmp_expr val1_type; - typedef __gmp_expr val2_type; - - __gmp_binary_expr expr; -public: - __gmp_expr(const val1_type &val1, const val2_type &val2) - : expr(val1, val2) { } - void eval(typename __gmp_resolve_expr::ptr_type p) const - { - __gmp_expr temp(expr.val1); - Op::eval(p, temp.__get_mp(), expr.val2.__get_mp()); - } - void eval(typename __gmp_resolve_expr::ptr_type p, - mp_bitcnt_t prec) const - { - __gmp_expr temp(expr.val1, prec); - Op::eval(p, temp.__get_mp(), expr.val2.__get_mp()); - } - const val1_type & get_val1() const { return expr.val1; } - const val2_type & get_val2() const { return expr.val2; } - unsigned long int get_prec() const - { - mp_bitcnt_t prec1 = expr.val1.get_prec(), - prec2 = expr.val2.get_prec(); - return (prec1 > prec2) ? prec1 : prec2; - } -}; - - -// one argument is a subexpression, one is a built-in - -template -class __gmp_expr, V, Op> > -{ -private: - typedef __gmp_expr val1_type; - typedef V val2_type; - - __gmp_binary_expr expr; -public: - __gmp_expr(const val1_type &val1, const val2_type &val2) - : expr(val1, val2) { } - void eval(typename __gmp_resolve_expr::ptr_type p) const - { - __gmp_expr temp(expr.val1); - Op::eval(p, temp.__get_mp(), expr.val2); - } - void eval(typename __gmp_resolve_expr::ptr_type p, - mp_bitcnt_t prec) const - { - __gmp_expr temp(expr.val1, prec); - Op::eval(p, temp.__get_mp(), expr.val2); - } - const val1_type & get_val1() const { return expr.val1; } - const val2_type & get_val2() const { return expr.val2; } - unsigned long int get_prec() const { return expr.val1.get_prec(); } -}; - -template -class __gmp_expr, Op> > -{ -private: - typedef U val1_type; - typedef __gmp_expr val2_type; - - __gmp_binary_expr expr; -public: - __gmp_expr(const val1_type &val1, const val2_type &val2) - : expr(val1, val2) { } - void eval(typename __gmp_resolve_expr::ptr_type p) const - { - __gmp_expr temp(expr.val2); - Op::eval(p, expr.val1, temp.__get_mp()); - } - void eval(typename __gmp_resolve_expr::ptr_type p, - mp_bitcnt_t prec) const - { - __gmp_expr temp(expr.val2, prec); - Op::eval(p, expr.val1, temp.__get_mp()); - } - const val1_type & get_val1() const { return expr.val1; } - const val2_type & get_val2() const { return expr.val2; } - unsigned long int get_prec() const { return expr.val2.get_prec(); } -}; - - -// both arguments are subexpressions - -template -class __gmp_expr -, __gmp_expr, Op> > -{ -private: - typedef __gmp_expr val1_type; - typedef __gmp_expr val2_type; - - __gmp_binary_expr expr; -public: - __gmp_expr(const val1_type &val1, const val2_type &val2) - : expr(val1, val2) { } - void eval(typename __gmp_resolve_expr::ptr_type p) const - { - __gmp_expr temp1(expr.val1), temp2(expr.val2); - Op::eval(p, temp1.__get_mp(), temp2.__get_mp()); - } - void eval(typename __gmp_resolve_expr::ptr_type p, - mp_bitcnt_t prec) const - { - __gmp_expr temp1(expr.val1, prec), temp2(expr.val2, prec); - Op::eval(p, temp1.__get_mp(), temp2.__get_mp()); - } - const val1_type & get_val1() const { return expr.val1; } - const val2_type & get_val2() const { return expr.val2; } - unsigned long int get_prec() const - { - mp_bitcnt_t prec1 = expr.val1.get_prec(), - prec2 = expr.val2.get_prec(); - return (prec1 > prec2) ? prec1 : prec2; - } -}; - -template -class __gmp_expr -, __gmp_expr, Op> > -{ -private: - typedef __gmp_expr val1_type; - typedef __gmp_expr val2_type; - - __gmp_binary_expr expr; -public: - __gmp_expr(const val1_type &val1, const val2_type &val2) - : expr(val1, val2) { } - void eval(typename __gmp_resolve_expr::ptr_type p) const - { - __gmp_expr temp1(expr.val1), temp2(expr.val2); - Op::eval(p, temp1.__get_mp(), temp2.__get_mp()); - } - void eval(typename __gmp_resolve_expr::ptr_type p, - mp_bitcnt_t prec) const - { - __gmp_expr temp1(expr.val1, prec), temp2(expr.val2, prec); - Op::eval(p, temp1.__get_mp(), temp2.__get_mp()); - } - const val1_type & get_val1() const { return expr.val1; } - const val2_type & get_val2() const { return expr.val2; } - unsigned long int get_prec() const - { - mp_bitcnt_t prec1 = expr.val1.get_prec(), - prec2 = expr.val2.get_prec(); - return (prec1 > prec2) ? prec1 : prec2; - } -}; - -template -class __gmp_expr -, __gmp_expr, Op> > -{ -private: - typedef __gmp_expr val1_type; - typedef __gmp_expr val2_type; - - __gmp_binary_expr expr; -public: - __gmp_expr(const val1_type &val1, const val2_type &val2) - : expr(val1, val2) { } - void eval(typename __gmp_resolve_expr::ptr_type p) const - { - __gmp_expr temp1(expr.val1), temp2(expr.val2); - Op::eval(p, temp1.__get_mp(), temp2.__get_mp()); - } - void eval(typename __gmp_resolve_expr::ptr_type p, - mp_bitcnt_t prec) const - { - __gmp_expr temp1(expr.val1, prec), temp2(expr.val2, prec); - Op::eval(p, temp1.__get_mp(), temp2.__get_mp()); - } - const val1_type & get_val1() const { return expr.val1; } - const val2_type & get_val2() const { return expr.val2; } - unsigned long int get_prec() const - { - mp_bitcnt_t prec1 = expr.val1.get_prec(), - prec2 = expr.val2.get_prec(); - return (prec1 > prec2) ? prec1 : prec2; - } -}; - - -/**************** Special cases ****************/ - -/* Some operations (i.e., add and subtract) with mixed mpz/mpq arguments - can be done directly without first converting the mpz to mpq. - Appropriate specializations of __gmp_expr are required. */ - - -#define __GMPZQ_DEFINE_EXPR(eval_fun) \ - \ -template <> \ -class __gmp_expr > \ -{ \ -private: \ - typedef mpz_class val1_type; \ - typedef mpq_class val2_type; \ - \ - __gmp_binary_expr expr; \ -public: \ - __gmp_expr(const val1_type &val1, const val2_type &val2) \ - : expr(val1, val2) { } \ - void eval(mpq_ptr q) const \ - { eval_fun::eval(q, expr.val1.get_mpz_t(), expr.val2.get_mpq_t()); } \ - const val1_type & get_val1() const { return expr.val1; } \ - const val2_type & get_val2() const { return expr.val2; } \ - unsigned long int get_prec() const { return mpf_get_default_prec(); } \ -}; \ - \ -template <> \ -class __gmp_expr > \ -{ \ -private: \ - typedef mpq_class val1_type; \ - typedef mpz_class val2_type; \ - \ - __gmp_binary_expr expr; \ -public: \ - __gmp_expr(const val1_type &val1, const val2_type &val2) \ - : expr(val1, val2) { } \ - void eval(mpq_ptr q) const \ - { eval_fun::eval(q, expr.val1.get_mpq_t(), expr.val2.get_mpz_t()); } \ - const val1_type & get_val1() const { return expr.val1; } \ - const val2_type & get_val2() const { return expr.val2; } \ - unsigned long int get_prec() const { return mpf_get_default_prec(); } \ -}; \ - \ -template \ -class __gmp_expr \ -, eval_fun> > \ -{ \ -private: \ - typedef mpz_class val1_type; \ - typedef __gmp_expr val2_type; \ - \ - __gmp_binary_expr expr; \ -public: \ - __gmp_expr(const val1_type &val1, const val2_type &val2) \ - : expr(val1, val2) { } \ - void eval(mpq_ptr q) const \ - { \ - mpq_class temp(expr.val2); \ - eval_fun::eval(q, expr.val1.get_mpz_t(), temp.get_mpq_t()); \ - } \ - const val1_type & get_val1() const { return expr.val1; } \ - const val2_type & get_val2() const { return expr.val2; } \ - unsigned long int get_prec() const { return mpf_get_default_prec(); } \ -}; \ - \ -template \ -class __gmp_expr \ -, eval_fun> > \ -{ \ -private: \ - typedef mpq_class val1_type; \ - typedef __gmp_expr val2_type; \ - \ - __gmp_binary_expr expr; \ -public: \ - __gmp_expr(const val1_type &val1, const val2_type &val2) \ - : expr(val1, val2) { } \ - void eval(mpq_ptr q) const \ - { \ - mpz_class temp(expr.val2); \ - eval_fun::eval(q, expr.val1.get_mpq_t(), temp.get_mpz_t()); \ - } \ - const val1_type & get_val1() const { return expr.val1; } \ - const val2_type & get_val2() const { return expr.val2; } \ - unsigned long int get_prec() const { return mpf_get_default_prec(); } \ -}; \ - \ -template \ -class __gmp_expr \ -, mpq_class, eval_fun> > \ -{ \ -private: \ - typedef __gmp_expr val1_type; \ - typedef mpq_class val2_type; \ - \ - __gmp_binary_expr expr; \ -public: \ - __gmp_expr(const val1_type &val1, const val2_type &val2) \ - : expr(val1, val2) { } \ - void eval(mpq_ptr q) const \ - { \ - mpz_class temp(expr.val1); \ - eval_fun::eval(q, temp.get_mpz_t(), expr.val2.get_mpq_t()); \ - } \ - const val1_type & get_val1() const { return expr.val1; } \ - const val2_type & get_val2() const { return expr.val2; } \ - unsigned long int get_prec() const { return mpf_get_default_prec(); } \ -}; \ - \ -template \ -class __gmp_expr \ -, mpz_class, eval_fun> > \ -{ \ -private: \ - typedef __gmp_expr val1_type; \ - typedef mpz_class val2_type; \ - \ - __gmp_binary_expr expr; \ -public: \ - __gmp_expr(const val1_type &val1, const val2_type &val2) \ - : expr(val1, val2) { } \ - void eval(mpq_ptr q) const \ - { \ - mpq_class temp(expr.val1); \ - eval_fun::eval(q, temp.get_mpq_t(), expr.val2.get_mpz_t()); \ - } \ - const val1_type & get_val1() const { return expr.val1; } \ - const val2_type & get_val2() const { return expr.val2; } \ - unsigned long int get_prec() const { return mpf_get_default_prec(); } \ -}; \ - \ -template \ -class __gmp_expr, __gmp_expr, eval_fun> > \ -{ \ -private: \ - typedef __gmp_expr val1_type; \ - typedef __gmp_expr val2_type; \ - \ - __gmp_binary_expr expr; \ -public: \ - __gmp_expr(const val1_type &val1, const val2_type &val2) \ - : expr(val1, val2) { } \ - void eval(mpq_ptr q) const \ - { \ - mpz_class temp1(expr.val1); \ - mpq_class temp2(expr.val2); \ - eval_fun::eval(q, temp1.get_mpz_t(), temp2.get_mpq_t()); \ - } \ - const val1_type & get_val1() const { return expr.val1; } \ - const val2_type & get_val2() const { return expr.val2; } \ - unsigned long int get_prec() const { return mpf_get_default_prec(); } \ -}; \ - \ -template \ -class __gmp_expr, __gmp_expr, eval_fun> > \ -{ \ -private: \ - typedef __gmp_expr val1_type; \ - typedef __gmp_expr val2_type; \ - \ - __gmp_binary_expr expr; \ -public: \ - __gmp_expr(const val1_type &val1, const val2_type &val2) \ - : expr(val1, val2) { } \ - void eval(mpq_ptr q) const \ - { \ - mpq_class temp1(expr.val1); \ - mpz_class temp2(expr.val2); \ - eval_fun::eval(q, temp1.get_mpq_t(), temp2.get_mpz_t()); \ - } \ - const val1_type & get_val1() const { return expr.val1; } \ - const val2_type & get_val2() const { return expr.val2; } \ - unsigned long int get_prec() const { return mpf_get_default_prec(); } \ -}; - - -__GMPZQ_DEFINE_EXPR(__gmp_binary_plus) -__GMPZQ_DEFINE_EXPR(__gmp_binary_minus) - - - -/**************** Macros for defining functions ****************/ -/* Results of operators and functions are instances of __gmp_expr. - T determines the numerical type of the expression: it can be either - mpz_t, mpq_t, or mpf_t. When the arguments of a binary - expression have different numerical types, __gmp_resolve_expr is used - to determine the "larger" type. - U is either __gmp_unary_expr or __gmp_binary_expr, - where V and W are the arguments' types -- they can in turn be - expressions, thus allowing to build compound expressions to any - degree of complexity. - Op is a function object that must have an eval() method accepting - appropriate arguments. - Actual evaluation of a __gmp_expr object is done when it gets - assigned to an mp*_class ("lazy" evaluation): this is done by calling - its eval() method. */ - - -// non-member unary operators and functions - -#define __GMP_DEFINE_UNARY_FUNCTION(fun, eval_fun) \ - \ -template \ -inline __gmp_expr, eval_fun> > \ -fun(const __gmp_expr &expr) \ -{ \ - return __gmp_expr, eval_fun> >(expr); \ -} - -#define __GMP_DEFINE_UNARY_TYPE_FUNCTION(type, fun, eval_fun) \ - \ -template \ -inline type fun(const __gmp_expr &expr) \ -{ \ - typename __gmp_resolve_temp::temp_type temp(expr); \ - return eval_fun::eval(temp.__get_mp()); \ -} - - -// non-member binary operators and functions - -#define __GMPP_DEFINE_BINARY_FUNCTION(fun, eval_fun) \ - \ -template \ -inline __gmp_expr::value_type, \ -__gmp_binary_expr<__gmp_expr, __gmp_expr, eval_fun> > \ -fun(const __gmp_expr &expr1, const __gmp_expr &expr2) \ -{ \ - return __gmp_expr::value_type, \ - __gmp_binary_expr<__gmp_expr, __gmp_expr, eval_fun> > \ - (expr1, expr2); \ -} - -#define __GMPNN_DEFINE_BINARY_FUNCTION(fun, eval_fun, type, bigtype) \ - \ -template \ -inline __gmp_expr \ -, bigtype, eval_fun> > \ -fun(const __gmp_expr &expr, type t) \ -{ \ - return __gmp_expr \ - , bigtype, eval_fun> >(expr, t); \ -} \ - \ -template \ -inline __gmp_expr \ -, eval_fun> > \ -fun(type t, const __gmp_expr &expr) \ -{ \ - return __gmp_expr \ - , eval_fun> >(t, expr); \ -} - -#define __GMPNS_DEFINE_BINARY_FUNCTION(fun, eval_fun, type) \ -__GMPNN_DEFINE_BINARY_FUNCTION(fun, eval_fun, type, signed long int) - -#define __GMPNU_DEFINE_BINARY_FUNCTION(fun, eval_fun, type) \ -__GMPNN_DEFINE_BINARY_FUNCTION(fun, eval_fun, type, unsigned long int) - -#define __GMPND_DEFINE_BINARY_FUNCTION(fun, eval_fun, type) \ -__GMPNN_DEFINE_BINARY_FUNCTION(fun, eval_fun, type, double) - -#define __GMPNLD_DEFINE_BINARY_FUNCTION(fun, eval_fun, type) \ -__GMPNN_DEFINE_BINARY_FUNCTION(fun, eval_fun, type, long double) - -#define __GMPN_DEFINE_BINARY_FUNCTION(fun, eval_fun) \ -__GMPNS_DEFINE_BINARY_FUNCTION(fun, eval_fun, signed char) \ -__GMPNU_DEFINE_BINARY_FUNCTION(fun, eval_fun, unsigned char) \ -__GMPNS_DEFINE_BINARY_FUNCTION(fun, eval_fun, signed int) \ -__GMPNU_DEFINE_BINARY_FUNCTION(fun, eval_fun, unsigned int) \ -__GMPNS_DEFINE_BINARY_FUNCTION(fun, eval_fun, signed short int) \ -__GMPNU_DEFINE_BINARY_FUNCTION(fun, eval_fun, unsigned short int) \ -__GMPNS_DEFINE_BINARY_FUNCTION(fun, eval_fun, signed long int) \ -__GMPNU_DEFINE_BINARY_FUNCTION(fun, eval_fun, unsigned long int) \ -__GMPND_DEFINE_BINARY_FUNCTION(fun, eval_fun, float) \ -__GMPND_DEFINE_BINARY_FUNCTION(fun, eval_fun, double) \ -__GMPNLD_DEFINE_BINARY_FUNCTION(fun, eval_fun, long double) - -#define __GMP_DEFINE_BINARY_FUNCTION(fun, eval_fun) \ -__GMPP_DEFINE_BINARY_FUNCTION(fun, eval_fun) \ -__GMPN_DEFINE_BINARY_FUNCTION(fun, eval_fun) - - -#define __GMP_DEFINE_BINARY_FUNCTION_UI(fun, eval_fun) \ - \ -template \ -inline __gmp_expr \ -, unsigned long int, eval_fun> > \ -fun(const __gmp_expr &expr, unsigned long int l) \ -{ \ - return __gmp_expr, unsigned long int, eval_fun> >(expr, l); \ -} - - -#define __GMPP_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun) \ - \ -template \ -inline type fun(const __gmp_expr &expr1, \ - const __gmp_expr &expr2) \ -{ \ - typedef typename __gmp_resolve_expr::value_type eval_type; \ - typename __gmp_resolve_temp::temp_type temp1(expr1); \ - typename __gmp_resolve_temp::temp_type temp2(expr2); \ - return eval_fun::eval(temp1.__get_mp(), temp2.__get_mp()); \ -} - -#define __GMPNN_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, \ - type2, bigtype) \ - \ -template \ -inline type fun(const __gmp_expr &expr, type2 t) \ -{ \ - typename __gmp_resolve_temp::temp_type temp(expr); \ - return eval_fun::eval(temp.__get_mp(), static_cast(t)); \ -} \ - \ -template \ -inline type fun(type2 t, const __gmp_expr &expr) \ -{ \ - typename __gmp_resolve_temp::temp_type temp(expr); \ - return eval_fun::eval(static_cast(t), temp.__get_mp()); \ -} - -#define __GMPNS_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, type2) \ -__GMPNN_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, \ - type2, signed long int) - -#define __GMPNU_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, type2) \ -__GMPNN_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, \ - type2, unsigned long int) - -#define __GMPND_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, type2) \ -__GMPNN_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, type2, double) - -#define __GMPNLD_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, type2) \ -__GMPNN_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, type2, long double) - -#define __GMPN_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun) \ -__GMPNS_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, signed char) \ -__GMPNU_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, unsigned char) \ -__GMPNS_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, signed int) \ -__GMPNU_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, unsigned int) \ -__GMPNS_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, signed short int) \ -__GMPNU_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, unsigned short int) \ -__GMPNS_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, signed long int) \ -__GMPNU_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, unsigned long int) \ -__GMPND_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, float) \ -__GMPND_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, double) \ -__GMPNLD_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, long double) - -#define __GMP_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun) \ -__GMPP_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun) \ -__GMPN_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun) - - -// member operators - -#define __GMPP_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun) \ - \ -template \ -inline type##_class & type##_class::fun(const __gmp_expr &expr) \ -{ \ - __gmp_set_expr(mp, __gmp_expr, eval_fun> >(*this, expr)); \ - return *this; \ -} - -#define __GMPNN_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, \ - type2, bigtype) \ - \ -inline type##_class & type##_class::fun(type2 t) \ -{ \ - __gmp_set_expr(mp, __gmp_expr >(*this, t)); \ - return *this; \ -} - -#define __GMPNS_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, type2) \ -__GMPNN_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, \ - type2, signed long int) - -#define __GMPNU_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, type2) \ -__GMPNN_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, \ - type2, unsigned long int) - -#define __GMPND_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, type2) \ -__GMPNN_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, type2, double) - -#define __GMPNLD_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, type2) \ -__GMPNN_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, type2, long double) - -#define __GMPN_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun) \ -__GMPNS_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, signed char) \ -__GMPNU_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, unsigned char) \ -__GMPNS_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, signed int) \ -__GMPNU_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, unsigned int) \ -__GMPNS_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, signed short int) \ -__GMPNU_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, unsigned short int) \ -__GMPNS_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, signed long int) \ -__GMPNU_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, unsigned long int) \ -__GMPND_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, float) \ -__GMPND_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, double) \ -/* __GMPNLD_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, long double) */ - -#define __GMP_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun) \ -__GMPP_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun) \ -__GMPN_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun) - -#define __GMPZ_DEFINE_COMPOUND_OPERATOR(fun, eval_fun) \ -__GMP_DEFINE_COMPOUND_OPERATOR(mpz, fun, eval_fun) - -#define __GMPQ_DEFINE_COMPOUND_OPERATOR(fun, eval_fun) \ -__GMP_DEFINE_COMPOUND_OPERATOR(mpq, fun, eval_fun) - -#define __GMPF_DEFINE_COMPOUND_OPERATOR(fun, eval_fun) \ -__GMP_DEFINE_COMPOUND_OPERATOR(mpf, fun, eval_fun) - - - -#define __GMP_DEFINE_COMPOUND_OPERATOR_UI(type, fun, eval_fun) \ - \ -inline type##_class & type##_class::fun(unsigned long int l) \ -{ \ - __gmp_set_expr(mp, __gmp_expr >(*this, l)); \ - return *this; \ -} - -#define __GMPZ_DEFINE_COMPOUND_OPERATOR_UI(fun, eval_fun) \ -__GMP_DEFINE_COMPOUND_OPERATOR_UI(mpz, fun, eval_fun) - -#define __GMPQ_DEFINE_COMPOUND_OPERATOR_UI(fun, eval_fun) \ -__GMP_DEFINE_COMPOUND_OPERATOR_UI(mpq, fun, eval_fun) - -#define __GMPF_DEFINE_COMPOUND_OPERATOR_UI(fun, eval_fun) \ -__GMP_DEFINE_COMPOUND_OPERATOR_UI(mpf, fun, eval_fun) - - - -#define __GMP_DEFINE_INCREMENT_OPERATOR(type, fun, eval_fun) \ - \ -inline type##_class & type##_class::fun() \ -{ \ - eval_fun::eval(mp); \ - return *this; \ -} \ - \ -inline type##_class type##_class::fun(int) \ -{ \ - type##_class temp(*this); \ - eval_fun::eval(mp); \ - return temp; \ -} - -#define __GMPZ_DEFINE_INCREMENT_OPERATOR(fun, eval_fun) \ -__GMP_DEFINE_INCREMENT_OPERATOR(mpz, fun, eval_fun) - -#define __GMPQ_DEFINE_INCREMENT_OPERATOR(fun, eval_fun) \ -__GMP_DEFINE_INCREMENT_OPERATOR(mpq, fun, eval_fun) - -#define __GMPF_DEFINE_INCREMENT_OPERATOR(fun, eval_fun) \ -__GMP_DEFINE_INCREMENT_OPERATOR(mpf, fun, eval_fun) - - - -/**************** Arithmetic operators and functions ****************/ - -// non-member operators and functions - -__GMP_DEFINE_UNARY_FUNCTION(operator+, __gmp_unary_plus) -__GMP_DEFINE_UNARY_FUNCTION(operator-, __gmp_unary_minus) -__GMP_DEFINE_UNARY_FUNCTION(operator~, __gmp_unary_com) - -__GMP_DEFINE_BINARY_FUNCTION(operator+, __gmp_binary_plus) -__GMP_DEFINE_BINARY_FUNCTION(operator-, __gmp_binary_minus) -__GMP_DEFINE_BINARY_FUNCTION(operator*, __gmp_binary_multiplies) -__GMP_DEFINE_BINARY_FUNCTION(operator/, __gmp_binary_divides) -__GMP_DEFINE_BINARY_FUNCTION(operator%, __gmp_binary_modulus) -__GMP_DEFINE_BINARY_FUNCTION(operator&, __gmp_binary_and) -__GMP_DEFINE_BINARY_FUNCTION(operator|, __gmp_binary_ior) -__GMP_DEFINE_BINARY_FUNCTION(operator^, __gmp_binary_xor) - -__GMP_DEFINE_BINARY_FUNCTION_UI(operator<<, __gmp_binary_lshift) -__GMP_DEFINE_BINARY_FUNCTION_UI(operator>>, __gmp_binary_rshift) - -__GMP_DEFINE_BINARY_TYPE_FUNCTION(bool, operator==, __gmp_binary_equal) -__GMP_DEFINE_BINARY_TYPE_FUNCTION(bool, operator!=, __gmp_binary_not_equal) -__GMP_DEFINE_BINARY_TYPE_FUNCTION(bool, operator<, __gmp_binary_less) -__GMP_DEFINE_BINARY_TYPE_FUNCTION(bool, operator<=, __gmp_binary_less_equal) -__GMP_DEFINE_BINARY_TYPE_FUNCTION(bool, operator>, __gmp_binary_greater) -__GMP_DEFINE_BINARY_TYPE_FUNCTION(bool, operator>=, \ - __gmp_binary_greater_equal) - -__GMP_DEFINE_UNARY_FUNCTION(abs, __gmp_abs_function) -__GMP_DEFINE_UNARY_FUNCTION(trunc, __gmp_trunc_function) -__GMP_DEFINE_UNARY_FUNCTION(floor, __gmp_floor_function) -__GMP_DEFINE_UNARY_FUNCTION(ceil, __gmp_ceil_function) -__GMP_DEFINE_UNARY_FUNCTION(sqrt, __gmp_sqrt_function) -__GMP_DEFINE_BINARY_FUNCTION(hypot, __gmp_hypot_function) - -__GMP_DEFINE_UNARY_TYPE_FUNCTION(int, sgn, __gmp_sgn_function) -__GMP_DEFINE_BINARY_TYPE_FUNCTION(int, cmp, __gmp_cmp_function) - -// member operators for mpz_class - -__GMPZ_DEFINE_COMPOUND_OPERATOR(operator+=, __gmp_binary_plus) -__GMPZ_DEFINE_COMPOUND_OPERATOR(operator-=, __gmp_binary_minus) -__GMPZ_DEFINE_COMPOUND_OPERATOR(operator*=, __gmp_binary_multiplies) -__GMPZ_DEFINE_COMPOUND_OPERATOR(operator/=, __gmp_binary_divides) -__GMPZ_DEFINE_COMPOUND_OPERATOR(operator%=, __gmp_binary_modulus) - -__GMPZ_DEFINE_COMPOUND_OPERATOR(operator&=, __gmp_binary_and) -__GMPZ_DEFINE_COMPOUND_OPERATOR(operator|=, __gmp_binary_ior) -__GMPZ_DEFINE_COMPOUND_OPERATOR(operator^=, __gmp_binary_xor) - -__GMPZ_DEFINE_COMPOUND_OPERATOR_UI(operator<<=, __gmp_binary_lshift) -__GMPZ_DEFINE_COMPOUND_OPERATOR_UI(operator>>=, __gmp_binary_rshift) - -__GMPZ_DEFINE_INCREMENT_OPERATOR(operator++, __gmp_unary_increment) -__GMPZ_DEFINE_INCREMENT_OPERATOR(operator--, __gmp_unary_decrement) - -// member operators for mpq_class - -__GMPQ_DEFINE_COMPOUND_OPERATOR(operator+=, __gmp_binary_plus) -__GMPQ_DEFINE_COMPOUND_OPERATOR(operator-=, __gmp_binary_minus) -__GMPQ_DEFINE_COMPOUND_OPERATOR(operator*=, __gmp_binary_multiplies) -__GMPQ_DEFINE_COMPOUND_OPERATOR(operator/=, __gmp_binary_divides) - -__GMPQ_DEFINE_COMPOUND_OPERATOR_UI(operator<<=, __gmp_binary_lshift) -__GMPQ_DEFINE_COMPOUND_OPERATOR_UI(operator>>=, __gmp_binary_rshift) - -__GMPQ_DEFINE_INCREMENT_OPERATOR(operator++, __gmp_unary_increment) -__GMPQ_DEFINE_INCREMENT_OPERATOR(operator--, __gmp_unary_decrement) - -// member operators for mpf_class - -__GMPF_DEFINE_COMPOUND_OPERATOR(operator+=, __gmp_binary_plus) -__GMPF_DEFINE_COMPOUND_OPERATOR(operator-=, __gmp_binary_minus) -__GMPF_DEFINE_COMPOUND_OPERATOR(operator*=, __gmp_binary_multiplies) -__GMPF_DEFINE_COMPOUND_OPERATOR(operator/=, __gmp_binary_divides) - -__GMPF_DEFINE_COMPOUND_OPERATOR_UI(operator<<=, __gmp_binary_lshift) -__GMPF_DEFINE_COMPOUND_OPERATOR_UI(operator>>=, __gmp_binary_rshift) - -__GMPF_DEFINE_INCREMENT_OPERATOR(operator++, __gmp_unary_increment) -__GMPF_DEFINE_INCREMENT_OPERATOR(operator--, __gmp_unary_decrement) - - - -/**************** Class wrapper for gmp_randstate_t ****************/ - -class __gmp_urandomb_value { }; -class __gmp_urandomm_value { }; - -template <> -class __gmp_expr -{ -private: - __gmp_randstate_struct *state; - unsigned long int bits; -public: - __gmp_expr(gmp_randstate_t s, unsigned long int l) : state(s), bits(l) { } - void eval(mpz_ptr z) const { __gmp_rand_function::eval(z, state, bits); } - unsigned long int get_prec() const { return mpf_get_default_prec(); } -}; - -template <> -class __gmp_expr -{ -private: - __gmp_randstate_struct *state; - mpz_class range; -public: - __gmp_expr(gmp_randstate_t s, const mpz_class &z) : state(s), range(z) { } - void eval(mpz_ptr z) const - { __gmp_rand_function::eval(z, state, range.get_mpz_t()); } - unsigned long int get_prec() const { return mpf_get_default_prec(); } -}; - -template <> -class __gmp_expr -{ -private: - __gmp_randstate_struct *state; - unsigned long int bits; -public: - __gmp_expr(gmp_randstate_t s, unsigned long int l) : state(s), bits(l) { } - void eval(mpf_ptr f, mp_bitcnt_t prec) const - { __gmp_rand_function::eval(f, state, (bits>0) ? get_prec() : prec); } - unsigned long int get_prec() const - { - if (bits == 0) - return mpf_get_default_prec(); - else - return bits; - } -}; - -extern "C" { - typedef void __gmp_randinit_default_t (gmp_randstate_t); - typedef void __gmp_randinit_lc_2exp_t (gmp_randstate_t, mpz_srcptr, unsigned long int, unsigned long int); - typedef int __gmp_randinit_lc_2exp_size_t (gmp_randstate_t, unsigned long int); -} - -class gmp_randclass -{ -private: - gmp_randstate_t state; - - // copy construction and assignment not allowed - gmp_randclass(const gmp_randclass &); - void operator=(const gmp_randclass &); -public: - // constructors and destructor - gmp_randclass(gmp_randalg_t alg, unsigned long int size) - { - switch (alg) - { - case GMP_RAND_ALG_LC: // no other cases for now - default: - gmp_randinit(state, alg, size); - break; - } - } - - // gmp_randinit_default - gmp_randclass(__gmp_randinit_default_t* f) { f(state); } - - // gmp_randinit_lc_2exp - gmp_randclass(__gmp_randinit_lc_2exp_t* f, - mpz_class z, unsigned long int l1, unsigned long int l2) - { f(state, z.get_mpz_t(), l1, l2); } - - // gmp_randinit_lc_2exp_size - gmp_randclass(__gmp_randinit_lc_2exp_size_t* f, - unsigned long int size) - { - if (f (state, size) == 0) - throw std::length_error ("gmp_randinit_lc_2exp_size"); - } - - ~gmp_randclass() { gmp_randclear(state); } - - // initialize - void seed(); // choose a random seed some way (?) - void seed(unsigned long int s) { gmp_randseed_ui(state, s); } - void seed(const mpz_class &z) { gmp_randseed(state, z.get_mpz_t()); } - - // get random number - __gmp_expr get_z_bits(unsigned long int l) - { return __gmp_expr(state, l); } - __gmp_expr get_z_bits(const mpz_class &z) - { return get_z_bits(z.get_ui()); } - - __gmp_expr get_z_range(const mpz_class &z) - { return __gmp_expr(state, z); } - - __gmp_expr get_f(mp_bitcnt_t prec = 0) - { return __gmp_expr(state, prec); } -}; - - -/**************** #undef all private macros ****************/ - -#undef __GMPP_DECLARE_COMPOUND_OPERATOR -#undef __GMPN_DECLARE_COMPOUND_OPERATOR -#undef __GMP_DECLARE_COMPOUND_OPERATOR -#undef __GMP_DECLARE_COMPOUND_OPERATOR_UI -#undef __GMP_DECLARE_INCREMENT_OPERATOR - -#undef __GMPZQ_DEFINE_EXPR - -#undef __GMP_DEFINE_UNARY_FUNCTION -#undef __GMP_DEFINE_UNARY_TYPE_FUNCTION - -#undef __GMPP_DEFINE_BINARY_FUNCTION -#undef __GMPNN_DEFINE_BINARY_FUNCTION -#undef __GMPNS_DEFINE_BINARY_FUNCTION -#undef __GMPNU_DEFINE_BINARY_FUNCTION -#undef __GMPND_DEFINE_BINARY_FUNCTION -#undef __GMPNLD_DEFINE_BINARY_FUNCTION -#undef __GMPN_DEFINE_BINARY_FUNCTION -#undef __GMP_DEFINE_BINARY_FUNCTION - -#undef __GMP_DEFINE_BINARY_FUNCTION_UI - -#undef __GMPP_DEFINE_BINARY_TYPE_FUNCTION -#undef __GMPNN_DEFINE_BINARY_TYPE_FUNCTION -#undef __GMPNS_DEFINE_BINARY_TYPE_FUNCTION -#undef __GMPNU_DEFINE_BINARY_TYPE_FUNCTION -#undef __GMPND_DEFINE_BINARY_TYPE_FUNCTION -#undef __GMPNLD_DEFINE_BINARY_TYPE_FUNCTION -#undef __GMPN_DEFINE_BINARY_TYPE_FUNCTION -#undef __GMP_DEFINE_BINARY_TYPE_FUNCTION - -#undef __GMPZ_DEFINE_COMPOUND_OPERATOR -#undef __GMPZN_DEFINE_COMPOUND_OPERATOR -#undef __GMPZNN_DEFINE_COMPOUND_OPERATOR -#undef __GMPZNS_DEFINE_COMPOUND_OPERATOR -#undef __GMPZNU_DEFINE_COMPOUND_OPERATOR -#undef __GMPZND_DEFINE_COMPOUND_OPERATOR -#undef __GMPZNLD_DEFINE_COMPOUND_OPERATOR - -#undef __GMPP_DEFINE_COMPOUND_OPERATOR -#undef __GMPNN_DEFINE_COMPOUND_OPERATOR -#undef __GMPNS_DEFINE_COMPOUND_OPERATOR -#undef __GMPNU_DEFINE_COMPOUND_OPERATOR -#undef __GMPND_DEFINE_COMPOUND_OPERATOR -#undef __GMPNLD_DEFINE_COMPOUND_OPERATOR -#undef __GMPN_DEFINE_COMPOUND_OPERATOR -#undef __GMP_DEFINE_COMPOUND_OPERATOR - -#undef __GMPQ_DEFINE_COMPOUND_OPERATOR -#undef __GMPF_DEFINE_COMPOUND_OPERATOR - -#undef __GMP_DEFINE_COMPOUND_OPERATOR_UI -#undef __GMPZ_DEFINE_COMPOUND_OPERATOR_UI -#undef __GMPQ_DEFINE_COMPOUND_OPERATOR_UI -#undef __GMPF_DEFINE_COMPOUND_OPERATOR_UI - -#undef __GMP_DEFINE_INCREMENT_OPERATOR -#undef __GMPZ_DEFINE_INCREMENT_OPERATOR -#undef __GMPQ_DEFINE_INCREMENT_OPERATOR -#undef __GMPF_DEFINE_INCREMENT_OPERATOR - -#endif /* __GMP_PLUSPLUS__ */ diff --git a/src/external/inc/macx/mpir-2.1.3/mpir.h b/src/external/inc/macx/mpir-2.1.3/mpir.h deleted file mode 100644 index 7f17e1e1c..000000000 --- a/src/external/inc/macx/mpir-2.1.3/mpir.h +++ /dev/null @@ -1,2396 +0,0 @@ -/* Definitions for GNU multiple precision functions. -*- mode: c -*- - -Copyright 1991, 1993, 1994, 1995, 1996, 1997, 1999, 2000, 2001, 2002, 2003, -2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc. - -Copyright 2008 William Hart, Gonzalo Tornaria - -This file is part of the MPIR Library. - -The MPIR Library is free software; you can redistribute it and/or modify -it under the terms of the GNU Lesser General Public License as published by -the Free Software Foundation; either version 3 of the License, or (at your -option) any later version. - -The MPIR Library is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public -License for more details. - -You should have received a copy of the GNU Lesser General Public License -along with the GNU MP Library. If not, see http://www.gnu.org/licenses/. */ - -#ifndef __GMP_H__ - -#if defined (__cplusplus) -#include /* for std::istream, std::ostream, std::string */ -#include -#endif - - -/* Instantiated by configure. */ -#if ! defined (__GMP_WITHIN_CONFIGURE) -#define __GMP_BITS_PER_MP_LIMB 32 -#define __GMP_HAVE_HOST_CPU_FAMILY_power 0 -#define __GMP_HAVE_HOST_CPU_FAMILY_powerpc 0 -#define GMP_LIMB_BITS 32 -#define GMP_NAIL_BITS 0 -#endif -#define GMP_NUMB_BITS (GMP_LIMB_BITS - GMP_NAIL_BITS) -#define GMP_NUMB_MASK ((~ __GMP_CAST (mp_limb_t, 0)) >> GMP_NAIL_BITS) -#define GMP_NUMB_MAX GMP_NUMB_MASK -#define GMP_NAIL_MASK (~ GMP_NUMB_MASK) - - -/* The following (everything under ifndef __GNU_MP__) must be identical in - mpir.h and mp.h to allow both to be included in an application or during - the library build. */ -#ifndef __GNU_MP__ -#define __GNU_MP__ 4 - -#define __need_size_t /* tell gcc stddef.h we only want size_t */ -#if defined (__cplusplus) -#include /* for size_t */ -#else -#include /* for size_t */ -#endif -#undef __need_size_t - -/* Instantiated by configure. */ -#if ! defined (__GMP_WITHIN_CONFIGURE) -/* #undef _LONG_LONG_LIMB */ -#define __GMP_LIBGMP_DLL 0 -#endif - - -/* __STDC__ - some ANSI compilers define this only to 0, hence the use of - "defined" and not "__STDC__-0". In particular Sun workshop C 5.0 - sets __STDC__ to 0, but requires "##" for token pasting. - - _AIX - gnu ansidecl.h asserts that all known AIX compilers are ANSI but - don't always define __STDC__. - - __DECC - current versions of DEC C (5.9 for instance) for alpha are ANSI, - but don't define __STDC__ in their default mode. Don't know if old - versions might have been K&R, but let's not worry about that unless - someone is still using one. - - _mips - gnu ansidecl.h says the RISC/OS MIPS compiler is ANSI in SVR4 - mode, but doesn't define __STDC__. - - _MSC_VER - Microsoft C is ANSI, but __STDC__ is undefined unless the /Za - option is given (in which case it's 1). - - _WIN32 - tested for by gnu ansidecl.h, no doubt on the assumption that - all w32 compilers are ansi. - - Note: This same set of tests is used by gen-psqr.c and - demos/expr/expr-impl.h, so if anything needs adding, then be sure to - update those too. */ - -#if defined (__STDC__) \ - || defined (__cplusplus) \ - || defined (_AIX) \ - || defined (__DECC) \ - || (defined (__mips) && defined (_SYSTYPE_SVR4)) \ - || defined (_MSC_VER) \ - || defined (_WIN32) -#define __GMP_HAVE_CONST 1 -#define __GMP_HAVE_PROTOTYPES 1 -#define __GMP_HAVE_TOKEN_PASTE 1 -#else -#define __GMP_HAVE_CONST 0 -#define __GMP_HAVE_PROTOTYPES 0 -#define __GMP_HAVE_TOKEN_PASTE 0 -#endif - - -#if __GMP_HAVE_CONST -#define __gmp_const const -#define __gmp_signed signed -#else -#define __gmp_const -#define __gmp_signed -#endif - - -/* __GMP_DECLSPEC supports Windows DLL versions of libmpir, and is empty in - all other circumstances. - - When compiling objects for libmpir, __GMP_DECLSPEC is an export directive, - or when compiling for an application it's an import directive. The two - cases are differentiated by __GMP_WITHIN_GMP defined by the GMP Makefiles - (and not defined from an application). - - __GMP_DECLSPEC_XX is similarly used for libmpirxx. __GMP_WITHIN_GMPXX - indicates when building libmpirxx, and in that case libmpirxx functions are - exports, but libmpir functions which might get called are imports. - - libmp.la uses __GMP_DECLSPEC, just as if it were libmpir.la. libmpir and - libmp don't call each other, so there's no conflict or confusion. - - Libtool DLL_EXPORT define is not used. - - There's no attempt to support GMP built both static and DLL. Doing so - would mean applications would have to tell us which of the two is going - to be used when linking, and that seems very tedious and error prone if - using GMP by hand, and equally tedious from a package since autoconf and - automake don't give much help. - - __GMP_DECLSPEC is required on all documented global functions and - variables, the various internals in gmp-impl.h etc can be left unadorned. - But internals used by the test programs or speed measuring programs - should have __GMP_DECLSPEC, and certainly constants or variables must - have it or the wrong address will be resolved. - - In gcc __declspec can go at either the start or end of a prototype. - - In Microsoft C __declspec must go at the start, or after the type like - void __declspec(...) *foo()". There's no __dllexport or anything to - guard against someone foolish #defining dllexport. _export used to be - available, but no longer. - - In Borland C _export still exists, but needs to go after the type, like - "void _export foo();". Would have to change the __GMP_DECLSPEC syntax to - make use of that. Probably more trouble than it's worth. */ - -#if defined (__GNUC__) -#define __GMP_DECLSPEC_EXPORT __declspec(__dllexport__) -#define __GMP_DECLSPEC_IMPORT __declspec(__dllimport__) -#endif -#if defined (_MSC_VER) || defined (__BORLANDC__) -#define __GMP_DECLSPEC_EXPORT __declspec(dllexport) -#define __GMP_DECLSPEC_IMPORT __declspec(dllimport) -#endif -#ifdef __WATCOMC__ -#define __GMP_DECLSPEC_EXPORT __export -#define __GMP_DECLSPEC_IMPORT __import -#endif -#ifdef __IBMC__ -#define __GMP_DECLSPEC_EXPORT _Export -#define __GMP_DECLSPEC_IMPORT _Import -#endif - -#if __GMP_LIBGMP_DLL -#if __GMP_WITHIN_GMP -/* compiling to go into a DLL libmpir */ -#define __GMP_DECLSPEC __GMP_DECLSPEC_EXPORT -#else -/* compiling to go into an application which will link to a DLL libmpir */ -#define __GMP_DECLSPEC __GMP_DECLSPEC_IMPORT -#endif -#else -/* all other cases */ -#define __GMP_DECLSPEC -#endif - - -#ifdef __GMP_SHORT_LIMB -typedef unsigned int mp_limb_t; -typedef int mp_limb_signed_t; -#else -#ifdef _LONG_LONG_LIMB -typedef unsigned long long int mp_limb_t; -typedef long long int mp_limb_signed_t; -#else -typedef unsigned long int mp_limb_t; -typedef long int mp_limb_signed_t; -#endif -#endif - -#if defined( _MSC_VER ) && defined( _WIN64 ) -typedef unsigned long long int mp_bitcnt_t; -#else -typedef unsigned long int mp_bitcnt_t; -#endif - -/* For reference, note that the name __mpz_struct gets into C++ mangled - function names, which means although the "__" suggests an internal, we - must leave this name for binary compatibility. */ -typedef struct -{ - int _mp_alloc; /* Number of *limbs* allocated and pointed - to by the _mp_d field. */ - int _mp_size; /* abs(_mp_size) is the number of limbs the - last field points to. If _mp_size is - negative this is a negative number. */ - mp_limb_t *_mp_d; /* Pointer to the limbs. */ -} __mpz_struct; - -#endif /* __GNU_MP__ */ - -typedef __mpz_struct mpz_t[1]; - -typedef mp_limb_t * mp_ptr; -typedef __gmp_const mp_limb_t * mp_srcptr; -#if defined (_CRAY) && ! defined (_CRAYMPP) -/* plain `int' is much faster (48 bits) */ -#define __GMP_MP_SIZE_T_INT 1 -typedef int mp_size_t; -typedef int mp_exp_t; -#elif defined( _WIN64) -#define __GMP_MP_SIZE_T_INT 0 -typedef long long int mp_size_t; -typedef long int mp_exp_t; -#else -#define __GMP_MP_SIZE_T_INT 0 -typedef long int mp_size_t; -typedef long int mp_exp_t; -#endif - -typedef struct -{ - __mpz_struct _mp_num; - __mpz_struct _mp_den; -} __mpq_struct; - -typedef __mpq_struct mpq_t[1]; - -typedef struct -{ - int _mp_prec; /* Max precision, in number of `mp_limb_t's. - Set by mpf_init and modified by - mpf_set_prec. The area pointed to by the - _mp_d field contains `prec' + 1 limbs. */ - int _mp_size; /* abs(_mp_size) is the number of limbs the - last field points to. If _mp_size is - negative this is a negative number. */ - mp_exp_t _mp_exp; /* Exponent, in the base of `mp_limb_t'. */ - mp_limb_t *_mp_d; /* Pointer to the limbs. */ -} __mpf_struct; - -typedef __mpf_struct mpf_t[1]; - -/* Available random number generation algorithms. */ -typedef enum -{ - GMP_RAND_ALG_DEFAULT = 0, - GMP_RAND_ALG_LC = GMP_RAND_ALG_DEFAULT /* Linear congruential. */ -} gmp_randalg_t; - -/* Random state struct. */ -typedef struct -{ - mpz_t _mp_seed; /* _mp_d member points to state of the generator. */ - gmp_randalg_t _mp_alg; /* Currently unused. */ - union { - void *_mp_lc; /* Pointer to function pointers structure. */ - } _mp_algdata; -} __gmp_randstate_struct; -typedef __gmp_randstate_struct gmp_randstate_t[1]; - -/* Types for function declarations in gmp files. */ -/* ??? Should not pollute user name space with these ??? */ -typedef __gmp_const __mpz_struct *mpz_srcptr; -typedef __mpz_struct *mpz_ptr; -typedef __gmp_const __mpf_struct *mpf_srcptr; -typedef __mpf_struct *mpf_ptr; -typedef __gmp_const __mpq_struct *mpq_srcptr; -typedef __mpq_struct *mpq_ptr; - - -/* This is not wanted in mp.h, so put it outside the __GNU_MP__ common - section. */ -#if __GMP_LIBGMP_DLL -#if __GMP_WITHIN_GMPXX -/* compiling to go into a DLL libmpirxx */ -#define __GMP_DECLSPEC_XX __GMP_DECLSPEC_EXPORT -#else -/* compiling to go into a application which will link to a DLL libmpirxx */ -#define __GMP_DECLSPEC_XX __GMP_DECLSPEC_IMPORT -#endif -#else -/* all other cases */ -#define __GMP_DECLSPEC_XX -#endif - - -#if __GMP_HAVE_PROTOTYPES -#define __GMP_PROTO(x) x -#else -#define __GMP_PROTO(x) () -#endif - -#ifndef __MPN -#if __GMP_HAVE_TOKEN_PASTE -#define __MPN(x) __gmpn_##x -#else -#define __MPN(x) __gmpn_/**/x -#endif -#endif - -/* For reference, "defined(EOF)" cannot be used here. In g++ 2.95.4, - defines EOF but not FILE. */ -#if defined (FILE) \ - || defined (H_STDIO) \ - || defined (_H_STDIO) /* AIX */ \ - || defined (_STDIO_H) /* glibc, Sun, SCO */ \ - || defined (_STDIO_H_) /* BSD, OSF */ \ - || defined (__STDIO_H) /* Borland */ \ - || defined (__STDIO_H__) /* IRIX */ \ - || defined (_STDIO_INCLUDED) /* HPUX */ \ - || defined (__dj_include_stdio_h_) /* DJGPP */ \ - || defined (_FILE_DEFINED) /* Microsoft */ \ - || defined (__STDIO__) /* Apple MPW MrC */ \ - || defined (_MSL_STDIO_H) /* Metrowerks */ \ - || defined (_STDIO_H_INCLUDED) /* QNX4 */ \ - || defined (_ISO_STDIO_ISO_H) /* Sun C++ */ -#define _GMP_H_HAVE_FILE 1 -#endif - -/* In ISO C, if a prototype involving "struct obstack *" is given without - that structure defined, then the struct is scoped down to just the - prototype, causing a conflict if it's subsequently defined for real. So - only give prototypes if we've got obstack.h. */ -#if defined (_OBSTACK_H) /* glibc */ -#define _GMP_H_HAVE_OBSTACK 1 -#endif - -/* The prototypes for gmp_vprintf etc are provided only if va_list is - available, via an application having included or . - Usually va_list is a typedef so can't be tested directly, but C99 - specifies that va_start is a macro (and it was normally a macro on past - systems too), so look for that. - - will define some sort of va_list for vprintf and vfprintf, but - let's not bother trying to use that since it's not standard and since - application uses for gmp_vprintf etc will almost certainly require the - whole or anyway. */ - -#ifdef va_start -#define _GMP_H_HAVE_VA_LIST 1 -#endif - -/* Test for gcc >= maj.min, as per __GNUC_PREREQ in glibc */ -#if defined (__GNUC__) && defined (__GNUC_MINOR__) -#define __GMP_GNUC_PREREQ(maj, min) \ - ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min)) -#else -#define __GMP_GNUC_PREREQ(maj, min) 0 -#endif - -/* "pure" is in gcc 2.96 and up, see "(gcc)Function Attributes". Basically - it means a function does nothing but examine its arguments and memory - (global or via arguments) to generate a return value, but changes nothing - and has no side-effects. __GMP_NO_ATTRIBUTE_CONST_PURE lets - tune/common.c etc turn this off when trying to write timing loops. */ -#if __GMP_GNUC_PREREQ (2,96) && ! defined (__GMP_NO_ATTRIBUTE_CONST_PURE) -#define __GMP_ATTRIBUTE_PURE __attribute__ ((__pure__)) -#else -#define __GMP_ATTRIBUTE_PURE -#endif - - -/* __GMP_CAST allows us to use static_cast in C++, so our macros are clean - to "g++ -Wold-style-cast". - - Casts in "extern inline" code within an extern "C" block don't induce - these warnings, so __GMP_CAST only needs to be used on documented - macros. */ - -#ifdef __cplusplus -#define __GMP_CAST(type, expr) (static_cast (expr)) -#else -#define __GMP_CAST(type, expr) ((type) (expr)) -#endif - - -/* An empty "throw ()" means the function doesn't throw any C++ exceptions, - this can save some stack frame info in applications. - - Currently it's given only on functions which never divide-by-zero etc, - don't allocate memory, and are expected to never need to allocate memory. - This leaves open the possibility of a C++ throw from a future GMP - exceptions scheme. - - mpz_set_ui etc are omitted to leave open the lazy allocation scheme - described in doc/tasks.html. mpz_get_d etc are omitted to leave open - exceptions for float overflows. - - Note that __GMP_NOTHROW must be given on any inlines the same as on their - prototypes (for g++ at least, where they're used together). Note also - that g++ 3.0 demands that __GMP_NOTHROW is before other attributes like - __GMP_ATTRIBUTE_PURE. */ - -#if defined (__cplusplus) -#define __GMP_NOTHROW throw () -#else -#define __GMP_NOTHROW -#endif - -/* PORTME: What other compilers have a useful "extern inline"? "static - inline" would be an acceptable substitute if the compiler (or linker) - discards unused statics. */ - -/* gcc has __inline__ in all modes, including strict ansi. Give a prototype - for an inline too, so as to correctly specify "dllimport" on windows, in - case the function is called rather than inlined. */ - -#ifdef __GNUC__ -#if defined(__APPLE_CC__) && (__APPLE_CC__ != 1) /* FSF GCC sets this flag to 1 on Apple machines */ - -#if ! (__APPLE_CC__ >= 5465 && __STDC_VERSION__ >= 199901L) -#define __GMP_EXTERN_INLINE extern __inline__ -#define __GMP_INLINE_PROTOTYPES 1 -#endif - -#else /*GNU CC*/ - -#if defined(__GNUC_STDC_INLINE__) || defined (__GNUC_GNU_INLINE__) -#define __GMP_EXTERN_INLINE extern __inline__ __attribute__((__gnu_inline__)) -#else -#define __GMP_EXTERN_INLINE extern __inline__ -#endif -#define __GMP_INLINE_PROTOTYPES 1 - -#endif -#endif - -/* DEC C (eg. version 5.9) supports "static __inline foo()", even in -std1 - strict ANSI mode. Inlining is done even when not optimizing (ie. -O0 - mode, which is the default), but an unnecessary local copy of foo is - emitted unless -O is used. "extern __inline" is accepted, but the - "extern" appears to be ignored, ie. it becomes a plain global function - but which is inlined within its file. Don't know if all old versions of - DEC C supported __inline, but as a start let's do the right thing for - current versions. */ -#ifdef __DECC -#define __GMP_EXTERN_INLINE static __inline -#endif - -/* SCO OpenUNIX 8 cc supports "static inline foo()" but not in -Xc strict - ANSI mode (__STDC__ is 1 in that mode). Inlining only actually takes - place under -O. Without -O "foo" seems to be emitted whether it's used - or not, which is wasteful. "extern inline foo()" isn't useful, the - "extern" is apparently ignored, so foo is inlined if possible but also - emitted as a global, which causes multiple definition errors when - building a shared libmpir. */ -#ifdef __SCO_VERSION__ -#if __SCO_VERSION__ > 400000000 && __STDC__ != 1 \ - && ! defined (__GMP_EXTERN_INLINE) -#define __GMP_EXTERN_INLINE static inline -#endif -#endif - -#if defined _MSC_VER -#define __GMP_EXTERN_INLINE static __inline -#endif - -/* C++ always has "inline" and since it's a normal feature the linker should - discard duplicate non-inlined copies, or if it doesn't then that's a - problem for everyone, not just GMP. */ -#if defined (__cplusplus) && ! defined (__GMP_EXTERN_INLINE) -#define __GMP_EXTERN_INLINE inline -#endif - -/* Don't do any inlining within a configure run, since if the compiler ends - up emitting copies of the code into the object file it can end up - demanding the various support routines (like mpn_popcount) for linking, - making the "alloca" test and perhaps others fail. And on hppa ia64 a - pre-release gcc 3.2 was seen not respecting the "extern" in "extern - __inline__", triggering this problem too. */ -#if defined (__GMP_WITHIN_CONFIGURE) && ! __GMP_WITHIN_CONFIGURE_INLINE -#undef __GMP_EXTERN_INLINE -#endif - -/* By default, don't give a prototype when there's going to be an inline - version. Note in particular that Cray C++ objects to the combination of - prototype and inline. */ -#ifdef __GMP_EXTERN_INLINE -#ifndef __GMP_INLINE_PROTOTYPES -#define __GMP_INLINE_PROTOTYPES 0 -#endif -#else -#define __GMP_INLINE_PROTOTYPES 1 -#endif - - -#define __GMP_ABS(x) ((x) >= 0 ? (x) : -(x)) -#define __GMP_MAX(h,i) ((h) > (i) ? (h) : (i)) - -/* __GMP_USHRT_MAX is not "~ (unsigned short) 0" because short is promoted - to int by "~". */ -#define __GMP_UINT_MAX (~ (unsigned) 0) -#define __GMP_ULONG_MAX (~ (unsigned long) 0) -#define __GMP_USHRT_MAX ((unsigned short) ~0) - - -/* __builtin_expect is in gcc 3.0, and not in 2.95. */ -#if __GMP_GNUC_PREREQ (3,0) -#define __GMP_LIKELY(cond) __builtin_expect ((cond) != 0, 1) -#define __GMP_UNLIKELY(cond) __builtin_expect ((cond) != 0, 0) -#else -#define __GMP_LIKELY(cond) (cond) -#define __GMP_UNLIKELY(cond) (cond) -#endif - -#ifdef _CRAY -#define __GMP_CRAY_Pragma(str) _Pragma (str) -#else -#define __GMP_CRAY_Pragma(str) -#endif - - -/* Allow direct user access to numerator and denominator of a mpq_t object. */ -#define mpq_numref(Q) (&((Q)->_mp_num)) -#define mpq_denref(Q) (&((Q)->_mp_den)) - - -#if defined (__cplusplus) -extern "C" { -using std::FILE; -#endif - -#define mp_set_memory_functions __gmp_set_memory_functions -__GMP_DECLSPEC void mp_set_memory_functions __GMP_PROTO ((void *(*) (size_t), - void *(*) (void *, size_t, size_t), - void (*) (void *, size_t))) __GMP_NOTHROW; - -#define mp_get_memory_functions __gmp_get_memory_functions -__GMP_DECLSPEC void mp_get_memory_functions __GMP_PROTO ((void *(**) (size_t), - void *(**) (void *, size_t, size_t), - void (**) (void *, size_t))) __GMP_NOTHROW; - -#define mp_bits_per_limb __gmp_bits_per_limb -__GMP_DECLSPEC extern __gmp_const int mp_bits_per_limb; - -#define gmp_errno __gmp_errno -__GMP_DECLSPEC extern int gmp_errno; - -#define gmp_version __gmp_version -__GMP_DECLSPEC extern __gmp_const char * __gmp_const gmp_version; - -#define mpir_version __mpir_version -__GMP_DECLSPEC extern __gmp_const char * __gmp_const mpir_version; - - -/**************** Random number routines. ****************/ - -#define gmp_randinit_default __gmp_randinit_default -__GMP_DECLSPEC void gmp_randinit_default __GMP_PROTO ((gmp_randstate_t)); - -#define gmp_randinit_lc_2exp __gmp_randinit_lc_2exp -__GMP_DECLSPEC void gmp_randinit_lc_2exp __GMP_PROTO ((gmp_randstate_t, - mpz_srcptr, unsigned long int, - mp_bitcnt_t)); - -#define gmp_randinit_lc_2exp_size __gmp_randinit_lc_2exp_size -__GMP_DECLSPEC int gmp_randinit_lc_2exp_size __GMP_PROTO ((gmp_randstate_t, mp_bitcnt_t)); - -#define gmp_randinit_mt __gmp_randinit_mt -__GMP_DECLSPEC void gmp_randinit_mt __GMP_PROTO ((gmp_randstate_t)); - -#define gmp_randinit_set __gmp_randinit_set -__GMP_DECLSPEC void gmp_randinit_set __GMP_PROTO ((gmp_randstate_t, __gmp_const __gmp_randstate_struct *)); - -#define gmp_randseed __gmp_randseed -__GMP_DECLSPEC void gmp_randseed __GMP_PROTO ((gmp_randstate_t, mpz_srcptr)); - -#define gmp_randseed_ui __gmp_randseed_ui -__GMP_DECLSPEC void gmp_randseed_ui __GMP_PROTO ((gmp_randstate_t, unsigned long int)); - -#define gmp_randclear __gmp_randclear -__GMP_DECLSPEC void gmp_randclear __GMP_PROTO ((gmp_randstate_t)); - -#define gmp_urandomb_ui __gmp_urandomb_ui -__GMP_DECLSPEC unsigned long gmp_urandomb_ui __GMP_PROTO ((gmp_randstate_t, unsigned long)); - -#define gmp_urandomm_ui __gmp_urandomm_ui -__GMP_DECLSPEC unsigned long gmp_urandomm_ui __GMP_PROTO ((gmp_randstate_t, unsigned long)); - - -/**************** Formatted output routines. ****************/ - -#define gmp_asprintf __gmp_asprintf -__GMP_DECLSPEC int gmp_asprintf __GMP_PROTO ((char **, __gmp_const char *, ...)); - -#define gmp_fprintf __gmp_fprintf -#ifdef _GMP_H_HAVE_FILE -__GMP_DECLSPEC int gmp_fprintf __GMP_PROTO ((FILE *, __gmp_const char *, ...)); -#endif - -#define gmp_obstack_printf __gmp_obstack_printf -#if defined (_GMP_H_HAVE_OBSTACK) -__GMP_DECLSPEC int gmp_obstack_printf __GMP_PROTO ((struct obstack *, __gmp_const char *, ...)); -#endif - -#define gmp_obstack_vprintf __gmp_obstack_vprintf -#if defined (_GMP_H_HAVE_OBSTACK) && defined (_GMP_H_HAVE_VA_LIST) -__GMP_DECLSPEC int gmp_obstack_vprintf __GMP_PROTO ((struct obstack *, __gmp_const char *, va_list)); -#endif - -#define gmp_printf __gmp_printf -__GMP_DECLSPEC int gmp_printf __GMP_PROTO ((__gmp_const char *, ...)); - -#define gmp_snprintf __gmp_snprintf -__GMP_DECLSPEC int gmp_snprintf __GMP_PROTO ((char *, size_t, __gmp_const char *, ...)); - -#define gmp_sprintf __gmp_sprintf -__GMP_DECLSPEC int gmp_sprintf __GMP_PROTO ((char *, __gmp_const char *, ...)); - -#define gmp_vasprintf __gmp_vasprintf -#if defined (_GMP_H_HAVE_VA_LIST) -__GMP_DECLSPEC int gmp_vasprintf __GMP_PROTO ((char **, __gmp_const char *, va_list)); -#endif - -#define gmp_vfprintf __gmp_vfprintf -#if defined (_GMP_H_HAVE_FILE) && defined (_GMP_H_HAVE_VA_LIST) -__GMP_DECLSPEC int gmp_vfprintf __GMP_PROTO ((FILE *, __gmp_const char *, va_list)); -#endif - -#define gmp_vprintf __gmp_vprintf -#if defined (_GMP_H_HAVE_VA_LIST) -__GMP_DECLSPEC int gmp_vprintf __GMP_PROTO ((__gmp_const char *, va_list)); -#endif - -#define gmp_vsnprintf __gmp_vsnprintf -#if defined (_GMP_H_HAVE_VA_LIST) -__GMP_DECLSPEC int gmp_vsnprintf __GMP_PROTO ((char *, size_t, __gmp_const char *, va_list)); -#endif - -#define gmp_vsprintf __gmp_vsprintf -#if defined (_GMP_H_HAVE_VA_LIST) -__GMP_DECLSPEC int gmp_vsprintf __GMP_PROTO ((char *, __gmp_const char *, va_list)); -#endif - - -/**************** Formatted input routines. ****************/ - -#define gmp_fscanf __gmp_fscanf -#ifdef _GMP_H_HAVE_FILE -__GMP_DECLSPEC int gmp_fscanf __GMP_PROTO ((FILE *, __gmp_const char *, ...)); -#endif - -#define gmp_scanf __gmp_scanf -__GMP_DECLSPEC int gmp_scanf __GMP_PROTO ((__gmp_const char *, ...)); - -#define gmp_sscanf __gmp_sscanf -__GMP_DECLSPEC int gmp_sscanf __GMP_PROTO ((__gmp_const char *, __gmp_const char *, ...)); - -#define gmp_vfscanf __gmp_vfscanf -#if defined (_GMP_H_HAVE_FILE) && defined (_GMP_H_HAVE_VA_LIST) -__GMP_DECLSPEC int gmp_vfscanf __GMP_PROTO ((FILE *, __gmp_const char *, va_list)); -#endif - -#define gmp_vscanf __gmp_vscanf -#if defined (_GMP_H_HAVE_VA_LIST) -__GMP_DECLSPEC int gmp_vscanf __GMP_PROTO ((__gmp_const char *, va_list)); -#endif - -#define gmp_vsscanf __gmp_vsscanf -#if defined (_GMP_H_HAVE_VA_LIST) -__GMP_DECLSPEC int gmp_vsscanf __GMP_PROTO ((__gmp_const char *, __gmp_const char *, va_list)); -#endif - - -/**************** Integer (i.e. Z) routines. ****************/ - -#define __GMP_BITS_PER_ULONG (8*sizeof(unsigned long)) - -#define _mpz_realloc __gmpz_realloc -#define mpz_realloc __gmpz_realloc -__GMP_DECLSPEC void *_mpz_realloc __GMP_PROTO ((mpz_ptr, mp_size_t)); - -#define mpz_abs __gmpz_abs -#define __GMP_MPZ_ABS_MIN_ALLOC(x,y) (__GMP_ABS(y->_mp_size)) -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_abs) -__GMP_DECLSPEC void mpz_abs __GMP_PROTO ((mpz_ptr, mpz_srcptr)); -#endif - -#define __GMP_MPZ_ADD_MIN_ALLOC(x,y,z) (__GMP_MAX(__GMP_ABS(y->_mp_size),__GMP_ABS(z->_mp_size))+1) -#define mpz_add __gmpz_add -__GMP_DECLSPEC void mpz_add __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define __GMP_MPZ_ADD_UI_MIN_ALLOC(x,y,z) (__GMP_MAX(__GMP_ABS(y->_mp_size),1+(__GMP_BITS_PER_ULONG-1)/GMP_NUMB_BITS)+1) -#define mpz_add_ui __gmpz_add_ui -__GMP_DECLSPEC void mpz_add_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_addmul __gmpz_addmul -__GMP_DECLSPEC void mpz_addmul __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_addmul_ui __gmpz_addmul_ui -__GMP_DECLSPEC void mpz_addmul_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_and __gmpz_and -__GMP_DECLSPEC void mpz_and __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_array_init __gmpz_array_init -__GMP_DECLSPEC void mpz_array_init __GMP_PROTO ((mpz_ptr, mp_size_t, mp_size_t)); - -#define mpz_bin_ui __gmpz_bin_ui -__GMP_DECLSPEC void mpz_bin_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_bin_uiui __gmpz_bin_uiui -__GMP_DECLSPEC void mpz_bin_uiui __GMP_PROTO ((mpz_ptr, unsigned long int, unsigned long int)); - -#define mpz_cdiv_q __gmpz_cdiv_q -__GMP_DECLSPEC void mpz_cdiv_q __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_cdiv_q_2exp __gmpz_cdiv_q_2exp -__GMP_DECLSPEC void mpz_cdiv_q_2exp __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long)); - -#define mpz_cdiv_q_ui __gmpz_cdiv_q_ui -__GMP_DECLSPEC unsigned long int mpz_cdiv_q_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_cdiv_qr __gmpz_cdiv_qr -__GMP_DECLSPEC void mpz_cdiv_qr __GMP_PROTO ((mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_cdiv_qr_ui __gmpz_cdiv_qr_ui -__GMP_DECLSPEC unsigned long int mpz_cdiv_qr_ui __GMP_PROTO ((mpz_ptr, mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_cdiv_r __gmpz_cdiv_r -__GMP_DECLSPEC void mpz_cdiv_r __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_cdiv_r_2exp __gmpz_cdiv_r_2exp -__GMP_DECLSPEC void mpz_cdiv_r_2exp __GMP_PROTO ((mpz_ptr, mpz_srcptr, mp_bitcnt_t)); - -#define mpz_cdiv_r_ui __gmpz_cdiv_r_ui -__GMP_DECLSPEC unsigned long int mpz_cdiv_r_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_cdiv_ui __gmpz_cdiv_ui -__GMP_DECLSPEC unsigned long int mpz_cdiv_ui __GMP_PROTO ((mpz_srcptr, unsigned long int)) __GMP_ATTRIBUTE_PURE; - -#define mpz_clear __gmpz_clear -__GMP_DECLSPEC void mpz_clear __GMP_PROTO ((mpz_ptr)); - -#define mpz_clears __gmpz_clears -__GMP_DECLSPEC void mpz_clears __GMP_PROTO ((mpz_ptr, ...)); - -#define mpz_clrbit __gmpz_clrbit -__GMP_DECLSPEC void mpz_clrbit __GMP_PROTO ((mpz_ptr, mp_bitcnt_t)); - -#define mpz_cmp __gmpz_cmp -__GMP_DECLSPEC int mpz_cmp __GMP_PROTO ((mpz_srcptr, mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpz_cmp_d __gmpz_cmp_d -__GMP_DECLSPEC int mpz_cmp_d __GMP_PROTO ((mpz_srcptr, double)) __GMP_ATTRIBUTE_PURE; - -#define _mpz_cmp_si __gmpz_cmp_si -__GMP_DECLSPEC int _mpz_cmp_si __GMP_PROTO ((mpz_srcptr, signed long int)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define _mpz_cmp_ui __gmpz_cmp_ui -__GMP_DECLSPEC int _mpz_cmp_ui __GMP_PROTO ((mpz_srcptr, unsigned long int)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpz_cmpabs __gmpz_cmpabs -__GMP_DECLSPEC int mpz_cmpabs __GMP_PROTO ((mpz_srcptr, mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpz_cmpabs_d __gmpz_cmpabs_d -__GMP_DECLSPEC int mpz_cmpabs_d __GMP_PROTO ((mpz_srcptr, double)) __GMP_ATTRIBUTE_PURE; - -#define mpz_cmpabs_ui __gmpz_cmpabs_ui -__GMP_DECLSPEC int mpz_cmpabs_ui __GMP_PROTO ((mpz_srcptr, unsigned long int)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpz_com __gmpz_com -__GMP_DECLSPEC void mpz_com __GMP_PROTO ((mpz_ptr, mpz_srcptr)); - -#define mpz_combit __gmpz_combit -__GMP_DECLSPEC void mpz_combit __GMP_PROTO ((mpz_ptr, mp_bitcnt_t)); - -#define mpz_congruent_p __gmpz_congruent_p -__GMP_DECLSPEC int mpz_congruent_p __GMP_PROTO ((mpz_srcptr, mpz_srcptr, mpz_srcptr)) __GMP_ATTRIBUTE_PURE; - -#define mpz_congruent_2exp_p __gmpz_congruent_2exp_p -__GMP_DECLSPEC int mpz_congruent_2exp_p __GMP_PROTO ((mpz_srcptr, mpz_srcptr, mp_bitcnt_t)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpz_congruent_ui_p __gmpz_congruent_ui_p -__GMP_DECLSPEC int mpz_congruent_ui_p __GMP_PROTO ((mpz_srcptr, unsigned long, unsigned long)) __GMP_ATTRIBUTE_PURE; - -#define mpz_divexact __gmpz_divexact -__GMP_DECLSPEC void mpz_divexact __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_divexact_ui __gmpz_divexact_ui -__GMP_DECLSPEC void mpz_divexact_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long)); - -#define mpz_divisible_p __gmpz_divisible_p -__GMP_DECLSPEC int mpz_divisible_p __GMP_PROTO ((mpz_srcptr, mpz_srcptr)) __GMP_ATTRIBUTE_PURE; - -#define mpz_divisible_ui_p __gmpz_divisible_ui_p -__GMP_DECLSPEC int mpz_divisible_ui_p __GMP_PROTO ((mpz_srcptr, unsigned long)) __GMP_ATTRIBUTE_PURE; - -#define mpz_divisible_2exp_p __gmpz_divisible_2exp_p -__GMP_DECLSPEC int mpz_divisible_2exp_p __GMP_PROTO ((mpz_srcptr, mp_bitcnt_t)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpz_dump __gmpz_dump -__GMP_DECLSPEC void mpz_dump __GMP_PROTO ((mpz_srcptr)); - -#define mpz_export __gmpz_export -__GMP_DECLSPEC void *mpz_export __GMP_PROTO ((void *, size_t *, int, size_t, int, size_t, mpz_srcptr)); - -#define mpz_fac_ui __gmpz_fac_ui -__GMP_DECLSPEC void mpz_fac_ui __GMP_PROTO ((mpz_ptr, unsigned long int)); - -#define mpz_fdiv_q __gmpz_fdiv_q -__GMP_DECLSPEC void mpz_fdiv_q __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_fdiv_q_2exp __gmpz_fdiv_q_2exp -__GMP_DECLSPEC void mpz_fdiv_q_2exp __GMP_PROTO ((mpz_ptr, mpz_srcptr, mp_bitcnt_t)); - -#define mpz_fdiv_q_ui __gmpz_fdiv_q_ui -__GMP_DECLSPEC unsigned long int mpz_fdiv_q_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_fdiv_qr __gmpz_fdiv_qr -__GMP_DECLSPEC void mpz_fdiv_qr __GMP_PROTO ((mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_fdiv_qr_ui __gmpz_fdiv_qr_ui -__GMP_DECLSPEC unsigned long int mpz_fdiv_qr_ui __GMP_PROTO ((mpz_ptr, mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_fdiv_r __gmpz_fdiv_r -__GMP_DECLSPEC void mpz_fdiv_r __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_fdiv_r_2exp __gmpz_fdiv_r_2exp -__GMP_DECLSPEC void mpz_fdiv_r_2exp __GMP_PROTO ((mpz_ptr, mpz_srcptr, mp_bitcnt_t)); - -#define mpz_fdiv_r_ui __gmpz_fdiv_r_ui -__GMP_DECLSPEC unsigned long int mpz_fdiv_r_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_fdiv_ui __gmpz_fdiv_ui -__GMP_DECLSPEC unsigned long int mpz_fdiv_ui __GMP_PROTO ((mpz_srcptr, unsigned long int)) __GMP_ATTRIBUTE_PURE; - -#define mpz_fib_ui __gmpz_fib_ui -__GMP_DECLSPEC void mpz_fib_ui __GMP_PROTO ((mpz_ptr, unsigned long int)); - -#define mpz_fib2_ui __gmpz_fib2_ui -__GMP_DECLSPEC void mpz_fib2_ui __GMP_PROTO ((mpz_ptr, mpz_ptr, unsigned long int)); - -#define mpz_fits_sint_p __gmpz_fits_sint_p -__GMP_DECLSPEC int mpz_fits_sint_p __GMP_PROTO ((mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpz_fits_slong_p __gmpz_fits_slong_p -__GMP_DECLSPEC int mpz_fits_slong_p __GMP_PROTO ((mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpz_fits_sshort_p __gmpz_fits_sshort_p -__GMP_DECLSPEC int mpz_fits_sshort_p __GMP_PROTO ((mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpz_fits_uint_p __gmpz_fits_uint_p -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_fits_uint_p) -__GMP_DECLSPEC int mpz_fits_uint_p __GMP_PROTO ((mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#endif - -#define mpz_fits_ulong_p __gmpz_fits_ulong_p -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_fits_ulong_p) -__GMP_DECLSPEC int mpz_fits_ulong_p __GMP_PROTO ((mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#endif - -#define mpz_fits_ushort_p __gmpz_fits_ushort_p -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_fits_ushort_p) -__GMP_DECLSPEC int mpz_fits_ushort_p __GMP_PROTO ((mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#endif - -#define mpz_gcd __gmpz_gcd -__GMP_DECLSPEC void mpz_gcd __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_gcd_ui __gmpz_gcd_ui -__GMP_DECLSPEC unsigned long int mpz_gcd_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_gcdext __gmpz_gcdext -__GMP_DECLSPEC void mpz_gcdext __GMP_PROTO ((mpz_ptr, mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_get_d __gmpz_get_d -__GMP_DECLSPEC double mpz_get_d __GMP_PROTO ((mpz_srcptr)) __GMP_ATTRIBUTE_PURE; - -#define mpz_get_d_2exp __gmpz_get_d_2exp -__GMP_DECLSPEC double mpz_get_d_2exp __GMP_PROTO ((signed long int *, mpz_srcptr)); - -#define mpz_get_si __gmpz_get_si -__GMP_DECLSPEC /* signed */ long int mpz_get_si __GMP_PROTO ((mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpz_get_str __gmpz_get_str -__GMP_DECLSPEC char *mpz_get_str __GMP_PROTO ((char *, int, mpz_srcptr)); - -#define mpz_get_ui __gmpz_get_ui -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_get_ui) -__GMP_DECLSPEC unsigned long int mpz_get_ui __GMP_PROTO ((mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#endif - -#define mpz_getlimbn __gmpz_getlimbn -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_getlimbn) -__GMP_DECLSPEC mp_limb_t mpz_getlimbn __GMP_PROTO ((mpz_srcptr, mp_size_t)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#endif - -#define mpz_hamdist __gmpz_hamdist -__GMP_DECLSPEC mp_bitcnt_t mpz_hamdist __GMP_PROTO ((mpz_srcptr, mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpz_import __gmpz_import -__GMP_DECLSPEC void mpz_import __GMP_PROTO ((mpz_ptr, size_t, int, size_t, int, size_t, __gmp_const void *)); - -#define mpz_init __gmpz_init -__GMP_DECLSPEC void mpz_init __GMP_PROTO ((mpz_ptr)); - -#define mpz_init2 __gmpz_init2 -__GMP_DECLSPEC void mpz_init2 __GMP_PROTO ((mpz_ptr, mp_bitcnt_t)); - -#define mpz_inits __gmpz_inits -__GMP_DECLSPEC void mpz_inits __GMP_PROTO ((mpz_ptr, ...)); - -#define mpz_init_set __gmpz_init_set -__GMP_DECLSPEC void mpz_init_set __GMP_PROTO ((mpz_ptr, mpz_srcptr)); - -#define mpz_init_set_d __gmpz_init_set_d -__GMP_DECLSPEC void mpz_init_set_d __GMP_PROTO ((mpz_ptr, double)); - -#define mpz_init_set_si __gmpz_init_set_si -__GMP_DECLSPEC void mpz_init_set_si __GMP_PROTO ((mpz_ptr, signed long int)); - -#define mpz_init_set_str __gmpz_init_set_str -__GMP_DECLSPEC int mpz_init_set_str __GMP_PROTO ((mpz_ptr, __gmp_const char *, int)); - -#define mpz_init_set_ui __gmpz_init_set_ui -__GMP_DECLSPEC void mpz_init_set_ui __GMP_PROTO ((mpz_ptr, unsigned long int)); - -#define mpz_inp_raw __gmpz_inp_raw -#ifdef _GMP_H_HAVE_FILE -__GMP_DECLSPEC size_t mpz_inp_raw __GMP_PROTO ((mpz_ptr, FILE *)); -#endif - -#define mpz_inp_str __gmpz_inp_str -#ifdef _GMP_H_HAVE_FILE -__GMP_DECLSPEC size_t mpz_inp_str __GMP_PROTO ((mpz_ptr, FILE *, int)); -#endif - -#define mpz_invert __gmpz_invert -__GMP_DECLSPEC int mpz_invert __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_ior __gmpz_ior -__GMP_DECLSPEC void mpz_ior __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_jacobi __gmpz_jacobi -__GMP_DECLSPEC int mpz_jacobi __GMP_PROTO ((mpz_srcptr, mpz_srcptr)) __GMP_ATTRIBUTE_PURE; - -#define mpz_kronecker mpz_jacobi /* alias */ - -#define mpz_kronecker_si __gmpz_kronecker_si -__GMP_DECLSPEC int mpz_kronecker_si __GMP_PROTO ((mpz_srcptr, long)) __GMP_ATTRIBUTE_PURE; - -#define mpz_kronecker_ui __gmpz_kronecker_ui -__GMP_DECLSPEC int mpz_kronecker_ui __GMP_PROTO ((mpz_srcptr, unsigned long)) __GMP_ATTRIBUTE_PURE; - -#define mpz_si_kronecker __gmpz_si_kronecker -__GMP_DECLSPEC int mpz_si_kronecker __GMP_PROTO ((long, mpz_srcptr)) __GMP_ATTRIBUTE_PURE; - -#define mpz_ui_kronecker __gmpz_ui_kronecker -__GMP_DECLSPEC int mpz_ui_kronecker __GMP_PROTO ((unsigned long, mpz_srcptr)) __GMP_ATTRIBUTE_PURE; - -#define mpz_lcm __gmpz_lcm -__GMP_DECLSPEC void mpz_lcm __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_lcm_ui __gmpz_lcm_ui -__GMP_DECLSPEC void mpz_lcm_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long)); - -#define mpz_legendre mpz_jacobi /* alias */ - -#define mpz_lucnum_ui __gmpz_lucnum_ui -__GMP_DECLSPEC void mpz_lucnum_ui __GMP_PROTO ((mpz_ptr, unsigned long int)); - -#define mpz_lucnum2_ui __gmpz_lucnum2_ui -__GMP_DECLSPEC void mpz_lucnum2_ui __GMP_PROTO ((mpz_ptr, mpz_ptr, unsigned long int)); - -#define mpz_millerrabin __gmpz_millerrabin -__GMP_DECLSPEC int mpz_millerrabin __GMP_PROTO ((mpz_srcptr, int)) __GMP_ATTRIBUTE_PURE; - -#define mpz_mod __gmpz_mod -__GMP_DECLSPEC void mpz_mod __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_mod_ui mpz_fdiv_r_ui /* same as fdiv_r because divisor unsigned */ - -#define __GMP_MPZ_MUL_MIN_ALLOC(x,y,z) (__GMP_ABS(y->_mp_size)+__GMP_ABS(z->_mp_size)+1) -#define mpz_mul __gmpz_mul -__GMP_DECLSPEC void mpz_mul __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_mul_2exp __gmpz_mul_2exp -__GMP_DECLSPEC void mpz_mul_2exp __GMP_PROTO ((mpz_ptr, mpz_srcptr, mp_bitcnt_t)); - -#define __GMP_MPZ_MUL_SI_MIN_ALLOC(x,y,z) (__GMP_ABS(y->_mp_size)+(__GMP_BITS_PER_ULONG-1)/GMP_NUMB_BITS+1) -#define mpz_mul_si __gmpz_mul_si -__GMP_DECLSPEC void mpz_mul_si __GMP_PROTO ((mpz_ptr, mpz_srcptr, long int)); - -#define __GMP_MPZ_MUL_UI_MIN_ALLOC(x,y,z) (__GMP_ABS(y->_mp_size)+(__GMP_BITS_PER_ULONG-1)/GMP_NUMB_BITS+1) -#define mpz_mul_ui __gmpz_mul_ui -__GMP_DECLSPEC void mpz_mul_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_neg __gmpz_neg -#define __GMP_MPZ_NEG_MIN_ALLOC(x,y) (__GMP_ABS(y->_mp_size)) -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_neg) -__GMP_DECLSPEC void mpz_neg __GMP_PROTO ((mpz_ptr, mpz_srcptr)); -#endif - -#define mpz_nextprime __gmpz_nextprime -__GMP_DECLSPEC void mpz_nextprime __GMP_PROTO ((mpz_ptr, mpz_srcptr)); - -#define mpz_next_likely_prime __gmpz_next_likely_prime -__GMP_DECLSPEC void mpz_next_likely_prime __GMP_PROTO ((mpz_ptr, mpz_srcptr,gmp_randstate_t)); - -#define mpz_out_raw __gmpz_out_raw -#ifdef _GMP_H_HAVE_FILE -__GMP_DECLSPEC size_t mpz_out_raw __GMP_PROTO ((FILE *, mpz_srcptr)); -#endif - -#define mpz_out_str __gmpz_out_str -#ifdef _GMP_H_HAVE_FILE -__GMP_DECLSPEC size_t mpz_out_str __GMP_PROTO ((FILE *, int, mpz_srcptr)); -#endif - -#define mpz_perfect_power_p __gmpz_perfect_power_p -__GMP_DECLSPEC int mpz_perfect_power_p __GMP_PROTO ((mpz_srcptr)) __GMP_ATTRIBUTE_PURE; - -#define mpz_perfect_square_p __gmpz_perfect_square_p -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_perfect_square_p) -__GMP_DECLSPEC int mpz_perfect_square_p __GMP_PROTO ((mpz_srcptr)) __GMP_ATTRIBUTE_PURE; -#endif - -#define mpz_popcount __gmpz_popcount -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_popcount) -__GMP_DECLSPEC mp_bitcnt_t mpz_popcount __GMP_PROTO ((mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#endif - -#define mpz_pow_ui __gmpz_pow_ui -__GMP_DECLSPEC void mpz_pow_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_powm __gmpz_powm -__GMP_DECLSPEC void mpz_powm __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_powm_ui __gmpz_powm_ui -__GMP_DECLSPEC void mpz_powm_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int, mpz_srcptr)); - -#define mpz_probab_prime_p __gmpz_probab_prime_p -__GMP_DECLSPEC int mpz_probab_prime_p __GMP_PROTO ((mpz_srcptr, int)) __GMP_ATTRIBUTE_PURE; - -#define mpz_probable_prime_p __gmpz_probable_prime_p -__GMP_DECLSPEC int mpz_probable_prime_p __GMP_PROTO ((mpz_srcptr,gmp_randstate_t, int,unsigned long)); - -#define mpz_likely_prime_p __gmpz_likely_prime_p -__GMP_DECLSPEC int mpz_likely_prime_p __GMP_PROTO ((mpz_srcptr,gmp_randstate_t, unsigned long)); - -#define mpz_realloc2 __gmpz_realloc2 -__GMP_DECLSPEC void mpz_realloc2 __GMP_PROTO ((mpz_ptr, mp_bitcnt_t)); - -#define mpz_remove __gmpz_remove -__GMP_DECLSPEC unsigned long int mpz_remove __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_root __gmpz_root -__GMP_DECLSPEC int mpz_root __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_nthroot __gmpz_nthroot -__GMP_DECLSPEC void mpz_nthroot __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_rootrem __gmpz_rootrem -__GMP_DECLSPEC void mpz_rootrem __GMP_PROTO ((mpz_ptr,mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_rrandomb __gmpz_rrandomb -__GMP_DECLSPEC void mpz_rrandomb __GMP_PROTO ((mpz_ptr, gmp_randstate_t, mp_bitcnt_t)); - -#define mpz_scan0 __gmpz_scan0 -__GMP_DECLSPEC mp_bitcnt_t mpz_scan0 __GMP_PROTO ((mpz_srcptr, mp_bitcnt_t)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpz_scan1 __gmpz_scan1 -__GMP_DECLSPEC mp_bitcnt_t mpz_scan1 __GMP_PROTO ((mpz_srcptr, mp_bitcnt_t)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define __GMP_MPZ_SET_MIN_ALLOC(x,y) __GMP_ABS(y->_mp_size) -#define mpz_set __gmpz_set -__GMP_DECLSPEC void mpz_set __GMP_PROTO ((mpz_ptr, mpz_srcptr)); - -#define mpz_set_d __gmpz_set_d -__GMP_DECLSPEC void mpz_set_d __GMP_PROTO ((mpz_ptr, double)); - -#define mpz_set_f __gmpz_set_f -__GMP_DECLSPEC void mpz_set_f __GMP_PROTO ((mpz_ptr, mpf_srcptr)); - -#define mpz_set_q __gmpz_set_q -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_set_q) -__GMP_DECLSPEC void mpz_set_q __GMP_PROTO ((mpz_ptr, mpq_srcptr)); -#endif - -#define __GMP_MPZ_SET_SI_MIN_ALLOC(x,y) (1+(__GMP_BITS_PER_ULONG-1)/GMP_NUMB_BITS) -#define mpz_set_si __gmpz_set_si -__GMP_DECLSPEC void mpz_set_si __GMP_PROTO ((mpz_ptr, signed long int)); - -#define mpz_set_str __gmpz_set_str -__GMP_DECLSPEC int mpz_set_str __GMP_PROTO ((mpz_ptr, __gmp_const char *, int)); - -#define __GMP_MPZ_SET_UI_MIN_ALLOC(x,y) (1+(__GMP_BITS_PER_ULONG-1)/GMP_NUMB_BITS) -#define mpz_set_ui __gmpz_set_ui -__GMP_DECLSPEC void mpz_set_ui __GMP_PROTO ((mpz_ptr, unsigned long int)); - -#define mpz_setbit __gmpz_setbit -__GMP_DECLSPEC void mpz_setbit __GMP_PROTO ((mpz_ptr, mp_bitcnt_t)); - -#define mpz_size __gmpz_size -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_size) -__GMP_DECLSPEC size_t mpz_size __GMP_PROTO ((mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#endif - -#define mpz_sizeinbase __gmpz_sizeinbase -__GMP_DECLSPEC size_t mpz_sizeinbase __GMP_PROTO ((mpz_srcptr, int)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpz_sqrt __gmpz_sqrt -__GMP_DECLSPEC void mpz_sqrt __GMP_PROTO ((mpz_ptr, mpz_srcptr)); - -#define mpz_sqrtrem __gmpz_sqrtrem -__GMP_DECLSPEC void mpz_sqrtrem __GMP_PROTO ((mpz_ptr, mpz_ptr, mpz_srcptr)); - -#define __GMP_MPZ_SUB_MIN_ALLOC(x,y,z) (__GMP_MAX(__GMP_ABS(y->_mp_size),__GMP_ABS(z->_mp_size))+1) -#define mpz_sub __gmpz_sub -__GMP_DECLSPEC void mpz_sub __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define __GMP_MPZ_SUB_UI_MIN_ALLOC(x,y,z) (__GMP_MAX(__GMP_ABS(y->_mp_size),1+(__GMP_BITS_PER_ULONG-1)/GMP_NUMB_BITS)+1) -#define mpz_sub_ui __gmpz_sub_ui -__GMP_DECLSPEC void mpz_sub_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); - -#define __GMP_MPZ_UI_SUB_MIN_ALLOC(x,y,z) (__GMP_MAX(__GMP_ABS(z->_mp_size),1+(__GMP_BITS_PER_ULONG-1)/GMP_NUMB_BITS)+1) -#define mpz_ui_sub __gmpz_ui_sub -__GMP_DECLSPEC void mpz_ui_sub __GMP_PROTO ((mpz_ptr, unsigned long int, mpz_srcptr)); - -#define mpz_submul __gmpz_submul -__GMP_DECLSPEC void mpz_submul __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_submul_ui __gmpz_submul_ui -__GMP_DECLSPEC void mpz_submul_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_swap __gmpz_swap -__GMP_DECLSPEC void mpz_swap __GMP_PROTO ((mpz_ptr, mpz_ptr)) __GMP_NOTHROW; - -#define mpz_tdiv_ui __gmpz_tdiv_ui -__GMP_DECLSPEC unsigned long int mpz_tdiv_ui __GMP_PROTO ((mpz_srcptr, unsigned long int)) __GMP_ATTRIBUTE_PURE; - -#define mpz_tdiv_q __gmpz_tdiv_q -__GMP_DECLSPEC void mpz_tdiv_q __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_tdiv_q_2exp __gmpz_tdiv_q_2exp -__GMP_DECLSPEC void mpz_tdiv_q_2exp __GMP_PROTO ((mpz_ptr, mpz_srcptr, mp_bitcnt_t)); - -#define mpz_tdiv_q_ui __gmpz_tdiv_q_ui -__GMP_DECLSPEC unsigned long int mpz_tdiv_q_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_tdiv_qr __gmpz_tdiv_qr -__GMP_DECLSPEC void mpz_tdiv_qr __GMP_PROTO ((mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_tdiv_qr_ui __gmpz_tdiv_qr_ui -__GMP_DECLSPEC unsigned long int mpz_tdiv_qr_ui __GMP_PROTO ((mpz_ptr, mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_tdiv_r __gmpz_tdiv_r -__GMP_DECLSPEC void mpz_tdiv_r __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_tdiv_r_2exp __gmpz_tdiv_r_2exp -__GMP_DECLSPEC void mpz_tdiv_r_2exp __GMP_PROTO ((mpz_ptr, mpz_srcptr, mp_bitcnt_t)); - -#define mpz_tdiv_r_ui __gmpz_tdiv_r_ui -__GMP_DECLSPEC unsigned long int mpz_tdiv_r_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_tstbit __gmpz_tstbit -__GMP_DECLSPEC int mpz_tstbit __GMP_PROTO ((mpz_srcptr, mp_bitcnt_t)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpz_ui_pow_ui __gmpz_ui_pow_ui -__GMP_DECLSPEC void mpz_ui_pow_ui __GMP_PROTO ((mpz_ptr, unsigned long int, unsigned long int)); - -#define mpz_urandomb __gmpz_urandomb -__GMP_DECLSPEC void mpz_urandomb __GMP_PROTO ((mpz_ptr, gmp_randstate_t, mp_bitcnt_t)); - -#define mpz_urandomm __gmpz_urandomm -__GMP_DECLSPEC void mpz_urandomm __GMP_PROTO ((mpz_ptr, gmp_randstate_t, mpz_srcptr)); - -#define mpz_xor __gmpz_xor -#define mpz_eor __gmpz_xor -__GMP_DECLSPEC void mpz_xor __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - - -/**************** Rational (i.e. Q) routines. ****************/ - -#define mpq_abs __gmpq_abs -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpq_abs) -__GMP_DECLSPEC void mpq_abs __GMP_PROTO ((mpq_ptr, mpq_srcptr)); -#endif - -#define mpq_add __gmpq_add -__GMP_DECLSPEC void mpq_add __GMP_PROTO ((mpq_ptr, mpq_srcptr, mpq_srcptr)); - -#define mpq_canonicalize __gmpq_canonicalize -__GMP_DECLSPEC void mpq_canonicalize __GMP_PROTO ((mpq_ptr)); - -#define mpq_clear __gmpq_clear -__GMP_DECLSPEC void mpq_clear __GMP_PROTO ((mpq_ptr)); - -#define mpq_clears __gmpq_clears -__GMP_DECLSPEC void mpq_clears __GMP_PROTO ((mpq_ptr, ...)); - -#define mpq_cmp __gmpq_cmp -__GMP_DECLSPEC int mpq_cmp __GMP_PROTO ((mpq_srcptr, mpq_srcptr)) __GMP_ATTRIBUTE_PURE; - -#define _mpq_cmp_si __gmpq_cmp_si -__GMP_DECLSPEC int _mpq_cmp_si __GMP_PROTO ((mpq_srcptr, long, unsigned long)) __GMP_ATTRIBUTE_PURE; - -#define _mpq_cmp_ui __gmpq_cmp_ui -__GMP_DECLSPEC int _mpq_cmp_ui __GMP_PROTO ((mpq_srcptr, unsigned long int, unsigned long int)) __GMP_ATTRIBUTE_PURE; - -#define mpq_div __gmpq_div -__GMP_DECLSPEC void mpq_div __GMP_PROTO ((mpq_ptr, mpq_srcptr, mpq_srcptr)); - -#define mpq_div_2exp __gmpq_div_2exp -__GMP_DECLSPEC void mpq_div_2exp __GMP_PROTO ((mpq_ptr, mpq_srcptr, mp_bitcnt_t)); - -#define mpq_equal __gmpq_equal -__GMP_DECLSPEC int mpq_equal __GMP_PROTO ((mpq_srcptr, mpq_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpq_get_num __gmpq_get_num -__GMP_DECLSPEC void mpq_get_num __GMP_PROTO ((mpz_ptr, mpq_srcptr)); - -#define mpq_get_den __gmpq_get_den -__GMP_DECLSPEC void mpq_get_den __GMP_PROTO ((mpz_ptr, mpq_srcptr)); - -#define mpq_get_d __gmpq_get_d -__GMP_DECLSPEC double mpq_get_d __GMP_PROTO ((mpq_srcptr)) __GMP_ATTRIBUTE_PURE; - -#define mpq_get_str __gmpq_get_str -__GMP_DECLSPEC char *mpq_get_str __GMP_PROTO ((char *, int, mpq_srcptr)); - -#define mpq_init __gmpq_init -__GMP_DECLSPEC void mpq_init __GMP_PROTO ((mpq_ptr)); - -#define mpq_inits __gmpq_inits -__GMP_DECLSPEC void mpq_inits __GMP_PROTO ((mpq_ptr, ...)); - -#define mpq_inp_str __gmpq_inp_str -#ifdef _GMP_H_HAVE_FILE -__GMP_DECLSPEC size_t mpq_inp_str __GMP_PROTO ((mpq_ptr, FILE *, int)); -#endif - -#define mpq_inv __gmpq_inv -__GMP_DECLSPEC void mpq_inv __GMP_PROTO ((mpq_ptr, mpq_srcptr)); - -#define mpq_mul __gmpq_mul -__GMP_DECLSPEC void mpq_mul __GMP_PROTO ((mpq_ptr, mpq_srcptr, mpq_srcptr)); - -#define mpq_mul_2exp __gmpq_mul_2exp -__GMP_DECLSPEC void mpq_mul_2exp __GMP_PROTO ((mpq_ptr, mpq_srcptr, mp_bitcnt_t)); - -#define mpq_neg __gmpq_neg -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpq_neg) -__GMP_DECLSPEC void mpq_neg __GMP_PROTO ((mpq_ptr, mpq_srcptr)); -#endif - -#define mpq_out_str __gmpq_out_str -#ifdef _GMP_H_HAVE_FILE -__GMP_DECLSPEC size_t mpq_out_str __GMP_PROTO ((FILE *, int, mpq_srcptr)); -#endif - -#define mpq_set __gmpq_set -__GMP_DECLSPEC void mpq_set __GMP_PROTO ((mpq_ptr, mpq_srcptr)); - -#define mpq_set_d __gmpq_set_d -__GMP_DECLSPEC void mpq_set_d __GMP_PROTO ((mpq_ptr, double)); - -#define mpq_set_den __gmpq_set_den -__GMP_DECLSPEC void mpq_set_den __GMP_PROTO ((mpq_ptr, mpz_srcptr)); - -#define mpq_set_f __gmpq_set_f -__GMP_DECLSPEC void mpq_set_f __GMP_PROTO ((mpq_ptr, mpf_srcptr)); - -#define mpq_set_num __gmpq_set_num -__GMP_DECLSPEC void mpq_set_num __GMP_PROTO ((mpq_ptr, mpz_srcptr)); - -#define mpq_set_si __gmpq_set_si -__GMP_DECLSPEC void mpq_set_si __GMP_PROTO ((mpq_ptr, signed long int, unsigned long int)); - -#define mpq_set_str __gmpq_set_str -__GMP_DECLSPEC int mpq_set_str __GMP_PROTO ((mpq_ptr, __gmp_const char *, int)); - -#define mpq_set_ui __gmpq_set_ui -__GMP_DECLSPEC void mpq_set_ui __GMP_PROTO ((mpq_ptr, unsigned long int, unsigned long int)); - -#define mpq_set_z __gmpq_set_z -__GMP_DECLSPEC void mpq_set_z __GMP_PROTO ((mpq_ptr, mpz_srcptr)); - -#define mpq_sub __gmpq_sub -__GMP_DECLSPEC void mpq_sub __GMP_PROTO ((mpq_ptr, mpq_srcptr, mpq_srcptr)); - -#define mpq_swap __gmpq_swap -__GMP_DECLSPEC void mpq_swap __GMP_PROTO ((mpq_ptr, mpq_ptr)) __GMP_NOTHROW; - - -/**************** Float (i.e. F) routines. ****************/ - -#define mpf_abs __gmpf_abs -__GMP_DECLSPEC void mpf_abs __GMP_PROTO ((mpf_ptr, mpf_srcptr)); - -#define mpf_add __gmpf_add -__GMP_DECLSPEC void mpf_add __GMP_PROTO ((mpf_ptr, mpf_srcptr, mpf_srcptr)); - -#define mpf_add_ui __gmpf_add_ui -__GMP_DECLSPEC void mpf_add_ui __GMP_PROTO ((mpf_ptr, mpf_srcptr, unsigned long int)); -#define mpf_ceil __gmpf_ceil -__GMP_DECLSPEC void mpf_ceil __GMP_PROTO ((mpf_ptr, mpf_srcptr)); - -#define mpf_clear __gmpf_clear -__GMP_DECLSPEC void mpf_clear __GMP_PROTO ((mpf_ptr)); - -#define mpf_clears __gmpf_clears -__GMP_DECLSPEC void mpf_clears __GMP_PROTO ((mpf_ptr, ...)); - -#define mpf_cmp __gmpf_cmp -__GMP_DECLSPEC int mpf_cmp __GMP_PROTO ((mpf_srcptr, mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpf_cmp_d __gmpf_cmp_d -__GMP_DECLSPEC int mpf_cmp_d __GMP_PROTO ((mpf_srcptr, double)) __GMP_ATTRIBUTE_PURE; - -#define mpf_cmp_si __gmpf_cmp_si -__GMP_DECLSPEC int mpf_cmp_si __GMP_PROTO ((mpf_srcptr, signed long int)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpf_cmp_ui __gmpf_cmp_ui -__GMP_DECLSPEC int mpf_cmp_ui __GMP_PROTO ((mpf_srcptr, unsigned long int)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpf_div __gmpf_div -__GMP_DECLSPEC void mpf_div __GMP_PROTO ((mpf_ptr, mpf_srcptr, mpf_srcptr)); - -#define mpf_div_2exp __gmpf_div_2exp -__GMP_DECLSPEC void mpf_div_2exp __GMP_PROTO ((mpf_ptr, mpf_srcptr, mp_bitcnt_t)); - -#define mpf_div_ui __gmpf_div_ui -__GMP_DECLSPEC void mpf_div_ui __GMP_PROTO ((mpf_ptr, mpf_srcptr, unsigned long int)); - -#define mpf_dump __gmpf_dump -__GMP_DECLSPEC void mpf_dump __GMP_PROTO ((mpf_srcptr)); - -#define mpf_eq __gmpf_eq -__GMP_DECLSPEC int mpf_eq __GMP_PROTO ((mpf_srcptr, mpf_srcptr, unsigned long int)) __GMP_ATTRIBUTE_PURE; - -#define mpf_fits_sint_p __gmpf_fits_sint_p -__GMP_DECLSPEC int mpf_fits_sint_p __GMP_PROTO ((mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpf_fits_slong_p __gmpf_fits_slong_p -__GMP_DECLSPEC int mpf_fits_slong_p __GMP_PROTO ((mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpf_fits_sshort_p __gmpf_fits_sshort_p -__GMP_DECLSPEC int mpf_fits_sshort_p __GMP_PROTO ((mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpf_fits_uint_p __gmpf_fits_uint_p -__GMP_DECLSPEC int mpf_fits_uint_p __GMP_PROTO ((mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpf_fits_ulong_p __gmpf_fits_ulong_p -__GMP_DECLSPEC int mpf_fits_ulong_p __GMP_PROTO ((mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpf_fits_ushort_p __gmpf_fits_ushort_p -__GMP_DECLSPEC int mpf_fits_ushort_p __GMP_PROTO ((mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpf_floor __gmpf_floor -__GMP_DECLSPEC void mpf_floor __GMP_PROTO ((mpf_ptr, mpf_srcptr)); - -#define mpf_get_d __gmpf_get_d -__GMP_DECLSPEC double mpf_get_d __GMP_PROTO ((mpf_srcptr)) __GMP_ATTRIBUTE_PURE; - -#define mpf_get_d_2exp __gmpf_get_d_2exp -__GMP_DECLSPEC double mpf_get_d_2exp __GMP_PROTO ((signed long int *, mpf_srcptr)); - -#define mpf_get_default_prec __gmpf_get_default_prec -__GMP_DECLSPEC mp_bitcnt_t mpf_get_default_prec __GMP_PROTO ((void)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpf_get_prec __gmpf_get_prec -__GMP_DECLSPEC mp_bitcnt_t mpf_get_prec __GMP_PROTO ((mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpf_get_si __gmpf_get_si -__GMP_DECLSPEC long mpf_get_si __GMP_PROTO ((mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpf_get_str __gmpf_get_str -__GMP_DECLSPEC char *mpf_get_str __GMP_PROTO ((char *, mp_exp_t *, int, size_t, mpf_srcptr)); - -#define mpf_get_ui __gmpf_get_ui -__GMP_DECLSPEC unsigned long mpf_get_ui __GMP_PROTO ((mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpf_init __gmpf_init -__GMP_DECLSPEC void mpf_init __GMP_PROTO ((mpf_ptr)); - -#define mpf_init2 __gmpf_init2 -__GMP_DECLSPEC void mpf_init2 __GMP_PROTO ((mpf_ptr, mp_bitcnt_t)); - -#define mpf_inits __gmpf_inits -__GMP_DECLSPEC void mpf_inits __GMP_PROTO ((mpf_ptr, ...)); - -#define mpf_init_set __gmpf_init_set -__GMP_DECLSPEC void mpf_init_set __GMP_PROTO ((mpf_ptr, mpf_srcptr)); - -#define mpf_init_set_d __gmpf_init_set_d -__GMP_DECLSPEC void mpf_init_set_d __GMP_PROTO ((mpf_ptr, double)); - -#define mpf_init_set_si __gmpf_init_set_si -__GMP_DECLSPEC void mpf_init_set_si __GMP_PROTO ((mpf_ptr, signed long int)); - -#define mpf_init_set_str __gmpf_init_set_str -__GMP_DECLSPEC int mpf_init_set_str __GMP_PROTO ((mpf_ptr, __gmp_const char *, int)); - -#define mpf_init_set_ui __gmpf_init_set_ui -__GMP_DECLSPEC void mpf_init_set_ui __GMP_PROTO ((mpf_ptr, unsigned long int)); - -#define mpf_inp_str __gmpf_inp_str -#ifdef _GMP_H_HAVE_FILE -__GMP_DECLSPEC size_t mpf_inp_str __GMP_PROTO ((mpf_ptr, FILE *, int)); -#endif - -#define mpf_integer_p __gmpf_integer_p -__GMP_DECLSPEC int mpf_integer_p __GMP_PROTO ((mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpf_mul __gmpf_mul -__GMP_DECLSPEC void mpf_mul __GMP_PROTO ((mpf_ptr, mpf_srcptr, mpf_srcptr)); - -#define mpf_mul_2exp __gmpf_mul_2exp -__GMP_DECLSPEC void mpf_mul_2exp __GMP_PROTO ((mpf_ptr, mpf_srcptr, mp_bitcnt_t)); - -#define mpf_mul_ui __gmpf_mul_ui -__GMP_DECLSPEC void mpf_mul_ui __GMP_PROTO ((mpf_ptr, mpf_srcptr, unsigned long int)); - -#define mpf_neg __gmpf_neg -__GMP_DECLSPEC void mpf_neg __GMP_PROTO ((mpf_ptr, mpf_srcptr)); - -#define mpf_out_str __gmpf_out_str -#ifdef _GMP_H_HAVE_FILE -__GMP_DECLSPEC size_t mpf_out_str __GMP_PROTO ((FILE *, int, size_t, mpf_srcptr)); -#endif - -#define mpf_pow_ui __gmpf_pow_ui -__GMP_DECLSPEC void mpf_pow_ui __GMP_PROTO ((mpf_ptr, mpf_srcptr, unsigned long int)); - -#define mpf_random2 __gmpf_random2 -__GMP_DECLSPEC void mpf_random2 __GMP_PROTO ((mpf_ptr, mp_size_t, mp_exp_t)); - -#define mpf_rrandomb __gmpf_rrandomb -__GMP_DECLSPEC void mpf_rrandomb __GMP_PROTO ((mpf_ptr, gmp_randstate_t, mp_size_t, mp_exp_t)); - -#define mpf_reldiff __gmpf_reldiff -__GMP_DECLSPEC void mpf_reldiff __GMP_PROTO ((mpf_ptr, mpf_srcptr, mpf_srcptr)); - -#define mpf_set __gmpf_set -__GMP_DECLSPEC void mpf_set __GMP_PROTO ((mpf_ptr, mpf_srcptr)); - -#define mpf_set_d __gmpf_set_d -__GMP_DECLSPEC void mpf_set_d __GMP_PROTO ((mpf_ptr, double)); - -#define mpf_set_default_prec __gmpf_set_default_prec -__GMP_DECLSPEC void mpf_set_default_prec __GMP_PROTO ((mp_bitcnt_t)) __GMP_NOTHROW; - -#define mpf_set_prec __gmpf_set_prec -__GMP_DECLSPEC void mpf_set_prec __GMP_PROTO ((mpf_ptr, mp_bitcnt_t)); - -#define mpf_set_prec_raw __gmpf_set_prec_raw -__GMP_DECLSPEC void mpf_set_prec_raw __GMP_PROTO ((mpf_ptr, mp_bitcnt_t)) __GMP_NOTHROW; - -#define mpf_set_q __gmpf_set_q -__GMP_DECLSPEC void mpf_set_q __GMP_PROTO ((mpf_ptr, mpq_srcptr)); - -#define mpf_set_si __gmpf_set_si -__GMP_DECLSPEC void mpf_set_si __GMP_PROTO ((mpf_ptr, signed long int)); - -#define mpf_set_str __gmpf_set_str -__GMP_DECLSPEC int mpf_set_str __GMP_PROTO ((mpf_ptr, __gmp_const char *, int)); - -#define mpf_set_ui __gmpf_set_ui -__GMP_DECLSPEC void mpf_set_ui __GMP_PROTO ((mpf_ptr, unsigned long int)); - -#define mpf_set_z __gmpf_set_z -__GMP_DECLSPEC void mpf_set_z __GMP_PROTO ((mpf_ptr, mpz_srcptr)); - -#define mpf_size __gmpf_size -__GMP_DECLSPEC size_t mpf_size __GMP_PROTO ((mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpf_sqrt __gmpf_sqrt -__GMP_DECLSPEC void mpf_sqrt __GMP_PROTO ((mpf_ptr, mpf_srcptr)); - -#define mpf_sqrt_ui __gmpf_sqrt_ui -__GMP_DECLSPEC void mpf_sqrt_ui __GMP_PROTO ((mpf_ptr, unsigned long int)); - -#define mpf_sub __gmpf_sub -__GMP_DECLSPEC void mpf_sub __GMP_PROTO ((mpf_ptr, mpf_srcptr, mpf_srcptr)); - -#define mpf_sub_ui __gmpf_sub_ui -__GMP_DECLSPEC void mpf_sub_ui __GMP_PROTO ((mpf_ptr, mpf_srcptr, unsigned long int)); - -#define mpf_swap __gmpf_swap -__GMP_DECLSPEC void mpf_swap __GMP_PROTO ((mpf_ptr, mpf_ptr)) __GMP_NOTHROW; - -#define mpf_trunc __gmpf_trunc -__GMP_DECLSPEC void mpf_trunc __GMP_PROTO ((mpf_ptr, mpf_srcptr)); - -#define mpf_ui_div __gmpf_ui_div -__GMP_DECLSPEC void mpf_ui_div __GMP_PROTO ((mpf_ptr, unsigned long int, mpf_srcptr)); - -#define mpf_ui_sub __gmpf_ui_sub -__GMP_DECLSPEC void mpf_ui_sub __GMP_PROTO ((mpf_ptr, unsigned long int, mpf_srcptr)); - -#define mpf_urandomb __gmpf_urandomb -__GMP_DECLSPEC void mpf_urandomb __GMP_PROTO ((mpf_t, gmp_randstate_t, mp_bitcnt_t)); - - -/************ Low level positive-integer (i.e. N) routines. ************/ - -/* This is ugly, but we need to make user calls reach the prefixed function. */ - -#define mpn_add __MPN(add) -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpn_add) -__GMP_DECLSPEC mp_limb_t mpn_add __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_srcptr,mp_size_t)); -#endif - -#define mpn_add_1 __MPN(add_1) -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpn_add_1) -__GMP_DECLSPEC mp_limb_t mpn_add_1 __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_limb_t)) __GMP_NOTHROW; -#endif - -#define mpn_add_n __MPN(add_n) -__GMP_DECLSPEC mp_limb_t mpn_add_n __GMP_PROTO ((mp_ptr, mp_srcptr, mp_srcptr, mp_size_t)); - -#define mpn_addmul_1 __MPN(addmul_1) -__GMP_DECLSPEC mp_limb_t mpn_addmul_1 __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_limb_t)); - -#define mpn_bdivmod __MPN(bdivmod) -__GMP_DECLSPEC mp_limb_t mpn_bdivmod __GMP_PROTO ((mp_ptr, mp_ptr, mp_size_t, mp_srcptr, mp_size_t, unsigned long int)); - -#define mpn_divrem __MPN(divrem) -__GMP_DECLSPEC mp_limb_t mpn_divrem __GMP_PROTO ((mp_ptr, mp_size_t, mp_ptr, mp_size_t, mp_srcptr, mp_size_t)); - -#define mpn_mulmod_2expp1 __MPN(mulmod_2expp1) -__GMP_DECLSPEC int mpn_mulmod_2expp1 __GMP_PROTO ((mp_ptr, mp_srcptr, mp_srcptr,int,unsigned long, mp_ptr)); - -#define mpn_mulmod_2expm1 __MPN(mulmod_2expm1) -__GMP_DECLSPEC void mpn_mulmod_2expm1 __GMP_PROTO ((mp_ptr, mp_ptr, mp_ptr,unsigned long, mp_ptr)); - -#define mpn_cmp __MPN(cmp) -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpn_cmp) -__GMP_DECLSPEC int mpn_cmp __GMP_PROTO ((mp_srcptr, mp_srcptr, mp_size_t)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#endif - -#define mpn_divexact_by3(dst,src,size) \ - mpn_divexact_by3c (dst, src, size, __GMP_CAST (mp_limb_t, 0)) - -#define mpn_divexact_by3c __MPN(divexact_by3c) -__GMP_DECLSPEC mp_limb_t mpn_divexact_by3c __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_limb_t)); - -#define mpn_divmod_1(qp,np,nsize,dlimb) \ - mpn_divrem_1 (qp, __GMP_CAST (mp_size_t, 0), np, nsize, dlimb) - -#define mpn_divrem_1 __MPN(divrem_1) -__GMP_DECLSPEC mp_limb_t mpn_divrem_1 __GMP_PROTO ((mp_ptr, mp_size_t, mp_srcptr, mp_size_t, mp_limb_t)); - -#define mpn_divrem_2 __MPN(divrem_2) -__GMP_DECLSPEC mp_limb_t mpn_divrem_2 __GMP_PROTO ((mp_ptr, mp_size_t, mp_ptr, mp_size_t, mp_srcptr)); - -#define mpn_invert __MPN(invert) -__GMP_DECLSPEC void mpn_invert __GMP_PROTO ((mp_ptr xp, mp_srcptr ap, mp_size_t n)); - -#define mpn_sb_divappr_q __MPN(sb_divappr_q) -__GMP_DECLSPEC mp_limb_t mpn_sb_divappr_q __GMP_PROTO ((mp_ptr qp, mp_ptr np, mp_size_t nn, - mp_srcptr dp, mp_size_t dn, mp_limb_t dip)); - -#define mpn_dc_divappr_q_n __MPN(dc_divappr_q_n) -__GMP_DECLSPEC mp_limb_t mpn_dc_divappr_q_n __GMP_PROTO ((mp_ptr qp, mp_ptr np, mp_srcptr dp, mp_size_t n, - mp_limb_t dip, mp_ptr tp)); - -#define mpn_dc_bdiv_q_n __MPN(dc_bdiv_q_n) -__GMP_DECLSPEC void mpn_dc_bdiv_q_n __GMP_PROTO ((mp_ptr qp, mp_ptr wp, mp_ptr np, mp_srcptr dp, mp_size_t n, - mp_limb_t dinv, mp_ptr scratch)); - -#define mpn_inv_divappr_q_n __MPN(inv_divappr_q_n) -__GMP_DECLSPEC mp_limb_t mpn_inv_divappr_q_n __GMP_PROTO ((mp_ptr qp, mp_ptr np, mp_srcptr dp, mp_size_t n, - mp_srcptr dip)); - -#define mpn_dc_divappr_q __MPN(dc_divappr_q) -__GMP_DECLSPEC mp_limb_t mpn_dc_divappr_q __GMP_PROTO ((mp_ptr qp, mp_ptr np, mp_size_t nn, mp_srcptr dp, mp_size_t n, - mp_limb_t dinv)); - -#define mpn_dc_div_q __MPN(dc_div_q) -__GMP_DECLSPEC mp_limb_t mpn_dc_div_q __GMP_PROTO ((mp_ptr qp, mp_ptr np, mp_size_t nn, - mp_srcptr dp, mp_size_t dn, mp_limb_t dinv)); - -#define mpn_inv_divappr_q __MPN(inv_divappr_q) -__GMP_DECLSPEC mp_limb_t mpn_inv_divappr_q __GMP_PROTO ((mp_ptr qp, mp_ptr np, mp_size_t nn, mp_srcptr dp, mp_size_t n, - mp_srcptr dinv)); - -#define mpn_inv_div_q __MPN(inv_div_q) -__GMP_DECLSPEC mp_limb_t mpn_inv_div_q __GMP_PROTO ((mp_ptr qp, mp_ptr np, mp_size_t nn, - mp_srcptr dp, mp_size_t dn, mp_srcptr dinv)); - -#define mpn_inv_div_qr __MPN(inv_div_qr) -__GMP_DECLSPEC mp_limb_t mpn_inv_div_qr __GMP_PROTO ((mp_ptr qp, mp_ptr np, mp_size_t nn, - mp_srcptr dp, mp_size_t dn, mp_srcptr dinv)); - -#define mpn_inv_div_qr_n __MPN(inv_div_qr_n) -__GMP_DECLSPEC mp_limb_t mpn_inv_div_qr_n __GMP_PROTO ((mp_ptr qp, mp_ptr np, - mp_srcptr dp, mp_size_t dn, mp_srcptr dinv)); - -#define mpn_dc_div_qr __MPN(dc_div_qr) -__GMP_DECLSPEC mp_limb_t mpn_dc_div_qr __GMP_PROTO ((mp_ptr qp, mp_ptr np, mp_size_t nn, - mp_srcptr dp, mp_size_t dn, mp_limb_t dinv)); - -#define mpn_dc_div_qr_n __MPN(dc_div_qr_n) -__GMP_DECLSPEC mp_limb_t mpn_dc_div_qr_n __GMP_PROTO ((mp_ptr qp, mp_ptr np, mp_srcptr dp, mp_size_t n, - mp_limb_t dinv, mp_ptr tp)); - -#define mpn_sb_div_q __MPN(sb_div_q) -__GMP_DECLSPEC mp_limb_t mpn_sb_div_q __GMP_PROTO ((mp_ptr qp, mp_ptr np, mp_size_t nn, - mp_srcptr dp, mp_size_t dn, mp_limb_t dinv)); - -#define mpn_sb_bdiv_q __MPN(sb_bdiv_q) -__GMP_DECLSPEC void mpn_sb_bdiv_q __GMP_PROTO ((mp_ptr qp, mp_ptr wp, mp_ptr np, mp_size_t nn, - mp_srcptr dp, mp_size_t dn, mp_limb_t dinv)); - -#define mpn_dc_bdiv_q __MPN(dc_bdiv_q) -__GMP_DECLSPEC void mpn_dc_bdiv_q __GMP_PROTO ((mp_ptr qp, mp_ptr np, mp_size_t nn, - mp_srcptr dp, mp_size_t dn, mp_limb_t dinv)); - -#define mpn_dc_bdiv_qr __MPN(dc_bdiv_qr) -__GMP_DECLSPEC mp_limb_t mpn_dc_bdiv_qr __GMP_PROTO ((mp_ptr qp, mp_ptr np, mp_size_t nn, - mp_srcptr dp, mp_size_t dn, mp_limb_t dinv)); - -#define mpn_dc_bdiv_qr_n __MPN(dc_bdiv_qr_n) -__GMP_DECLSPEC mp_limb_t mpn_dc_bdiv_qr_n __GMP_PROTO ((mp_ptr qp, mp_ptr np, - mp_srcptr dp, mp_size_t n, mp_limb_t dinv, mp_ptr tp)); - -#define mpn_sb_div_qr __MPN(sb_div_qr) -__GMP_DECLSPEC mp_limb_t mpn_sb_div_qr __GMP_PROTO ((mp_ptr qp, mp_ptr np, mp_size_t nn, - mp_srcptr dp, mp_size_t dn, mp_limb_t dinv)); - -#define mpn_sb_bdiv_qr __MPN(sb_bdiv_qr) -__GMP_DECLSPEC mp_limb_t mpn_sb_bdiv_qr __GMP_PROTO ((mp_ptr qp, mp_ptr np, mp_size_t nn, - mp_srcptr dp, mp_size_t dn, mp_limb_t dinv)); - -#define mpn_tdiv_q __MPN(tdiv_q) -__GMP_DECLSPEC void mpn_tdiv_q __GMP_PROTO ((mp_ptr qp, mp_srcptr np, mp_size_t nn, - mp_srcptr dp, mp_size_t dn)); - -#define mpn_divexact __MPN(divexact) -__GMP_DECLSPEC void mpn_divexact __GMP_PROTO ((mp_ptr qp, - mp_srcptr np, mp_size_t nn, mp_srcptr dp, mp_size_t dn)); - -#define mpn_gcd __MPN(gcd) -__GMP_DECLSPEC mp_size_t mpn_gcd __GMP_PROTO ((mp_ptr, mp_ptr, mp_size_t, mp_ptr, mp_size_t)); - -#define mpn_gcd_1 __MPN(gcd_1) -__GMP_DECLSPEC mp_limb_t mpn_gcd_1 __GMP_PROTO ((mp_srcptr, mp_size_t, mp_limb_t)) __GMP_ATTRIBUTE_PURE; - -#define mpn_gcdext __MPN(gcdext) -__GMP_DECLSPEC mp_size_t mpn_gcdext __GMP_PROTO ((mp_ptr, mp_ptr, mp_size_t *, mp_ptr, mp_size_t, mp_ptr, mp_size_t)); - -#define mpn_get_str __MPN(get_str) -__GMP_DECLSPEC size_t mpn_get_str __GMP_PROTO ((unsigned char *, int, mp_ptr, mp_size_t)); - -#define mpn_hamdist __MPN(hamdist) -__GMP_DECLSPEC mp_bitcnt_t mpn_hamdist __GMP_PROTO ((mp_srcptr, mp_srcptr, mp_size_t)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpn_lshift __MPN(lshift) -__GMP_DECLSPEC mp_limb_t mpn_lshift __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, unsigned int)); - -#define mpn_mod_1 __MPN(mod_1) -__GMP_DECLSPEC mp_limb_t mpn_mod_1 __GMP_PROTO ((mp_srcptr, mp_size_t, mp_limb_t)) __GMP_ATTRIBUTE_PURE; - -#define mpn_mul __MPN(mul) -__GMP_DECLSPEC mp_limb_t mpn_mul __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t)); - -#define mpn_mul_1 __MPN(mul_1) -__GMP_DECLSPEC mp_limb_t mpn_mul_1 __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_limb_t)); - -#define mpn_mul_n __MPN(mul_n) -__GMP_DECLSPEC void mpn_mul_n __GMP_PROTO ((mp_ptr, mp_srcptr, mp_srcptr, mp_size_t)); - -#define mpn_sqr __MPN(sqr) -__GMP_DECLSPEC void mpn_sqr __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t)); - -#define mpn_neg_n __MPN(neg_n) -#define mpn_neg __MPN(neg_n) -__GMP_DECLSPEC mp_limb_t mpn_neg_n __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t)); - -#define mpn_com_n __MPN(com_n) -#define mpn_com __MPN(com_n) -__GMP_DECLSPEC void mpn_com_n __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t)); - -#define mpn_perfect_square_p __MPN(perfect_square_p) -__GMP_DECLSPEC int mpn_perfect_square_p __GMP_PROTO ((mp_srcptr, mp_size_t)) __GMP_ATTRIBUTE_PURE; - -#define mpn_popcount __MPN(popcount) -__GMP_DECLSPEC mp_bitcnt_t mpn_popcount __GMP_PROTO ((mp_srcptr, mp_size_t)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpn_pow_1 __MPN(pow_1) -__GMP_DECLSPEC mp_size_t mpn_pow_1 __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_limb_t, mp_ptr)); - -/* undocumented now, but retained here for upward compatibility */ -#define mpn_preinv_mod_1 __MPN(preinv_mod_1) -__GMP_DECLSPEC mp_limb_t mpn_preinv_mod_1 __GMP_PROTO ((mp_srcptr, mp_size_t, mp_limb_t, mp_limb_t)) __GMP_ATTRIBUTE_PURE; - -#define mpn_random __MPN(random) -__GMP_DECLSPEC void mpn_random __GMP_PROTO ((mp_ptr, mp_size_t)); - -#define mpn_random2 __MPN(random2) -__GMP_DECLSPEC void mpn_random2 __GMP_PROTO ((mp_ptr, mp_size_t)); - -#define mpn_urandomb __MPN(urandomb) -__GMP_DECLSPEC void mpn_urandomb __GMP_PROTO ((mp_ptr, gmp_randstate_t, unsigned long)); - -#define mpn_urandomm __MPN(urandomm) -__GMP_DECLSPEC void mpn_urandomm __GMP_PROTO ((mp_ptr, gmp_randstate_t, mp_srcptr, mp_size_t)); - -#define mpn_randomb __MPN(randomb) -__GMP_DECLSPEC void mpn_randomb __GMP_PROTO ((mp_ptr, gmp_randstate_t, mp_size_t)); - -#define mpn_rrandom __MPN(rrandom) -__GMP_DECLSPEC void mpn_rrandom __GMP_PROTO ((mp_ptr, gmp_randstate_t, mp_size_t)); - -#define mpn_rshift __MPN(rshift) -__GMP_DECLSPEC mp_limb_t mpn_rshift __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, unsigned int)); - -#define mpn_scan0 __MPN(scan0) -__GMP_DECLSPEC mp_bitcnt_t mpn_scan0 __GMP_PROTO ((mp_srcptr, mp_bitcnt_t)) __GMP_ATTRIBUTE_PURE; - -#define mpn_scan1 __MPN(scan1) -__GMP_DECLSPEC mp_bitcnt_t mpn_scan1 __GMP_PROTO ((mp_srcptr, mp_bitcnt_t)) __GMP_ATTRIBUTE_PURE; - -#define mpn_set_str __MPN(set_str) -__GMP_DECLSPEC mp_size_t mpn_set_str __GMP_PROTO ((mp_ptr, __gmp_const unsigned char *, size_t, int)); - -#define mpn_sqrtrem __MPN(sqrtrem) -__GMP_DECLSPEC mp_size_t mpn_sqrtrem __GMP_PROTO ((mp_ptr, mp_ptr, mp_srcptr, mp_size_t)); - -#define mpn_sub __MPN(sub) -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpn_sub) -__GMP_DECLSPEC mp_limb_t mpn_sub __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_srcptr,mp_size_t)); -#endif - -#define mpn_sub_1 __MPN(sub_1) -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpn_sub_1) -__GMP_DECLSPEC mp_limb_t mpn_sub_1 __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_limb_t)) __GMP_NOTHROW; -#endif - -#define mpn_sub_n __MPN(sub_n) -__GMP_DECLSPEC mp_limb_t mpn_sub_n __GMP_PROTO ((mp_ptr, mp_srcptr, mp_srcptr, mp_size_t)); - -#define mpn_submul_1 __MPN(submul_1) -__GMP_DECLSPEC mp_limb_t mpn_submul_1 __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_limb_t)); - -#define mpn_tdiv_qr __MPN(tdiv_qr) -__GMP_DECLSPEC void mpn_tdiv_qr __GMP_PROTO ((mp_ptr, mp_ptr, mp_size_t, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t)); - -#define mpn_and_n __MPN(and_n) -__GMP_DECLSPEC void mpn_and_n __GMP_PROTO ((mp_ptr, mp_srcptr, mp_srcptr, mp_size_t)); -#define mpn_andn_n __MPN(andn_n) -__GMP_DECLSPEC void mpn_andn_n __GMP_PROTO ((mp_ptr, mp_srcptr, mp_srcptr, mp_size_t)); -#define mpn_nand_n __MPN(nand_n) -__GMP_DECLSPEC void mpn_nand_n __GMP_PROTO ((mp_ptr, mp_srcptr, mp_srcptr, mp_size_t)); -#define mpn_ior_n __MPN(ior_n) -__GMP_DECLSPEC void mpn_ior_n __GMP_PROTO ((mp_ptr, mp_srcptr, mp_srcptr, mp_size_t)); -#define mpn_iorn_n __MPN(iorn_n) -__GMP_DECLSPEC void mpn_iorn_n __GMP_PROTO ((mp_ptr, mp_srcptr, mp_srcptr, mp_size_t)); -#define mpn_nior_n __MPN(nior_n) -__GMP_DECLSPEC void mpn_nior_n __GMP_PROTO ((mp_ptr, mp_srcptr, mp_srcptr, mp_size_t)); -#define mpn_xor_n __MPN(xor_n) -__GMP_DECLSPEC void mpn_xor_n __GMP_PROTO ((mp_ptr, mp_srcptr, mp_srcptr, mp_size_t)); -#define mpn_xnor_n __MPN(xnor_n) -__GMP_DECLSPEC void mpn_xnor_n __GMP_PROTO ((mp_ptr, mp_srcptr, mp_srcptr, mp_size_t)); - -#define mpn_copyi __MPN(copyi) -__GMP_DECLSPEC void mpn_copyi __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t)); -#define mpn_copyd __MPN(copyd) -__GMP_DECLSPEC void mpn_copyd __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t)); -#define mpn_zero __MPN(zero) -__GMP_DECLSPEC void mpn_zero __GMP_PROTO ((mp_ptr, mp_size_t)); - -/**************** mpz inlines ****************/ - -/* The following are provided as inlines where possible, but always exist as - library functions too, for binary compatibility. - - Within gmp itself this inlining generally isn't relied on, since it - doesn't get done for all compilers, whereas if something is worth - inlining then it's worth arranging always. - - There are two styles of inlining here. When the same bit of code is - wanted for the inline as for the library version, then __GMP_FORCE_foo - arranges for that code to be emitted and the __GMP_EXTERN_INLINE - directive suppressed, eg. mpz_fits_uint_p. When a different bit of code - is wanted for the inline than for the library version, then - __GMP_FORCE_foo arranges the inline to be suppressed, eg. mpz_abs. */ - -#if defined (__GMP_EXTERN_INLINE) && ! defined (__GMP_FORCE_mpz_abs) -__GMP_EXTERN_INLINE void -mpz_abs (mpz_ptr __gmp_w, mpz_srcptr __gmp_u) -{ - if (__gmp_w != __gmp_u) - mpz_set (__gmp_w, __gmp_u); - __gmp_w->_mp_size = __GMP_ABS (__gmp_w->_mp_size); -} -#endif - -#if GMP_NAIL_BITS == 0 -#define __GMPZ_FITS_UTYPE_P(z,maxval) \ - mp_size_t __gmp_n = z->_mp_size; \ - mp_ptr __gmp_p = z->_mp_d; \ - return (__gmp_n == 0 || (__gmp_n == 1 && __gmp_p[0] <= maxval)); -#else -#define __GMPZ_FITS_UTYPE_P(z,maxval) \ - mp_size_t __gmp_n = z->_mp_size; \ - mp_ptr __gmp_p = z->_mp_d; \ - return (__gmp_n == 0 || (__gmp_n == 1 && __gmp_p[0] <= maxval) \ - || (__gmp_n == 2 && __gmp_p[1] <= ((mp_limb_t) maxval >> GMP_NUMB_BITS))); -#endif - -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_fits_uint_p) -#if ! defined (__GMP_FORCE_mpz_fits_uint_p) -__GMP_EXTERN_INLINE -#endif -int -mpz_fits_uint_p (mpz_srcptr __gmp_z) __GMP_NOTHROW -{ - __GMPZ_FITS_UTYPE_P (__gmp_z, __GMP_UINT_MAX); -} -#endif - -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_fits_ulong_p) -#if ! defined (__GMP_FORCE_mpz_fits_ulong_p) -__GMP_EXTERN_INLINE -#endif -int -mpz_fits_ulong_p (mpz_srcptr __gmp_z) __GMP_NOTHROW -{ - __GMPZ_FITS_UTYPE_P (__gmp_z, __GMP_ULONG_MAX); -} -#endif - -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_fits_ushort_p) -#if ! defined (__GMP_FORCE_mpz_fits_ushort_p) -__GMP_EXTERN_INLINE -#endif -int -mpz_fits_ushort_p (mpz_srcptr __gmp_z) __GMP_NOTHROW -{ - __GMPZ_FITS_UTYPE_P (__gmp_z, __GMP_USHRT_MAX); -} -#endif - -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_get_ui) -#if ! defined (__GMP_FORCE_mpz_get_ui) -__GMP_EXTERN_INLINE -#endif -unsigned long -mpz_get_ui (mpz_srcptr __gmp_z) __GMP_NOTHROW -{ - mp_ptr __gmp_p = __gmp_z->_mp_d; - mp_size_t __gmp_n = __gmp_z->_mp_size; - mp_limb_t __gmp_l = __gmp_p[0]; - /* This is a "#if" rather than a plain "if" so as to avoid gcc warnings - about "<< GMP_NUMB_BITS" exceeding the type size, and to avoid Borland - C++ 6.0 warnings about condition always true for something like - "__GMP_ULONG_MAX < GMP_NUMB_MASK". */ -#if GMP_NAIL_BITS == 0 || defined (_LONG_LONG_LIMB) - /* limb==long and no nails, or limb==longlong, one limb is enough */ - return (__gmp_n != 0 ? __gmp_l : 0); -#else - /* limb==long and nails, need two limbs when available */ - __gmp_n = __GMP_ABS (__gmp_n); - if (__gmp_n <= 1) - return (__gmp_n != 0 ? __gmp_l : 0); - else - return __gmp_l + (__gmp_p[1] << GMP_NUMB_BITS); -#endif -} -#endif - -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_getlimbn) -#if ! defined (__GMP_FORCE_mpz_getlimbn) -__GMP_EXTERN_INLINE -#endif -mp_limb_t -mpz_getlimbn (mpz_srcptr __gmp_z, mp_size_t __gmp_n) __GMP_NOTHROW -{ - mp_limb_t __gmp_result = 0; - if (__GMP_LIKELY (__gmp_n >= 0 && __gmp_n < __GMP_ABS (__gmp_z->_mp_size))) - __gmp_result = __gmp_z->_mp_d[__gmp_n]; - return __gmp_result; -} -#endif - -#if defined (__GMP_EXTERN_INLINE) && ! defined (__GMP_FORCE_mpz_neg) -__GMP_EXTERN_INLINE void -mpz_neg (mpz_ptr __gmp_w, mpz_srcptr __gmp_u) -{ - if (__gmp_w != __gmp_u) - mpz_set (__gmp_w, __gmp_u); - __gmp_w->_mp_size = - __gmp_w->_mp_size; -} -#endif - -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_perfect_square_p) -#if ! defined (__GMP_FORCE_mpz_perfect_square_p) -__GMP_EXTERN_INLINE -#endif -int -mpz_perfect_square_p (mpz_srcptr __gmp_a) -{ - mp_size_t __gmp_asize; - int __gmp_result; - - __gmp_asize = __gmp_a->_mp_size; - __gmp_result = (__gmp_asize >= 0); /* zero is a square, negatives are not */ - if (__GMP_LIKELY (__gmp_asize > 0)) - __gmp_result = mpn_perfect_square_p (__gmp_a->_mp_d, __gmp_asize); - return __gmp_result; -} -#endif - -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_popcount) -#if ! defined (__GMP_FORCE_mpz_popcount) -__GMP_EXTERN_INLINE -#endif -mp_bitcnt_t -mpz_popcount (mpz_srcptr __gmp_u) __GMP_NOTHROW -{ - mp_size_t __gmp_usize; - mp_bitcnt_t __gmp_result; - - __gmp_usize = __gmp_u->_mp_size; - __gmp_result = (__gmp_usize < 0 ? __GMP_ULONG_MAX : 0); - if (__GMP_LIKELY (__gmp_usize > 0)) - __gmp_result = mpn_popcount (__gmp_u->_mp_d, __gmp_usize); - return __gmp_result; -} -#endif - -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_set_q) -#if ! defined (__GMP_FORCE_mpz_set_q) -__GMP_EXTERN_INLINE -#endif -void -mpz_set_q (mpz_ptr __gmp_w, mpq_srcptr __gmp_u) -{ - mpz_tdiv_q (__gmp_w, mpq_numref (__gmp_u), mpq_denref (__gmp_u)); -} -#endif - -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_size) -#if ! defined (__GMP_FORCE_mpz_size) -__GMP_EXTERN_INLINE -#endif -size_t -mpz_size (mpz_srcptr __gmp_z) __GMP_NOTHROW -{ - return __GMP_ABS (__gmp_z->_mp_size); -} -#endif - - -/**************** mpq inlines ****************/ - -#if defined (__GMP_EXTERN_INLINE) && ! defined (__GMP_FORCE_mpq_abs) -__GMP_EXTERN_INLINE void -mpq_abs (mpq_ptr __gmp_w, mpq_srcptr __gmp_u) -{ - if (__gmp_w != __gmp_u) - mpq_set (__gmp_w, __gmp_u); - __gmp_w->_mp_num._mp_size = __GMP_ABS (__gmp_w->_mp_num._mp_size); -} -#endif - -#if defined (__GMP_EXTERN_INLINE) && ! defined (__GMP_FORCE_mpq_neg) -__GMP_EXTERN_INLINE void -mpq_neg (mpq_ptr __gmp_w, mpq_srcptr __gmp_u) -{ - if (__gmp_w != __gmp_u) - mpq_set (__gmp_w, __gmp_u); - __gmp_w->_mp_num._mp_size = - __gmp_w->_mp_num._mp_size; -} -#endif - - -/**************** mpn inlines ****************/ - -/* The comments with __GMPN_ADD_1 below apply here too. - - The test for FUNCTION returning 0 should predict well. If it's assumed - {yp,ysize} will usually have a random number of bits then the high limb - won't be full and a carry out will occur a good deal less than 50% of the - time. - - ysize==0 isn't a documented feature, but is used internally in a few - places. - - Producing cout last stops it using up a register during the main part of - the calculation, though gcc (as of 3.0) on an "if (mpn_add (...))" - doesn't seem able to move the true and false legs of the conditional up - to the two places cout is generated. */ - -#define __GMPN_AORS(cout, wp, xp, xsize, yp, ysize, FUNCTION, TEST) \ - do { \ - mp_size_t __gmp_i; \ - mp_limb_t __gmp_x; \ - \ - /* ASSERT ((ysize) >= 0); */ \ - /* ASSERT ((xsize) >= (ysize)); */ \ - /* ASSERT (MPN_SAME_OR_SEPARATE2_P (wp, xsize, xp, xsize)); */ \ - /* ASSERT (MPN_SAME_OR_SEPARATE2_P (wp, xsize, yp, ysize)); */ \ - \ - __gmp_i = (ysize); \ - if (__gmp_i != 0) \ - { \ - if (FUNCTION (wp, xp, yp, __gmp_i)) \ - { \ - do \ - { \ - if (__gmp_i >= (xsize)) \ - { \ - (cout) = 1; \ - goto __gmp_done; \ - } \ - __gmp_x = (xp)[__gmp_i]; \ - } \ - while (TEST); \ - } \ - } \ - if ((wp) != (xp)) \ - __GMPN_COPY_REST (wp, xp, xsize, __gmp_i); \ - (cout) = 0; \ - __gmp_done: \ - ; \ - } while (0) - -#define __GMPN_ADD(cout, wp, xp, xsize, yp, ysize) \ - __GMPN_AORS (cout, wp, xp, xsize, yp, ysize, mpn_add_n, \ - (((wp)[__gmp_i++] = (__gmp_x + 1) & GMP_NUMB_MASK) == 0)) -#define __GMPN_SUB(cout, wp, xp, xsize, yp, ysize) \ - __GMPN_AORS (cout, wp, xp, xsize, yp, ysize, mpn_sub_n, \ - (((wp)[__gmp_i++] = (__gmp_x - 1) & GMP_NUMB_MASK), __gmp_x == 0)) - - -/* The use of __gmp_i indexing is designed to ensure a compile time src==dst - remains nice and clear to the compiler, so that __GMPN_COPY_REST can - disappear, and the load/add/store gets a chance to become a - read-modify-write on CISC CPUs. - - Alternatives: - - Using a pair of pointers instead of indexing would be possible, but gcc - isn't able to recognise compile-time src==dst in that case, even when the - pointers are incremented more or less together. Other compilers would - very likely have similar difficulty. - - gcc could use "if (__builtin_constant_p(src==dst) && src==dst)" or - similar to detect a compile-time src==dst. This works nicely on gcc - 2.95.x, it's not good on gcc 3.0 where __builtin_constant_p(p==p) seems - to be always false, for a pointer p. But the current code form seems - good enough for src==dst anyway. - - gcc on x86 as usual doesn't give particularly good flags handling for the - carry/borrow detection. It's tempting to want some multi instruction asm - blocks to help it, and this was tried, but in truth there's only a few - instructions to save and any gain is all too easily lost by register - juggling setting up for the asm. */ - -#if GMP_NAIL_BITS == 0 -#define __GMPN_AORS_1(cout, dst, src, n, v, OP, CB) \ - do { \ - mp_size_t __gmp_i; \ - mp_limb_t __gmp_x, __gmp_r; \ - \ - /* ASSERT ((n) >= 1); */ \ - /* ASSERT (MPN_SAME_OR_SEPARATE_P (dst, src, n)); */ \ - \ - __gmp_x = (src)[0]; \ - __gmp_r = __gmp_x OP (v); \ - (dst)[0] = __gmp_r; \ - if (CB (__gmp_r, __gmp_x, (v))) \ - { \ - (cout) = 1; \ - for (__gmp_i = 1; __gmp_i < (n);) \ - { \ - __gmp_x = (src)[__gmp_i]; \ - __gmp_r = __gmp_x OP 1; \ - (dst)[__gmp_i] = __gmp_r; \ - ++__gmp_i; \ - if (!CB (__gmp_r, __gmp_x, 1)) \ - { \ - if ((src) != (dst)) \ - __GMPN_COPY_REST (dst, src, n, __gmp_i); \ - (cout) = 0; \ - break; \ - } \ - } \ - } \ - else \ - { \ - if ((src) != (dst)) \ - __GMPN_COPY_REST (dst, src, n, 1); \ - (cout) = 0; \ - } \ - } while (0) -#endif - -#if GMP_NAIL_BITS >= 1 -#define __GMPN_AORS_1(cout, dst, src, n, v, OP, CB) \ - do { \ - mp_size_t __gmp_i; \ - mp_limb_t __gmp_x, __gmp_r; \ - \ - /* ASSERT ((n) >= 1); */ \ - /* ASSERT (MPN_SAME_OR_SEPARATE_P (dst, src, n)); */ \ - \ - __gmp_x = (src)[0]; \ - __gmp_r = __gmp_x OP (v); \ - (dst)[0] = __gmp_r & GMP_NUMB_MASK; \ - if (__gmp_r >> GMP_NUMB_BITS != 0) \ - { \ - (cout) = 1; \ - for (__gmp_i = 1; __gmp_i < (n);) \ - { \ - __gmp_x = (src)[__gmp_i]; \ - __gmp_r = __gmp_x OP 1; \ - (dst)[__gmp_i] = __gmp_r & GMP_NUMB_MASK; \ - ++__gmp_i; \ - if (__gmp_r >> GMP_NUMB_BITS == 0) \ - { \ - if ((src) != (dst)) \ - __GMPN_COPY_REST (dst, src, n, __gmp_i); \ - (cout) = 0; \ - break; \ - } \ - } \ - } \ - else \ - { \ - if ((src) != (dst)) \ - __GMPN_COPY_REST (dst, src, n, 1); \ - (cout) = 0; \ - } \ - } while (0) -#endif - -#define __GMPN_ADDCB(r,x,y) ((r) < (y)) -#define __GMPN_SUBCB(r,x,y) ((x) < (y)) - -#define __GMPN_ADD_1(cout, dst, src, n, v) \ - __GMPN_AORS_1(cout, dst, src, n, v, +, __GMPN_ADDCB) -#define __GMPN_SUB_1(cout, dst, src, n, v) \ - __GMPN_AORS_1(cout, dst, src, n, v, -, __GMPN_SUBCB) - - -/* Compare {xp,size} and {yp,size}, setting "result" to positive, zero or - negative. size==0 is allowed. On random data usually only one limb will - need to be examined to get a result, so it's worth having it inline. */ -#define __GMPN_CMP(result, xp, yp, size) \ - do { \ - mp_size_t __gmp_i; \ - mp_limb_t __gmp_x, __gmp_y; \ - \ - /* ASSERT ((size) >= 0); */ \ - \ - (result) = 0; \ - __gmp_i = (size); \ - while (--__gmp_i >= 0) \ - { \ - __gmp_x = (xp)[__gmp_i]; \ - __gmp_y = (yp)[__gmp_i]; \ - if (__gmp_x != __gmp_y) \ - { \ - /* Cannot use __gmp_x - __gmp_y, may overflow an "int" */ \ - (result) = (__gmp_x > __gmp_y ? 1 : -1); \ - break; \ - } \ - } \ - } while (0) - - -#if defined (__GMPN_COPY) && ! defined (__GMPN_COPY_REST) -#define __GMPN_COPY_REST(dst, src, size, start) \ - do { \ - /* ASSERT ((start) >= 0); */ \ - /* ASSERT ((start) <= (size)); */ \ - __GMPN_COPY ((dst)+(start), (src)+(start), (size)-(start)); \ - } while (0) -#endif - -/* Copy {src,size} to {dst,size}, starting at "start". This is designed to - keep the indexing dst[j] and src[j] nice and simple for __GMPN_ADD_1, - __GMPN_ADD, etc. */ -#if ! defined (__GMPN_COPY_REST) -#define __GMPN_COPY_REST(dst, src, size, start) \ - do { \ - mp_size_t __gmp_j; \ - /* ASSERT ((size) >= 0); */ \ - /* ASSERT ((start) >= 0); */ \ - /* ASSERT ((start) <= (size)); */ \ - /* ASSERT (MPN_SAME_OR_SEPARATE_P (dst, src, size)); */ \ - __GMP_CRAY_Pragma ("_CRI ivdep"); \ - for (__gmp_j = (start); __gmp_j < (size); __gmp_j++) \ - (dst)[__gmp_j] = (src)[__gmp_j]; \ - } while (0) -#endif - -/* Enhancement: Use some of the smarter code from gmp-impl.h. Maybe use - mpn_copyi if there's a native version, and if we don't mind demanding - binary compatibility for it (on targets which use it). */ - -#if ! defined (__GMPN_COPY) -#define __GMPN_COPY(dst, src, size) __GMPN_COPY_REST (dst, src, size, 0) -#endif - - -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpn_add) -#if ! defined (__GMP_FORCE_mpn_add) -__GMP_EXTERN_INLINE -#endif -mp_limb_t -mpn_add (mp_ptr __gmp_wp, mp_srcptr __gmp_xp, mp_size_t __gmp_xsize, mp_srcptr __gmp_yp, mp_size_t __gmp_ysize) -{ - mp_limb_t __gmp_c; - __GMPN_ADD (__gmp_c, __gmp_wp, __gmp_xp, __gmp_xsize, __gmp_yp, __gmp_ysize); - return __gmp_c; -} -#endif - -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpn_add_1) -#if ! defined (__GMP_FORCE_mpn_add_1) -__GMP_EXTERN_INLINE -#endif -mp_limb_t -mpn_add_1 (mp_ptr __gmp_dst, mp_srcptr __gmp_src, mp_size_t __gmp_size, mp_limb_t __gmp_n) __GMP_NOTHROW -{ - mp_limb_t __gmp_c; - __GMPN_ADD_1 (__gmp_c, __gmp_dst, __gmp_src, __gmp_size, __gmp_n); - return __gmp_c; -} -#endif - -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpn_cmp) -#if ! defined (__GMP_FORCE_mpn_cmp) -__GMP_EXTERN_INLINE -#endif -int -mpn_cmp (mp_srcptr __gmp_xp, mp_srcptr __gmp_yp, mp_size_t __gmp_size) __GMP_NOTHROW -{ - int __gmp_result; - __GMPN_CMP (__gmp_result, __gmp_xp, __gmp_yp, __gmp_size); - return __gmp_result; -} -#endif - -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpn_sub) -#if ! defined (__GMP_FORCE_mpn_sub) -__GMP_EXTERN_INLINE -#endif -mp_limb_t -mpn_sub (mp_ptr __gmp_wp, mp_srcptr __gmp_xp, mp_size_t __gmp_xsize, mp_srcptr __gmp_yp, mp_size_t __gmp_ysize) -{ - mp_limb_t __gmp_c; - __GMPN_SUB (__gmp_c, __gmp_wp, __gmp_xp, __gmp_xsize, __gmp_yp, __gmp_ysize); - return __gmp_c; -} -#endif - -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpn_sub_1) -#if ! defined (__GMP_FORCE_mpn_sub_1) -__GMP_EXTERN_INLINE -#endif -mp_limb_t -mpn_sub_1 (mp_ptr __gmp_dst, mp_srcptr __gmp_src, mp_size_t __gmp_size, mp_limb_t __gmp_n) __GMP_NOTHROW -{ - mp_limb_t __gmp_c; - __GMPN_SUB_1 (__gmp_c, __gmp_dst, __gmp_src, __gmp_size, __gmp_n); - return __gmp_c; -} -#endif - -#if defined (__cplusplus) -} -#endif - - -/* Allow faster testing for negative, zero, and positive. */ -#define mpz_sgn(Z) ((Z)->_mp_size < 0 ? -1 : (Z)->_mp_size > 0) -#define mpf_sgn(F) ((F)->_mp_size < 0 ? -1 : (F)->_mp_size > 0) -#define mpq_sgn(Q) ((Q)->_mp_num._mp_size < 0 ? -1 : (Q)->_mp_num._mp_size > 0) - -/* When using GCC, optimize certain common comparisons. */ -#if defined (__GNUC__) -#define mpz_cmp_ui(Z,UI) \ - (__builtin_constant_p (UI) && (UI) == 0 \ - ? mpz_sgn (Z) : _mpz_cmp_ui (Z,UI)) -#define mpz_cmp_si(Z,SI) \ - (__builtin_constant_p (SI) && (SI) == 0 ? mpz_sgn (Z) \ - : __builtin_constant_p (SI) && (SI) > 0 \ - ? _mpz_cmp_ui (Z, __GMP_CAST (unsigned long int, SI)) \ - : _mpz_cmp_si (Z,SI)) -#define mpq_cmp_ui(Q,NUI,DUI) \ - (__builtin_constant_p (NUI) && (NUI) == 0 \ - ? mpq_sgn (Q) : _mpq_cmp_ui (Q,NUI,DUI)) -#define mpq_cmp_si(q,n,d) \ - (__builtin_constant_p ((n) >= 0) && (n) >= 0 \ - ? mpq_cmp_ui (q, __GMP_CAST (unsigned long, n), d) \ - : _mpq_cmp_si (q, n, d)) -#else -#define mpz_cmp_ui(Z,UI) _mpz_cmp_ui (Z,UI) -#define mpz_cmp_si(Z,UI) _mpz_cmp_si (Z,UI) -#define mpq_cmp_ui(Q,NUI,DUI) _mpq_cmp_ui (Q,NUI,DUI) -#define mpq_cmp_si(q,n,d) _mpq_cmp_si(q,n,d) -#endif - - -/* Using "&" rather than "&&" means these can come out branch-free. Every - mpz_t has at least one limb allocated, so fetching the low limb is always - allowed. */ -#define mpz_odd_p(z) (((z)->_mp_size != 0) & __GMP_CAST (int, (z)->_mp_d[0])) -#define mpz_even_p(z) (! mpz_odd_p (z)) - - -/**************** C++ routines ****************/ - -#ifdef __cplusplus -__GMP_DECLSPEC_XX std::ostream& operator<< (std::ostream &, mpz_srcptr); -__GMP_DECLSPEC_XX std::ostream& operator<< (std::ostream &, mpq_srcptr); -__GMP_DECLSPEC_XX std::ostream& operator<< (std::ostream &, mpf_srcptr); -__GMP_DECLSPEC_XX std::istream& operator>> (std::istream &, mpz_ptr); -__GMP_DECLSPEC_XX std::istream& operator>> (std::istream &, mpq_ptr); -__GMP_DECLSPEC_XX std::istream& operator>> (std::istream &, mpf_ptr); -#endif - -/* Source-level compatibility with GMP 1. */ -#define mpz_mdiv mpz_fdiv_q -#define mpz_mdivmod mpz_fdiv_qr -#define mpz_mmod mpz_fdiv_r -#define mpz_mdiv_ui mpz_fdiv_q_ui -#define mpz_mdivmod_ui(q,r,n,d) \ - (((r) == 0) ? mpz_fdiv_q_ui (q,n,d) : mpz_fdiv_qr_ui (q,r,n,d)) -#define mpz_mmod_ui(r,n,d) \ - (((r) == 0) ? mpz_fdiv_ui (n,d) : mpz_fdiv_r_ui (r,n,d)) - -#define gmp_randinit(x,y,z) gmp_randinit_lc_2exp_size(x,z) - -typedef __mpz_struct MP_INT; /* gmp 1 source compatibility */ -typedef __mpq_struct MP_RAT; /* gmp 1 source compatibility */ - -#define mpz_div mpz_fdiv_q -#define mpz_divmod mpz_fdiv_qr -#define mpz_div_ui mpz_fdiv_q_ui -#define mpz_divmod_ui mpz_fdiv_qr_ui -#define mpz_div_2exp mpz_fdiv_q_2exp -#define mpz_mod_2exp mpz_fdiv_r_2exp - -enum -{ - GMP_ERROR_NONE = 0, - GMP_ERROR_UNSUPPORTED_ARGUMENT = 1, - GMP_ERROR_DIVISION_BY_ZERO = 2, - GMP_ERROR_SQRT_OF_NEGATIVE = 4, - GMP_ERROR_INVALID_ARGUMENT = 8 -}; - -/* Major version number is the value of __GNU_MP__ too, above and in mp.h. */ -#define __GNU_MP_VERSION 5 -#define __GNU_MP_VERSION_MINOR 0 -#define __GNU_MP_VERSION_PATCHLEVEL 1 -#define GMP_VERSION "5.0.1" - -#define __MPIR_VERSION 2 -#define __MPIR_VERSION_MINOR 1 -#define __MPIR_VERSION_PATCHLEVEL 3 -#if defined( _MSC_VER ) -#define _MSC_MPIR_VERSION "2.1.3" -#endif - -/* These are for programs like MPFR to use the same CC and CFLAGS as MPIR */ - -#if ! defined (__GMP_WITHIN_CONFIGURE) -/* No __GMP_CC here as --enable-gmpcompat option not selected */ - -#define __MPIR_CC "gcc -std=gnu99" -#define __MPIR_CFLAGS "-mmacosx-version-min=10.5 -arch i386" -#endif - -#define __GMP_H__ -#endif /* __GMP_H__ */ diff --git a/src/external/inc/macx/mpir-2.1.3/mpirxx.h b/src/external/inc/macx/mpir-2.1.3/mpirxx.h deleted file mode 100644 index 3ad1dcf6f..000000000 --- a/src/external/inc/macx/mpir-2.1.3/mpirxx.h +++ /dev/null @@ -1,3403 +0,0 @@ -/* mpirxx.h -- C++ class wrapper for GMP types. -*- C++ -*- - -Copyright 2001, 2002, 2003, 2006, 2008 Free Software Foundation, Inc. - -Copyright 2009 William Hart - -This file is part of the GNU MP Library. - -The GNU MP Library is free software; you can redistribute it and/or modify -it under the terms of the GNU Lesser General Public License as published by -the Free Software Foundation; either version 3 of the License, or (at your -option) any later version. - -The GNU MP Library is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public -License for more details. - -You should have received a copy of the GNU Lesser General Public License -along with the GNU MP Library. If not, see http://www.gnu.org/licenses/. */ - -/* the C++ compiler must implement the following features: - - member templates - - partial specialization of templates - - namespace support - for g++, this means version 2.91 or higher - for other compilers, I don't know */ -#ifdef __GNUC__ -#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 91) -#error mpirxx.h requires g++ version 2.91 (egcs 1.1.2) or higher -#endif -#endif - -#ifndef __GMP_PLUSPLUS__ -#define __GMP_PLUSPLUS__ - -#include - -#include /* for strlen */ -#include -#include -#include -#include - - -/**************** Function objects ****************/ -/* Any evaluation of a __gmp_expr ends up calling one of these functions - all intermediate functions being inline, the evaluation should optimize - to a direct call to the relevant function, thus yielding no overhead - over the C interface. */ - -struct __gmp_unary_plus -{ - static void eval(mpz_ptr z, mpz_srcptr w) { mpz_set(z, w); } - static void eval(mpq_ptr q, mpq_srcptr r) { mpq_set(q, r); } - static void eval(mpf_ptr f, mpf_srcptr g) { mpf_set(f, g); } -}; - -struct __gmp_unary_minus -{ - static void eval(mpz_ptr z, mpz_srcptr w) { mpz_neg(z, w); } - static void eval(mpq_ptr q, mpq_srcptr r) { mpq_neg(q, r); } - static void eval(mpf_ptr f, mpf_srcptr g) { mpf_neg(f, g); } -}; - -struct __gmp_unary_com -{ - static void eval(mpz_ptr z, mpz_srcptr w) { mpz_com(z, w); } -}; - -struct __gmp_binary_plus -{ - static void eval(mpz_ptr z, mpz_srcptr w, mpz_srcptr v) - { mpz_add(z, w, v); } - - static void eval(mpz_ptr z, mpz_srcptr w, unsigned long int l) - { mpz_add_ui(z, w, l); } - static void eval(mpz_ptr z, unsigned long int l, mpz_srcptr w) - { mpz_add_ui(z, w, l); } - static void eval(mpz_ptr z, mpz_srcptr w, signed long int l) - { - if (l >= 0) - mpz_add_ui(z, w, l); - else - mpz_sub_ui(z, w, -l); - } - static void eval(mpz_ptr z, signed long int l, mpz_srcptr w) - { - if (l >= 0) - mpz_add_ui(z, w, l); - else - mpz_sub_ui(z, w, -l); - } - static void eval(mpz_ptr z, mpz_srcptr w, double d) - { - mpz_t temp; - mpz_init_set_d(temp, d); - mpz_add(z, w, temp); - mpz_clear(temp); - } - static void eval(mpz_ptr z, double d, mpz_srcptr w) - { - mpz_t temp; - mpz_init_set_d(temp, d); - mpz_add(z, temp, w); - mpz_clear(temp); - } - - static void eval(mpq_ptr q, mpq_srcptr r, mpq_srcptr s) - { mpq_add(q, r, s); } - - static void eval(mpq_ptr q, mpq_srcptr r, unsigned long int l) - { mpq_set(q, r); mpz_addmul_ui(mpq_numref(q), mpq_denref(q), l); } - static void eval(mpq_ptr q, unsigned long int l, mpq_srcptr r) - { mpq_set(q, r); mpz_addmul_ui(mpq_numref(q), mpq_denref(q), l); } - static void eval(mpq_ptr q, mpq_srcptr r, signed long int l) - { - mpq_set(q, r); - if (l >= 0) - mpz_addmul_ui(mpq_numref(q), mpq_denref(q), l); - else - mpz_submul_ui(mpq_numref(q), mpq_denref(q), -l); - } - static void eval(mpq_ptr q, signed long int l, mpq_srcptr r) - { - mpq_set(q, r); - if (l >= 0) - mpz_addmul_ui(mpq_numref(q), mpq_denref(q), l); - else - mpz_submul_ui(mpq_numref(q), mpq_denref(q), -l); - } - static void eval(mpq_ptr q, mpq_srcptr r, double d) - { - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - mpq_add(q, r, temp); - mpq_clear(temp); - } - static void eval(mpq_ptr q, double d, mpq_srcptr r) - { - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - mpq_add(q, temp, r); - mpq_clear(temp); - } - - static void eval(mpq_ptr q, mpq_srcptr r, mpz_srcptr z) - { mpq_set(q, r); mpz_addmul(mpq_numref(q), mpq_denref(q), z); } - static void eval(mpq_ptr q, mpz_srcptr z, mpq_srcptr r) - { mpq_set(q, r); mpz_addmul(mpq_numref(q), mpq_denref(q), z); } - - static void eval(mpf_ptr f, mpf_srcptr g, mpf_srcptr h) - { mpf_add(f, g, h); } - - static void eval(mpf_ptr f, mpf_srcptr g, unsigned long int l) - { mpf_add_ui(f, g, l); } - static void eval(mpf_ptr f, unsigned long int l, mpf_srcptr g) - { mpf_add_ui(f, g, l); } - static void eval(mpf_ptr f, mpf_srcptr g, signed long int l) - { - if (l >= 0) - mpf_add_ui(f, g, l); - else - mpf_sub_ui(f, g, -l); - } - static void eval(mpf_ptr f, signed long int l, mpf_srcptr g) - { - if (l >= 0) - mpf_add_ui(f, g, l); - else - mpf_sub_ui(f, g, -l); - } - static void eval(mpf_ptr f, mpf_srcptr g, double d) - { - mpf_t temp; - mpf_init2(temp, 8*sizeof(double)); - mpf_set_d(temp, d); - mpf_add(f, g, temp); - mpf_clear(temp); - } - static void eval(mpf_ptr f, double d, mpf_srcptr g) - { - mpf_t temp; - mpf_init2(temp, 8*sizeof(double)); - mpf_set_d(temp, d); - mpf_add(f, temp, g); - mpf_clear(temp); - } -}; - -struct __gmp_binary_minus -{ - static void eval(mpz_ptr z, mpz_srcptr w, mpz_srcptr v) - { mpz_sub(z, w, v); } - - static void eval(mpz_ptr z, mpz_srcptr w, unsigned long int l) - { mpz_sub_ui(z, w, l); } - static void eval(mpz_ptr z, unsigned long int l, mpz_srcptr w) - { mpz_ui_sub(z, l, w); } - static void eval(mpz_ptr z, mpz_srcptr w, signed long int l) - { - if (l >= 0) - mpz_sub_ui(z, w, l); - else - mpz_add_ui(z, w, -l); - } - static void eval(mpz_ptr z, signed long int l, mpz_srcptr w) - { - if (l >= 0) - mpz_ui_sub(z, l, w); - else - { - mpz_add_ui(z, w, -l); - mpz_neg(z, z); - } - } - static void eval(mpz_ptr z, mpz_srcptr w, double d) - { - mpz_t temp; - mpz_init_set_d(temp, d); - mpz_sub(z, w, temp); - mpz_clear(temp); - } - static void eval(mpz_ptr z, double d, mpz_srcptr w) - { - mpz_t temp; - mpz_init_set_d(temp, d); - mpz_sub(z, temp, w); - mpz_clear(temp); - } - - static void eval(mpq_ptr q, mpq_srcptr r, mpq_srcptr s) - { mpq_sub(q, r, s); } - - static void eval(mpq_ptr q, mpq_srcptr r, unsigned long int l) - { mpq_set(q, r); mpz_submul_ui(mpq_numref(q), mpq_denref(q), l); } - static void eval(mpq_ptr q, unsigned long int l, mpq_srcptr r) - { mpq_neg(q, r); mpz_addmul_ui(mpq_numref(q), mpq_denref(q), l); } - static void eval(mpq_ptr q, mpq_srcptr r, signed long int l) - { - mpq_set(q, r); - if (l >= 0) - mpz_submul_ui(mpq_numref(q), mpq_denref(q), l); - else - mpz_addmul_ui(mpq_numref(q), mpq_denref(q), -l); - } - static void eval(mpq_ptr q, signed long int l, mpq_srcptr r) - { - mpq_neg(q, r); - if (l >= 0) - mpz_addmul_ui(mpq_numref(q), mpq_denref(q), l); - else - mpz_submul_ui(mpq_numref(q), mpq_denref(q), -l); - } - static void eval(mpq_ptr q, mpq_srcptr r, double d) - { - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - mpq_sub(q, r, temp); - mpq_clear(temp); - } - static void eval(mpq_ptr q, double d, mpq_srcptr r) - { - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - mpq_sub(q, temp, r); - mpq_clear(temp); - } - - static void eval(mpq_ptr q, mpq_srcptr r, mpz_srcptr z) - { mpq_set(q, r); mpz_submul(mpq_numref(q), mpq_denref(q), z); } - static void eval(mpq_ptr q, mpz_srcptr z, mpq_srcptr r) - { mpq_neg(q, r); mpz_addmul(mpq_numref(q), mpq_denref(q), z); } - - static void eval(mpf_ptr f, mpf_srcptr g, mpf_srcptr h) - { mpf_sub(f, g, h); } - - static void eval(mpf_ptr f, mpf_srcptr g, unsigned long int l) - { mpf_sub_ui(f, g, l); } - static void eval(mpf_ptr f, unsigned long int l, mpf_srcptr g) - { mpf_ui_sub(f, l, g); } - static void eval(mpf_ptr f, mpf_srcptr g, signed long int l) - { - if (l >= 0) - mpf_sub_ui(f, g, l); - else - mpf_add_ui(f, g, -l); - } - static void eval(mpf_ptr f, signed long int l, mpf_srcptr g) - { - if (l >= 0) - mpf_sub_ui(f, g, l); - else - mpf_add_ui(f, g, -l); - mpf_neg(f, f); - } - static void eval(mpf_ptr f, mpf_srcptr g, double d) - { - mpf_t temp; - mpf_init2(temp, 8*sizeof(double)); - mpf_set_d(temp, d); - mpf_sub(f, g, temp); - mpf_clear(temp); - } - static void eval(mpf_ptr f, double d, mpf_srcptr g) - { - mpf_t temp; - mpf_init2(temp, 8*sizeof(double)); - mpf_set_d(temp, d); - mpf_sub(f, temp, g); - mpf_clear(temp); - } -}; - -struct __gmp_binary_multiplies -{ - static void eval(mpz_ptr z, mpz_srcptr w, mpz_srcptr v) - { mpz_mul(z, w, v); } - - static void eval(mpz_ptr z, mpz_srcptr w, unsigned long int l) - { mpz_mul_ui(z, w, l); } - static void eval(mpz_ptr z, unsigned long int l, mpz_srcptr w) - { mpz_mul_ui(z, w, l); } - static void eval(mpz_ptr z, mpz_srcptr w, signed long int l) - { mpz_mul_si (z, w, l); } - static void eval(mpz_ptr z, signed long int l, mpz_srcptr w) - { mpz_mul_si (z, w, l); } - static void eval(mpz_ptr z, mpz_srcptr w, double d) - { - mpz_t temp; - mpz_init_set_d(temp, d); - mpz_mul(z, w, temp); - mpz_clear(temp); - } - static void eval(mpz_ptr z, double d, mpz_srcptr w) - { - mpz_t temp; - mpz_init_set_d(temp, d); - mpz_mul(z, temp, w); - mpz_clear(temp); - } - - static void eval(mpq_ptr q, mpq_srcptr r, mpq_srcptr s) - { mpq_mul(q, r, s); } - - static void eval(mpq_ptr q, mpq_srcptr r, unsigned long int l) - { - mpq_t temp; - mpq_init(temp); - mpq_set_ui(temp, l, 1); - mpq_mul(q, r, temp); - mpq_clear(temp); - } - static void eval(mpq_ptr q, unsigned long int l, mpq_srcptr r) - { - mpq_t temp; - mpq_init(temp); - mpq_set_ui(temp, l, 1); - mpq_mul(q, temp, r); - mpq_clear(temp); - } - static void eval(mpq_ptr q, mpq_srcptr r, signed long int l) - { - mpq_t temp; - mpq_init(temp); - mpq_set_si(temp, l, 1); - mpq_mul(q, r, temp); - mpq_clear(temp); - } - static void eval(mpq_ptr q, signed long int l, mpq_srcptr r) - { - mpq_t temp; - mpq_init(temp); - mpq_set_si(temp, l, 1); - mpq_mul(q, temp, r); - mpq_clear(temp); - } - static void eval(mpq_ptr q, mpq_srcptr r, double d) - { - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - mpq_mul(q, r, temp); - mpq_clear(temp); - } - static void eval(mpq_ptr q, double d, mpq_srcptr r) - { - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - mpq_mul(q, temp, r); - mpq_clear(temp); - } - - static void eval(mpf_ptr f, mpf_srcptr g, mpf_srcptr h) - { mpf_mul(f, g, h); } - - static void eval(mpf_ptr f, mpf_srcptr g, unsigned long int l) - { mpf_mul_ui(f, g, l); } - static void eval(mpf_ptr f, unsigned long int l, mpf_srcptr g) - { mpf_mul_ui(f, g, l); } - static void eval(mpf_ptr f, mpf_srcptr g, signed long int l) - { - if (l >= 0) - mpf_mul_ui(f, g, l); - else - { - mpf_mul_ui(f, g, -l); - mpf_neg(f, f); - } - } - static void eval(mpf_ptr f, signed long int l, mpf_srcptr g) - { - if (l >= 0) - mpf_mul_ui(f, g, l); - else - { - mpf_mul_ui(f, g, -l); - mpf_neg(f, f); - } - } - static void eval(mpf_ptr f, mpf_srcptr g, double d) - { - mpf_t temp; - mpf_init2(temp, 8*sizeof(double)); - mpf_set_d(temp, d); - mpf_mul(f, g, temp); - mpf_clear(temp); - } - static void eval(mpf_ptr f, double d, mpf_srcptr g) - { - mpf_t temp; - mpf_init2(temp, 8*sizeof(double)); - mpf_set_d(temp, d); - mpf_mul(f, temp, g); - mpf_clear(temp); - } -}; - -struct __gmp_binary_divides -{ - static void eval(mpz_ptr z, mpz_srcptr w, mpz_srcptr v) - { mpz_tdiv_q(z, w, v); } - - static void eval(mpz_ptr z, mpz_srcptr w, unsigned long int l) - { mpz_tdiv_q_ui(z, w, l); } - static void eval(mpz_ptr z, unsigned long int l, mpz_srcptr w) - { - if (mpz_sgn(w) >= 0) - { - if (mpz_fits_ulong_p(w)) - mpz_set_ui(z, l / mpz_get_ui(w)); - else - mpz_set_ui(z, 0); - } - else - { - mpz_neg(z, w); - if (mpz_fits_ulong_p(z)) - { - mpz_set_ui(z, l / mpz_get_ui(z)); - mpz_neg(z, z); - } - else - mpz_set_ui(z, 0); - } - } - static void eval(mpz_ptr z, mpz_srcptr w, signed long int l) - { - if (l >= 0) - mpz_tdiv_q_ui(z, w, l); - else - { - mpz_tdiv_q_ui(z, w, -l); - mpz_neg(z, z); - } - } - static void eval(mpz_ptr z, signed long int l, mpz_srcptr w) - { - if (mpz_fits_slong_p(w)) - mpz_set_si(z, l / mpz_get_si(w)); - else - { - /* if w is bigger than a long then the quotient must be zero, unless - l==LONG_MIN and w==-LONG_MIN in which case the quotient is -1 */ - mpz_set_si (z, (mpz_cmpabs_ui (w, (l >= 0 ? l : -l)) == 0 ? -1 : 0)); - } - } - static void eval(mpz_ptr z, mpz_srcptr w, double d) - { - mpz_t temp; - mpz_init_set_d(temp, d); - mpz_tdiv_q(z, w, temp); - mpz_clear(temp); - } - static void eval(mpz_ptr z, double d, mpz_srcptr w) - { - mpz_t temp; - mpz_init_set_d(temp, d); - mpz_tdiv_q(z, temp, w); - mpz_clear(temp); - } - - static void eval(mpq_ptr q, mpq_srcptr r, mpq_srcptr s) - { mpq_div(q, r, s); } - - static void eval(mpq_ptr q, mpq_srcptr r, unsigned long int l) - { - mpq_t temp; - mpq_init(temp); - mpq_set_ui(temp, l, 1); - mpq_div(q, r, temp); - mpq_clear(temp); - } - static void eval(mpq_ptr q, unsigned long int l, mpq_srcptr r) - { - mpq_t temp; - mpq_init(temp); - mpq_set_ui(temp, l, 1); - mpq_div(q, temp, r); - mpq_clear(temp); - } - static void eval(mpq_ptr q, mpq_srcptr r, signed long int l) - { - mpq_t temp; - mpq_init(temp); - mpq_set_si(temp, l, 1); - mpq_div(q, r, temp); - mpq_clear(temp); - } - static void eval(mpq_ptr q, signed long int l, mpq_srcptr r) - { - mpq_t temp; - mpq_init(temp); - mpq_set_si(temp, l, 1); - mpq_div(q, temp, r); - mpq_clear(temp); - } - static void eval(mpq_ptr q, mpq_srcptr r, double d) - { - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - mpq_div(q, r, temp); - mpq_clear(temp); - } - static void eval(mpq_ptr q, double d, mpq_srcptr r) - { - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - mpq_div(q, temp, r); - mpq_clear(temp); - } - - static void eval(mpf_ptr f, mpf_srcptr g, mpf_srcptr h) - { mpf_div(f, g, h); } - - static void eval(mpf_ptr f, mpf_srcptr g, unsigned long int l) - { mpf_div_ui(f, g, l); } - static void eval(mpf_ptr f, unsigned long int l, mpf_srcptr g) - { mpf_ui_div(f, l, g); } - static void eval(mpf_ptr f, mpf_srcptr g, signed long int l) - { - if (l >= 0) - mpf_div_ui(f, g, l); - else - { - mpf_div_ui(f, g, -l); - mpf_neg(f, f); - } - } - static void eval(mpf_ptr f, signed long int l, mpf_srcptr g) - { - if (l >= 0) - mpf_ui_div(f, l, g); - else - { - mpf_ui_div(f, -l, g); - mpf_neg(f, f); - } - } - static void eval(mpf_ptr f, mpf_srcptr g, double d) - { - mpf_t temp; - mpf_init2(temp, 8*sizeof(double)); - mpf_set_d(temp, d); - mpf_div(f, g, temp); - mpf_clear(temp); - } - static void eval(mpf_ptr f, double d, mpf_srcptr g) - { - mpf_t temp; - mpf_init2(temp, 8*sizeof(double)); - mpf_set_d(temp, d); - mpf_div(f, temp, g); - mpf_clear(temp); - } -}; - -struct __gmp_binary_modulus -{ - static void eval(mpz_ptr z, mpz_srcptr w, mpz_srcptr v) - { mpz_tdiv_r(z, w, v); } - - static void eval(mpz_ptr z, mpz_srcptr w, unsigned long int l) - { mpz_tdiv_r_ui(z, w, l); } - static void eval(mpz_ptr z, unsigned long int l, mpz_srcptr w) - { - if (mpz_sgn(w) >= 0) - { - if (mpz_fits_ulong_p(w)) - mpz_set_ui(z, l % mpz_get_ui(w)); - else - mpz_set_ui(z, l); - } - else - { - mpz_neg(z, w); - if (mpz_fits_ulong_p(z)) - mpz_set_ui(z, l % mpz_get_ui(z)); - else - mpz_set_ui(z, l); - } - } - static void eval(mpz_ptr z, mpz_srcptr w, signed long int l) - { - mpz_tdiv_r_ui (z, w, (l >= 0 ? l : -l)); - } - static void eval(mpz_ptr z, signed long int l, mpz_srcptr w) - { - if (mpz_fits_slong_p(w)) - mpz_set_si(z, l % mpz_get_si(w)); - else - { - /* if w is bigger than a long then the remainder is l unchanged, - unless l==LONG_MIN and w==-LONG_MIN in which case it's 0 */ - mpz_set_si (z, mpz_cmpabs_ui (w, (l >= 0 ? l : -l)) == 0 ? 0 : l); - } - } - static void eval(mpz_ptr z, mpz_srcptr w, double d) - { - mpz_t temp; - mpz_init_set_d(temp, d); - mpz_tdiv_r(z, w, temp); - mpz_clear(temp); - } - static void eval(mpz_ptr z, double d, mpz_srcptr w) - { - mpz_t temp; - mpz_init_set_d(temp, d); - mpz_tdiv_r(z, temp, w); - mpz_clear(temp); - } -}; - -// Max allocations for plain types when converted to mpz_t -#define __GMP_DBL_LIMBS (2 + DBL_MAX_EXP / GMP_NUMB_BITS) -#define __GMP_ULI_LIMBS (1 + (8 * sizeof (long) - 1) / GMP_NUMB_BITS) - -#define __GMPXX_TMP_UI \ - mpz_t temp; \ - mp_limb_t limbs[__GMP_ULI_LIMBS]; \ - temp->_mp_d = limbs; \ - temp->_mp_alloc = __GMP_ULI_LIMBS; \ - mpz_set_ui (temp, l) -#define __GMPXX_TMP_SI \ - mpz_t temp; \ - mp_limb_t limbs[__GMP_ULI_LIMBS]; \ - temp->_mp_d = limbs; \ - temp->_mp_alloc = __GMP_ULI_LIMBS; \ - mpz_set_si (temp, l) -#define __GMPXX_TMP_D \ - mpz_t temp; \ - mp_limb_t limbs[__GMP_DBL_LIMBS]; \ - temp->_mp_d = limbs; \ - temp->_mp_alloc = __GMP_DBL_LIMBS; \ - mpz_set_d (temp, d) - -struct __gmp_binary_and -{ - static void eval(mpz_ptr z, mpz_srcptr w, mpz_srcptr v) - { mpz_and(z, w, v); } - - static void eval(mpz_ptr z, mpz_srcptr w, unsigned long int l) - { __GMPXX_TMP_UI; mpz_and (z, w, temp); } - static void eval(mpz_ptr z, unsigned long int l, mpz_srcptr w) - { __GMPXX_TMP_UI; mpz_and (z, w, temp); } - static void eval(mpz_ptr z, mpz_srcptr w, signed long int l) - { __GMPXX_TMP_SI; mpz_and (z, w, temp); } - static void eval(mpz_ptr z, signed long int l, mpz_srcptr w) - { __GMPXX_TMP_SI; mpz_and (z, w, temp); } - static void eval(mpz_ptr z, mpz_srcptr w, double d) - { __GMPXX_TMP_D; mpz_and (z, w, temp); } - static void eval(mpz_ptr z, double d, mpz_srcptr w) - { __GMPXX_TMP_D; mpz_and (z, w, temp); } -}; - -struct __gmp_binary_ior -{ - static void eval(mpz_ptr z, mpz_srcptr w, mpz_srcptr v) - { mpz_ior(z, w, v); } - static void eval(mpz_ptr z, mpz_srcptr w, unsigned long int l) - { __GMPXX_TMP_UI; mpz_ior (z, w, temp); } - static void eval(mpz_ptr z, unsigned long int l, mpz_srcptr w) - { __GMPXX_TMP_UI; mpz_ior (z, w, temp); } - static void eval(mpz_ptr z, mpz_srcptr w, signed long int l) - { __GMPXX_TMP_SI; mpz_ior (z, w, temp); } - static void eval(mpz_ptr z, signed long int l, mpz_srcptr w) - { __GMPXX_TMP_SI; mpz_ior (z, w, temp); } - static void eval(mpz_ptr z, mpz_srcptr w, double d) - { __GMPXX_TMP_D; mpz_ior (z, w, temp); } - static void eval(mpz_ptr z, double d, mpz_srcptr w) - { __GMPXX_TMP_D; mpz_ior (z, w, temp); } -}; - -struct __gmp_binary_xor -{ - static void eval(mpz_ptr z, mpz_srcptr w, mpz_srcptr v) - { mpz_xor(z, w, v); } - static void eval(mpz_ptr z, mpz_srcptr w, unsigned long int l) - { __GMPXX_TMP_UI; mpz_xor (z, w, temp); } - static void eval(mpz_ptr z, unsigned long int l, mpz_srcptr w) - { __GMPXX_TMP_UI; mpz_xor (z, w, temp); } - static void eval(mpz_ptr z, mpz_srcptr w, signed long int l) - { __GMPXX_TMP_SI; mpz_xor (z, w, temp); } - static void eval(mpz_ptr z, signed long int l, mpz_srcptr w) - { __GMPXX_TMP_SI; mpz_xor (z, w, temp); } - static void eval(mpz_ptr z, mpz_srcptr w, double d) - { __GMPXX_TMP_D; mpz_xor (z, w, temp); } - static void eval(mpz_ptr z, double d, mpz_srcptr w) - { __GMPXX_TMP_D; mpz_xor (z, w, temp); } -}; - -struct __gmp_binary_lshift -{ - static void eval(mpz_ptr z, mpz_srcptr w, unsigned long int l) - { mpz_mul_2exp(z, w, l); } - static void eval(mpq_ptr q, mpq_srcptr r, unsigned long int l) - { mpq_mul_2exp(q, r, l); } - static void eval(mpf_ptr f, mpf_srcptr g, unsigned long int l) - { mpf_mul_2exp(f, g, l); } -}; - -struct __gmp_binary_rshift -{ - static void eval(mpz_ptr z, mpz_srcptr w, unsigned long int l) - { mpz_fdiv_q_2exp(z, w, l); } - static void eval(mpq_ptr q, mpq_srcptr r, unsigned long int l) - { mpq_div_2exp(q, r, l); } - static void eval(mpf_ptr f, mpf_srcptr g, unsigned long int l) - { mpf_div_2exp(f, g, l); } -}; - -struct __gmp_binary_equal -{ - static bool eval(mpz_srcptr z, mpz_srcptr w) { return mpz_cmp(z, w) == 0; } - - static bool eval(mpz_srcptr z, unsigned long int l) - { return mpz_cmp_ui(z, l) == 0; } - static bool eval(unsigned long int l, mpz_srcptr z) - { return mpz_cmp_ui(z, l) == 0; } - static bool eval(mpz_srcptr z, signed long int l) - { return mpz_cmp_si(z, l) == 0; } - static bool eval(signed long int l, mpz_srcptr z) - { return mpz_cmp_si(z, l) == 0; } - static bool eval(mpz_srcptr z, double d) - { return mpz_cmp_d(z, d) == 0; } - static bool eval(double d, mpz_srcptr z) - { return mpz_cmp_d(z, d) == 0; } - - static bool eval(mpq_srcptr q, mpq_srcptr r) - { return mpq_equal(q, r) != 0; } - - static bool eval(mpq_srcptr q, unsigned long int l) - { return mpq_cmp_ui(q, l, 1) == 0; } - static bool eval(unsigned long int l, mpq_srcptr q) - { return mpq_cmp_ui(q, l, 1) == 0; } - static bool eval(mpq_srcptr q, signed long int l) - { return mpq_cmp_si(q, l, 1) == 0; } - static bool eval(signed long int l, mpq_srcptr q) - { return mpq_cmp_si(q, l, 1) == 0; } - static bool eval(mpq_srcptr q, double d) - { - bool b; - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - b = (mpq_equal(q, temp) != 0); - mpq_clear(temp); - return b; - } - static bool eval(double d, mpq_srcptr q) - { - bool b; - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - b = (mpq_equal(temp, q) != 0); - mpq_clear(temp); - return b; - } - - static bool eval(mpf_srcptr f, mpf_srcptr g) { return mpf_cmp(f, g) == 0; } - - static bool eval(mpf_srcptr f, unsigned long int l) - { return mpf_cmp_ui(f, l) == 0; } - static bool eval(unsigned long int l, mpf_srcptr f) - { return mpf_cmp_ui(f, l) == 0; } - static bool eval(mpf_srcptr f, signed long int l) - { return mpf_cmp_si(f, l) == 0; } - static bool eval(signed long int l, mpf_srcptr f) - { return mpf_cmp_si(f, l) == 0; } - static bool eval(mpf_srcptr f, double d) - { return mpf_cmp_d(f, d) == 0; } - static bool eval(double d, mpf_srcptr f) - { return mpf_cmp_d(f, d) == 0; } -}; - -struct __gmp_binary_not_equal -{ - static bool eval(mpz_srcptr z, mpz_srcptr w) { return mpz_cmp(z, w) != 0; } - - static bool eval(mpz_srcptr z, unsigned long int l) - { return mpz_cmp_ui(z, l) != 0; } - static bool eval(unsigned long int l, mpz_srcptr z) - { return mpz_cmp_ui(z, l) != 0; } - static bool eval(mpz_srcptr z, signed long int l) - { return mpz_cmp_si(z, l) != 0; } - static bool eval(signed long int l, mpz_srcptr z) - { return mpz_cmp_si(z, l) != 0; } - static bool eval(mpz_srcptr z, double d) - { return mpz_cmp_d(z, d) != 0; } - static bool eval(double d, mpz_srcptr z) - { return mpz_cmp_d(z, d) != 0; } - - static bool eval(mpq_srcptr q, mpq_srcptr r) - { return mpq_equal(q, r) == 0; } - - static bool eval(mpq_srcptr q, unsigned long int l) - { return mpq_cmp_ui(q, l, 1) != 0; } - static bool eval(unsigned long int l, mpq_srcptr q) - { return mpq_cmp_ui(q, l, 1) != 0; } - static bool eval(mpq_srcptr q, signed long int l) - { return mpq_cmp_si(q, l, 1) != 0; } - static bool eval(signed long int l, mpq_srcptr q) - { return mpq_cmp_si(q, l, 1) != 0; } - static bool eval(mpq_srcptr q, double d) - { - bool b; - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - b = (mpq_equal(q, temp) == 0); - mpq_clear(temp); - return b; - } - static bool eval(double d, mpq_srcptr q) - { - bool b; - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - b = (mpq_equal(temp, q) == 0); - mpq_clear(temp); - return b; - } - - static bool eval(mpf_srcptr f, mpf_srcptr g) { return mpf_cmp(f, g) != 0; } - - static bool eval(mpf_srcptr f, unsigned long int l) - { return mpf_cmp_ui(f, l) != 0; } - static bool eval(unsigned long int l, mpf_srcptr f) - { return mpf_cmp_ui(f, l) != 0; } - static bool eval(mpf_srcptr f, signed long int l) - { return mpf_cmp_si(f, l) != 0; } - static bool eval(signed long int l, mpf_srcptr f) - { return mpf_cmp_si(f, l) != 0; } - static bool eval(mpf_srcptr f, double d) - { return mpf_cmp_d(f, d) != 0; } - static bool eval(double d, mpf_srcptr f) - { return mpf_cmp_d(f, d) != 0; } -}; - -struct __gmp_binary_less -{ - static bool eval(mpz_srcptr z, mpz_srcptr w) { return mpz_cmp(z, w) < 0; } - - static bool eval(mpz_srcptr z, unsigned long int l) - { return mpz_cmp_ui(z, l) < 0; } - static bool eval(unsigned long int l, mpz_srcptr z) - { return mpz_cmp_ui(z, l) > 0; } - static bool eval(mpz_srcptr z, signed long int l) - { return mpz_cmp_si(z, l) < 0; } - static bool eval(signed long int l, mpz_srcptr z) - { return mpz_cmp_si(z, l) > 0; } - static bool eval(mpz_srcptr z, double d) - { return mpz_cmp_d(z, d) < 0; } - static bool eval(double d, mpz_srcptr z) - { return mpz_cmp_d(z, d) > 0; } - - static bool eval(mpq_srcptr q, mpq_srcptr r) { return mpq_cmp(q, r) < 0; } - - static bool eval(mpq_srcptr q, unsigned long int l) - { return mpq_cmp_ui(q, l, 1) < 0; } - static bool eval(unsigned long int l, mpq_srcptr q) - { return mpq_cmp_ui(q, l, 1) > 0; } - static bool eval(mpq_srcptr q, signed long int l) - { return mpq_cmp_si(q, l, 1) < 0; } - static bool eval(signed long int l, mpq_srcptr q) - { return mpq_cmp_si(q, l, 1) > 0; } - static bool eval(mpq_srcptr q, double d) - { - bool b; - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - b = (mpq_cmp(q, temp) < 0); - mpq_clear(temp); - return b; - } - static bool eval(double d, mpq_srcptr q) - { - bool b; - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - b = (mpq_cmp(temp, q) < 0); - mpq_clear(temp); - return b; - } - - static bool eval(mpf_srcptr f, mpf_srcptr g) { return mpf_cmp(f, g) < 0; } - - static bool eval(mpf_srcptr f, unsigned long int l) - { return mpf_cmp_ui(f, l) < 0; } - static bool eval(unsigned long int l, mpf_srcptr f) - { return mpf_cmp_ui(f, l) > 0; } - static bool eval(mpf_srcptr f, signed long int l) - { return mpf_cmp_si(f, l) < 0; } - static bool eval(signed long int l, mpf_srcptr f) - { return mpf_cmp_si(f, l) > 0; } - static bool eval(mpf_srcptr f, double d) - { return mpf_cmp_d(f, d) < 0; } - static bool eval(double d, mpf_srcptr f) - { return mpf_cmp_d(f, d) > 0; } -}; - -struct __gmp_binary_less_equal -{ - static bool eval(mpz_srcptr z, mpz_srcptr w) { return mpz_cmp(z, w) <= 0; } - - static bool eval(mpz_srcptr z, unsigned long int l) - { return mpz_cmp_ui(z, l) <= 0; } - static bool eval(unsigned long int l, mpz_srcptr z) - { return mpz_cmp_ui(z, l) >= 0; } - static bool eval(mpz_srcptr z, signed long int l) - { return mpz_cmp_si(z, l) <= 0; } - static bool eval(signed long int l, mpz_srcptr z) - { return mpz_cmp_si(z, l) >= 0; } - static bool eval(mpz_srcptr z, double d) - { return mpz_cmp_d(z, d) <= 0; } - static bool eval(double d, mpz_srcptr z) - { return mpz_cmp_d(z, d) >= 0; } - - static bool eval(mpq_srcptr q, mpq_srcptr r) { return mpq_cmp(q, r) <= 0; } - - static bool eval(mpq_srcptr q, unsigned long int l) - { return mpq_cmp_ui(q, l, 1) <= 0; } - static bool eval(unsigned long int l, mpq_srcptr q) - { return mpq_cmp_ui(q, l, 1) >= 0; } - static bool eval(mpq_srcptr q, signed long int l) - { return mpq_cmp_si(q, l, 1) <= 0; } - static bool eval(signed long int l, mpq_srcptr q) - { return mpq_cmp_si(q, l, 1) >= 0; } - static bool eval(mpq_srcptr q, double d) - { - bool b; - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - b = (mpq_cmp(q, temp) <= 0); - mpq_clear(temp); - return b; - } - static bool eval(double d, mpq_srcptr q) - { - bool b; - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - b = (mpq_cmp(temp, q) <= 0); - mpq_clear(temp); - return b; - } - - static bool eval(mpf_srcptr f, mpf_srcptr g) { return mpf_cmp(f, g) <= 0; } - - static bool eval(mpf_srcptr f, unsigned long int l) - { return mpf_cmp_ui(f, l) <= 0; } - static bool eval(unsigned long int l, mpf_srcptr f) - { return mpf_cmp_ui(f, l) >= 0; } - static bool eval(mpf_srcptr f, signed long int l) - { return mpf_cmp_si(f, l) <= 0; } - static bool eval(signed long int l, mpf_srcptr f) - { return mpf_cmp_si(f, l) >= 0; } - static bool eval(mpf_srcptr f, double d) - { return mpf_cmp_d(f, d) <= 0; } - static bool eval(double d, mpf_srcptr f) - { return mpf_cmp_d(f, d) >= 0; } -}; - -struct __gmp_binary_greater -{ - static bool eval(mpz_srcptr z, mpz_srcptr w) { return mpz_cmp(z, w) > 0; } - - static bool eval(mpz_srcptr z, unsigned long int l) - { return mpz_cmp_ui(z, l) > 0; } - static bool eval(unsigned long int l, mpz_srcptr z) - { return mpz_cmp_ui(z, l) < 0; } - static bool eval(mpz_srcptr z, signed long int l) - { return mpz_cmp_si(z, l) > 0; } - static bool eval(signed long int l, mpz_srcptr z) - { return mpz_cmp_si(z, l) < 0; } - static bool eval(mpz_srcptr z, double d) - { return mpz_cmp_d(z, d) > 0; } - static bool eval(double d, mpz_srcptr z) - { return mpz_cmp_d(z, d) < 0; } - - static bool eval(mpq_srcptr q, mpq_srcptr r) { return mpq_cmp(q, r) > 0; } - - static bool eval(mpq_srcptr q, unsigned long int l) - { return mpq_cmp_ui(q, l, 1) > 0; } - static bool eval(unsigned long int l, mpq_srcptr q) - { return mpq_cmp_ui(q, l, 1) < 0; } - static bool eval(mpq_srcptr q, signed long int l) - { return mpq_cmp_si(q, l, 1) > 0; } - static bool eval(signed long int l, mpq_srcptr q) - { return mpq_cmp_si(q, l, 1) < 0; } - static bool eval(mpq_srcptr q, double d) - { - bool b; - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - b = (mpq_cmp(q, temp) > 0); - mpq_clear(temp); - return b; - } - static bool eval(double d, mpq_srcptr q) - { - bool b; - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - b = (mpq_cmp(temp, q) > 0); - mpq_clear(temp); - return b; - } - - static bool eval(mpf_srcptr f, mpf_srcptr g) { return mpf_cmp(f, g) > 0; } - - static bool eval(mpf_srcptr f, unsigned long int l) - { return mpf_cmp_ui(f, l) > 0; } - static bool eval(unsigned long int l, mpf_srcptr f) - { return mpf_cmp_ui(f, l) < 0; } - static bool eval(mpf_srcptr f, signed long int l) - { return mpf_cmp_si(f, l) > 0; } - static bool eval(signed long int l, mpf_srcptr f) - { return mpf_cmp_si(f, l) < 0; } - static bool eval(mpf_srcptr f, double d) - { return mpf_cmp_d(f, d) > 0; } - static bool eval(double d, mpf_srcptr f) - { return mpf_cmp_d(f, d) < 0; } -}; - -struct __gmp_binary_greater_equal -{ - static bool eval(mpz_srcptr z, mpz_srcptr w) { return mpz_cmp(z, w) >= 0; } - - static bool eval(mpz_srcptr z, unsigned long int l) - { return mpz_cmp_ui(z, l) >= 0; } - static bool eval(unsigned long int l, mpz_srcptr z) - { return mpz_cmp_ui(z, l) <= 0; } - static bool eval(mpz_srcptr z, signed long int l) - { return mpz_cmp_si(z, l) >= 0; } - static bool eval(signed long int l, mpz_srcptr z) - { return mpz_cmp_si(z, l) <= 0; } - static bool eval(mpz_srcptr z, double d) - { return mpz_cmp_d(z, d) >= 0; } - static bool eval(double d, mpz_srcptr z) - { return mpz_cmp_d(z, d) <= 0; } - - static bool eval(mpq_srcptr q, mpq_srcptr r) { return mpq_cmp(q, r) >= 0; } - - static bool eval(mpq_srcptr q, unsigned long int l) - { return mpq_cmp_ui(q, l, 1) >= 0; } - static bool eval(unsigned long int l, mpq_srcptr q) - { return mpq_cmp_ui(q, l, 1) <= 0; } - static bool eval(mpq_srcptr q, signed long int l) - { return mpq_cmp_si(q, l, 1) >= 0; } - static bool eval(signed long int l, mpq_srcptr q) - { return mpq_cmp_si(q, l, 1) <= 0; } - static bool eval(mpq_srcptr q, double d) - { - bool b; - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - b = (mpq_cmp(q, temp) >= 0); - mpq_clear(temp); - return b; - } - static bool eval(double d, mpq_srcptr q) - { - bool b; - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - b = (mpq_cmp(temp, q) >= 0); - mpq_clear(temp); - return b; - } - - static bool eval(mpf_srcptr f, mpf_srcptr g) { return mpf_cmp(f, g) >= 0; } - - static bool eval(mpf_srcptr f, unsigned long int l) - { return mpf_cmp_ui(f, l) >= 0; } - static bool eval(unsigned long int l, mpf_srcptr f) - { return mpf_cmp_ui(f, l) <= 0; } - static bool eval(mpf_srcptr f, signed long int l) - { return mpf_cmp_si(f, l) >= 0; } - static bool eval(signed long int l, mpf_srcptr f) - { return mpf_cmp_si(f, l) <= 0; } - static bool eval(mpf_srcptr f, double d) - { return mpf_cmp_d(f, d) >= 0; } - static bool eval(double d, mpf_srcptr f) - { return mpf_cmp_d(f, d) <= 0; } -}; - -struct __gmp_unary_increment -{ - static void eval(mpz_ptr z) { mpz_add_ui(z, z, 1); } - static void eval(mpq_ptr q) - { mpz_add(mpq_numref(q), mpq_numref(q), mpq_denref(q)); } - static void eval(mpf_ptr f) { mpf_add_ui(f, f, 1); } -}; - -struct __gmp_unary_decrement -{ - static void eval(mpz_ptr z) { mpz_sub_ui(z, z, 1); } - static void eval(mpq_ptr q) - { mpz_sub(mpq_numref(q), mpq_numref(q), mpq_denref(q)); } - static void eval(mpf_ptr f) { mpf_sub_ui(f, f, 1); } -}; - -struct __gmp_abs_function -{ - static void eval(mpz_ptr z, mpz_srcptr w) { mpz_abs(z, w); } - static void eval(mpq_ptr q, mpq_srcptr r) { mpq_abs(q, r); } - static void eval(mpf_ptr f, mpf_srcptr g) { mpf_abs(f, g); } -}; - -struct __gmp_trunc_function -{ - static void eval(mpf_ptr f, mpf_srcptr g) { mpf_trunc(f, g); } -}; - -struct __gmp_floor_function -{ - static void eval(mpf_ptr f, mpf_srcptr g) { mpf_floor(f, g); } -}; - -struct __gmp_ceil_function -{ - static void eval(mpf_ptr f, mpf_srcptr g) { mpf_ceil(f, g); } -}; - -struct __gmp_sqrt_function -{ - static void eval(mpz_ptr z, mpz_srcptr w) { mpz_sqrt(z, w); } - static void eval(mpf_ptr f, mpf_srcptr g) { mpf_sqrt(f, g); } -}; - -struct __gmp_hypot_function -{ - static void eval(mpf_ptr f, mpf_srcptr g, mpf_srcptr h) - { - mpf_t temp; - mpf_init2(temp, mpf_get_prec(f)); - mpf_mul(temp, g, g); - mpf_mul(f, h, h); - mpf_add(f, f, temp); - mpf_sqrt(f, f); - mpf_clear(temp); - } - - static void eval(mpf_ptr f, mpf_srcptr g, unsigned long int l) - { - mpf_t temp; - mpf_init2(temp, mpf_get_prec(f)); - mpf_mul(temp, g, g); - mpf_set_ui(f, l); - mpf_mul(f, f, f); - mpf_add(f, f, temp); - mpf_sqrt(f, f); - mpf_clear(temp); - } - static void eval(mpf_ptr f, unsigned long int l, mpf_srcptr g) - { - mpf_t temp; - mpf_init2(temp, mpf_get_prec(f)); - mpf_mul(temp, g, g); - mpf_set_ui(f, l); - mpf_mul(f, f, f); - mpf_add(f, f, temp); - mpf_sqrt(f, f); - mpf_clear(temp); - } - static void eval(mpf_ptr f, mpf_srcptr g, signed long int l) - { - mpf_t temp; - mpf_init2(temp, mpf_get_prec(f)); - mpf_mul(temp, g, g); - mpf_set_si(f, l); - mpf_mul(f, f, f); - mpf_add(f, f, temp); - mpf_sqrt(f, f); - mpf_clear(temp); - } - static void eval(mpf_ptr f, signed long int l, mpf_srcptr g) - { - mpf_t temp; - mpf_init2(temp, mpf_get_prec(f)); - mpf_mul(temp, g, g); - mpf_set_si(f, l); - mpf_mul(f, f, f); - mpf_add(f, f, temp); - mpf_sqrt(f, f); - mpf_clear(temp); - } - static void eval(mpf_ptr f, mpf_srcptr g, double d) - { - mpf_t temp; - mpf_init2(temp, mpf_get_prec(f)); - mpf_mul(temp, g, g); - mpf_set_d(f, d); - mpf_mul(f, f, f); - mpf_add(f, f, temp); - mpf_sqrt(f, f); - mpf_clear(temp); - } - static void eval(mpf_ptr f, double d, mpf_srcptr g) - { - mpf_t temp; - mpf_init2(temp, mpf_get_prec(f)); - mpf_mul(temp, g, g); - mpf_set_d(f, d); - mpf_mul(f, f, f); - mpf_add(f, f, temp); - mpf_sqrt(f, f); - mpf_clear(temp); - } -}; - -struct __gmp_sgn_function -{ - static int eval(mpz_srcptr z) { return mpz_sgn(z); } - static int eval(mpq_srcptr q) { return mpq_sgn(q); } - static int eval(mpf_srcptr f) { return mpf_sgn(f); } -}; - -struct __gmp_cmp_function -{ - static int eval(mpz_srcptr z, mpz_srcptr w) { return mpz_cmp(z, w); } - - static int eval(mpz_srcptr z, unsigned long int l) - { return mpz_cmp_ui(z, l); } - static int eval(unsigned long int l, mpz_srcptr z) - { return -mpz_cmp_ui(z, l); } - static int eval(mpz_srcptr z, signed long int l) - { return mpz_cmp_si(z, l); } - static int eval(signed long int l, mpz_srcptr z) - { return -mpz_cmp_si(z, l); } - static int eval(mpz_srcptr z, double d) - { return mpz_cmp_d(z, d); } - static int eval(double d, mpz_srcptr z) - { return -mpz_cmp_d(z, d); } - - static int eval(mpq_srcptr q, mpq_srcptr r) { return mpq_cmp(q, r); } - - static int eval(mpq_srcptr q, unsigned long int l) - { return mpq_cmp_ui(q, l, 1); } - static int eval(unsigned long int l, mpq_srcptr q) - { return -mpq_cmp_ui(q, l, 1); } - static int eval(mpq_srcptr q, signed long int l) - { return mpq_cmp_si(q, l, 1); } - static int eval(signed long int l, mpq_srcptr q) - { return -mpq_cmp_si(q, l, 1); } - static int eval(mpq_srcptr q, double d) - { - int i; - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - i = mpq_cmp(q, temp); - mpq_clear(temp); - return i; - } - static int eval(double d, mpq_srcptr q) - { - int i; - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - i = mpq_cmp(temp, q); - mpq_clear(temp); - return i; - } - - static int eval(mpf_srcptr f, mpf_srcptr g) { return mpf_cmp(f, g); } - - static int eval(mpf_srcptr f, unsigned long int l) - { return mpf_cmp_ui(f, l); } - static int eval(unsigned long int l, mpf_srcptr f) - { return -mpf_cmp_ui(f, l); } - static int eval(mpf_srcptr f, signed long int l) - { return mpf_cmp_si(f, l); } - static int eval(signed long int l, mpf_srcptr f) - { return -mpf_cmp_si(f, l); } - static int eval(mpf_srcptr f, double d) - { return mpf_cmp_d(f, d); } - static int eval(double d, mpf_srcptr f) - { return -mpf_cmp_d(f, d); } -}; - -struct __gmp_rand_function -{ - static void eval(mpz_ptr z, gmp_randstate_t s, unsigned long int l) - { mpz_urandomb(z, s, l); } - static void eval(mpz_ptr z, gmp_randstate_t s, mpz_srcptr w) - { mpz_urandomm(z, s, w); } - static void eval(mpf_ptr f, gmp_randstate_t s, mp_bitcnt_t prec) - { mpf_urandomb(f, s, prec); } -}; - - -/**************** Auxiliary classes ****************/ - -/* this is much the same as gmp_allocated_string in gmp-impl.h - since gmp-impl.h is not publicly available, I redefine it here - I use a different name to avoid possible clashes */ -extern "C" { -struct __gmp_alloc_cstring_c -{ - void (*free_func) (void *, size_t); -}; -} - -struct __gmp_alloc_cstring : __gmp_alloc_cstring_c -{ - char *str; - __gmp_alloc_cstring(char *s) { str = s; } - ~__gmp_alloc_cstring() - { - mp_get_memory_functions (NULL, NULL, &free_func); - (*free_func) (str, std::strlen(str)+1); - } -}; - -// general expression template class -template -class __gmp_expr; - - -// templates for resolving expression types -template -struct __gmp_resolve_ref -{ - typedef T ref_type; -}; - -template -struct __gmp_resolve_ref<__gmp_expr > -{ - typedef const __gmp_expr & ref_type; -}; - - -template -struct __gmp_resolve_expr; - -template <> -struct __gmp_resolve_expr -{ - typedef mpz_t value_type; - typedef mpz_ptr ptr_type; -}; - -template <> -struct __gmp_resolve_expr -{ - typedef mpq_t value_type; - typedef mpq_ptr ptr_type; -}; - -template <> -struct __gmp_resolve_expr -{ - typedef mpf_t value_type; - typedef mpf_ptr ptr_type; -}; - -template <> -struct __gmp_resolve_expr -{ - typedef mpq_t value_type; -}; - -template <> -struct __gmp_resolve_expr -{ - typedef mpq_t value_type; -}; - -template <> -struct __gmp_resolve_expr -{ - typedef mpf_t value_type; -}; - -template <> -struct __gmp_resolve_expr -{ - typedef mpf_t value_type; -}; - -template <> -struct __gmp_resolve_expr -{ - typedef mpf_t value_type; -}; - -template <> -struct __gmp_resolve_expr -{ - typedef mpf_t value_type; -}; - - - -template -struct __gmp_resolve_temp -{ - typedef __gmp_expr temp_type; -}; - -template -struct __gmp_resolve_temp -{ - typedef const __gmp_expr & temp_type; -}; - - -// classes for evaluating unary and binary expressions -template -struct __gmp_unary_expr -{ - const T &val; - - __gmp_unary_expr(const T &v) : val(v) { } -private: - __gmp_unary_expr(); -}; - -template -struct __gmp_binary_expr -{ - typename __gmp_resolve_ref::ref_type val1; - typename __gmp_resolve_ref::ref_type val2; - - __gmp_binary_expr(const T &v1, const U &v2) : val1(v1), val2(v2) { } -private: - __gmp_binary_expr(); -}; - - -// functions for evaluating expressions -template -void __gmp_set_expr(mpz_ptr, const __gmp_expr &); -template -void __gmp_set_expr(mpq_ptr, const __gmp_expr &); -template -void __gmp_set_expr(mpf_ptr, const __gmp_expr &); - - -/**************** Macros for in-class declarations ****************/ -/* This is just repetitive code that is easier to maintain if it's written - only once */ - -#define __GMPP_DECLARE_COMPOUND_OPERATOR(fun) \ - template \ - __gmp_expr & fun(const __gmp_expr &); - -#define __GMPN_DECLARE_COMPOUND_OPERATOR(fun) \ - __gmp_expr & fun(signed char); \ - __gmp_expr & fun(unsigned char); \ - __gmp_expr & fun(signed int); \ - __gmp_expr & fun(unsigned int); \ - __gmp_expr & fun(signed short int); \ - __gmp_expr & fun(unsigned short int); \ - __gmp_expr & fun(signed long int); \ - __gmp_expr & fun(unsigned long int); \ - __gmp_expr & fun(float); \ - __gmp_expr & fun(double); \ - __gmp_expr & fun(long double); - -#define __GMP_DECLARE_COMPOUND_OPERATOR(fun) \ -__GMPP_DECLARE_COMPOUND_OPERATOR(fun) \ -__GMPN_DECLARE_COMPOUND_OPERATOR(fun) - -#define __GMP_DECLARE_COMPOUND_OPERATOR_UI(fun) \ - __gmp_expr & fun(unsigned long int); - -#define __GMP_DECLARE_INCREMENT_OPERATOR(fun) \ - inline __gmp_expr & fun(); \ - inline __gmp_expr fun(int); - - -/**************** mpz_class -- wrapper for mpz_t ****************/ - -template <> -class __gmp_expr -{ -private: - typedef mpz_t value_type; - value_type mp; -public: - mp_bitcnt_t get_prec() const { return mpf_get_default_prec(); } - - // constructors and destructor - __gmp_expr() { mpz_init(mp); } - - __gmp_expr(const __gmp_expr &z) { mpz_init_set(mp, z.mp); } - template - __gmp_expr(const __gmp_expr &expr) - { mpz_init(mp); __gmp_set_expr(mp, expr); } - - __gmp_expr(signed char c) { mpz_init_set_si(mp, c); } - __gmp_expr(unsigned char c) { mpz_init_set_ui(mp, c); } - - __gmp_expr(signed int i) { mpz_init_set_si(mp, i); } - __gmp_expr(unsigned int i) { mpz_init_set_ui(mp, i); } - - __gmp_expr(signed short int s) { mpz_init_set_si(mp, s); } - __gmp_expr(unsigned short int s) { mpz_init_set_ui(mp, s); } - - __gmp_expr(signed long int l) { mpz_init_set_si(mp, l); } - __gmp_expr(unsigned long int l) { mpz_init_set_ui(mp, l); } - - __gmp_expr(float f) { mpz_init_set_d(mp, f); } - __gmp_expr(double d) { mpz_init_set_d(mp, d); } - // __gmp_expr(long double ld) { mpz_init_set_d(mp, ld); } - - explicit __gmp_expr(const char *s) - { - if (mpz_init_set_str (mp, s, 0) != 0) - { - mpz_clear (mp); - throw std::invalid_argument ("mpz_set_str"); - } - } - __gmp_expr(const char *s, int base) - { - if (mpz_init_set_str (mp, s, base) != 0) - { - mpz_clear (mp); - throw std::invalid_argument ("mpz_set_str"); - } - } - explicit __gmp_expr(const std::string &s) - { - if (mpz_init_set_str (mp, s.c_str(), 0) != 0) - { - mpz_clear (mp); - throw std::invalid_argument ("mpz_set_str"); - } - } - __gmp_expr(const std::string &s, int base) - { - if (mpz_init_set_str(mp, s.c_str(), base) != 0) - { - mpz_clear (mp); - throw std::invalid_argument ("mpz_set_str"); - } - } - - explicit __gmp_expr(mpz_srcptr z) { mpz_init_set(mp, z); } - - ~__gmp_expr() { mpz_clear(mp); } - - // assignment operators - __gmp_expr & operator=(const __gmp_expr &z) - { mpz_set(mp, z.mp); return *this; } - template - __gmp_expr & operator=(const __gmp_expr &expr) - { __gmp_set_expr(mp, expr); return *this; } - - __gmp_expr & operator=(signed char c) { mpz_set_si(mp, c); return *this; } - __gmp_expr & operator=(unsigned char c) { mpz_set_ui(mp, c); return *this; } - - __gmp_expr & operator=(signed int i) { mpz_set_si(mp, i); return *this; } - __gmp_expr & operator=(unsigned int i) { mpz_set_ui(mp, i); return *this; } - - __gmp_expr & operator=(signed short int s) - { mpz_set_si(mp, s); return *this; } - __gmp_expr & operator=(unsigned short int s) - { mpz_set_ui(mp, s); return *this; } - - __gmp_expr & operator=(signed long int l) - { mpz_set_si(mp, l); return *this; } - __gmp_expr & operator=(unsigned long int l) - { mpz_set_ui(mp, l); return *this; } - - __gmp_expr & operator=(float f) { mpz_set_d(mp, f); return *this; } - __gmp_expr & operator=(double d) { mpz_set_d(mp, d); return *this; } - // __gmp_expr & operator=(long double ld) - // { mpz_set_ld(mp, ld); return *this; } - - __gmp_expr & operator=(const char *s) - { - if (mpz_set_str (mp, s, 0) != 0) - throw std::invalid_argument ("mpz_set_str"); - return *this; - } - __gmp_expr & operator=(const std::string &s) - { - if (mpz_set_str(mp, s.c_str(), 0) != 0) - throw std::invalid_argument ("mpz_set_str"); - return *this; - } - - // string input/output functions - int set_str(const char *s, int base) - { return mpz_set_str(mp, s, base); } - int set_str(const std::string &s, int base) - { return mpz_set_str(mp, s.c_str(), base); } - std::string get_str(int base = 10) const - { - __gmp_alloc_cstring temp(mpz_get_str(0, base, mp)); - return std::string(temp.str); - } - - // conversion functions - mpz_srcptr __get_mp() const { return mp; } - mpz_ptr __get_mp() { return mp; } - mpz_srcptr get_mpz_t() const { return mp; } - mpz_ptr get_mpz_t() { return mp; } - - signed long int get_si() const { return mpz_get_si(mp); } - unsigned long int get_ui() const { return mpz_get_ui(mp); } - double get_d() const { return mpz_get_d(mp); } - - // bool fits_schar_p() const { return mpz_fits_schar_p(mp); } - // bool fits_uchar_p() const { return mpz_fits_uchar_p(mp); } - bool fits_sint_p() const { return mpz_fits_sint_p(mp); } - bool fits_uint_p() const { return mpz_fits_uint_p(mp); } - bool fits_sshort_p() const { return mpz_fits_sshort_p(mp); } - bool fits_ushort_p() const { return mpz_fits_ushort_p(mp); } - bool fits_slong_p() const { return mpz_fits_slong_p(mp); } - bool fits_ulong_p() const { return mpz_fits_ulong_p(mp); } - // bool fits_float_p() const { return mpz_fits_float_p(mp); } - // bool fits_double_p() const { return mpz_fits_double_p(mp); } - // bool fits_ldouble_p() const { return mpz_fits_ldouble_p(mp); } - - // member operators - __GMP_DECLARE_COMPOUND_OPERATOR(operator+=) - __GMP_DECLARE_COMPOUND_OPERATOR(operator-=) - __GMP_DECLARE_COMPOUND_OPERATOR(operator*=) - __GMP_DECLARE_COMPOUND_OPERATOR(operator/=) - __GMP_DECLARE_COMPOUND_OPERATOR(operator%=) - - __GMPP_DECLARE_COMPOUND_OPERATOR(operator&=) - __GMPP_DECLARE_COMPOUND_OPERATOR(operator|=) - __GMPP_DECLARE_COMPOUND_OPERATOR(operator^=) - - __GMP_DECLARE_COMPOUND_OPERATOR_UI(operator<<=) - __GMP_DECLARE_COMPOUND_OPERATOR_UI(operator>>=) - - __GMP_DECLARE_INCREMENT_OPERATOR(operator++) - __GMP_DECLARE_INCREMENT_OPERATOR(operator--) -}; - -typedef __gmp_expr mpz_class; - - -/**************** mpq_class -- wrapper for mpq_t ****************/ - -template <> -class __gmp_expr -{ -private: - typedef mpq_t value_type; - value_type mp; -public: - mp_bitcnt_t get_prec() const { return mpf_get_default_prec(); } - void canonicalize() { mpq_canonicalize(mp); } - - // constructors and destructor - __gmp_expr() { mpq_init(mp); } - - __gmp_expr(const __gmp_expr &q) { mpq_init(mp); mpq_set(mp, q.mp); } - template - __gmp_expr(const __gmp_expr &expr) - { mpq_init(mp); __gmp_set_expr(mp, expr); } - - __gmp_expr(signed char c) { mpq_init(mp); mpq_set_si(mp, c, 1); } - __gmp_expr(unsigned char c) { mpq_init(mp); mpq_set_ui(mp, c, 1); } - - __gmp_expr(signed int i) { mpq_init(mp); mpq_set_si(mp, i, 1); } - __gmp_expr(unsigned int i) { mpq_init(mp); mpq_set_ui(mp, i, 1); } - - __gmp_expr(signed short int s) { mpq_init(mp); mpq_set_si(mp, s, 1); } - __gmp_expr(unsigned short int s) { mpq_init(mp); mpq_set_ui(mp, s, 1); } - - __gmp_expr(signed long int l) { mpq_init(mp); mpq_set_si(mp, l, 1); } - __gmp_expr(unsigned long int l) { mpq_init(mp); mpq_set_ui(mp, l, 1); } - - __gmp_expr(float f) { mpq_init(mp); mpq_set_d(mp, f); } - __gmp_expr(double d) { mpq_init(mp); mpq_set_d(mp, d); } - // __gmp_expr(long double ld) { mpq_init(mp); mpq_set_ld(mp, ld); } - - explicit __gmp_expr(const char *s) - { - mpq_init (mp); - if (mpq_set_str (mp, s, 0) != 0) - { - mpq_clear (mp); - throw std::invalid_argument ("mpq_set_str"); - } - } - __gmp_expr(const char *s, int base) - { - mpq_init (mp); - if (mpq_set_str(mp, s, base) != 0) - { - mpq_clear (mp); - throw std::invalid_argument ("mpq_set_str"); - } - } - explicit __gmp_expr(const std::string &s) - { - mpq_init (mp); - if (mpq_set_str (mp, s.c_str(), 0) != 0) - { - mpq_clear (mp); - throw std::invalid_argument ("mpq_set_str"); - } - } - __gmp_expr(const std::string &s, int base) - { - mpq_init(mp); - if (mpq_set_str (mp, s.c_str(), base) != 0) - { - mpq_clear (mp); - throw std::invalid_argument ("mpq_set_str"); - } - } - explicit __gmp_expr(mpq_srcptr q) { mpq_init(mp); mpq_set(mp, q); } - - __gmp_expr(const mpz_class &num, const mpz_class &den) - { - mpq_init(mp); - mpz_set(mpq_numref(mp), num.get_mpz_t()); - mpz_set(mpq_denref(mp), den.get_mpz_t()); - } - - ~__gmp_expr() { mpq_clear(mp); } - - // assignment operators - __gmp_expr & operator=(const __gmp_expr &q) - { mpq_set(mp, q.mp); return *this; } - template - __gmp_expr & operator=(const __gmp_expr &expr) - { __gmp_set_expr(mp, expr); return *this; } - - __gmp_expr & operator=(signed char c) - { mpq_set_si(mp, c, 1); return *this; } - __gmp_expr & operator=(unsigned char c) - { mpq_set_ui(mp, c, 1); return *this; } - - __gmp_expr & operator=(signed int i) { mpq_set_si(mp, i, 1); return *this; } - __gmp_expr & operator=(unsigned int i) - { mpq_set_ui(mp, i, 1); return *this; } - - __gmp_expr & operator=(signed short int s) - { mpq_set_si(mp, s, 1); return *this; } - __gmp_expr & operator=(unsigned short int s) - { mpq_set_ui(mp, s, 1); return *this; } - - __gmp_expr & operator=(signed long int l) - { mpq_set_si(mp, l, 1); return *this; } - __gmp_expr & operator=(unsigned long int l) - { mpq_set_ui(mp, l, 1); return *this; } - - __gmp_expr & operator=(float f) { mpq_set_d(mp, f); return *this; } - __gmp_expr & operator=(double d) { mpq_set_d(mp, d); return *this; } - // __gmp_expr & operator=(long double ld) - // { mpq_set_ld(mp, ld); return *this; } - - __gmp_expr & operator=(const char *s) - { - if (mpq_set_str (mp, s, 0) != 0) - throw std::invalid_argument ("mpq_set_str"); - return *this; - } - __gmp_expr & operator=(const std::string &s) - { - if (mpq_set_str(mp, s.c_str(), 0) != 0) - throw std::invalid_argument ("mpq_set_str"); - return *this; - } - - // string input/output functions - int set_str(const char *s, int base) - { return mpq_set_str(mp, s, base); } - int set_str(const std::string &s, int base) - { return mpq_set_str(mp, s.c_str(), base); } - std::string get_str(int base = 10) const - { - __gmp_alloc_cstring temp(mpq_get_str(0, base, mp)); - return std::string(temp.str); - } - - // conversion functions - - // casting a reference to an mpz_t to mpz_class & is a dirty hack, - // but works because the internal representation of mpz_class is - // exactly an mpz_t - const mpz_class & get_num() const - { return reinterpret_cast(*mpq_numref(mp)); } - mpz_class & get_num() - { return reinterpret_cast(*mpq_numref(mp)); } - const mpz_class & get_den() const - { return reinterpret_cast(*mpq_denref(mp)); } - mpz_class & get_den() - { return reinterpret_cast(*mpq_denref(mp)); } - - mpq_srcptr __get_mp() const { return mp; } - mpq_ptr __get_mp() { return mp; } - mpq_srcptr get_mpq_t() const { return mp; } - mpq_ptr get_mpq_t() { return mp; } - - mpz_srcptr get_num_mpz_t() const { return mpq_numref(mp); } - mpz_ptr get_num_mpz_t() { return mpq_numref(mp); } - mpz_srcptr get_den_mpz_t() const { return mpq_denref(mp); } - mpz_ptr get_den_mpz_t() { return mpq_denref(mp); } - - double get_d() const { return mpq_get_d(mp); } - - // compound assignments - __GMP_DECLARE_COMPOUND_OPERATOR(operator+=) - __GMP_DECLARE_COMPOUND_OPERATOR(operator-=) - __GMP_DECLARE_COMPOUND_OPERATOR(operator*=) - __GMP_DECLARE_COMPOUND_OPERATOR(operator/=) - - __GMP_DECLARE_COMPOUND_OPERATOR_UI(operator<<=) - __GMP_DECLARE_COMPOUND_OPERATOR_UI(operator>>=) - - __GMP_DECLARE_INCREMENT_OPERATOR(operator++) - __GMP_DECLARE_INCREMENT_OPERATOR(operator--) -}; - -typedef __gmp_expr mpq_class; - - -/**************** mpf_class -- wrapper for mpf_t ****************/ - -template <> -class __gmp_expr -{ -private: - typedef mpf_t value_type; - value_type mp; -public: - mp_bitcnt_t get_prec() const { return mpf_get_prec(mp); } - - void set_prec(mp_bitcnt_t prec) { mpf_set_prec(mp, prec); } - void set_prec_raw(mp_bitcnt_t prec) { mpf_set_prec_raw(mp, prec); } - - // constructors and destructor - __gmp_expr() { mpf_init(mp); } - - __gmp_expr(const __gmp_expr &f) - { mpf_init2(mp, f.get_prec()); mpf_set(mp, f.mp); } - __gmp_expr(const __gmp_expr &f, mp_bitcnt_t prec) - { mpf_init2(mp, prec); mpf_set(mp, f.mp); } - template - __gmp_expr(const __gmp_expr &expr) - { mpf_init2(mp, expr.get_prec()); __gmp_set_expr(mp, expr); } - template - __gmp_expr(const __gmp_expr &expr, mp_bitcnt_t prec) - { mpf_init2(mp, prec); __gmp_set_expr(mp, expr); } - - __gmp_expr(signed char c) { mpf_init_set_si(mp, c); } - __gmp_expr(signed char c, mp_bitcnt_t prec) - { mpf_init2(mp, prec); mpf_set_si(mp, c); } - __gmp_expr(unsigned char c) { mpf_init_set_ui(mp, c); } - __gmp_expr(unsigned char c, mp_bitcnt_t prec) - { mpf_init2(mp, prec); mpf_set_ui(mp, c); } - - __gmp_expr(signed int i) { mpf_init_set_si(mp, i); } - __gmp_expr(signed int i, mp_bitcnt_t prec) - { mpf_init2(mp, prec); mpf_set_si(mp, i); } - __gmp_expr(unsigned int i) { mpf_init_set_ui(mp, i); } - __gmp_expr(unsigned int i, mp_bitcnt_t prec) - { mpf_init2(mp, prec); mpf_set_ui(mp, i); } - - __gmp_expr(signed short int s) { mpf_init_set_si(mp, s); } - __gmp_expr(signed short int s, mp_bitcnt_t prec) - { mpf_init2(mp, prec); mpf_set_si(mp, s); } - __gmp_expr(unsigned short int s) { mpf_init_set_ui(mp, s); } - __gmp_expr(unsigned short int s, mp_bitcnt_t prec) - { mpf_init2(mp, prec); mpf_set_ui(mp, s); } - - __gmp_expr(signed long int l) { mpf_init_set_si(mp, l); } - __gmp_expr(signed long int l, mp_bitcnt_t prec) - { mpf_init2(mp, prec); mpf_set_si(mp, l); } - __gmp_expr(unsigned long int l) { mpf_init_set_ui(mp, l); } - __gmp_expr(unsigned long int l, mp_bitcnt_t prec) - { mpf_init2(mp, prec); mpf_set_ui(mp, l); } - - __gmp_expr(float f) { mpf_init_set_d(mp, f); } - __gmp_expr(float f, mp_bitcnt_t prec) - { mpf_init2(mp, prec); mpf_set_d(mp, f); } - __gmp_expr(double d) { mpf_init_set_d(mp, d); } - __gmp_expr(double d, mp_bitcnt_t prec) - { mpf_init2(mp, prec); mpf_set_d(mp, d); } - // __gmp_expr(long double ld) { mpf_init_set_d(mp, ld); } - // __gmp_expr(long double ld, mp_bitcnt_t prec) - // { mpf_init2(mp, prec); mpf_set_d(mp, ld); } - - explicit __gmp_expr(const char *s) - { - if (mpf_init_set_str (mp, s, 0) != 0) - { - mpf_clear (mp); - throw std::invalid_argument ("mpf_set_str"); - } - } - __gmp_expr(const char *s, mp_bitcnt_t prec, int base = 0) - { - mpf_init2(mp, prec); - if (mpf_set_str(mp, s, base) != 0) - { - mpf_clear (mp); - throw std::invalid_argument ("mpf_set_str"); - } - } - explicit __gmp_expr(const std::string &s) - { - if (mpf_init_set_str(mp, s.c_str(), 0) != 0) - { - mpf_clear (mp); - throw std::invalid_argument ("mpf_set_str"); - } - } - __gmp_expr(const std::string &s, mp_bitcnt_t prec, int base = 0) - { - mpf_init2(mp, prec); - if (mpf_set_str(mp, s.c_str(), base) != 0) - { - mpf_clear (mp); - throw std::invalid_argument ("mpf_set_str"); - } - } - - explicit __gmp_expr(mpf_srcptr f) - { mpf_init2(mp, mpf_get_prec(f)); mpf_set(mp, f); } - __gmp_expr(mpf_srcptr f, mp_bitcnt_t prec) - { mpf_init2(mp, prec); mpf_set(mp, f); } - - ~__gmp_expr() { mpf_clear(mp); } - - // assignment operators - __gmp_expr & operator=(const __gmp_expr &f) - { mpf_set(mp, f.mp); return *this; } - template - __gmp_expr & operator=(const __gmp_expr &expr) - { __gmp_set_expr(mp, expr); return *this; } - - __gmp_expr & operator=(signed char c) { mpf_set_si(mp, c); return *this; } - __gmp_expr & operator=(unsigned char c) { mpf_set_ui(mp, c); return *this; } - - __gmp_expr & operator=(signed int i) { mpf_set_si(mp, i); return *this; } - __gmp_expr & operator=(unsigned int i) { mpf_set_ui(mp, i); return *this; } - - __gmp_expr & operator=(signed short int s) - { mpf_set_si(mp, s); return *this; } - __gmp_expr & operator=(unsigned short int s) - { mpf_set_ui(mp, s); return *this; } - - __gmp_expr & operator=(signed long int l) - { mpf_set_si(mp, l); return *this; } - __gmp_expr & operator=(unsigned long int l) - { mpf_set_ui(mp, l); return *this; } - - __gmp_expr & operator=(float f) { mpf_set_d(mp, f); return *this; } - __gmp_expr & operator=(double d) { mpf_set_d(mp, d); return *this; } - // __gmp_expr & operator=(long double ld) - // { mpf_set_ld(mp, ld); return *this; } - - __gmp_expr & operator=(const char *s) - { - if (mpf_set_str (mp, s, 0) != 0) - throw std::invalid_argument ("mpf_set_str"); - return *this; - } - __gmp_expr & operator=(const std::string &s) - { - if (mpf_set_str(mp, s.c_str(), 0) != 0) - throw std::invalid_argument ("mpf_set_str"); - return *this; - } - - // string input/output functions - int set_str(const char *s, int base) - { return mpf_set_str(mp, s, base); } - int set_str(const std::string &s, int base) - { return mpf_set_str(mp, s.c_str(), base); } - std::string get_str(mp_exp_t &expo, int base = 10, size_t size = 0) const - { - __gmp_alloc_cstring temp(mpf_get_str(0, &expo, base, size, mp)); - return std::string(temp.str); - } - - // conversion functions - mpf_srcptr __get_mp() const { return mp; } - mpf_ptr __get_mp() { return mp; } - mpf_srcptr get_mpf_t() const { return mp; } - mpf_ptr get_mpf_t() { return mp; } - - signed long int get_si() const { return mpf_get_si(mp); } - unsigned long int get_ui() const { return mpf_get_ui(mp); } - double get_d() const { return mpf_get_d(mp); } - - // bool fits_schar_p() const { return mpf_fits_schar_p(mp); } - // bool fits_uchar_p() const { return mpf_fits_uchar_p(mp); } - bool fits_sint_p() const { return mpf_fits_sint_p(mp); } - bool fits_uint_p() const { return mpf_fits_uint_p(mp); } - bool fits_sshort_p() const { return mpf_fits_sshort_p(mp); } - bool fits_ushort_p() const { return mpf_fits_ushort_p(mp); } - bool fits_slong_p() const { return mpf_fits_slong_p(mp); } - bool fits_ulong_p() const { return mpf_fits_ulong_p(mp); } - // bool fits_float_p() const { return mpf_fits_float_p(mp); } - // bool fits_double_p() const { return mpf_fits_double_p(mp); } - // bool fits_ldouble_p() const { return mpf_fits_ldouble_p(mp); } - - // compound assignments - __GMP_DECLARE_COMPOUND_OPERATOR(operator+=) - __GMP_DECLARE_COMPOUND_OPERATOR(operator-=) - __GMP_DECLARE_COMPOUND_OPERATOR(operator*=) - __GMP_DECLARE_COMPOUND_OPERATOR(operator/=) - - __GMP_DECLARE_COMPOUND_OPERATOR_UI(operator<<=) - __GMP_DECLARE_COMPOUND_OPERATOR_UI(operator>>=) - - __GMP_DECLARE_INCREMENT_OPERATOR(operator++) - __GMP_DECLARE_INCREMENT_OPERATOR(operator--) -}; - -typedef __gmp_expr mpf_class; - - - -/**************** I/O operators ****************/ - -// these should (and will) be provided separately - -template -inline std::ostream & operator<< -(std::ostream &o, const __gmp_expr &expr) -{ - return o << expr.__get_mp(); -} - -template -inline std::ostream & operator<< -(std::ostream &o, const __gmp_expr &expr) -{ - __gmp_expr temp(expr); - return o << temp.__get_mp(); -} - - -template -inline std::istream & operator>>(std::istream &i, __gmp_expr &expr) -{ - return i >> expr.__get_mp(); -} - -inline std::istream & operator>>(std::istream &i, mpq_class &q) -{ - i >> q.get_mpq_t(); - // q.canonicalize(); // you might want to uncomment this - return i; -} - - -/**************** Functions for type conversion ****************/ - -template <> -inline void __gmp_set_expr(mpz_ptr z, const mpz_class &w) -{ - mpz_set(z, w.get_mpz_t()); -} - -template -inline void __gmp_set_expr(mpz_ptr z, const __gmp_expr &expr) -{ - expr.eval(z); -} - -template <> -inline void __gmp_set_expr(mpz_ptr z, const mpq_class &q) -{ - mpz_set_q(z, q.get_mpq_t()); -} - -template -inline void __gmp_set_expr(mpz_ptr z, const __gmp_expr &expr) -{ - mpq_class temp(expr); - mpz_set_q(z, temp.get_mpq_t()); -} - -template -inline void __gmp_set_expr(mpz_ptr z, const mpf_class &f) -{ - mpz_set_f(z, f.get_mpf_t()); -} - -template -inline void __gmp_set_expr(mpz_ptr z, const __gmp_expr &expr) -{ - mpf_class temp(expr); - mpz_set_f(z, temp.get_mpf_t()); -} - -template <> -inline void __gmp_set_expr(mpq_ptr q, const mpz_class &z) -{ - mpq_set_z(q, z.get_mpz_t()); -} - -template -inline void __gmp_set_expr(mpq_ptr q, const __gmp_expr &expr) -{ - mpz_class temp(expr); - mpq_set_z(q, temp.get_mpz_t()); -} - -template <> -inline void __gmp_set_expr(mpq_ptr q, const mpq_class &r) -{ - mpq_set(q, r.get_mpq_t()); -} - -template -inline void __gmp_set_expr(mpq_ptr q, const __gmp_expr &expr) -{ - expr.eval(q); -} - -template -inline void __gmp_set_expr(mpq_ptr q, const mpf_class &f) -{ - mpq_set_f(q, f.get_mpf_t()); -} - -template -inline void __gmp_set_expr(mpq_ptr q, const __gmp_expr &expr) -{ - mpf_class temp(expr); - mpq_set_f(q, temp.get_mpf_t()); -} - -template -inline void __gmp_set_expr(mpf_ptr f, const mpz_class &z) -{ - mpf_set_z(f, z.get_mpz_t()); -} - -template -inline void __gmp_set_expr(mpf_ptr f, const __gmp_expr &expr) -{ - mpz_class temp(expr); - mpf_set_z(f, temp.get_mpz_t()); -} - -template -inline void __gmp_set_expr(mpf_ptr f, const mpq_class &q) -{ - mpf_set_q(f, q.get_mpq_t()); -} - -template -inline void __gmp_set_expr(mpf_ptr f, const __gmp_expr &expr) -{ - mpq_class temp(expr); - mpf_set_q(f, temp.get_mpq_t()); -} - -template <> -inline void __gmp_set_expr(mpf_ptr f, const mpf_class &g) -{ - mpf_set(f, g.get_mpf_t()); -} - -template -inline void __gmp_set_expr(mpf_ptr f, const __gmp_expr &expr) -{ - expr.eval(f, mpf_get_prec(f)); -} - - -/**************** Specializations of __gmp_expr ****************/ -/* The eval() method of __gmp_expr evaluates the corresponding - expression and assigns the result to its argument, which is either an - mpz_t, mpq_t, or mpf_t as specified by the T argument. - Compound expressions are evaluated recursively (temporaries are created - to hold intermediate values), while for simple expressions the eval() - method of the appropriate function object (available as the Op argument - of either __gmp_unary_expr or __gmp_binary_expr) is - called. */ - - -/**************** Unary expressions ****************/ -/* cases: - - simple: argument is mp*_class, that is, __gmp_expr - - compound: argument is __gmp_expr (with U not equal to T) */ - - -// simple expressions - -template -class __gmp_expr, Op> > -{ -private: - typedef __gmp_expr val_type; - - __gmp_unary_expr expr; -public: - __gmp_expr(const val_type &val) : expr(val) { } - void eval(typename __gmp_resolve_expr::ptr_type p, - unsigned long int = 0) const - { Op::eval(p, expr.val.__get_mp()); } - const val_type & get_val() const { return expr.val; } - unsigned long int get_prec() const { return expr.val.get_prec(); } -}; - - -// compound expressions - -template -class __gmp_expr, Op> > -{ -private: - typedef __gmp_expr val_type; - - __gmp_unary_expr expr; -public: - __gmp_expr(const val_type &val) : expr(val) { } - void eval(typename __gmp_resolve_expr::ptr_type p) const - { __gmp_expr temp(expr.val); Op::eval(p, temp.__get_mp()); } - void eval(typename __gmp_resolve_expr::ptr_type p, - mp_bitcnt_t prec) const - { __gmp_expr temp(expr.val, prec); Op::eval(p, temp.__get_mp()); } - const val_type & get_val() const { return expr.val; } - unsigned long int get_prec() const { return expr.val.get_prec(); } -}; - - -/**************** Binary expressions ****************/ -/* simple: - - arguments are both mp*_class - - one argument is mp*_class, one is a built-in type - compound: - - one is mp*_class, one is __gmp_expr - - one is __gmp_expr, one is built-in - - both arguments are __gmp_expr<...> */ - - -// simple expressions - -template -class __gmp_expr -, __gmp_expr, Op> > -{ -private: - typedef __gmp_expr val1_type; - typedef __gmp_expr val2_type; - - __gmp_binary_expr expr; -public: - __gmp_expr(const val1_type &val1, const val2_type &val2) - : expr(val1, val2) { } - void eval(typename __gmp_resolve_expr::ptr_type p, - unsigned long int = 0) const - { Op::eval(p, expr.val1.__get_mp(), expr.val2.__get_mp()); } - const val1_type & get_val1() const { return expr.val1; } - const val2_type & get_val2() const { return expr.val2; } - unsigned long int get_prec() const - { - mp_bitcnt_t prec1 = expr.val1.get_prec(), - prec2 = expr.val2.get_prec(); - return (prec1 > prec2) ? prec1 : prec2; - } -}; - - -// simple expressions, T is a built-in numerical type - -template -class __gmp_expr, U, Op> > -{ -private: - typedef __gmp_expr val1_type; - typedef U val2_type; - - __gmp_binary_expr expr; -public: - __gmp_expr(const val1_type &val1, const val2_type &val2) - : expr(val1, val2) { } - void eval(typename __gmp_resolve_expr::ptr_type p, - unsigned long int = 0) const - { Op::eval(p, expr.val1.__get_mp(), expr.val2); } - const val1_type & get_val1() const { return expr.val1; } - const val2_type & get_val2() const { return expr.val2; } - unsigned long int get_prec() const { return expr.val1.get_prec(); } -}; - -template -class __gmp_expr, Op> > -{ -private: - typedef U val1_type; - typedef __gmp_expr val2_type; - - __gmp_binary_expr expr; -public: - __gmp_expr(const val1_type &val1, const val2_type &val2) - : expr(val1, val2) { } - void eval(typename __gmp_resolve_expr::ptr_type p, - unsigned long int = 0) const - { Op::eval(p, expr.val1, expr.val2.__get_mp()); } - const val1_type & get_val1() const { return expr.val1; } - const val2_type & get_val2() const { return expr.val2; } - unsigned long int get_prec() const { return expr.val2.get_prec(); } -}; - - -// compound expressions, one argument is a subexpression - -template -class __gmp_expr -, __gmp_expr, Op> > -{ -private: - typedef __gmp_expr val1_type; - typedef __gmp_expr val2_type; - - __gmp_binary_expr expr; -public: - __gmp_expr(const val1_type &val1, const val2_type &val2) - : expr(val1, val2) { } - void eval(typename __gmp_resolve_expr::ptr_type p) const - { - __gmp_expr temp(expr.val2); - Op::eval(p, expr.val1.__get_mp(), temp.__get_mp()); - } - void eval(typename __gmp_resolve_expr::ptr_type p, - mp_bitcnt_t prec) const - { - __gmp_expr temp(expr.val2, prec); - Op::eval(p, expr.val1.__get_mp(), temp.__get_mp()); - } - const val1_type & get_val1() const { return expr.val1; } - const val2_type & get_val2() const { return expr.val2; } - unsigned long int get_prec() const - { - mp_bitcnt_t prec1 = expr.val1.get_prec(), - prec2 = expr.val2.get_prec(); - return (prec1 > prec2) ? prec1 : prec2; - } -}; - -template -class __gmp_expr -, __gmp_expr, Op> > -{ -private: - typedef __gmp_expr val1_type; - typedef __gmp_expr val2_type; - - __gmp_binary_expr expr; -public: - __gmp_expr(const val1_type &val1, const val2_type &val2) - : expr(val1, val2) { } - void eval(typename __gmp_resolve_expr::ptr_type p) const - { - __gmp_expr temp(expr.val1); - Op::eval(p, temp.__get_mp(), expr.val2.__get_mp()); - } - void eval(typename __gmp_resolve_expr::ptr_type p, - mp_bitcnt_t prec) const - { - __gmp_expr temp(expr.val1, prec); - Op::eval(p, temp.__get_mp(), expr.val2.__get_mp()); - } - const val1_type & get_val1() const { return expr.val1; } - const val2_type & get_val2() const { return expr.val2; } - unsigned long int get_prec() const - { - mp_bitcnt_t prec1 = expr.val1.get_prec(), - prec2 = expr.val2.get_prec(); - return (prec1 > prec2) ? prec1 : prec2; - } -}; - -template -class __gmp_expr -, __gmp_expr, Op> > -{ -private: - typedef __gmp_expr val1_type; - typedef __gmp_expr val2_type; - - __gmp_binary_expr expr; -public: - __gmp_expr(const val1_type &val1, const val2_type &val2) - : expr(val1, val2) { } - void eval(typename __gmp_resolve_expr::ptr_type p) const - { - __gmp_expr temp(expr.val2); - Op::eval(p, expr.val1.__get_mp(), temp.__get_mp()); - } - void eval(typename __gmp_resolve_expr::ptr_type p, - mp_bitcnt_t prec) const - { - __gmp_expr temp(expr.val2, prec); - Op::eval(p, expr.val1.__get_mp(), temp.__get_mp()); - } - const val1_type & get_val1() const { return expr.val1; } - const val2_type & get_val2() const { return expr.val2; } - unsigned long int get_prec() const - { - mp_bitcnt_t prec1 = expr.val1.get_prec(), - prec2 = expr.val2.get_prec(); - return (prec1 > prec2) ? prec1 : prec2; - } -}; - -template -class __gmp_expr -, __gmp_expr, Op> > -{ -private: - typedef __gmp_expr val1_type; - typedef __gmp_expr val2_type; - - __gmp_binary_expr expr; -public: - __gmp_expr(const val1_type &val1, const val2_type &val2) - : expr(val1, val2) { } - void eval(typename __gmp_resolve_expr::ptr_type p) const - { - __gmp_expr temp(expr.val1); - Op::eval(p, temp.__get_mp(), expr.val2.__get_mp()); - } - void eval(typename __gmp_resolve_expr::ptr_type p, - mp_bitcnt_t prec) const - { - __gmp_expr temp(expr.val1, prec); - Op::eval(p, temp.__get_mp(), expr.val2.__get_mp()); - } - const val1_type & get_val1() const { return expr.val1; } - const val2_type & get_val2() const { return expr.val2; } - unsigned long int get_prec() const - { - mp_bitcnt_t prec1 = expr.val1.get_prec(), - prec2 = expr.val2.get_prec(); - return (prec1 > prec2) ? prec1 : prec2; - } -}; - - -// one argument is a subexpression, one is a built-in - -template -class __gmp_expr, V, Op> > -{ -private: - typedef __gmp_expr val1_type; - typedef V val2_type; - - __gmp_binary_expr expr; -public: - __gmp_expr(const val1_type &val1, const val2_type &val2) - : expr(val1, val2) { } - void eval(typename __gmp_resolve_expr::ptr_type p) const - { - __gmp_expr temp(expr.val1); - Op::eval(p, temp.__get_mp(), expr.val2); - } - void eval(typename __gmp_resolve_expr::ptr_type p, - mp_bitcnt_t prec) const - { - __gmp_expr temp(expr.val1, prec); - Op::eval(p, temp.__get_mp(), expr.val2); - } - const val1_type & get_val1() const { return expr.val1; } - const val2_type & get_val2() const { return expr.val2; } - unsigned long int get_prec() const { return expr.val1.get_prec(); } -}; - -template -class __gmp_expr, Op> > -{ -private: - typedef U val1_type; - typedef __gmp_expr val2_type; - - __gmp_binary_expr expr; -public: - __gmp_expr(const val1_type &val1, const val2_type &val2) - : expr(val1, val2) { } - void eval(typename __gmp_resolve_expr::ptr_type p) const - { - __gmp_expr temp(expr.val2); - Op::eval(p, expr.val1, temp.__get_mp()); - } - void eval(typename __gmp_resolve_expr::ptr_type p, - mp_bitcnt_t prec) const - { - __gmp_expr temp(expr.val2, prec); - Op::eval(p, expr.val1, temp.__get_mp()); - } - const val1_type & get_val1() const { return expr.val1; } - const val2_type & get_val2() const { return expr.val2; } - unsigned long int get_prec() const { return expr.val2.get_prec(); } -}; - - -// both arguments are subexpressions - -template -class __gmp_expr -, __gmp_expr, Op> > -{ -private: - typedef __gmp_expr val1_type; - typedef __gmp_expr val2_type; - - __gmp_binary_expr expr; -public: - __gmp_expr(const val1_type &val1, const val2_type &val2) - : expr(val1, val2) { } - void eval(typename __gmp_resolve_expr::ptr_type p) const - { - __gmp_expr temp1(expr.val1), temp2(expr.val2); - Op::eval(p, temp1.__get_mp(), temp2.__get_mp()); - } - void eval(typename __gmp_resolve_expr::ptr_type p, - mp_bitcnt_t prec) const - { - __gmp_expr temp1(expr.val1, prec), temp2(expr.val2, prec); - Op::eval(p, temp1.__get_mp(), temp2.__get_mp()); - } - const val1_type & get_val1() const { return expr.val1; } - const val2_type & get_val2() const { return expr.val2; } - unsigned long int get_prec() const - { - mp_bitcnt_t prec1 = expr.val1.get_prec(), - prec2 = expr.val2.get_prec(); - return (prec1 > prec2) ? prec1 : prec2; - } -}; - -template -class __gmp_expr -, __gmp_expr, Op> > -{ -private: - typedef __gmp_expr val1_type; - typedef __gmp_expr val2_type; - - __gmp_binary_expr expr; -public: - __gmp_expr(const val1_type &val1, const val2_type &val2) - : expr(val1, val2) { } - void eval(typename __gmp_resolve_expr::ptr_type p) const - { - __gmp_expr temp1(expr.val1), temp2(expr.val2); - Op::eval(p, temp1.__get_mp(), temp2.__get_mp()); - } - void eval(typename __gmp_resolve_expr::ptr_type p, - mp_bitcnt_t prec) const - { - __gmp_expr temp1(expr.val1, prec), temp2(expr.val2, prec); - Op::eval(p, temp1.__get_mp(), temp2.__get_mp()); - } - const val1_type & get_val1() const { return expr.val1; } - const val2_type & get_val2() const { return expr.val2; } - unsigned long int get_prec() const - { - mp_bitcnt_t prec1 = expr.val1.get_prec(), - prec2 = expr.val2.get_prec(); - return (prec1 > prec2) ? prec1 : prec2; - } -}; - -template -class __gmp_expr -, __gmp_expr, Op> > -{ -private: - typedef __gmp_expr val1_type; - typedef __gmp_expr val2_type; - - __gmp_binary_expr expr; -public: - __gmp_expr(const val1_type &val1, const val2_type &val2) - : expr(val1, val2) { } - void eval(typename __gmp_resolve_expr::ptr_type p) const - { - __gmp_expr temp1(expr.val1), temp2(expr.val2); - Op::eval(p, temp1.__get_mp(), temp2.__get_mp()); - } - void eval(typename __gmp_resolve_expr::ptr_type p, - mp_bitcnt_t prec) const - { - __gmp_expr temp1(expr.val1, prec), temp2(expr.val2, prec); - Op::eval(p, temp1.__get_mp(), temp2.__get_mp()); - } - const val1_type & get_val1() const { return expr.val1; } - const val2_type & get_val2() const { return expr.val2; } - unsigned long int get_prec() const - { - mp_bitcnt_t prec1 = expr.val1.get_prec(), - prec2 = expr.val2.get_prec(); - return (prec1 > prec2) ? prec1 : prec2; - } -}; - - -/**************** Special cases ****************/ - -/* Some operations (i.e., add and subtract) with mixed mpz/mpq arguments - can be done directly without first converting the mpz to mpq. - Appropriate specializations of __gmp_expr are required. */ - - -#define __GMPZQ_DEFINE_EXPR(eval_fun) \ - \ -template <> \ -class __gmp_expr > \ -{ \ -private: \ - typedef mpz_class val1_type; \ - typedef mpq_class val2_type; \ - \ - __gmp_binary_expr expr; \ -public: \ - __gmp_expr(const val1_type &val1, const val2_type &val2) \ - : expr(val1, val2) { } \ - void eval(mpq_ptr q) const \ - { eval_fun::eval(q, expr.val1.get_mpz_t(), expr.val2.get_mpq_t()); } \ - const val1_type & get_val1() const { return expr.val1; } \ - const val2_type & get_val2() const { return expr.val2; } \ - unsigned long int get_prec() const { return mpf_get_default_prec(); } \ -}; \ - \ -template <> \ -class __gmp_expr > \ -{ \ -private: \ - typedef mpq_class val1_type; \ - typedef mpz_class val2_type; \ - \ - __gmp_binary_expr expr; \ -public: \ - __gmp_expr(const val1_type &val1, const val2_type &val2) \ - : expr(val1, val2) { } \ - void eval(mpq_ptr q) const \ - { eval_fun::eval(q, expr.val1.get_mpq_t(), expr.val2.get_mpz_t()); } \ - const val1_type & get_val1() const { return expr.val1; } \ - const val2_type & get_val2() const { return expr.val2; } \ - unsigned long int get_prec() const { return mpf_get_default_prec(); } \ -}; \ - \ -template \ -class __gmp_expr \ -, eval_fun> > \ -{ \ -private: \ - typedef mpz_class val1_type; \ - typedef __gmp_expr val2_type; \ - \ - __gmp_binary_expr expr; \ -public: \ - __gmp_expr(const val1_type &val1, const val2_type &val2) \ - : expr(val1, val2) { } \ - void eval(mpq_ptr q) const \ - { \ - mpq_class temp(expr.val2); \ - eval_fun::eval(q, expr.val1.get_mpz_t(), temp.get_mpq_t()); \ - } \ - const val1_type & get_val1() const { return expr.val1; } \ - const val2_type & get_val2() const { return expr.val2; } \ - unsigned long int get_prec() const { return mpf_get_default_prec(); } \ -}; \ - \ -template \ -class __gmp_expr \ -, eval_fun> > \ -{ \ -private: \ - typedef mpq_class val1_type; \ - typedef __gmp_expr val2_type; \ - \ - __gmp_binary_expr expr; \ -public: \ - __gmp_expr(const val1_type &val1, const val2_type &val2) \ - : expr(val1, val2) { } \ - void eval(mpq_ptr q) const \ - { \ - mpz_class temp(expr.val2); \ - eval_fun::eval(q, expr.val1.get_mpq_t(), temp.get_mpz_t()); \ - } \ - const val1_type & get_val1() const { return expr.val1; } \ - const val2_type & get_val2() const { return expr.val2; } \ - unsigned long int get_prec() const { return mpf_get_default_prec(); } \ -}; \ - \ -template \ -class __gmp_expr \ -, mpq_class, eval_fun> > \ -{ \ -private: \ - typedef __gmp_expr val1_type; \ - typedef mpq_class val2_type; \ - \ - __gmp_binary_expr expr; \ -public: \ - __gmp_expr(const val1_type &val1, const val2_type &val2) \ - : expr(val1, val2) { } \ - void eval(mpq_ptr q) const \ - { \ - mpz_class temp(expr.val1); \ - eval_fun::eval(q, temp.get_mpz_t(), expr.val2.get_mpq_t()); \ - } \ - const val1_type & get_val1() const { return expr.val1; } \ - const val2_type & get_val2() const { return expr.val2; } \ - unsigned long int get_prec() const { return mpf_get_default_prec(); } \ -}; \ - \ -template \ -class __gmp_expr \ -, mpz_class, eval_fun> > \ -{ \ -private: \ - typedef __gmp_expr val1_type; \ - typedef mpz_class val2_type; \ - \ - __gmp_binary_expr expr; \ -public: \ - __gmp_expr(const val1_type &val1, const val2_type &val2) \ - : expr(val1, val2) { } \ - void eval(mpq_ptr q) const \ - { \ - mpq_class temp(expr.val1); \ - eval_fun::eval(q, temp.get_mpq_t(), expr.val2.get_mpz_t()); \ - } \ - const val1_type & get_val1() const { return expr.val1; } \ - const val2_type & get_val2() const { return expr.val2; } \ - unsigned long int get_prec() const { return mpf_get_default_prec(); } \ -}; \ - \ -template \ -class __gmp_expr, __gmp_expr, eval_fun> > \ -{ \ -private: \ - typedef __gmp_expr val1_type; \ - typedef __gmp_expr val2_type; \ - \ - __gmp_binary_expr expr; \ -public: \ - __gmp_expr(const val1_type &val1, const val2_type &val2) \ - : expr(val1, val2) { } \ - void eval(mpq_ptr q) const \ - { \ - mpz_class temp1(expr.val1); \ - mpq_class temp2(expr.val2); \ - eval_fun::eval(q, temp1.get_mpz_t(), temp2.get_mpq_t()); \ - } \ - const val1_type & get_val1() const { return expr.val1; } \ - const val2_type & get_val2() const { return expr.val2; } \ - unsigned long int get_prec() const { return mpf_get_default_prec(); } \ -}; \ - \ -template \ -class __gmp_expr, __gmp_expr, eval_fun> > \ -{ \ -private: \ - typedef __gmp_expr val1_type; \ - typedef __gmp_expr val2_type; \ - \ - __gmp_binary_expr expr; \ -public: \ - __gmp_expr(const val1_type &val1, const val2_type &val2) \ - : expr(val1, val2) { } \ - void eval(mpq_ptr q) const \ - { \ - mpq_class temp1(expr.val1); \ - mpz_class temp2(expr.val2); \ - eval_fun::eval(q, temp1.get_mpq_t(), temp2.get_mpz_t()); \ - } \ - const val1_type & get_val1() const { return expr.val1; } \ - const val2_type & get_val2() const { return expr.val2; } \ - unsigned long int get_prec() const { return mpf_get_default_prec(); } \ -}; - - -__GMPZQ_DEFINE_EXPR(__gmp_binary_plus) -__GMPZQ_DEFINE_EXPR(__gmp_binary_minus) - -/**************** Macros for defining functions ****************/ -/* Results of operators and functions are instances of __gmp_expr. - T determines the numerical type of the expression: it can be either - mpz_t, mpq_t, or mpf_t. When the arguments of a binary - expression have different numerical types, __gmp_resolve_expr is used - to determine the "larger" type. - U is either __gmp_unary_expr or __gmp_binary_expr, - where V and W are the arguments' types -- they can in turn be - expressions, thus allowing to build compound expressions to any - degree of complexity. - Op is a function object that must have an eval() method accepting - appropriate arguments. - Actual evaluation of a __gmp_expr object is done when it gets - assigned to an mp*_class ("lazy" evaluation): this is done by calling - its eval() method. */ - - -// non-member unary operators and functions - -#define __GMP_DEFINE_UNARY_FUNCTION(fun, eval_fun) \ - \ -template \ -inline __gmp_expr, eval_fun> > \ -fun(const __gmp_expr &expr) \ -{ \ - return __gmp_expr, eval_fun> >(expr); \ -} - -#define __GMP_DEFINE_UNARY_TYPE_FUNCTION(type, fun, eval_fun) \ - \ -template \ -inline type fun(const __gmp_expr &expr) \ -{ \ - typename __gmp_resolve_temp::temp_type temp(expr); \ - return eval_fun::eval(temp.__get_mp()); \ -} - - -// non-member binary operators and functions - -#define __GMPP_DEFINE_BINARY_FUNCTION(fun, eval_fun) \ - \ -template \ -inline __gmp_expr::value_type, \ -__gmp_binary_expr<__gmp_expr, __gmp_expr, eval_fun> > \ -fun(const __gmp_expr &expr1, const __gmp_expr &expr2) \ -{ \ - return __gmp_expr::value_type, \ - __gmp_binary_expr<__gmp_expr, __gmp_expr, eval_fun> > \ - (expr1, expr2); \ -} - -#define __GMPNN_DEFINE_BINARY_FUNCTION(fun, eval_fun, type, bigtype) \ - \ -template \ -inline __gmp_expr \ -, bigtype, eval_fun> > \ -fun(const __gmp_expr &expr, type t) \ -{ \ - return __gmp_expr \ - , bigtype, eval_fun> >(expr, t); \ -} \ - \ -template \ -inline __gmp_expr \ -, eval_fun> > \ -fun(type t, const __gmp_expr &expr) \ -{ \ - return __gmp_expr \ - , eval_fun> >(t, expr); \ -} - -#define __GMPNS_DEFINE_BINARY_FUNCTION(fun, eval_fun, type) \ -__GMPNN_DEFINE_BINARY_FUNCTION(fun, eval_fun, type, signed long int) - -#define __GMPNU_DEFINE_BINARY_FUNCTION(fun, eval_fun, type) \ -__GMPNN_DEFINE_BINARY_FUNCTION(fun, eval_fun, type, unsigned long int) - -#define __GMPND_DEFINE_BINARY_FUNCTION(fun, eval_fun, type) \ -__GMPNN_DEFINE_BINARY_FUNCTION(fun, eval_fun, type, double) - -#define __GMPNLD_DEFINE_BINARY_FUNCTION(fun, eval_fun, type) \ -__GMPNN_DEFINE_BINARY_FUNCTION(fun, eval_fun, type, long double) - -#define __GMPN_DEFINE_BINARY_FUNCTION(fun, eval_fun) \ -__GMPNS_DEFINE_BINARY_FUNCTION(fun, eval_fun, signed char) \ -__GMPNU_DEFINE_BINARY_FUNCTION(fun, eval_fun, unsigned char) \ -__GMPNS_DEFINE_BINARY_FUNCTION(fun, eval_fun, signed int) \ -__GMPNU_DEFINE_BINARY_FUNCTION(fun, eval_fun, unsigned int) \ -__GMPNS_DEFINE_BINARY_FUNCTION(fun, eval_fun, signed short int) \ -__GMPNU_DEFINE_BINARY_FUNCTION(fun, eval_fun, unsigned short int) \ -__GMPNS_DEFINE_BINARY_FUNCTION(fun, eval_fun, signed long int) \ -__GMPNU_DEFINE_BINARY_FUNCTION(fun, eval_fun, unsigned long int) \ -__GMPND_DEFINE_BINARY_FUNCTION(fun, eval_fun, float) \ -__GMPND_DEFINE_BINARY_FUNCTION(fun, eval_fun, double) \ -__GMPNLD_DEFINE_BINARY_FUNCTION(fun, eval_fun, long double) - -#define __GMP_DEFINE_BINARY_FUNCTION(fun, eval_fun) \ -__GMPP_DEFINE_BINARY_FUNCTION(fun, eval_fun) \ -__GMPN_DEFINE_BINARY_FUNCTION(fun, eval_fun) - - -#define __GMP_DEFINE_BINARY_FUNCTION_UI(fun, eval_fun) \ - \ -template \ -inline __gmp_expr \ -, unsigned long int, eval_fun> > \ -fun(const __gmp_expr &expr, unsigned long int l) \ -{ \ - return __gmp_expr, unsigned long int, eval_fun> >(expr, l); \ -} - - -#define __GMPP_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun) \ - \ -template \ -inline type fun(const __gmp_expr &expr1, \ - const __gmp_expr &expr2) \ -{ \ - typedef typename __gmp_resolve_expr::value_type eval_type; \ - typename __gmp_resolve_temp::temp_type temp1(expr1); \ - typename __gmp_resolve_temp::temp_type temp2(expr2); \ - return eval_fun::eval(temp1.__get_mp(), temp2.__get_mp()); \ -} - -#define __GMPNN_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, \ - type2, bigtype) \ - \ -template \ -inline type fun(const __gmp_expr &expr, type2 t) \ -{ \ - typename __gmp_resolve_temp::temp_type temp(expr); \ - return eval_fun::eval(temp.__get_mp(), static_cast(t)); \ -} \ - \ -template \ -inline type fun(type2 t, const __gmp_expr &expr) \ -{ \ - typename __gmp_resolve_temp::temp_type temp(expr); \ - return eval_fun::eval(static_cast(t), temp.__get_mp()); \ -} - -#define __GMPNS_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, type2) \ -__GMPNN_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, \ - type2, signed long int) - -#define __GMPNU_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, type2) \ -__GMPNN_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, \ - type2, unsigned long int) - -#define __GMPND_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, type2) \ -__GMPNN_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, type2, double) - -#define __GMPNLD_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, type2) \ -__GMPNN_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, type2, long double) - -#define __GMPN_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun) \ -__GMPNS_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, signed char) \ -__GMPNU_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, unsigned char) \ -__GMPNS_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, signed int) \ -__GMPNU_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, unsigned int) \ -__GMPNS_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, signed short int) \ -__GMPNU_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, unsigned short int) \ -__GMPNS_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, signed long int) \ -__GMPNU_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, unsigned long int) \ -__GMPND_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, float) \ -__GMPND_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, double) \ -__GMPNLD_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, long double) - -#define __GMP_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun) \ -__GMPP_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun) \ -__GMPN_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun) - - -// member operators - -#define __GMPP_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun) \ - \ -template \ -inline type##_class & type##_class::fun(const __gmp_expr &expr) \ -{ \ - __gmp_set_expr(mp, __gmp_expr, eval_fun> >(*this, expr)); \ - return *this; \ -} - -#define __GMPNN_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, \ - type2, bigtype) \ - \ -inline type##_class & type##_class::fun(type2 t) \ -{ \ - __gmp_set_expr(mp, __gmp_expr >(*this, t)); \ - return *this; \ -} - -#define __GMPNS_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, type2) \ -__GMPNN_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, \ - type2, signed long int) - -#define __GMPNU_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, type2) \ -__GMPNN_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, \ - type2, unsigned long int) - -#define __GMPND_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, type2) \ -__GMPNN_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, type2, double) - -#define __GMPNLD_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, type2) \ -__GMPNN_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, type2, long double) - -#define __GMPN_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun) \ -__GMPNS_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, signed char) \ -__GMPNU_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, unsigned char) \ -__GMPNS_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, signed int) \ -__GMPNU_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, unsigned int) \ -__GMPNS_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, signed short int) \ -__GMPNU_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, unsigned short int) \ -__GMPNS_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, signed long int) \ -__GMPNU_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, unsigned long int) \ -__GMPND_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, float) \ -__GMPND_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, double) \ -/* __GMPNLD_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, long double) */ - -#define __GMP_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun) \ -__GMPP_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun) \ -__GMPN_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun) - -#define __GMPZ_DEFINE_COMPOUND_OPERATOR(fun, eval_fun) \ -__GMP_DEFINE_COMPOUND_OPERATOR(mpz, fun, eval_fun) - -#define __GMPZZ_DEFINE_COMPOUND_OPERATOR(fun, eval_fun) \ -__GMPP_DEFINE_COMPOUND_OPERATOR(mpz, fun, eval_fun) - -#define __GMPQ_DEFINE_COMPOUND_OPERATOR(fun, eval_fun) \ -__GMP_DEFINE_COMPOUND_OPERATOR(mpq, fun, eval_fun) - -#define __GMPF_DEFINE_COMPOUND_OPERATOR(fun, eval_fun) \ -__GMP_DEFINE_COMPOUND_OPERATOR(mpf, fun, eval_fun) - - - -#define __GMP_DEFINE_COMPOUND_OPERATOR_UI(type, fun, eval_fun) \ - \ -inline type##_class & type##_class::fun(unsigned long int l) \ -{ \ - __gmp_set_expr(mp, __gmp_expr >(*this, l)); \ - return *this; \ -} - -#define __GMPZ_DEFINE_COMPOUND_OPERATOR_UI(fun, eval_fun) \ -__GMP_DEFINE_COMPOUND_OPERATOR_UI(mpz, fun, eval_fun) - -#define __GMPQ_DEFINE_COMPOUND_OPERATOR_UI(fun, eval_fun) \ -__GMP_DEFINE_COMPOUND_OPERATOR_UI(mpq, fun, eval_fun) - -#define __GMPF_DEFINE_COMPOUND_OPERATOR_UI(fun, eval_fun) \ -__GMP_DEFINE_COMPOUND_OPERATOR_UI(mpf, fun, eval_fun) - - - -#define __GMP_DEFINE_INCREMENT_OPERATOR(type, fun, eval_fun) \ - \ -inline type##_class & type##_class::fun() \ -{ \ - eval_fun::eval(mp); \ - return *this; \ -} \ - \ -inline type##_class type##_class::fun(int) \ -{ \ - type##_class temp(*this); \ - eval_fun::eval(mp); \ - return temp; \ -} - -#define __GMPZ_DEFINE_INCREMENT_OPERATOR(fun, eval_fun) \ -__GMP_DEFINE_INCREMENT_OPERATOR(mpz, fun, eval_fun) - -#define __GMPQ_DEFINE_INCREMENT_OPERATOR(fun, eval_fun) \ -__GMP_DEFINE_INCREMENT_OPERATOR(mpq, fun, eval_fun) - -#define __GMPF_DEFINE_INCREMENT_OPERATOR(fun, eval_fun) \ -__GMP_DEFINE_INCREMENT_OPERATOR(mpf, fun, eval_fun) - - - -/**************** Arithmetic operators and functions ****************/ - -// non-member operators and functions - -__GMP_DEFINE_UNARY_FUNCTION(operator+, __gmp_unary_plus) -__GMP_DEFINE_UNARY_FUNCTION(operator-, __gmp_unary_minus) -__GMP_DEFINE_UNARY_FUNCTION(operator~, __gmp_unary_com) - -__GMP_DEFINE_BINARY_FUNCTION(operator+, __gmp_binary_plus) -__GMP_DEFINE_BINARY_FUNCTION(operator-, __gmp_binary_minus) -__GMP_DEFINE_BINARY_FUNCTION(operator*, __gmp_binary_multiplies) -__GMP_DEFINE_BINARY_FUNCTION(operator/, __gmp_binary_divides) -__GMP_DEFINE_BINARY_FUNCTION(operator%, __gmp_binary_modulus) -__GMP_DEFINE_BINARY_FUNCTION(operator&, __gmp_binary_and) -__GMP_DEFINE_BINARY_FUNCTION(operator|, __gmp_binary_ior) -__GMP_DEFINE_BINARY_FUNCTION(operator^, __gmp_binary_xor) - -__GMP_DEFINE_BINARY_FUNCTION_UI(operator<<, __gmp_binary_lshift) -__GMP_DEFINE_BINARY_FUNCTION_UI(operator>>, __gmp_binary_rshift) - -__GMP_DEFINE_BINARY_TYPE_FUNCTION(bool, operator==, __gmp_binary_equal) -__GMP_DEFINE_BINARY_TYPE_FUNCTION(bool, operator!=, __gmp_binary_not_equal) -__GMP_DEFINE_BINARY_TYPE_FUNCTION(bool, operator<, __gmp_binary_less) -__GMP_DEFINE_BINARY_TYPE_FUNCTION(bool, operator<=, __gmp_binary_less_equal) -__GMP_DEFINE_BINARY_TYPE_FUNCTION(bool, operator>, __gmp_binary_greater) -__GMP_DEFINE_BINARY_TYPE_FUNCTION(bool, operator>=, \ - __gmp_binary_greater_equal) - -__GMP_DEFINE_UNARY_FUNCTION(abs, __gmp_abs_function) -__GMP_DEFINE_UNARY_FUNCTION(trunc, __gmp_trunc_function) -__GMP_DEFINE_UNARY_FUNCTION(floor, __gmp_floor_function) -__GMP_DEFINE_UNARY_FUNCTION(ceil, __gmp_ceil_function) -__GMP_DEFINE_UNARY_FUNCTION(sqrt, __gmp_sqrt_function) -__GMP_DEFINE_BINARY_FUNCTION(hypot, __gmp_hypot_function) - -__GMP_DEFINE_UNARY_TYPE_FUNCTION(int, sgn, __gmp_sgn_function) -__GMP_DEFINE_BINARY_TYPE_FUNCTION(int, cmp, __gmp_cmp_function) - -// member operators for mpz_class - -__GMPZ_DEFINE_COMPOUND_OPERATOR(operator+=, __gmp_binary_plus) -__GMPZ_DEFINE_COMPOUND_OPERATOR(operator-=, __gmp_binary_minus) -__GMPZ_DEFINE_COMPOUND_OPERATOR(operator*=, __gmp_binary_multiplies) -__GMPZ_DEFINE_COMPOUND_OPERATOR(operator/=, __gmp_binary_divides) -__GMPZ_DEFINE_COMPOUND_OPERATOR(operator%=, __gmp_binary_modulus) - -__GMPZZ_DEFINE_COMPOUND_OPERATOR(operator&=, __gmp_binary_and) -__GMPZZ_DEFINE_COMPOUND_OPERATOR(operator|=, __gmp_binary_ior) -__GMPZZ_DEFINE_COMPOUND_OPERATOR(operator^=, __gmp_binary_xor) - -__GMPZ_DEFINE_COMPOUND_OPERATOR_UI(operator<<=, __gmp_binary_lshift) -__GMPZ_DEFINE_COMPOUND_OPERATOR_UI(operator>>=, __gmp_binary_rshift) - -__GMPZ_DEFINE_INCREMENT_OPERATOR(operator++, __gmp_unary_increment) -__GMPZ_DEFINE_INCREMENT_OPERATOR(operator--, __gmp_unary_decrement) - -// member operators for mpq_class - -__GMPQ_DEFINE_COMPOUND_OPERATOR(operator+=, __gmp_binary_plus) -__GMPQ_DEFINE_COMPOUND_OPERATOR(operator-=, __gmp_binary_minus) -__GMPQ_DEFINE_COMPOUND_OPERATOR(operator*=, __gmp_binary_multiplies) -__GMPQ_DEFINE_COMPOUND_OPERATOR(operator/=, __gmp_binary_divides) - -__GMPQ_DEFINE_COMPOUND_OPERATOR_UI(operator<<=, __gmp_binary_lshift) -__GMPQ_DEFINE_COMPOUND_OPERATOR_UI(operator>>=, __gmp_binary_rshift) - -__GMPQ_DEFINE_INCREMENT_OPERATOR(operator++, __gmp_unary_increment) -__GMPQ_DEFINE_INCREMENT_OPERATOR(operator--, __gmp_unary_decrement) - -// member operators for mpf_class - -__GMPF_DEFINE_COMPOUND_OPERATOR(operator+=, __gmp_binary_plus) -__GMPF_DEFINE_COMPOUND_OPERATOR(operator-=, __gmp_binary_minus) -__GMPF_DEFINE_COMPOUND_OPERATOR(operator*=, __gmp_binary_multiplies) -__GMPF_DEFINE_COMPOUND_OPERATOR(operator/=, __gmp_binary_divides) - -__GMPF_DEFINE_COMPOUND_OPERATOR_UI(operator<<=, __gmp_binary_lshift) -__GMPF_DEFINE_COMPOUND_OPERATOR_UI(operator>>=, __gmp_binary_rshift) - -__GMPF_DEFINE_INCREMENT_OPERATOR(operator++, __gmp_unary_increment) -__GMPF_DEFINE_INCREMENT_OPERATOR(operator--, __gmp_unary_decrement) - - - -/**************** Class wrapper for gmp_randstate_t ****************/ - -class __gmp_urandomb_value { }; -class __gmp_urandomm_value { }; - -template <> -class __gmp_expr -{ -private: - __gmp_randstate_struct *state; - unsigned long int bits; -public: - __gmp_expr(gmp_randstate_t s, unsigned long int l) : state(s), bits(l) { } - void eval(mpz_ptr z) const { __gmp_rand_function::eval(z, state, bits); } - unsigned long int get_prec() const { return mpf_get_default_prec(); } -}; - -template <> -class __gmp_expr -{ -private: - __gmp_randstate_struct *state; - mpz_class range; -public: - __gmp_expr(gmp_randstate_t s, const mpz_class &z) : state(s), range(z) { } - void eval(mpz_ptr z) const - { __gmp_rand_function::eval(z, state, range.get_mpz_t()); } - unsigned long int get_prec() const { return mpf_get_default_prec(); } -}; - -template <> -class __gmp_expr -{ -private: - __gmp_randstate_struct *state; - unsigned long int bits; -public: - __gmp_expr(gmp_randstate_t s, unsigned long int l) : state(s), bits(l) { } - void eval(mpf_ptr f, mp_bitcnt_t prec) const - { __gmp_rand_function::eval(f, state, (bits>0) ? get_prec() : prec); } - unsigned long int get_prec() const - { - if (bits == 0) - return mpf_get_default_prec(); - else - return bits; - } -}; - -extern "C" { - typedef void __gmp_randinit_default_t (gmp_randstate_t); - typedef void __gmp_randinit_lc_2exp_t (gmp_randstate_t, mpz_srcptr, unsigned long int, mp_bitcnt_t); - typedef int __gmp_randinit_lc_2exp_size_t (gmp_randstate_t, mp_bitcnt_t); -} - -class gmp_randclass -{ -private: - gmp_randstate_t state; - - // copy construction and assignment not allowed - gmp_randclass(const gmp_randclass &); - void operator=(const gmp_randclass &); -public: - // constructors and destructor - gmp_randclass(gmp_randalg_t alg, unsigned long int size) - { - switch (alg) - { - case GMP_RAND_ALG_LC: // no other cases for now - default: - gmp_randinit_lc_2exp_size(state, size); - break; - } - } - - // gmp_randinit_default - gmp_randclass(__gmp_randinit_default_t* f) { f(state); } - - // gmp_randinit_lc_2exp - gmp_randclass(__gmp_randinit_lc_2exp_t* f, - mpz_class z, unsigned long int l1, unsigned long int l2) - { f(state, z.get_mpz_t(), l1, l2); } - - // gmp_randinit_lc_2exp_size - gmp_randclass(__gmp_randinit_lc_2exp_size_t* f, - unsigned long int size) - { - if (f (state, size) == 0) - throw std::length_error ("gmp_randinit_lc_2exp_size"); - } - - ~gmp_randclass() { gmp_randclear(state); } - - // initialize - void seed(); // choose a random seed some way (?) - void seed(unsigned long int s) { gmp_randseed_ui(state, s); } - void seed(const mpz_class &z) { gmp_randseed(state, z.get_mpz_t()); } - - // get random number - __gmp_expr get_z_bits(unsigned long int l) - { return __gmp_expr(state, l); } - __gmp_expr get_z_bits(const mpz_class &z) - { return get_z_bits(z.get_ui()); } - - __gmp_expr get_z_range(const mpz_class &z) - { return __gmp_expr(state, z); } - - __gmp_expr get_f(unsigned long int prec = 0) - { return __gmp_expr(state, prec); } -}; - - -/**************** #undef all private macros ****************/ - -#undef __GMPP_DECLARE_COMPOUND_OPERATOR -#undef __GMPN_DECLARE_COMPOUND_OPERATOR -#undef __GMP_DECLARE_COMPOUND_OPERATOR -#undef __GMP_DECLARE_COMPOUND_OPERATOR_UI -#undef __GMP_DECLARE_INCREMENT_OPERATOR - -#undef __GMPZQ_DEFINE_EXPR -#undef __GMP_DEFINE_TERNARY_EXPR - -#undef __GMP_DEFINE_UNARY_FUNCTION -#undef __GMP_DEFINE_UNARY_TYPE_FUNCTION - -#undef __GMPP_DEFINE_BINARY_FUNCTION -#undef __GMPNN_DEFINE_BINARY_FUNCTION -#undef __GMPNS_DEFINE_BINARY_FUNCTION -#undef __GMPNU_DEFINE_BINARY_FUNCTION -#undef __GMPND_DEFINE_BINARY_FUNCTION -#undef __GMPNLD_DEFINE_BINARY_FUNCTION -#undef __GMPN_DEFINE_BINARY_FUNCTION -#undef __GMP_DEFINE_BINARY_FUNCTION - -#undef __GMP_DEFINE_BINARY_FUNCTION_UI - -#undef __GMPP_DEFINE_BINARY_TYPE_FUNCTION -#undef __GMPNN_DEFINE_BINARY_TYPE_FUNCTION -#undef __GMPNS_DEFINE_BINARY_TYPE_FUNCTION -#undef __GMPNU_DEFINE_BINARY_TYPE_FUNCTION -#undef __GMPND_DEFINE_BINARY_TYPE_FUNCTION -#undef __GMPNLD_DEFINE_BINARY_TYPE_FUNCTION -#undef __GMPN_DEFINE_BINARY_TYPE_FUNCTION -#undef __GMP_DEFINE_BINARY_TYPE_FUNCTION - -#undef __GMPP_DECLARE_COMPOUND_OPERATOR -#undef __GMPN_DECLARE_COMPOUND_OPERATOR -#undef __GMP_DECLARE_COMPOUND_OPERATOR - -#undef __GMP_DECLARE_COMPOUND_OPERATOR_UI -#undef __GMP_DECLARE_INCREMENT_OPERATOR - -#undef __GMPZ_DEFINE_COMPOUND_OPERATOR -#undef __GMPZZ_DEFINE_COMPOUND_OPERATOR -#undef __GMPZN_DEFINE_COMPOUND_OPERATOR -#undef __GMPZNN_DEFINE_COMPOUND_OPERATOR -#undef __GMPZNS_DEFINE_COMPOUND_OPERATOR -#undef __GMPZNU_DEFINE_COMPOUND_OPERATOR -#undef __GMPZND_DEFINE_COMPOUND_OPERATOR -#undef __GMPZNLD_DEFINE_COMPOUND_OPERATOR - -#undef __GMPP_DEFINE_COMPOUND_OPERATOR -#undef __GMPNN_DEFINE_COMPOUND_OPERATOR -#undef __GMPNS_DEFINE_COMPOUND_OPERATOR -#undef __GMPNU_DEFINE_COMPOUND_OPERATOR -#undef __GMPND_DEFINE_COMPOUND_OPERATOR -#undef __GMPNLD_DEFINE_COMPOUND_OPERATOR -#undef __GMPN_DEFINE_COMPOUND_OPERATOR -#undef __GMP_DEFINE_COMPOUND_OPERATOR - -#undef __GMPZ_DEFINE_COMPOUND_OPERATOR -#undef __GMPZZ_DEFINE_COMPOUND_OPERATOR -#undef __GMPQ_DEFINE_COMPOUND_OPERATOR -#undef __GMPF_DEFINE_COMPOUND_OPERATOR - -#undef __GMP_DEFINE_COMPOUND_OPERATOR_UI -#undef __GMPZ_DEFINE_COMPOUND_OPERATOR_UI -#undef __GMPQ_DEFINE_COMPOUND_OPERATOR_UI -#undef __GMPF_DEFINE_COMPOUND_OPERATOR_UI - -#undef __GMP_DEFINE_INCREMENT_OPERATOR -#undef __GMPZ_DEFINE_INCREMENT_OPERATOR -#undef __GMPQ_DEFINE_INCREMENT_OPERATOR -#undef __GMPF_DEFINE_INCREMENT_OPERATOR - -#endif /* __GMP_PLUSPLUS__ */ diff --git a/src/external/inc/macx64/mpir-2.4.0/mpir.h b/src/external/inc/macx64/mpir-2.4.0/mpir.h deleted file mode 100644 index 98af77bc1..000000000 --- a/src/external/inc/macx64/mpir-2.4.0/mpir.h +++ /dev/null @@ -1,2413 +0,0 @@ -/* Definitions for GNU multiple precision functions. -*- mode: c -*- - -Copyright 1991, 1993, 1994, 1995, 1996, 1997, 1999, 2000, 2001, 2002, 2003, -2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc. - -Copyright 2008 William Hart, Gonzalo Tornaria - -This file is part of the MPIR Library. - -The MPIR Library is free software; you can redistribute it and/or modify -it under the terms of the GNU Lesser General Public License as published by -the Free Software Foundation; either version 3 of the License, or (at your -option) any later version. - -The MPIR Library is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public -License for more details. - -You should have received a copy of the GNU Lesser General Public License -along with the GNU MP Library. If not, see http://www.gnu.org/licenses/. */ - -#ifndef __GMP_H__ - -#if defined (__cplusplus) -#include /* for std::istream, std::ostream, std::string */ -#include -#endif - - -/* Instantiated by configure. */ -#if ! defined (__GMP_WITHIN_CONFIGURE) -#define __GMP_BITS_PER_MP_LIMB 64 -#define __GMP_HAVE_HOST_CPU_FAMILY_power 0 -#define __GMP_HAVE_HOST_CPU_FAMILY_powerpc 0 -#define GMP_LIMB_BITS 64 -#define GMP_NAIL_BITS 0 -#endif -#define GMP_NUMB_BITS (GMP_LIMB_BITS - GMP_NAIL_BITS) -#define GMP_NUMB_MASK ((~ __GMP_CAST (mp_limb_t, 0)) >> GMP_NAIL_BITS) -#define GMP_NUMB_MAX GMP_NUMB_MASK -#define GMP_NAIL_MASK (~ GMP_NUMB_MASK) - - -#ifndef __GNU_MP__ -#define __GNU_MP__ 4 - -#define __need_size_t /* tell gcc stddef.h we only want size_t */ -#if defined (__cplusplus) -#include /* for size_t */ -#else -#include /* for size_t */ -#endif -#undef __need_size_t - -/* Instantiated by configure. */ -#if ! defined (__GMP_WITHIN_CONFIGURE) -/* #undef _LONG_LONG_LIMB */ -#define __GMP_LIBGMP_DLL 0 -#endif - -/* #if defined(__GMP_WITHIN_CONFIGURE) && defined(_WIN64) */ -#ifdef __WIN64 -#define _LONG_LONG_LIMB 1 -#endif - -/* __STDC__ - some ANSI compilers define this only to 0, hence the use of - "defined" and not "__STDC__-0". In particular Sun workshop C 5.0 - sets __STDC__ to 0, but requires "##" for token pasting. - - _AIX - gnu ansidecl.h asserts that all known AIX compilers are ANSI but - don't always define __STDC__. - - __DECC - current versions of DEC C (5.9 for instance) for alpha are ANSI, - but don't define __STDC__ in their default mode. Don't know if old - versions might have been K&R, but let's not worry about that unless - someone is still using one. - - _mips - gnu ansidecl.h says the RISC/OS MIPS compiler is ANSI in SVR4 - mode, but doesn't define __STDC__. - - _MSC_VER - Microsoft C is ANSI, but __STDC__ is undefined unless the /Za - option is given (in which case it's 1). - - _WIN32 - tested for by gnu ansidecl.h, no doubt on the assumption that - all w32 compilers are ansi. - - Note: This same set of tests is used by gen-psqr.c and - demos/expr/expr-impl.h, so if anything needs adding, then be sure to - update those too. */ - -#if defined (__STDC__) \ - || defined (__cplusplus) \ - || defined (_AIX) \ - || defined (__DECC) \ - || (defined (__mips) && defined (_SYSTYPE_SVR4)) \ - || defined (_MSC_VER) \ - || defined (_WIN32) -#define __GMP_HAVE_CONST 1 -#define __GMP_HAVE_PROTOTYPES 1 -#define __GMP_HAVE_TOKEN_PASTE 1 -#else -#define __GMP_HAVE_CONST 0 -#define __GMP_HAVE_PROTOTYPES 0 -#define __GMP_HAVE_TOKEN_PASTE 0 -#endif - - -#if __GMP_HAVE_CONST -#define __gmp_const const -#define __gmp_signed signed -#else -#define __gmp_const -#define __gmp_signed -#endif - - -/* __GMP_DECLSPEC supports Windows DLL versions of libmpir, and is empty in - all other circumstances. - - When compiling objects for libmpir, __GMP_DECLSPEC is an export directive, - or when compiling for an application it's an import directive. The two - cases are differentiated by __GMP_WITHIN_GMP defined by the GMP Makefiles - (and not defined from an application). - - __GMP_DECLSPEC_XX is similarly used for libmpirxx. __GMP_WITHIN_GMPXX - indicates when building libmpirxx, and in that case libmpirxx functions are - exports, but libmpir functions which might get called are imports. - - libmp.la uses __GMP_DECLSPEC, just as if it were libmpir.la. libmpir and - libmp don't call each other, so there's no conflict or confusion. - - Libtool DLL_EXPORT define is not used. - - There's no attempt to support GMP built both static and DLL. Doing so - would mean applications would have to tell us which of the two is going - to be used when linking, and that seems very tedious and error prone if - using GMP by hand, and equally tedious from a package since autoconf and - automake don't give much help. - - __GMP_DECLSPEC is required on all documented global functions and - variables, the various internals in gmp-impl.h etc can be left unadorned. - But internals used by the test programs or speed measuring programs - should have __GMP_DECLSPEC, and certainly constants or variables must - have it or the wrong address will be resolved. - - In gcc __declspec can go at either the start or end of a prototype. - - In Microsoft C __declspec must go at the start, or after the type like - void __declspec(...) *foo()". There's no __dllexport or anything to - guard against someone foolish #defining dllexport. _export used to be - available, but no longer. - - In Borland C _export still exists, but needs to go after the type, like - "void _export foo();". Would have to change the __GMP_DECLSPEC syntax to - make use of that. Probably more trouble than it's worth. */ - -#if defined (__GNUC__) -#define __GMP_DECLSPEC_EXPORT __declspec(__dllexport__) -#define __GMP_DECLSPEC_IMPORT __declspec(__dllimport__) -#endif -#if defined (_MSC_VER) || defined (__BORLANDC__) -#define __GMP_DECLSPEC_EXPORT __declspec(dllexport) -#define __GMP_DECLSPEC_IMPORT __declspec(dllimport) -#endif -#ifdef __WATCOMC__ -#define __GMP_DECLSPEC_EXPORT __export -#define __GMP_DECLSPEC_IMPORT __import -#endif -#ifdef __IBMC__ -#define __GMP_DECLSPEC_EXPORT _Export -#define __GMP_DECLSPEC_IMPORT _Import -#endif - -#if __GMP_LIBGMP_DLL -#if __GMP_WITHIN_GMP -/* compiling to go into a DLL libmpir */ -#define __GMP_DECLSPEC __GMP_DECLSPEC_EXPORT -#else -/* compiling to go into an application which will link to a DLL libmpir */ -#define __GMP_DECLSPEC __GMP_DECLSPEC_IMPORT -#endif -#else -/* all other cases */ -#define __GMP_DECLSPEC -#endif - - -#ifdef __GMP_SHORT_LIMB -typedef unsigned int mp_limb_t; -typedef int mp_limb_signed_t; -#else -#ifdef _LONG_LONG_LIMB -typedef unsigned long long int mp_limb_t; -typedef long long int mp_limb_signed_t; -#else -typedef unsigned long int mp_limb_t; -typedef long int mp_limb_signed_t; -#endif -#endif - -#ifdef _WIN64 -typedef unsigned long long int mp_bitcnt_t; -#define __GMP_BITCNT_MAX (~(unsigned long long) 0) -#else -typedef unsigned long int mp_bitcnt_t; -#define __GMP_BITCNT_MAX (~(unsigned long) 0) -#endif - -/* For reference, note that the name __mpz_struct gets into C++ mangled - function names, which means although the "__" suggests an internal, we - must leave this name for binary compatibility. */ -typedef struct -{ - int _mp_alloc; /* Number of *limbs* allocated and pointed - to by the _mp_d field. */ - int _mp_size; /* abs(_mp_size) is the number of limbs the - last field points to. If _mp_size is - negative this is a negative number. */ - mp_limb_t *_mp_d; /* Pointer to the limbs. */ -} __mpz_struct; - -#endif /* __GNU_MP__ */ - -typedef __mpz_struct mpz_t[1]; - -typedef mp_limb_t * mp_ptr; -typedef __gmp_const mp_limb_t * mp_srcptr; -#if defined( _WIN64) -#define __GMP_MP_SIZE_T_INT 0 -typedef long long int mp_size_t; -typedef long int mp_exp_t; -#else -#define __GMP_MP_SIZE_T_INT 0 -typedef long int mp_size_t; -typedef long int mp_exp_t; -#endif - -typedef struct -{ - __mpz_struct _mp_num; - __mpz_struct _mp_den; -} __mpq_struct; - -typedef __mpq_struct mpq_t[1]; - -typedef struct -{ - int _mp_prec; /* Max precision, in number of `mp_limb_t's. - Set by mpf_init and modified by - mpf_set_prec. The area pointed to by the - _mp_d field contains `prec' + 1 limbs. */ - int _mp_size; /* abs(_mp_size) is the number of limbs the - last field points to. If _mp_size is - negative this is a negative number. */ - mp_exp_t _mp_exp; /* Exponent, in the base of `mp_limb_t'. */ - mp_limb_t *_mp_d; /* Pointer to the limbs. */ -} __mpf_struct; - -typedef __mpf_struct mpf_t[1]; - -/* Available random number generation algorithms. */ -typedef enum -{ - GMP_RAND_ALG_DEFAULT = 0, - GMP_RAND_ALG_LC = GMP_RAND_ALG_DEFAULT /* Linear congruential. */ -} gmp_randalg_t; - -/* Random state struct. */ -typedef struct -{ - mpz_t _mp_seed; /* _mp_d member points to state of the generator. */ - gmp_randalg_t _mp_alg; /* Currently unused. */ - union { - void *_mp_lc; /* Pointer to function pointers structure. */ - } _mp_algdata; -} __gmp_randstate_struct; -typedef __gmp_randstate_struct gmp_randstate_t[1]; - -/* Types for function declarations in gmp files. */ -/* ??? Should not pollute user name space with these ??? */ -typedef __gmp_const __mpz_struct *mpz_srcptr; -typedef __mpz_struct *mpz_ptr; -typedef __gmp_const __mpf_struct *mpf_srcptr; -typedef __mpf_struct *mpf_ptr; -typedef __gmp_const __mpq_struct *mpq_srcptr; -typedef __mpq_struct *mpq_ptr; - - -#if __GMP_LIBGMP_DLL -#if __GMP_WITHIN_GMPXX -/* compiling to go into a DLL libmpirxx */ -#define __GMP_DECLSPEC_XX __GMP_DECLSPEC_EXPORT -#else -/* compiling to go into a application which will link to a DLL libmpirxx */ -#define __GMP_DECLSPEC_XX __GMP_DECLSPEC_IMPORT -#endif -#else -/* all other cases */ -#define __GMP_DECLSPEC_XX -#endif - - -#if __GMP_HAVE_PROTOTYPES -#define __GMP_PROTO(x) x -#else -#define __GMP_PROTO(x) () -#endif - -#ifndef __MPN -#if __GMP_HAVE_TOKEN_PASTE -#define __MPN(x) __gmpn_##x -#else -#define __MPN(x) __gmpn_/**/x -#endif -#endif - -/* For reference, "defined(EOF)" cannot be used here. In g++ 2.95.4, - defines EOF but not FILE. */ -#if defined (FILE) \ - || defined (H_STDIO) \ - || defined (_H_STDIO) /* AIX */ \ - || defined (_STDIO_H) /* glibc, Sun, SCO */ \ - || defined (_STDIO_H_) /* BSD, OSF */ \ - || defined (__STDIO_H) /* Borland */ \ - || defined (__STDIO_H__) /* IRIX */ \ - || defined (_STDIO_INCLUDED) /* HPUX */ \ - || defined (_FILE_DEFINED) /* Microsoft */ \ - || defined (__STDIO__) /* Apple MPW MrC */ \ - || defined (_MSL_STDIO_H) /* Metrowerks */ \ - || defined (_STDIO_H_INCLUDED) /* QNX4 */ \ - || defined (_ISO_STDIO_ISO_H) /* Sun C++ */ -#define _GMP_H_HAVE_FILE 1 -#endif - -/* In ISO C, if a prototype involving "struct obstack *" is given without - that structure defined, then the struct is scoped down to just the - prototype, causing a conflict if it's subsequently defined for real. So - only give prototypes if we've got obstack.h. */ -#if defined (_OBSTACK_H) /* glibc */ -#define _GMP_H_HAVE_OBSTACK 1 -#endif - -/* The prototypes for gmp_vprintf etc are provided only if va_list is - available, via an application having included or . - Usually va_list is a typedef so can't be tested directly, but C99 - specifies that va_start is a macro (and it was normally a macro on past - systems too), so look for that. - - will define some sort of va_list for vprintf and vfprintf, but - let's not bother trying to use that since it's not standard and since - application uses for gmp_vprintf etc will almost certainly require the - whole or anyway. */ - -#ifdef va_start -#define _GMP_H_HAVE_VA_LIST 1 -#endif - -/* Test for gcc >= maj.min, as per __GNUC_PREREQ in glibc */ -#if defined (__GNUC__) && defined (__GNUC_MINOR__) -#define __GMP_GNUC_PREREQ(maj, min) \ - ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min)) -#else -#define __GMP_GNUC_PREREQ(maj, min) 0 -#endif - -/* "pure" is in gcc 2.96 and up, see "(gcc)Function Attributes". Basically - it means a function does nothing but examine its arguments and memory - (global or via arguments) to generate a return value, but changes nothing - and has no side-effects. __GMP_NO_ATTRIBUTE_CONST_PURE lets - tune/common.c etc turn this off when trying to write timing loops. */ -#if __GMP_GNUC_PREREQ (2,96) && ! defined (__GMP_NO_ATTRIBUTE_CONST_PURE) -#define __GMP_ATTRIBUTE_PURE __attribute__ ((__pure__)) -#else -#define __GMP_ATTRIBUTE_PURE -#endif - - -/* __GMP_CAST allows us to use static_cast in C++, so our macros are clean - to "g++ -Wold-style-cast". - - Casts in "extern inline" code within an extern "C" block don't induce - these warnings, so __GMP_CAST only needs to be used on documented - macros. */ - -#ifdef __cplusplus -#define __GMP_CAST(type, expr) (static_cast (expr)) -#else -#define __GMP_CAST(type, expr) ((type) (expr)) -#endif - - -/* An empty "throw ()" means the function doesn't throw any C++ exceptions, - this can save some stack frame info in applications. - - Currently it's given only on functions which never divide-by-zero etc, - don't allocate memory, and are expected to never need to allocate memory. - This leaves open the possibility of a C++ throw from a future GMP - exceptions scheme. - - mpz_set_ui etc are omitted to leave open the lazy allocation scheme - described in doc/tasks.html. mpz_get_d etc are omitted to leave open - exceptions for float overflows. - - Note that __GMP_NOTHROW must be given on any inlines the same as on their - prototypes (for g++ at least, where they're used together). Note also - that g++ 3.0 demands that __GMP_NOTHROW is before other attributes like - __GMP_ATTRIBUTE_PURE. */ - -#if defined (__cplusplus) -#define __GMP_NOTHROW throw () -#else -#define __GMP_NOTHROW -#endif - -/* PORTME: What other compilers have a useful "extern inline"? "static - inline" would be an acceptable substitute if the compiler (or linker) - discards unused statics. */ - -/* gcc has __inline__ in all modes, including strict ansi. Give a prototype - for an inline too, so as to correctly specify "dllimport" on windows, in - case the function is called rather than inlined. */ - -#ifdef __GNUC__ -#if defined(__APPLE_CC__) && (__APPLE_CC__ != 1) /* FSF GCC sets this flag to 1 on Apple machines */ - -#if ! (__APPLE_CC__ >= 5465 && __STDC_VERSION__ >= 199901L) -#define __GMP_EXTERN_INLINE extern __inline__ -#define __GMP_INLINE_PROTOTYPES 1 -#endif - -#else /*GNU CC*/ - -#if defined(__GNUC_STDC_INLINE__) || defined (__GNUC_GNU_INLINE__) -#define __GMP_EXTERN_INLINE extern __inline__ __attribute__((__gnu_inline__)) -#else -#define __GMP_EXTERN_INLINE extern __inline__ -#endif -#define __GMP_INLINE_PROTOTYPES 1 - -#endif -#endif - -/* DEC C (eg. version 5.9) supports "static __inline foo()", even in -std1 - strict ANSI mode. Inlining is done even when not optimizing (ie. -O0 - mode, which is the default), but an unnecessary local copy of foo is - emitted unless -O is used. "extern __inline" is accepted, but the - "extern" appears to be ignored, ie. it becomes a plain global function - but which is inlined within its file. Don't know if all old versions of - DEC C supported __inline, but as a start let's do the right thing for - current versions. */ -#ifdef __DECC -#define __GMP_EXTERN_INLINE static __inline -#endif - -/* SCO OpenUNIX 8 cc supports "static inline foo()" but not in -Xc strict - ANSI mode (__STDC__ is 1 in that mode). Inlining only actually takes - place under -O. Without -O "foo" seems to be emitted whether it's used - or not, which is wasteful. "extern inline foo()" isn't useful, the - "extern" is apparently ignored, so foo is inlined if possible but also - emitted as a global, which causes multiple definition errors when - building a shared libmpir. */ -#ifdef __SCO_VERSION__ -#if __SCO_VERSION__ > 400000000 && __STDC__ != 1 \ - && ! defined (__GMP_EXTERN_INLINE) -#define __GMP_EXTERN_INLINE static inline -#endif -#endif - -#if defined _MSC_VER -#define __GMP_EXTERN_INLINE static __inline -#endif - -/* C++ always has "inline" and since it's a normal feature the linker should - discard duplicate non-inlined copies, or if it doesn't then that's a - problem for everyone, not just GMP. */ -#if defined (__cplusplus) && ! defined (__GMP_EXTERN_INLINE) -#define __GMP_EXTERN_INLINE inline -#endif - -/* Don't do any inlining within a configure run, since if the compiler ends - up emitting copies of the code into the object file it can end up - demanding the various support routines (like mpn_popcount) for linking, - making the "alloca" test and perhaps others fail. And on hppa ia64 a - pre-release gcc 3.2 was seen not respecting the "extern" in "extern - __inline__", triggering this problem too. */ -#if defined (__GMP_WITHIN_CONFIGURE) && ! __GMP_WITHIN_CONFIGURE_INLINE -#undef __GMP_EXTERN_INLINE -#endif - -/* By default, don't give a prototype when there's going to be an inline - version. Note in particular that Cray C++ objects to the combination of - prototype and inline. */ -#ifdef __GMP_EXTERN_INLINE -#ifndef __GMP_INLINE_PROTOTYPES -#define __GMP_INLINE_PROTOTYPES 0 -#endif -#else -#define __GMP_INLINE_PROTOTYPES 1 -#endif - - -#define __GMP_ABS(x) ((x) >= 0 ? (x) : -(x)) -#define __GMP_MAX(h,i) ((h) > (i) ? (h) : (i)) - -/* __GMP_USHRT_MAX is not "~ (unsigned short) 0" because short is promoted - to int by "~". */ -#define __GMP_UINT_MAX (~ (unsigned) 0) -#define __GMP_ULONG_MAX (~ (unsigned long) 0) -#define __GMP_USHRT_MAX ((unsigned short) ~0) - - -/* __builtin_expect is in gcc 3.0, and not in 2.95. */ -#if __GMP_GNUC_PREREQ (3,0) -#define __GMP_LIKELY(cond) __builtin_expect ((cond) != 0, 1) -#define __GMP_UNLIKELY(cond) __builtin_expect ((cond) != 0, 0) -#else -#define __GMP_LIKELY(cond) (cond) -#define __GMP_UNLIKELY(cond) (cond) -#endif - -/* Allow direct user access to numerator and denominator of a mpq_t object. */ -#define mpq_numref(Q) (&((Q)->_mp_num)) -#define mpq_denref(Q) (&((Q)->_mp_den)) - - -#if defined (__cplusplus) -extern "C" { -using std::FILE; -#endif - -#define mp_set_memory_functions __gmp_set_memory_functions -__GMP_DECLSPEC void mp_set_memory_functions __GMP_PROTO ((void *(*) (size_t), - void *(*) (void *, size_t, size_t), - void (*) (void *, size_t))) __GMP_NOTHROW; - -#define mp_get_memory_functions __gmp_get_memory_functions -__GMP_DECLSPEC void mp_get_memory_functions __GMP_PROTO ((void *(**) (size_t), - void *(**) (void *, size_t, size_t), - void (**) (void *, size_t))) __GMP_NOTHROW; - -#define mp_bits_per_limb __gmp_bits_per_limb -__GMP_DECLSPEC extern __gmp_const int mp_bits_per_limb; - -#define gmp_errno __gmp_errno -__GMP_DECLSPEC extern int gmp_errno; - -#define gmp_version __gmp_version -__GMP_DECLSPEC extern __gmp_const char * __gmp_const gmp_version; - -#define mpir_version __mpir_version -__GMP_DECLSPEC extern __gmp_const char * __gmp_const mpir_version; - - -/**************** Random number routines. ****************/ - -#define gmp_randinit_default __gmp_randinit_default -__GMP_DECLSPEC void gmp_randinit_default __GMP_PROTO ((gmp_randstate_t)); - -#define gmp_randinit_lc_2exp __gmp_randinit_lc_2exp -__GMP_DECLSPEC void gmp_randinit_lc_2exp __GMP_PROTO ((gmp_randstate_t, - mpz_srcptr, unsigned long int, - mp_bitcnt_t)); - -#define gmp_randinit_lc_2exp_size __gmp_randinit_lc_2exp_size -__GMP_DECLSPEC int gmp_randinit_lc_2exp_size __GMP_PROTO ((gmp_randstate_t, mp_bitcnt_t)); - -#define gmp_randinit_mt __gmp_randinit_mt -__GMP_DECLSPEC void gmp_randinit_mt __GMP_PROTO ((gmp_randstate_t)); - -#define gmp_randinit_set __gmp_randinit_set -__GMP_DECLSPEC void gmp_randinit_set __GMP_PROTO ((gmp_randstate_t, __gmp_const __gmp_randstate_struct *)); - -#define gmp_randseed __gmp_randseed -__GMP_DECLSPEC void gmp_randseed __GMP_PROTO ((gmp_randstate_t, mpz_srcptr)); - -#define gmp_randseed_ui __gmp_randseed_ui -__GMP_DECLSPEC void gmp_randseed_ui __GMP_PROTO ((gmp_randstate_t, unsigned long int)); - -#define gmp_randclear __gmp_randclear -__GMP_DECLSPEC void gmp_randclear __GMP_PROTO ((gmp_randstate_t)); - -#define gmp_urandomb_ui __gmp_urandomb_ui -__GMP_DECLSPEC unsigned long gmp_urandomb_ui __GMP_PROTO ((gmp_randstate_t, unsigned long)); - -#define gmp_urandomm_ui __gmp_urandomm_ui -__GMP_DECLSPEC unsigned long gmp_urandomm_ui __GMP_PROTO ((gmp_randstate_t, unsigned long)); - - -/**************** Formatted output routines. ****************/ - -#define gmp_asprintf __gmp_asprintf -__GMP_DECLSPEC int gmp_asprintf __GMP_PROTO ((char **, __gmp_const char *, ...)); - -#define gmp_fprintf __gmp_fprintf -#ifdef _GMP_H_HAVE_FILE -__GMP_DECLSPEC int gmp_fprintf __GMP_PROTO ((FILE *, __gmp_const char *, ...)); -#endif - -#define gmp_obstack_printf __gmp_obstack_printf -#if defined (_GMP_H_HAVE_OBSTACK) -__GMP_DECLSPEC int gmp_obstack_printf __GMP_PROTO ((struct obstack *, __gmp_const char *, ...)); -#endif - -#define gmp_obstack_vprintf __gmp_obstack_vprintf -#if defined (_GMP_H_HAVE_OBSTACK) && defined (_GMP_H_HAVE_VA_LIST) -__GMP_DECLSPEC int gmp_obstack_vprintf __GMP_PROTO ((struct obstack *, __gmp_const char *, va_list)); -#endif - -#define gmp_printf __gmp_printf -__GMP_DECLSPEC int gmp_printf __GMP_PROTO ((__gmp_const char *, ...)); - -#define gmp_snprintf __gmp_snprintf -__GMP_DECLSPEC int gmp_snprintf __GMP_PROTO ((char *, size_t, __gmp_const char *, ...)); - -#define gmp_sprintf __gmp_sprintf -__GMP_DECLSPEC int gmp_sprintf __GMP_PROTO ((char *, __gmp_const char *, ...)); - -#define gmp_vasprintf __gmp_vasprintf -#if defined (_GMP_H_HAVE_VA_LIST) -__GMP_DECLSPEC int gmp_vasprintf __GMP_PROTO ((char **, __gmp_const char *, va_list)); -#endif - -#define gmp_vfprintf __gmp_vfprintf -#if defined (_GMP_H_HAVE_FILE) && defined (_GMP_H_HAVE_VA_LIST) -__GMP_DECLSPEC int gmp_vfprintf __GMP_PROTO ((FILE *, __gmp_const char *, va_list)); -#endif - -#define gmp_vprintf __gmp_vprintf -#if defined (_GMP_H_HAVE_VA_LIST) -__GMP_DECLSPEC int gmp_vprintf __GMP_PROTO ((__gmp_const char *, va_list)); -#endif - -#define gmp_vsnprintf __gmp_vsnprintf -#if defined (_GMP_H_HAVE_VA_LIST) -__GMP_DECLSPEC int gmp_vsnprintf __GMP_PROTO ((char *, size_t, __gmp_const char *, va_list)); -#endif - -#define gmp_vsprintf __gmp_vsprintf -#if defined (_GMP_H_HAVE_VA_LIST) -__GMP_DECLSPEC int gmp_vsprintf __GMP_PROTO ((char *, __gmp_const char *, va_list)); -#endif - - -/**************** Formatted input routines. ****************/ - -#define gmp_fscanf __gmp_fscanf -#ifdef _GMP_H_HAVE_FILE -__GMP_DECLSPEC int gmp_fscanf __GMP_PROTO ((FILE *, __gmp_const char *, ...)); -#endif - -#define gmp_scanf __gmp_scanf -__GMP_DECLSPEC int gmp_scanf __GMP_PROTO ((__gmp_const char *, ...)); - -#define gmp_sscanf __gmp_sscanf -__GMP_DECLSPEC int gmp_sscanf __GMP_PROTO ((__gmp_const char *, __gmp_const char *, ...)); - -#define gmp_vfscanf __gmp_vfscanf -#if defined (_GMP_H_HAVE_FILE) && defined (_GMP_H_HAVE_VA_LIST) -__GMP_DECLSPEC int gmp_vfscanf __GMP_PROTO ((FILE *, __gmp_const char *, va_list)); -#endif - -#define gmp_vscanf __gmp_vscanf -#if defined (_GMP_H_HAVE_VA_LIST) -__GMP_DECLSPEC int gmp_vscanf __GMP_PROTO ((__gmp_const char *, va_list)); -#endif - -#define gmp_vsscanf __gmp_vsscanf -#if defined (_GMP_H_HAVE_VA_LIST) -__GMP_DECLSPEC int gmp_vsscanf __GMP_PROTO ((__gmp_const char *, __gmp_const char *, va_list)); -#endif - - -/**************** Integer (i.e. Z) routines. ****************/ - -#define __GMP_BITS_PER_ULONG (8*sizeof(unsigned long)) - -#define _mpz_realloc __gmpz_realloc -#define mpz_realloc __gmpz_realloc -__GMP_DECLSPEC void *_mpz_realloc __GMP_PROTO ((mpz_ptr, mp_size_t)); - -#define mpz_abs __gmpz_abs -#define __GMP_MPZ_ABS_MIN_ALLOC(x,y) (__GMP_ABS(y->_mp_size)) -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_abs) -__GMP_DECLSPEC void mpz_abs __GMP_PROTO ((mpz_ptr, mpz_srcptr)); -#endif - -#define __GMP_MPZ_ADD_MIN_ALLOC(x,y,z) (__GMP_MAX(__GMP_ABS(y->_mp_size),__GMP_ABS(z->_mp_size))+1) -#define mpz_add __gmpz_add -__GMP_DECLSPEC void mpz_add __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define __GMP_MPZ_ADD_UI_MIN_ALLOC(x,y,z) (__GMP_MAX(__GMP_ABS(y->_mp_size),1+(__GMP_BITS_PER_ULONG-1)/GMP_NUMB_BITS)+1) -#define mpz_add_ui __gmpz_add_ui -__GMP_DECLSPEC void mpz_add_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_addmul __gmpz_addmul -__GMP_DECLSPEC void mpz_addmul __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_addmul_ui __gmpz_addmul_ui -__GMP_DECLSPEC void mpz_addmul_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_and __gmpz_and -__GMP_DECLSPEC void mpz_and __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_array_init __gmpz_array_init -__GMP_DECLSPEC void mpz_array_init __GMP_PROTO ((mpz_ptr, mp_size_t, mp_size_t)); - -#define mpz_bin_ui __gmpz_bin_ui -__GMP_DECLSPEC void mpz_bin_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_bin_uiui __gmpz_bin_uiui -__GMP_DECLSPEC void mpz_bin_uiui __GMP_PROTO ((mpz_ptr, unsigned long int, unsigned long int)); - -#define mpz_cdiv_q __gmpz_cdiv_q -__GMP_DECLSPEC void mpz_cdiv_q __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_cdiv_q_2exp __gmpz_cdiv_q_2exp -__GMP_DECLSPEC void mpz_cdiv_q_2exp __GMP_PROTO ((mpz_ptr, mpz_srcptr, mp_bitcnt_t)); - -#define mpz_cdiv_q_ui __gmpz_cdiv_q_ui -__GMP_DECLSPEC unsigned long int mpz_cdiv_q_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_cdiv_qr __gmpz_cdiv_qr -__GMP_DECLSPEC void mpz_cdiv_qr __GMP_PROTO ((mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_cdiv_qr_ui __gmpz_cdiv_qr_ui -__GMP_DECLSPEC unsigned long int mpz_cdiv_qr_ui __GMP_PROTO ((mpz_ptr, mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_cdiv_r __gmpz_cdiv_r -__GMP_DECLSPEC void mpz_cdiv_r __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_cdiv_r_2exp __gmpz_cdiv_r_2exp -__GMP_DECLSPEC void mpz_cdiv_r_2exp __GMP_PROTO ((mpz_ptr, mpz_srcptr, mp_bitcnt_t)); - -#define mpz_cdiv_r_ui __gmpz_cdiv_r_ui -__GMP_DECLSPEC unsigned long int mpz_cdiv_r_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_cdiv_ui __gmpz_cdiv_ui -__GMP_DECLSPEC unsigned long int mpz_cdiv_ui __GMP_PROTO ((mpz_srcptr, unsigned long int)) __GMP_ATTRIBUTE_PURE; - -#define mpz_clear __gmpz_clear -__GMP_DECLSPEC void mpz_clear __GMP_PROTO ((mpz_ptr)); - -#define mpz_clears __gmpz_clears -__GMP_DECLSPEC void mpz_clears __GMP_PROTO ((mpz_ptr, ...)); - -#define mpz_clrbit __gmpz_clrbit -__GMP_DECLSPEC void mpz_clrbit __GMP_PROTO ((mpz_ptr, mp_bitcnt_t)); - -#define mpz_cmp __gmpz_cmp -__GMP_DECLSPEC int mpz_cmp __GMP_PROTO ((mpz_srcptr, mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpz_cmp_d __gmpz_cmp_d -__GMP_DECLSPEC int mpz_cmp_d __GMP_PROTO ((mpz_srcptr, double)) __GMP_ATTRIBUTE_PURE; - -#define _mpz_cmp_si __gmpz_cmp_si -__GMP_DECLSPEC int _mpz_cmp_si __GMP_PROTO ((mpz_srcptr, signed long int)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define _mpz_cmp_ui __gmpz_cmp_ui -__GMP_DECLSPEC int _mpz_cmp_ui __GMP_PROTO ((mpz_srcptr, unsigned long int)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpz_cmpabs __gmpz_cmpabs -__GMP_DECLSPEC int mpz_cmpabs __GMP_PROTO ((mpz_srcptr, mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpz_cmpabs_d __gmpz_cmpabs_d -__GMP_DECLSPEC int mpz_cmpabs_d __GMP_PROTO ((mpz_srcptr, double)) __GMP_ATTRIBUTE_PURE; - -#define mpz_cmpabs_ui __gmpz_cmpabs_ui -__GMP_DECLSPEC int mpz_cmpabs_ui __GMP_PROTO ((mpz_srcptr, unsigned long int)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpz_com __gmpz_com -__GMP_DECLSPEC void mpz_com __GMP_PROTO ((mpz_ptr, mpz_srcptr)); - -#define mpz_combit __gmpz_combit -__GMP_DECLSPEC void mpz_combit __GMP_PROTO ((mpz_ptr, mp_bitcnt_t)); - -#define mpz_congruent_p __gmpz_congruent_p -__GMP_DECLSPEC int mpz_congruent_p __GMP_PROTO ((mpz_srcptr, mpz_srcptr, mpz_srcptr)) __GMP_ATTRIBUTE_PURE; - -#define mpz_congruent_2exp_p __gmpz_congruent_2exp_p -__GMP_DECLSPEC int mpz_congruent_2exp_p __GMP_PROTO ((mpz_srcptr, mpz_srcptr, mp_bitcnt_t)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpz_congruent_ui_p __gmpz_congruent_ui_p -__GMP_DECLSPEC int mpz_congruent_ui_p __GMP_PROTO ((mpz_srcptr, unsigned long, unsigned long)) __GMP_ATTRIBUTE_PURE; - -#define mpz_divexact __gmpz_divexact -__GMP_DECLSPEC void mpz_divexact __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_divexact_ui __gmpz_divexact_ui -__GMP_DECLSPEC void mpz_divexact_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long)); - -#define mpz_divisible_p __gmpz_divisible_p -__GMP_DECLSPEC int mpz_divisible_p __GMP_PROTO ((mpz_srcptr, mpz_srcptr)) __GMP_ATTRIBUTE_PURE; - -#define mpz_divisible_ui_p __gmpz_divisible_ui_p -__GMP_DECLSPEC int mpz_divisible_ui_p __GMP_PROTO ((mpz_srcptr, unsigned long)) __GMP_ATTRIBUTE_PURE; - -#define mpz_divisible_2exp_p __gmpz_divisible_2exp_p -__GMP_DECLSPEC int mpz_divisible_2exp_p __GMP_PROTO ((mpz_srcptr, mp_bitcnt_t)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpz_dump __gmpz_dump -__GMP_DECLSPEC void mpz_dump __GMP_PROTO ((mpz_srcptr)); - -#define mpz_export __gmpz_export -__GMP_DECLSPEC void *mpz_export __GMP_PROTO ((void *, size_t *, int, size_t, int, size_t, mpz_srcptr)); - -#define mpz_fac_ui __gmpz_fac_ui -__GMP_DECLSPEC void mpz_fac_ui __GMP_PROTO ((mpz_ptr, unsigned long int)); - -#define mpz_fdiv_q __gmpz_fdiv_q -__GMP_DECLSPEC void mpz_fdiv_q __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_fdiv_q_2exp __gmpz_fdiv_q_2exp -__GMP_DECLSPEC void mpz_fdiv_q_2exp __GMP_PROTO ((mpz_ptr, mpz_srcptr, mp_bitcnt_t)); - -#define mpz_fdiv_q_ui __gmpz_fdiv_q_ui -__GMP_DECLSPEC unsigned long int mpz_fdiv_q_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_fdiv_qr __gmpz_fdiv_qr -__GMP_DECLSPEC void mpz_fdiv_qr __GMP_PROTO ((mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_fdiv_qr_ui __gmpz_fdiv_qr_ui -__GMP_DECLSPEC unsigned long int mpz_fdiv_qr_ui __GMP_PROTO ((mpz_ptr, mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_fdiv_r __gmpz_fdiv_r -__GMP_DECLSPEC void mpz_fdiv_r __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_fdiv_r_2exp __gmpz_fdiv_r_2exp -__GMP_DECLSPEC void mpz_fdiv_r_2exp __GMP_PROTO ((mpz_ptr, mpz_srcptr, mp_bitcnt_t)); - -#define mpz_fdiv_r_ui __gmpz_fdiv_r_ui -__GMP_DECLSPEC unsigned long int mpz_fdiv_r_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_fdiv_ui __gmpz_fdiv_ui -__GMP_DECLSPEC unsigned long int mpz_fdiv_ui __GMP_PROTO ((mpz_srcptr, unsigned long int)) __GMP_ATTRIBUTE_PURE; - -#define mpz_fib_ui __gmpz_fib_ui -__GMP_DECLSPEC void mpz_fib_ui __GMP_PROTO ((mpz_ptr, unsigned long int)); - -#define mpz_fib2_ui __gmpz_fib2_ui -__GMP_DECLSPEC void mpz_fib2_ui __GMP_PROTO ((mpz_ptr, mpz_ptr, unsigned long int)); - -#define mpz_fits_sint_p __gmpz_fits_sint_p -__GMP_DECLSPEC int mpz_fits_sint_p __GMP_PROTO ((mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpz_fits_slong_p __gmpz_fits_slong_p -__GMP_DECLSPEC int mpz_fits_slong_p __GMP_PROTO ((mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpz_fits_sshort_p __gmpz_fits_sshort_p -__GMP_DECLSPEC int mpz_fits_sshort_p __GMP_PROTO ((mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpz_fits_uint_p __gmpz_fits_uint_p -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_fits_uint_p) -__GMP_DECLSPEC int mpz_fits_uint_p __GMP_PROTO ((mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#endif - -#define mpz_fits_ulong_p __gmpz_fits_ulong_p -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_fits_ulong_p) -__GMP_DECLSPEC int mpz_fits_ulong_p __GMP_PROTO ((mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#endif - -#define mpz_fits_ushort_p __gmpz_fits_ushort_p -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_fits_ushort_p) -__GMP_DECLSPEC int mpz_fits_ushort_p __GMP_PROTO ((mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#endif - -#define mpz_gcd __gmpz_gcd -__GMP_DECLSPEC void mpz_gcd __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_gcd_ui __gmpz_gcd_ui -__GMP_DECLSPEC unsigned long int mpz_gcd_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_gcdext __gmpz_gcdext -__GMP_DECLSPEC void mpz_gcdext __GMP_PROTO ((mpz_ptr, mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_get_d __gmpz_get_d -__GMP_DECLSPEC double mpz_get_d __GMP_PROTO ((mpz_srcptr)) __GMP_ATTRIBUTE_PURE; - -#define mpz_get_d_2exp __gmpz_get_d_2exp -__GMP_DECLSPEC double mpz_get_d_2exp __GMP_PROTO ((signed long int *, mpz_srcptr)); - -#define mpz_get_si __gmpz_get_si -__GMP_DECLSPEC /* signed */ long int mpz_get_si __GMP_PROTO ((mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpz_get_str __gmpz_get_str -__GMP_DECLSPEC char *mpz_get_str __GMP_PROTO ((char *, int, mpz_srcptr)); - -#define mpz_get_ui __gmpz_get_ui -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_get_ui) -__GMP_DECLSPEC unsigned long int mpz_get_ui __GMP_PROTO ((mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#endif - -#define mpz_getlimbn __gmpz_getlimbn -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_getlimbn) -__GMP_DECLSPEC mp_limb_t mpz_getlimbn __GMP_PROTO ((mpz_srcptr, mp_size_t)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#endif - -#define mpz_hamdist __gmpz_hamdist -__GMP_DECLSPEC mp_bitcnt_t mpz_hamdist __GMP_PROTO ((mpz_srcptr, mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpz_import __gmpz_import -__GMP_DECLSPEC void mpz_import __GMP_PROTO ((mpz_ptr, size_t, int, size_t, int, size_t, __gmp_const void *)); - -#define mpz_init __gmpz_init -__GMP_DECLSPEC void mpz_init __GMP_PROTO ((mpz_ptr)); - -#define mpz_init2 __gmpz_init2 -__GMP_DECLSPEC void mpz_init2 __GMP_PROTO ((mpz_ptr, mp_bitcnt_t)); - -#define mpz_inits __gmpz_inits -__GMP_DECLSPEC void mpz_inits __GMP_PROTO ((mpz_ptr, ...)); - -#define mpz_init_set __gmpz_init_set -__GMP_DECLSPEC void mpz_init_set __GMP_PROTO ((mpz_ptr, mpz_srcptr)); - -#define mpz_init_set_d __gmpz_init_set_d -__GMP_DECLSPEC void mpz_init_set_d __GMP_PROTO ((mpz_ptr, double)); - -#define mpz_init_set_si __gmpz_init_set_si -__GMP_DECLSPEC void mpz_init_set_si __GMP_PROTO ((mpz_ptr, signed long int)); - -#define mpz_init_set_str __gmpz_init_set_str -__GMP_DECLSPEC int mpz_init_set_str __GMP_PROTO ((mpz_ptr, __gmp_const char *, int)); - -#define mpz_init_set_ui __gmpz_init_set_ui -__GMP_DECLSPEC void mpz_init_set_ui __GMP_PROTO ((mpz_ptr, unsigned long int)); - -#define mpz_inp_raw __gmpz_inp_raw -#ifdef _GMP_H_HAVE_FILE -__GMP_DECLSPEC size_t mpz_inp_raw __GMP_PROTO ((mpz_ptr, FILE *)); -#endif - -#define mpz_inp_str __gmpz_inp_str -#ifdef _GMP_H_HAVE_FILE -__GMP_DECLSPEC size_t mpz_inp_str __GMP_PROTO ((mpz_ptr, FILE *, int)); -#endif - -#define mpz_invert __gmpz_invert -__GMP_DECLSPEC int mpz_invert __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_ior __gmpz_ior -__GMP_DECLSPEC void mpz_ior __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_jacobi __gmpz_jacobi -__GMP_DECLSPEC int mpz_jacobi __GMP_PROTO ((mpz_srcptr, mpz_srcptr)) __GMP_ATTRIBUTE_PURE; - -#define mpz_kronecker mpz_jacobi /* alias */ - -#define mpz_kronecker_si __gmpz_kronecker_si -__GMP_DECLSPEC int mpz_kronecker_si __GMP_PROTO ((mpz_srcptr, long)) __GMP_ATTRIBUTE_PURE; - -#define mpz_kronecker_ui __gmpz_kronecker_ui -__GMP_DECLSPEC int mpz_kronecker_ui __GMP_PROTO ((mpz_srcptr, unsigned long)) __GMP_ATTRIBUTE_PURE; - -#define mpz_si_kronecker __gmpz_si_kronecker -__GMP_DECLSPEC int mpz_si_kronecker __GMP_PROTO ((long, mpz_srcptr)) __GMP_ATTRIBUTE_PURE; - -#define mpz_ui_kronecker __gmpz_ui_kronecker -__GMP_DECLSPEC int mpz_ui_kronecker __GMP_PROTO ((unsigned long, mpz_srcptr)) __GMP_ATTRIBUTE_PURE; - -#define mpz_lcm __gmpz_lcm -__GMP_DECLSPEC void mpz_lcm __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_lcm_ui __gmpz_lcm_ui -__GMP_DECLSPEC void mpz_lcm_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long)); - -#define mpz_legendre mpz_jacobi /* alias */ - -#define mpz_lucnum_ui __gmpz_lucnum_ui -__GMP_DECLSPEC void mpz_lucnum_ui __GMP_PROTO ((mpz_ptr, unsigned long int)); - -#define mpz_lucnum2_ui __gmpz_lucnum2_ui -__GMP_DECLSPEC void mpz_lucnum2_ui __GMP_PROTO ((mpz_ptr, mpz_ptr, unsigned long int)); - -#define mpz_millerrabin __gmpz_millerrabin -__GMP_DECLSPEC int mpz_millerrabin __GMP_PROTO ((mpz_srcptr, int)) __GMP_ATTRIBUTE_PURE; - -#define mpz_mod __gmpz_mod -__GMP_DECLSPEC void mpz_mod __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_mod_ui mpz_fdiv_r_ui /* same as fdiv_r because divisor unsigned */ - -#define __GMP_MPZ_MUL_MIN_ALLOC(x,y,z) (__GMP_ABS(y->_mp_size)+__GMP_ABS(z->_mp_size)+1) -#define mpz_mul __gmpz_mul -__GMP_DECLSPEC void mpz_mul __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_mul_2exp __gmpz_mul_2exp -__GMP_DECLSPEC void mpz_mul_2exp __GMP_PROTO ((mpz_ptr, mpz_srcptr, mp_bitcnt_t)); - -#define __GMP_MPZ_MUL_SI_MIN_ALLOC(x,y,z) (__GMP_ABS(y->_mp_size)+(__GMP_BITS_PER_ULONG-1)/GMP_NUMB_BITS+1) -#define mpz_mul_si __gmpz_mul_si -__GMP_DECLSPEC void mpz_mul_si __GMP_PROTO ((mpz_ptr, mpz_srcptr, long int)); - -#define __GMP_MPZ_MUL_UI_MIN_ALLOC(x,y,z) (__GMP_ABS(y->_mp_size)+(__GMP_BITS_PER_ULONG-1)/GMP_NUMB_BITS+1) -#define mpz_mul_ui __gmpz_mul_ui -__GMP_DECLSPEC void mpz_mul_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_neg __gmpz_neg -#define __GMP_MPZ_NEG_MIN_ALLOC(x,y) (__GMP_ABS(y->_mp_size)) -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_neg) -__GMP_DECLSPEC void mpz_neg __GMP_PROTO ((mpz_ptr, mpz_srcptr)); -#endif - -#define mpz_nextprime __gmpz_nextprime -__GMP_DECLSPEC void mpz_nextprime __GMP_PROTO ((mpz_ptr, mpz_srcptr)); - -#define mpz_next_likely_prime __gmpz_next_likely_prime -__GMP_DECLSPEC void mpz_next_likely_prime __GMP_PROTO ((mpz_ptr, mpz_srcptr,gmp_randstate_t)); - -#define mpz_out_raw __gmpz_out_raw -#ifdef _GMP_H_HAVE_FILE -__GMP_DECLSPEC size_t mpz_out_raw __GMP_PROTO ((FILE *, mpz_srcptr)); -#endif - -#define mpz_out_str __gmpz_out_str -#ifdef _GMP_H_HAVE_FILE -__GMP_DECLSPEC size_t mpz_out_str __GMP_PROTO ((FILE *, int, mpz_srcptr)); -#endif - -#define mpz_perfect_power_p __gmpz_perfect_power_p -__GMP_DECLSPEC int mpz_perfect_power_p __GMP_PROTO ((mpz_srcptr)) __GMP_ATTRIBUTE_PURE; - -#define mpz_perfect_square_p __gmpz_perfect_square_p -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_perfect_square_p) -__GMP_DECLSPEC int mpz_perfect_square_p __GMP_PROTO ((mpz_srcptr)) __GMP_ATTRIBUTE_PURE; -#endif - -#define mpz_popcount __gmpz_popcount -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_popcount) -__GMP_DECLSPEC mp_bitcnt_t mpz_popcount __GMP_PROTO ((mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#endif - -#define mpz_pow_ui __gmpz_pow_ui -__GMP_DECLSPEC void mpz_pow_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_powm __gmpz_powm -__GMP_DECLSPEC void mpz_powm __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_powm_ui __gmpz_powm_ui -__GMP_DECLSPEC void mpz_powm_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int, mpz_srcptr)); - -#define mpz_probab_prime_p __gmpz_probab_prime_p -__GMP_DECLSPEC int mpz_probab_prime_p __GMP_PROTO ((mpz_srcptr, int)) __GMP_ATTRIBUTE_PURE; - -#define mpz_probable_prime_p __gmpz_probable_prime_p -__GMP_DECLSPEC int mpz_probable_prime_p __GMP_PROTO ((mpz_srcptr,gmp_randstate_t, int,unsigned long)); - -#define mpz_likely_prime_p __gmpz_likely_prime_p -__GMP_DECLSPEC int mpz_likely_prime_p __GMP_PROTO ((mpz_srcptr,gmp_randstate_t, unsigned long)); - -#define mpz_realloc2 __gmpz_realloc2 -__GMP_DECLSPEC void mpz_realloc2 __GMP_PROTO ((mpz_ptr, mp_bitcnt_t)); - -#define mpz_remove __gmpz_remove -__GMP_DECLSPEC mp_bitcnt_t mpz_remove __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_root __gmpz_root -__GMP_DECLSPEC int mpz_root __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_nthroot __gmpz_nthroot -__GMP_DECLSPEC void mpz_nthroot __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_rootrem __gmpz_rootrem -__GMP_DECLSPEC void mpz_rootrem __GMP_PROTO ((mpz_ptr,mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_rrandomb __gmpz_rrandomb -__GMP_DECLSPEC void mpz_rrandomb __GMP_PROTO ((mpz_ptr, gmp_randstate_t, mp_bitcnt_t)); - -#define mpz_scan0 __gmpz_scan0 -__GMP_DECLSPEC mp_bitcnt_t mpz_scan0 __GMP_PROTO ((mpz_srcptr, mp_bitcnt_t)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpz_scan1 __gmpz_scan1 -__GMP_DECLSPEC mp_bitcnt_t mpz_scan1 __GMP_PROTO ((mpz_srcptr, mp_bitcnt_t)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define __GMP_MPZ_SET_MIN_ALLOC(x,y) __GMP_ABS(y->_mp_size) -#define mpz_set __gmpz_set -__GMP_DECLSPEC void mpz_set __GMP_PROTO ((mpz_ptr, mpz_srcptr)); - -#define mpz_set_d __gmpz_set_d -__GMP_DECLSPEC void mpz_set_d __GMP_PROTO ((mpz_ptr, double)); - -#define mpz_set_f __gmpz_set_f -__GMP_DECLSPEC void mpz_set_f __GMP_PROTO ((mpz_ptr, mpf_srcptr)); - -#define mpz_set_q __gmpz_set_q -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_set_q) -__GMP_DECLSPEC void mpz_set_q __GMP_PROTO ((mpz_ptr, mpq_srcptr)); -#endif - -#define __GMP_MPZ_SET_SI_MIN_ALLOC(x,y) (1+(__GMP_BITS_PER_ULONG-1)/GMP_NUMB_BITS) -#define mpz_set_si __gmpz_set_si -__GMP_DECLSPEC void mpz_set_si __GMP_PROTO ((mpz_ptr, signed long int)); - -#define mpz_set_str __gmpz_set_str -__GMP_DECLSPEC int mpz_set_str __GMP_PROTO ((mpz_ptr, __gmp_const char *, int)); - -#define __GMP_MPZ_SET_UI_MIN_ALLOC(x,y) (1+(__GMP_BITS_PER_ULONG-1)/GMP_NUMB_BITS) -#define mpz_set_ui __gmpz_set_ui -__GMP_DECLSPEC void mpz_set_ui __GMP_PROTO ((mpz_ptr, unsigned long int)); - -#define mpz_setbit __gmpz_setbit -__GMP_DECLSPEC void mpz_setbit __GMP_PROTO ((mpz_ptr, mp_bitcnt_t)); - -#define mpz_size __gmpz_size -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_size) -__GMP_DECLSPEC size_t mpz_size __GMP_PROTO ((mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#endif - -#define mpz_sizeinbase __gmpz_sizeinbase -__GMP_DECLSPEC size_t mpz_sizeinbase __GMP_PROTO ((mpz_srcptr, int)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpz_sqrt __gmpz_sqrt -__GMP_DECLSPEC void mpz_sqrt __GMP_PROTO ((mpz_ptr, mpz_srcptr)); - -#define mpz_sqrtrem __gmpz_sqrtrem -__GMP_DECLSPEC void mpz_sqrtrem __GMP_PROTO ((mpz_ptr, mpz_ptr, mpz_srcptr)); - -#define __GMP_MPZ_SUB_MIN_ALLOC(x,y,z) (__GMP_MAX(__GMP_ABS(y->_mp_size),__GMP_ABS(z->_mp_size))+1) -#define mpz_sub __gmpz_sub -__GMP_DECLSPEC void mpz_sub __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define __GMP_MPZ_SUB_UI_MIN_ALLOC(x,y,z) (__GMP_MAX(__GMP_ABS(y->_mp_size),1+(__GMP_BITS_PER_ULONG-1)/GMP_NUMB_BITS)+1) -#define mpz_sub_ui __gmpz_sub_ui -__GMP_DECLSPEC void mpz_sub_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); - -#define __GMP_MPZ_UI_SUB_MIN_ALLOC(x,y,z) (__GMP_MAX(__GMP_ABS(z->_mp_size),1+(__GMP_BITS_PER_ULONG-1)/GMP_NUMB_BITS)+1) -#define mpz_ui_sub __gmpz_ui_sub -__GMP_DECLSPEC void mpz_ui_sub __GMP_PROTO ((mpz_ptr, unsigned long int, mpz_srcptr)); - -#define mpz_submul __gmpz_submul -__GMP_DECLSPEC void mpz_submul __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_submul_ui __gmpz_submul_ui -__GMP_DECLSPEC void mpz_submul_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_swap __gmpz_swap -__GMP_DECLSPEC void mpz_swap __GMP_PROTO ((mpz_ptr, mpz_ptr)) __GMP_NOTHROW; - -#define mpz_tdiv_ui __gmpz_tdiv_ui -__GMP_DECLSPEC unsigned long int mpz_tdiv_ui __GMP_PROTO ((mpz_srcptr, unsigned long int)) __GMP_ATTRIBUTE_PURE; - -#define mpz_tdiv_q __gmpz_tdiv_q -__GMP_DECLSPEC void mpz_tdiv_q __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_tdiv_q_2exp __gmpz_tdiv_q_2exp -__GMP_DECLSPEC void mpz_tdiv_q_2exp __GMP_PROTO ((mpz_ptr, mpz_srcptr, mp_bitcnt_t)); - -#define mpz_tdiv_q_ui __gmpz_tdiv_q_ui -__GMP_DECLSPEC unsigned long int mpz_tdiv_q_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_tdiv_qr __gmpz_tdiv_qr -__GMP_DECLSPEC void mpz_tdiv_qr __GMP_PROTO ((mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_tdiv_qr_ui __gmpz_tdiv_qr_ui -__GMP_DECLSPEC unsigned long int mpz_tdiv_qr_ui __GMP_PROTO ((mpz_ptr, mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_tdiv_r __gmpz_tdiv_r -__GMP_DECLSPEC void mpz_tdiv_r __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_tdiv_r_2exp __gmpz_tdiv_r_2exp -__GMP_DECLSPEC void mpz_tdiv_r_2exp __GMP_PROTO ((mpz_ptr, mpz_srcptr, mp_bitcnt_t)); - -#define mpz_tdiv_r_ui __gmpz_tdiv_r_ui -__GMP_DECLSPEC unsigned long int mpz_tdiv_r_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_tstbit __gmpz_tstbit -__GMP_DECLSPEC int mpz_tstbit __GMP_PROTO ((mpz_srcptr, mp_bitcnt_t)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpz_ui_pow_ui __gmpz_ui_pow_ui -__GMP_DECLSPEC void mpz_ui_pow_ui __GMP_PROTO ((mpz_ptr, unsigned long int, unsigned long int)); - -#define mpz_urandomb __gmpz_urandomb -__GMP_DECLSPEC void mpz_urandomb __GMP_PROTO ((mpz_ptr, gmp_randstate_t, mp_bitcnt_t)); - -#define mpz_urandomm __gmpz_urandomm -__GMP_DECLSPEC void mpz_urandomm __GMP_PROTO ((mpz_ptr, gmp_randstate_t, mpz_srcptr)); - -#define mpz_xor __gmpz_xor -#define mpz_eor __gmpz_xor -__GMP_DECLSPEC void mpz_xor __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - - -/****** Integer (i.e. Z) routines for intmaax_t/uintmax_t types ******/ - -#if defined( _STDINT_H ) || defined ( _STDINT_H_ ) || defined ( _STDINT ) - -#define __GMP_BITS_PER_UINTMAX (8*sizeof(uintmax_t)) - -#define mpz_get_ux __gmpz_get_ux -__GMP_DECLSPEC uintmax_t mpz_get_ux __GMP_PROTO ((mpz_srcptr)); - -#define mpz_get_sx __gmpz_get_sx -__GMP_DECLSPEC intmax_t mpz_get_sx __GMP_PROTO ((mpz_srcptr)); - -#define mpz_set_ux __gmpz_set_ux -__GMP_DECLSPEC void mpz_set_ux __GMP_PROTO ((mpz_ptr, uintmax_t)); - -#define mpz_set_sx __gmpz_set_sx -__GMP_DECLSPEC void mpz_set_sx __GMP_PROTO ((mpz_ptr, intmax_t)); - -#define mpz_init_set_ux __gmpz_init_set_ux -__GMP_DECLSPEC void mpz_init_set_ux __GMP_PROTO ((mpz_ptr, uintmax_t)); - -#define mpz_init_set_sx __gmpz_init_set_sx -__GMP_DECLSPEC void mpz_init_set_sx __GMP_PROTO ((mpz_ptr, intmax_t)); - -#endif - - -/**************** Rational (i.e. Q) routines. ****************/ - -#define mpq_abs __gmpq_abs -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpq_abs) -__GMP_DECLSPEC void mpq_abs __GMP_PROTO ((mpq_ptr, mpq_srcptr)); -#endif - -#define mpq_add __gmpq_add -__GMP_DECLSPEC void mpq_add __GMP_PROTO ((mpq_ptr, mpq_srcptr, mpq_srcptr)); - -#define mpq_canonicalize __gmpq_canonicalize -__GMP_DECLSPEC void mpq_canonicalize __GMP_PROTO ((mpq_ptr)); - -#define mpq_clear __gmpq_clear -__GMP_DECLSPEC void mpq_clear __GMP_PROTO ((mpq_ptr)); - -#define mpq_clears __gmpq_clears -__GMP_DECLSPEC void mpq_clears __GMP_PROTO ((mpq_ptr, ...)); - -#define mpq_cmp __gmpq_cmp -__GMP_DECLSPEC int mpq_cmp __GMP_PROTO ((mpq_srcptr, mpq_srcptr)) __GMP_ATTRIBUTE_PURE; - -#define _mpq_cmp_si __gmpq_cmp_si -__GMP_DECLSPEC int _mpq_cmp_si __GMP_PROTO ((mpq_srcptr, long, unsigned long)) __GMP_ATTRIBUTE_PURE; - -#define _mpq_cmp_ui __gmpq_cmp_ui -__GMP_DECLSPEC int _mpq_cmp_ui __GMP_PROTO ((mpq_srcptr, unsigned long int, unsigned long int)) __GMP_ATTRIBUTE_PURE; - -#define mpq_div __gmpq_div -__GMP_DECLSPEC void mpq_div __GMP_PROTO ((mpq_ptr, mpq_srcptr, mpq_srcptr)); - -#define mpq_div_2exp __gmpq_div_2exp -__GMP_DECLSPEC void mpq_div_2exp __GMP_PROTO ((mpq_ptr, mpq_srcptr, mp_bitcnt_t)); - -#define mpq_equal __gmpq_equal -__GMP_DECLSPEC int mpq_equal __GMP_PROTO ((mpq_srcptr, mpq_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpq_get_num __gmpq_get_num -__GMP_DECLSPEC void mpq_get_num __GMP_PROTO ((mpz_ptr, mpq_srcptr)); - -#define mpq_get_den __gmpq_get_den -__GMP_DECLSPEC void mpq_get_den __GMP_PROTO ((mpz_ptr, mpq_srcptr)); - -#define mpq_get_d __gmpq_get_d -__GMP_DECLSPEC double mpq_get_d __GMP_PROTO ((mpq_srcptr)) __GMP_ATTRIBUTE_PURE; - -#define mpq_get_str __gmpq_get_str -__GMP_DECLSPEC char *mpq_get_str __GMP_PROTO ((char *, int, mpq_srcptr)); - -#define mpq_init __gmpq_init -__GMP_DECLSPEC void mpq_init __GMP_PROTO ((mpq_ptr)); - -#define mpq_inits __gmpq_inits -__GMP_DECLSPEC void mpq_inits __GMP_PROTO ((mpq_ptr, ...)); - -#define mpq_inp_str __gmpq_inp_str -#ifdef _GMP_H_HAVE_FILE -__GMP_DECLSPEC size_t mpq_inp_str __GMP_PROTO ((mpq_ptr, FILE *, int)); -#endif - -#define mpq_inv __gmpq_inv -__GMP_DECLSPEC void mpq_inv __GMP_PROTO ((mpq_ptr, mpq_srcptr)); - -#define mpq_mul __gmpq_mul -__GMP_DECLSPEC void mpq_mul __GMP_PROTO ((mpq_ptr, mpq_srcptr, mpq_srcptr)); - -#define mpq_mul_2exp __gmpq_mul_2exp -__GMP_DECLSPEC void mpq_mul_2exp __GMP_PROTO ((mpq_ptr, mpq_srcptr, mp_bitcnt_t)); - -#define mpq_neg __gmpq_neg -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpq_neg) -__GMP_DECLSPEC void mpq_neg __GMP_PROTO ((mpq_ptr, mpq_srcptr)); -#endif - -#define mpq_out_str __gmpq_out_str -#ifdef _GMP_H_HAVE_FILE -__GMP_DECLSPEC size_t mpq_out_str __GMP_PROTO ((FILE *, int, mpq_srcptr)); -#endif - -#define mpq_set __gmpq_set -__GMP_DECLSPEC void mpq_set __GMP_PROTO ((mpq_ptr, mpq_srcptr)); - -#define mpq_set_d __gmpq_set_d -__GMP_DECLSPEC void mpq_set_d __GMP_PROTO ((mpq_ptr, double)); - -#define mpq_set_den __gmpq_set_den -__GMP_DECLSPEC void mpq_set_den __GMP_PROTO ((mpq_ptr, mpz_srcptr)); - -#define mpq_set_f __gmpq_set_f -__GMP_DECLSPEC void mpq_set_f __GMP_PROTO ((mpq_ptr, mpf_srcptr)); - -#define mpq_set_num __gmpq_set_num -__GMP_DECLSPEC void mpq_set_num __GMP_PROTO ((mpq_ptr, mpz_srcptr)); - -#define mpq_set_si __gmpq_set_si -__GMP_DECLSPEC void mpq_set_si __GMP_PROTO ((mpq_ptr, signed long int, unsigned long int)); - -#define mpq_set_str __gmpq_set_str -__GMP_DECLSPEC int mpq_set_str __GMP_PROTO ((mpq_ptr, __gmp_const char *, int)); - -#define mpq_set_ui __gmpq_set_ui -__GMP_DECLSPEC void mpq_set_ui __GMP_PROTO ((mpq_ptr, unsigned long int, unsigned long int)); - -#define mpq_set_z __gmpq_set_z -__GMP_DECLSPEC void mpq_set_z __GMP_PROTO ((mpq_ptr, mpz_srcptr)); - -#define mpq_sub __gmpq_sub -__GMP_DECLSPEC void mpq_sub __GMP_PROTO ((mpq_ptr, mpq_srcptr, mpq_srcptr)); - -#define mpq_swap __gmpq_swap -__GMP_DECLSPEC void mpq_swap __GMP_PROTO ((mpq_ptr, mpq_ptr)) __GMP_NOTHROW; - - -/**************** Float (i.e. F) routines. ****************/ - -#define mpf_abs __gmpf_abs -__GMP_DECLSPEC void mpf_abs __GMP_PROTO ((mpf_ptr, mpf_srcptr)); - -#define mpf_add __gmpf_add -__GMP_DECLSPEC void mpf_add __GMP_PROTO ((mpf_ptr, mpf_srcptr, mpf_srcptr)); - -#define mpf_add_ui __gmpf_add_ui -__GMP_DECLSPEC void mpf_add_ui __GMP_PROTO ((mpf_ptr, mpf_srcptr, unsigned long int)); -#define mpf_ceil __gmpf_ceil -__GMP_DECLSPEC void mpf_ceil __GMP_PROTO ((mpf_ptr, mpf_srcptr)); - -#define mpf_clear __gmpf_clear -__GMP_DECLSPEC void mpf_clear __GMP_PROTO ((mpf_ptr)); - -#define mpf_clears __gmpf_clears -__GMP_DECLSPEC void mpf_clears __GMP_PROTO ((mpf_ptr, ...)); - -#define mpf_cmp __gmpf_cmp -__GMP_DECLSPEC int mpf_cmp __GMP_PROTO ((mpf_srcptr, mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpf_cmp_d __gmpf_cmp_d -__GMP_DECLSPEC int mpf_cmp_d __GMP_PROTO ((mpf_srcptr, double)) __GMP_ATTRIBUTE_PURE; - -#define mpf_cmp_si __gmpf_cmp_si -__GMP_DECLSPEC int mpf_cmp_si __GMP_PROTO ((mpf_srcptr, signed long int)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpf_cmp_ui __gmpf_cmp_ui -__GMP_DECLSPEC int mpf_cmp_ui __GMP_PROTO ((mpf_srcptr, unsigned long int)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpf_div __gmpf_div -__GMP_DECLSPEC void mpf_div __GMP_PROTO ((mpf_ptr, mpf_srcptr, mpf_srcptr)); - -#define mpf_div_2exp __gmpf_div_2exp -__GMP_DECLSPEC void mpf_div_2exp __GMP_PROTO ((mpf_ptr, mpf_srcptr, mp_bitcnt_t)); - -#define mpf_div_ui __gmpf_div_ui -__GMP_DECLSPEC void mpf_div_ui __GMP_PROTO ((mpf_ptr, mpf_srcptr, unsigned long int)); - -#define mpf_dump __gmpf_dump -__GMP_DECLSPEC void mpf_dump __GMP_PROTO ((mpf_srcptr)); - -#define mpf_eq __gmpf_eq -__GMP_DECLSPEC int mpf_eq __GMP_PROTO ((mpf_srcptr, mpf_srcptr, mp_bitcnt_t)) __GMP_ATTRIBUTE_PURE; - -#define mpf_fits_sint_p __gmpf_fits_sint_p -__GMP_DECLSPEC int mpf_fits_sint_p __GMP_PROTO ((mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpf_fits_slong_p __gmpf_fits_slong_p -__GMP_DECLSPEC int mpf_fits_slong_p __GMP_PROTO ((mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpf_fits_sshort_p __gmpf_fits_sshort_p -__GMP_DECLSPEC int mpf_fits_sshort_p __GMP_PROTO ((mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpf_fits_uint_p __gmpf_fits_uint_p -__GMP_DECLSPEC int mpf_fits_uint_p __GMP_PROTO ((mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpf_fits_ulong_p __gmpf_fits_ulong_p -__GMP_DECLSPEC int mpf_fits_ulong_p __GMP_PROTO ((mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpf_fits_ushort_p __gmpf_fits_ushort_p -__GMP_DECLSPEC int mpf_fits_ushort_p __GMP_PROTO ((mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpf_floor __gmpf_floor -__GMP_DECLSPEC void mpf_floor __GMP_PROTO ((mpf_ptr, mpf_srcptr)); - -#define mpf_get_d __gmpf_get_d -__GMP_DECLSPEC double mpf_get_d __GMP_PROTO ((mpf_srcptr)) __GMP_ATTRIBUTE_PURE; - -#define mpf_get_d_2exp __gmpf_get_d_2exp -__GMP_DECLSPEC double mpf_get_d_2exp __GMP_PROTO ((signed long int *, mpf_srcptr)); - -#define mpf_get_default_prec __gmpf_get_default_prec -__GMP_DECLSPEC mp_bitcnt_t mpf_get_default_prec __GMP_PROTO ((void)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpf_get_prec __gmpf_get_prec -__GMP_DECLSPEC mp_bitcnt_t mpf_get_prec __GMP_PROTO ((mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpf_get_si __gmpf_get_si -__GMP_DECLSPEC long mpf_get_si __GMP_PROTO ((mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpf_get_str __gmpf_get_str -__GMP_DECLSPEC char *mpf_get_str __GMP_PROTO ((char *, mp_exp_t *, int, size_t, mpf_srcptr)); - -#define mpf_get_ui __gmpf_get_ui -__GMP_DECLSPEC unsigned long mpf_get_ui __GMP_PROTO ((mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpf_init __gmpf_init -__GMP_DECLSPEC void mpf_init __GMP_PROTO ((mpf_ptr)); - -#define mpf_init2 __gmpf_init2 -__GMP_DECLSPEC void mpf_init2 __GMP_PROTO ((mpf_ptr, mp_bitcnt_t)); - -#define mpf_inits __gmpf_inits -__GMP_DECLSPEC void mpf_inits __GMP_PROTO ((mpf_ptr, ...)); - -#define mpf_init_set __gmpf_init_set -__GMP_DECLSPEC void mpf_init_set __GMP_PROTO ((mpf_ptr, mpf_srcptr)); - -#define mpf_init_set_d __gmpf_init_set_d -__GMP_DECLSPEC void mpf_init_set_d __GMP_PROTO ((mpf_ptr, double)); - -#define mpf_init_set_si __gmpf_init_set_si -__GMP_DECLSPEC void mpf_init_set_si __GMP_PROTO ((mpf_ptr, signed long int)); - -#define mpf_init_set_str __gmpf_init_set_str -__GMP_DECLSPEC int mpf_init_set_str __GMP_PROTO ((mpf_ptr, __gmp_const char *, int)); - -#define mpf_init_set_ui __gmpf_init_set_ui -__GMP_DECLSPEC void mpf_init_set_ui __GMP_PROTO ((mpf_ptr, unsigned long int)); - -#define mpf_inp_str __gmpf_inp_str -#ifdef _GMP_H_HAVE_FILE -__GMP_DECLSPEC size_t mpf_inp_str __GMP_PROTO ((mpf_ptr, FILE *, int)); -#endif - -#define mpf_integer_p __gmpf_integer_p -__GMP_DECLSPEC int mpf_integer_p __GMP_PROTO ((mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpf_mul __gmpf_mul -__GMP_DECLSPEC void mpf_mul __GMP_PROTO ((mpf_ptr, mpf_srcptr, mpf_srcptr)); - -#define mpf_mul_2exp __gmpf_mul_2exp -__GMP_DECLSPEC void mpf_mul_2exp __GMP_PROTO ((mpf_ptr, mpf_srcptr, mp_bitcnt_t)); - -#define mpf_mul_ui __gmpf_mul_ui -__GMP_DECLSPEC void mpf_mul_ui __GMP_PROTO ((mpf_ptr, mpf_srcptr, unsigned long int)); - -#define mpf_neg __gmpf_neg -__GMP_DECLSPEC void mpf_neg __GMP_PROTO ((mpf_ptr, mpf_srcptr)); - -#define mpf_out_str __gmpf_out_str -#ifdef _GMP_H_HAVE_FILE -__GMP_DECLSPEC size_t mpf_out_str __GMP_PROTO ((FILE *, int, size_t, mpf_srcptr)); -#endif - -#define mpf_pow_ui __gmpf_pow_ui -__GMP_DECLSPEC void mpf_pow_ui __GMP_PROTO ((mpf_ptr, mpf_srcptr, unsigned long int)); - -#define mpf_random2 __gmpf_random2 -__GMP_DECLSPEC void mpf_random2 __GMP_PROTO ((mpf_ptr, mp_size_t, mp_exp_t)); - -#define mpf_rrandomb __gmpf_rrandomb -__GMP_DECLSPEC void mpf_rrandomb __GMP_PROTO ((mpf_ptr, gmp_randstate_t, mp_size_t, mp_exp_t)); - -#define mpf_reldiff __gmpf_reldiff -__GMP_DECLSPEC void mpf_reldiff __GMP_PROTO ((mpf_ptr, mpf_srcptr, mpf_srcptr)); - -#define mpf_set __gmpf_set -__GMP_DECLSPEC void mpf_set __GMP_PROTO ((mpf_ptr, mpf_srcptr)); - -#define mpf_set_d __gmpf_set_d -__GMP_DECLSPEC void mpf_set_d __GMP_PROTO ((mpf_ptr, double)); - -#define mpf_set_default_prec __gmpf_set_default_prec -__GMP_DECLSPEC void mpf_set_default_prec __GMP_PROTO ((mp_bitcnt_t)) __GMP_NOTHROW; - -#define mpf_set_prec __gmpf_set_prec -__GMP_DECLSPEC void mpf_set_prec __GMP_PROTO ((mpf_ptr, mp_bitcnt_t)); - -#define mpf_set_prec_raw __gmpf_set_prec_raw -__GMP_DECLSPEC void mpf_set_prec_raw __GMP_PROTO ((mpf_ptr, mp_bitcnt_t)) __GMP_NOTHROW; - -#define mpf_set_q __gmpf_set_q -__GMP_DECLSPEC void mpf_set_q __GMP_PROTO ((mpf_ptr, mpq_srcptr)); - -#define mpf_set_si __gmpf_set_si -__GMP_DECLSPEC void mpf_set_si __GMP_PROTO ((mpf_ptr, signed long int)); - -#define mpf_set_str __gmpf_set_str -__GMP_DECLSPEC int mpf_set_str __GMP_PROTO ((mpf_ptr, __gmp_const char *, int)); - -#define mpf_set_ui __gmpf_set_ui -__GMP_DECLSPEC void mpf_set_ui __GMP_PROTO ((mpf_ptr, unsigned long int)); - -#define mpf_set_z __gmpf_set_z -__GMP_DECLSPEC void mpf_set_z __GMP_PROTO ((mpf_ptr, mpz_srcptr)); - -#define mpf_size __gmpf_size -__GMP_DECLSPEC size_t mpf_size __GMP_PROTO ((mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpf_sqrt __gmpf_sqrt -__GMP_DECLSPEC void mpf_sqrt __GMP_PROTO ((mpf_ptr, mpf_srcptr)); - -#define mpf_sqrt_ui __gmpf_sqrt_ui -__GMP_DECLSPEC void mpf_sqrt_ui __GMP_PROTO ((mpf_ptr, unsigned long int)); - -#define mpf_sub __gmpf_sub -__GMP_DECLSPEC void mpf_sub __GMP_PROTO ((mpf_ptr, mpf_srcptr, mpf_srcptr)); - -#define mpf_sub_ui __gmpf_sub_ui -__GMP_DECLSPEC void mpf_sub_ui __GMP_PROTO ((mpf_ptr, mpf_srcptr, unsigned long int)); - -#define mpf_swap __gmpf_swap -__GMP_DECLSPEC void mpf_swap __GMP_PROTO ((mpf_ptr, mpf_ptr)) __GMP_NOTHROW; - -#define mpf_trunc __gmpf_trunc -__GMP_DECLSPEC void mpf_trunc __GMP_PROTO ((mpf_ptr, mpf_srcptr)); - -#define mpf_ui_div __gmpf_ui_div -__GMP_DECLSPEC void mpf_ui_div __GMP_PROTO ((mpf_ptr, unsigned long int, mpf_srcptr)); - -#define mpf_ui_sub __gmpf_ui_sub -__GMP_DECLSPEC void mpf_ui_sub __GMP_PROTO ((mpf_ptr, unsigned long int, mpf_srcptr)); - -#define mpf_urandomb __gmpf_urandomb -__GMP_DECLSPEC void mpf_urandomb __GMP_PROTO ((mpf_t, gmp_randstate_t, mp_bitcnt_t)); - - -/************ Low level positive-integer (i.e. N) routines. ************/ - -/* This is ugly, but we need to make user calls reach the prefixed function. */ - -#define mpn_add __MPN(add) -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpn_add) -__GMP_DECLSPEC mp_limb_t mpn_add __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_srcptr,mp_size_t)); -#endif - -#define mpn_add_1 __MPN(add_1) -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpn_add_1) -__GMP_DECLSPEC mp_limb_t mpn_add_1 __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_limb_t)) __GMP_NOTHROW; -#endif - -#define mpn_add_n __MPN(add_n) -__GMP_DECLSPEC mp_limb_t mpn_add_n __GMP_PROTO ((mp_ptr, mp_srcptr, mp_srcptr, mp_size_t)); - -#define mpn_addmul_1 __MPN(addmul_1) -__GMP_DECLSPEC mp_limb_t mpn_addmul_1 __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_limb_t)); - -#define mpn_bdivmod __MPN(bdivmod) -__GMP_DECLSPEC mp_limb_t mpn_bdivmod __GMP_PROTO ((mp_ptr, mp_ptr, mp_size_t, mp_srcptr, mp_size_t, unsigned long int)); - -#define mpn_divrem __MPN(divrem) -__GMP_DECLSPEC mp_limb_t mpn_divrem __GMP_PROTO ((mp_ptr, mp_size_t, mp_ptr, mp_size_t, mp_srcptr, mp_size_t)); - -#define mpn_mulmod_2expp1 __MPN(mulmod_2expp1) -__GMP_DECLSPEC int mpn_mulmod_2expp1 __GMP_PROTO ((mp_ptr, mp_srcptr, mp_srcptr,int,unsigned long, mp_ptr)); - -#define mpn_mulmod_2expm1 __MPN(mulmod_2expm1) -__GMP_DECLSPEC void mpn_mulmod_2expm1 __GMP_PROTO ((mp_ptr, mp_ptr, mp_ptr,unsigned long, mp_ptr)); - -#define mpn_cmp __MPN(cmp) -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpn_cmp) -__GMP_DECLSPEC int mpn_cmp __GMP_PROTO ((mp_srcptr, mp_srcptr, mp_size_t)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#endif - -#define mpn_redc_1 __MPN(redc_1) -__GMP_DECLSPEC void mpn_redc_1 __GMP_PROTO ((mp_ptr, mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);) - -#define mpn_divexact_by3(dst,src,size) \ - mpn_divexact_by3c (dst, src, size, __GMP_CAST (mp_limb_t, 0)) - -#define mpn_divexact_by3c __MPN(divexact_by3c) -__GMP_DECLSPEC mp_limb_t mpn_divexact_by3c __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_limb_t)); - -#define mpn_divmod_1(qp,np,nsize,dlimb) \ - mpn_divrem_1 (qp, __GMP_CAST (mp_size_t, 0), np, nsize, dlimb) - -#define mpn_divrem_1 __MPN(divrem_1) -__GMP_DECLSPEC mp_limb_t mpn_divrem_1 __GMP_PROTO ((mp_ptr, mp_size_t, mp_srcptr, mp_size_t, mp_limb_t)); - -#define mpn_divrem_2 __MPN(divrem_2) -__GMP_DECLSPEC mp_limb_t mpn_divrem_2 __GMP_PROTO ((mp_ptr, mp_size_t, mp_ptr, mp_size_t, mp_srcptr)); - -#define mpn_invert __MPN(invert) -__GMP_DECLSPEC void mpn_invert __GMP_PROTO ((mp_ptr xp, mp_srcptr ap, mp_size_t n)); - -#define mpn_sb_divappr_q __MPN(sb_divappr_q) -__GMP_DECLSPEC mp_limb_t mpn_sb_divappr_q __GMP_PROTO ((mp_ptr qp, mp_ptr np, mp_size_t nn, - mp_srcptr dp, mp_size_t dn, mp_limb_t dip)); - -#define mpn_dc_divappr_q_n __MPN(dc_divappr_q_n) -__GMP_DECLSPEC mp_limb_t mpn_dc_divappr_q_n __GMP_PROTO ((mp_ptr qp, mp_ptr np, mp_srcptr dp, mp_size_t n, - mp_limb_t dip, mp_ptr tp)); - -#define mpn_dc_bdiv_q_n __MPN(dc_bdiv_q_n) -__GMP_DECLSPEC void mpn_dc_bdiv_q_n __GMP_PROTO ((mp_ptr qp, mp_ptr wp, mp_ptr np, mp_srcptr dp, mp_size_t n, - mp_limb_t dinv, mp_ptr scratch)); - -#define mpn_inv_divappr_q_n __MPN(inv_divappr_q_n) -__GMP_DECLSPEC mp_limb_t mpn_inv_divappr_q_n __GMP_PROTO ((mp_ptr qp, mp_ptr np, mp_srcptr dp, mp_size_t n, - mp_srcptr dip)); - -#define mpn_dc_divappr_q __MPN(dc_divappr_q) -__GMP_DECLSPEC mp_limb_t mpn_dc_divappr_q __GMP_PROTO ((mp_ptr qp, mp_ptr np, mp_size_t nn, mp_srcptr dp, mp_size_t n, - mp_limb_t dinv)); - -#define mpn_dc_div_q __MPN(dc_div_q) -__GMP_DECLSPEC mp_limb_t mpn_dc_div_q __GMP_PROTO ((mp_ptr qp, mp_ptr np, mp_size_t nn, - mp_srcptr dp, mp_size_t dn, mp_limb_t dinv)); - -#define mpn_inv_divappr_q __MPN(inv_divappr_q) -__GMP_DECLSPEC mp_limb_t mpn_inv_divappr_q __GMP_PROTO ((mp_ptr qp, mp_ptr np, mp_size_t nn, mp_srcptr dp, mp_size_t n, - mp_srcptr dinv)); - -#define mpn_inv_div_q __MPN(inv_div_q) -__GMP_DECLSPEC mp_limb_t mpn_inv_div_q __GMP_PROTO ((mp_ptr qp, mp_ptr np, mp_size_t nn, - mp_srcptr dp, mp_size_t dn, mp_srcptr dinv)); - -#define mpn_inv_div_qr __MPN(inv_div_qr) -__GMP_DECLSPEC mp_limb_t mpn_inv_div_qr __GMP_PROTO ((mp_ptr qp, mp_ptr np, mp_size_t nn, - mp_srcptr dp, mp_size_t dn, mp_srcptr dinv)); - -#define mpn_inv_div_qr_n __MPN(inv_div_qr_n) -__GMP_DECLSPEC mp_limb_t mpn_inv_div_qr_n __GMP_PROTO ((mp_ptr qp, mp_ptr np, - mp_srcptr dp, mp_size_t dn, mp_srcptr dinv)); - -#define mpn_dc_div_qr __MPN(dc_div_qr) -__GMP_DECLSPEC mp_limb_t mpn_dc_div_qr __GMP_PROTO ((mp_ptr qp, mp_ptr np, mp_size_t nn, - mp_srcptr dp, mp_size_t dn, mp_limb_t dinv)); - -#define mpn_dc_div_qr_n __MPN(dc_div_qr_n) -__GMP_DECLSPEC mp_limb_t mpn_dc_div_qr_n __GMP_PROTO ((mp_ptr qp, mp_ptr np, mp_srcptr dp, mp_size_t n, - mp_limb_t dinv, mp_ptr tp)); - -#define mpn_sb_div_q __MPN(sb_div_q) -__GMP_DECLSPEC mp_limb_t mpn_sb_div_q __GMP_PROTO ((mp_ptr qp, mp_ptr np, mp_size_t nn, - mp_srcptr dp, mp_size_t dn, mp_limb_t dinv)); - -#define mpn_sb_bdiv_q __MPN(sb_bdiv_q) -__GMP_DECLSPEC void mpn_sb_bdiv_q __GMP_PROTO ((mp_ptr qp, mp_ptr wp, mp_ptr np, mp_size_t nn, - mp_srcptr dp, mp_size_t dn, mp_limb_t dinv)); - -#define mpn_dc_bdiv_q __MPN(dc_bdiv_q) -__GMP_DECLSPEC void mpn_dc_bdiv_q __GMP_PROTO ((mp_ptr qp, mp_ptr np, mp_size_t nn, - mp_srcptr dp, mp_size_t dn, mp_limb_t dinv)); - -#define mpn_dc_bdiv_qr __MPN(dc_bdiv_qr) -__GMP_DECLSPEC mp_limb_t mpn_dc_bdiv_qr __GMP_PROTO ((mp_ptr qp, mp_ptr np, mp_size_t nn, - mp_srcptr dp, mp_size_t dn, mp_limb_t dinv)); - -#define mpn_dc_bdiv_qr_n __MPN(dc_bdiv_qr_n) -__GMP_DECLSPEC mp_limb_t mpn_dc_bdiv_qr_n __GMP_PROTO ((mp_ptr qp, mp_ptr np, - mp_srcptr dp, mp_size_t n, mp_limb_t dinv, mp_ptr tp)); - -#define mpn_sb_div_qr __MPN(sb_div_qr) -__GMP_DECLSPEC mp_limb_t mpn_sb_div_qr __GMP_PROTO ((mp_ptr qp, mp_ptr np, mp_size_t nn, - mp_srcptr dp, mp_size_t dn, mp_limb_t dinv)); - -#define mpn_sb_bdiv_qr __MPN(sb_bdiv_qr) -__GMP_DECLSPEC mp_limb_t mpn_sb_bdiv_qr __GMP_PROTO ((mp_ptr qp, mp_ptr np, mp_size_t nn, - mp_srcptr dp, mp_size_t dn, mp_limb_t dinv)); - -#define mpn_tdiv_q __MPN(tdiv_q) -__GMP_DECLSPEC void mpn_tdiv_q __GMP_PROTO ((mp_ptr qp, mp_srcptr np, mp_size_t nn, - mp_srcptr dp, mp_size_t dn)); - -#define mpn_divexact __MPN(divexact) -__GMP_DECLSPEC void mpn_divexact __GMP_PROTO ((mp_ptr qp, - mp_srcptr np, mp_size_t nn, mp_srcptr dp, mp_size_t dn)); - -#define mpn_gcd __MPN(gcd) -__GMP_DECLSPEC mp_size_t mpn_gcd __GMP_PROTO ((mp_ptr, mp_ptr, mp_size_t, mp_ptr, mp_size_t)); - -#define mpn_gcd_1 __MPN(gcd_1) -__GMP_DECLSPEC mp_limb_t mpn_gcd_1 __GMP_PROTO ((mp_srcptr, mp_size_t, mp_limb_t)) __GMP_ATTRIBUTE_PURE; - -#define mpn_gcdext __MPN(gcdext) -__GMP_DECLSPEC mp_size_t mpn_gcdext __GMP_PROTO ((mp_ptr, mp_ptr, mp_size_t *, mp_ptr, mp_size_t, mp_ptr, mp_size_t)); - -#define mpn_get_str __MPN(get_str) -__GMP_DECLSPEC size_t mpn_get_str __GMP_PROTO ((unsigned char *, int, mp_ptr, mp_size_t)); - -#define mpn_hamdist __MPN(hamdist) -__GMP_DECLSPEC mp_bitcnt_t mpn_hamdist __GMP_PROTO ((mp_srcptr, mp_srcptr, mp_size_t)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpn_lshift __MPN(lshift) -__GMP_DECLSPEC mp_limb_t mpn_lshift __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, unsigned int)); - -#define mpn_mod_1 __MPN(mod_1) -__GMP_DECLSPEC mp_limb_t mpn_mod_1 __GMP_PROTO ((mp_srcptr, mp_size_t, mp_limb_t)) __GMP_ATTRIBUTE_PURE; - -#define mpn_mul __MPN(mul) -__GMP_DECLSPEC mp_limb_t mpn_mul __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t)); - -#define mpn_mul_1 __MPN(mul_1) -__GMP_DECLSPEC mp_limb_t mpn_mul_1 __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_limb_t)); - -#define mpn_mul_n __MPN(mul_n) -__GMP_DECLSPEC void mpn_mul_n __GMP_PROTO ((mp_ptr, mp_srcptr, mp_srcptr, mp_size_t)); - -#define mpn_sqr __MPN(sqr) -__GMP_DECLSPEC void mpn_sqr __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t)); - -#define mpn_neg_n __MPN(neg_n) -#define mpn_neg __MPN(neg_n) -__GMP_DECLSPEC mp_limb_t mpn_neg_n __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t)); - -#define mpn_com_n __MPN(com_n) -#define mpn_com __MPN(com_n) -__GMP_DECLSPEC void mpn_com_n __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t)); - -#define mpn_perfect_square_p __MPN(perfect_square_p) -__GMP_DECLSPEC int mpn_perfect_square_p __GMP_PROTO ((mp_srcptr, mp_size_t)) __GMP_ATTRIBUTE_PURE; - -#define mpn_popcount __MPN(popcount) -__GMP_DECLSPEC mp_bitcnt_t mpn_popcount __GMP_PROTO ((mp_srcptr, mp_size_t)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpn_pow_1 __MPN(pow_1) -__GMP_DECLSPEC mp_size_t mpn_pow_1 __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_limb_t, mp_ptr)); - -/* undocumented now, but retained here for upward compatibility */ -#define mpn_preinv_mod_1 __MPN(preinv_mod_1) -__GMP_DECLSPEC mp_limb_t mpn_preinv_mod_1 __GMP_PROTO ((mp_srcptr, mp_size_t, mp_limb_t, mp_limb_t)) __GMP_ATTRIBUTE_PURE; - -#define mpn_random __MPN(random) -__GMP_DECLSPEC void mpn_random __GMP_PROTO ((mp_ptr, mp_size_t)); - -#define mpn_random2 __MPN(random2) -__GMP_DECLSPEC void mpn_random2 __GMP_PROTO ((mp_ptr, mp_size_t)); - -#define mpn_urandomb __MPN(urandomb) -__GMP_DECLSPEC void mpn_urandomb __GMP_PROTO ((mp_ptr, gmp_randstate_t, unsigned long)); - -#define mpn_urandomm __MPN(urandomm) -__GMP_DECLSPEC void mpn_urandomm __GMP_PROTO ((mp_ptr, gmp_randstate_t, mp_srcptr, mp_size_t)); - -#define mpn_randomb __MPN(randomb) -__GMP_DECLSPEC void mpn_randomb __GMP_PROTO ((mp_ptr, gmp_randstate_t, mp_size_t)); - -#define mpn_rrandom __MPN(rrandom) -__GMP_DECLSPEC void mpn_rrandom __GMP_PROTO ((mp_ptr, gmp_randstate_t, mp_size_t)); - -#define mpn_rshift __MPN(rshift) -__GMP_DECLSPEC mp_limb_t mpn_rshift __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, unsigned int)); - -#define mpn_scan0 __MPN(scan0) -__GMP_DECLSPEC mp_bitcnt_t mpn_scan0 __GMP_PROTO ((mp_srcptr, mp_bitcnt_t)) __GMP_ATTRIBUTE_PURE; - -#define mpn_scan1 __MPN(scan1) -__GMP_DECLSPEC mp_bitcnt_t mpn_scan1 __GMP_PROTO ((mp_srcptr, mp_bitcnt_t)) __GMP_ATTRIBUTE_PURE; - -#define mpn_set_str __MPN(set_str) -__GMP_DECLSPEC mp_size_t mpn_set_str __GMP_PROTO ((mp_ptr, __gmp_const unsigned char *, size_t, int)); - -#define mpn_sqrtrem __MPN(sqrtrem) -__GMP_DECLSPEC mp_size_t mpn_sqrtrem __GMP_PROTO ((mp_ptr, mp_ptr, mp_srcptr, mp_size_t)); - -#define mpn_sub __MPN(sub) -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpn_sub) -__GMP_DECLSPEC mp_limb_t mpn_sub __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_srcptr,mp_size_t)); -#endif - -#define mpn_sub_1 __MPN(sub_1) -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpn_sub_1) -__GMP_DECLSPEC mp_limb_t mpn_sub_1 __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_limb_t)) __GMP_NOTHROW; -#endif - -#define mpn_sub_n __MPN(sub_n) -__GMP_DECLSPEC mp_limb_t mpn_sub_n __GMP_PROTO ((mp_ptr, mp_srcptr, mp_srcptr, mp_size_t)); - -#define mpn_submul_1 __MPN(submul_1) -__GMP_DECLSPEC mp_limb_t mpn_submul_1 __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_limb_t)); - -#define mpn_tdiv_qr __MPN(tdiv_qr) -__GMP_DECLSPEC void mpn_tdiv_qr __GMP_PROTO ((mp_ptr, mp_ptr, mp_size_t, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t)); - -#define mpn_and_n __MPN(and_n) -__GMP_DECLSPEC void mpn_and_n __GMP_PROTO ((mp_ptr, mp_srcptr, mp_srcptr, mp_size_t)); -#define mpn_andn_n __MPN(andn_n) -__GMP_DECLSPEC void mpn_andn_n __GMP_PROTO ((mp_ptr, mp_srcptr, mp_srcptr, mp_size_t)); -#define mpn_nand_n __MPN(nand_n) -__GMP_DECLSPEC void mpn_nand_n __GMP_PROTO ((mp_ptr, mp_srcptr, mp_srcptr, mp_size_t)); -#define mpn_ior_n __MPN(ior_n) -__GMP_DECLSPEC void mpn_ior_n __GMP_PROTO ((mp_ptr, mp_srcptr, mp_srcptr, mp_size_t)); -#define mpn_iorn_n __MPN(iorn_n) -__GMP_DECLSPEC void mpn_iorn_n __GMP_PROTO ((mp_ptr, mp_srcptr, mp_srcptr, mp_size_t)); -#define mpn_nior_n __MPN(nior_n) -__GMP_DECLSPEC void mpn_nior_n __GMP_PROTO ((mp_ptr, mp_srcptr, mp_srcptr, mp_size_t)); -#define mpn_xor_n __MPN(xor_n) -__GMP_DECLSPEC void mpn_xor_n __GMP_PROTO ((mp_ptr, mp_srcptr, mp_srcptr, mp_size_t)); -#define mpn_xnor_n __MPN(xnor_n) -__GMP_DECLSPEC void mpn_xnor_n __GMP_PROTO ((mp_ptr, mp_srcptr, mp_srcptr, mp_size_t)); - -#define mpn_copyi __MPN(copyi) -__GMP_DECLSPEC void mpn_copyi __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t)); -#define mpn_copyd __MPN(copyd) -__GMP_DECLSPEC void mpn_copyd __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t)); -#define mpn_zero __MPN(zero) -__GMP_DECLSPEC void mpn_zero __GMP_PROTO ((mp_ptr, mp_size_t)); - -/**************** mpz inlines ****************/ - -/* The following are provided as inlines where possible, but always exist as - library functions too, for binary compatibility. - - Within gmp itself this inlining generally isn't relied on, since it - doesn't get done for all compilers, whereas if something is worth - inlining then it's worth arranging always. - - There are two styles of inlining here. When the same bit of code is - wanted for the inline as for the library version, then __GMP_FORCE_foo - arranges for that code to be emitted and the __GMP_EXTERN_INLINE - directive suppressed, eg. mpz_fits_uint_p. When a different bit of code - is wanted for the inline than for the library version, then - __GMP_FORCE_foo arranges the inline to be suppressed, eg. mpz_abs. */ - -#if defined (__GMP_EXTERN_INLINE) && ! defined (__GMP_FORCE_mpz_abs) -__GMP_EXTERN_INLINE void -mpz_abs (mpz_ptr __gmp_w, mpz_srcptr __gmp_u) -{ - if (__gmp_w != __gmp_u) - mpz_set (__gmp_w, __gmp_u); - __gmp_w->_mp_size = __GMP_ABS (__gmp_w->_mp_size); -} -#endif - -#if GMP_NAIL_BITS == 0 -#define __GMPZ_FITS_UTYPE_P(z,maxval) \ - mp_size_t __gmp_n = z->_mp_size; \ - mp_ptr __gmp_p = z->_mp_d; \ - return (__gmp_n == 0 || (__gmp_n == 1 && __gmp_p[0] <= maxval)); -#else -#define __GMPZ_FITS_UTYPE_P(z,maxval) \ - mp_size_t __gmp_n = z->_mp_size; \ - mp_ptr __gmp_p = z->_mp_d; \ - return (__gmp_n == 0 || (__gmp_n == 1 && __gmp_p[0] <= maxval) \ - || (__gmp_n == 2 && __gmp_p[1] <= ((mp_limb_t) maxval >> GMP_NUMB_BITS))); -#endif - -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_fits_uint_p) -#if ! defined (__GMP_FORCE_mpz_fits_uint_p) -__GMP_EXTERN_INLINE -#endif -int -mpz_fits_uint_p (mpz_srcptr __gmp_z) __GMP_NOTHROW -{ - __GMPZ_FITS_UTYPE_P (__gmp_z, __GMP_UINT_MAX); -} -#endif - -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_fits_ulong_p) -#if ! defined (__GMP_FORCE_mpz_fits_ulong_p) -__GMP_EXTERN_INLINE -#endif -int -mpz_fits_ulong_p (mpz_srcptr __gmp_z) __GMP_NOTHROW -{ - __GMPZ_FITS_UTYPE_P (__gmp_z, __GMP_ULONG_MAX); -} -#endif - -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_fits_ushort_p) -#if ! defined (__GMP_FORCE_mpz_fits_ushort_p) -__GMP_EXTERN_INLINE -#endif -int -mpz_fits_ushort_p (mpz_srcptr __gmp_z) __GMP_NOTHROW -{ - __GMPZ_FITS_UTYPE_P (__gmp_z, __GMP_USHRT_MAX); -} -#endif - -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_get_ui) -#if ! defined (__GMP_FORCE_mpz_get_ui) -__GMP_EXTERN_INLINE -#endif -unsigned long -mpz_get_ui (mpz_srcptr __gmp_z) __GMP_NOTHROW -{ - mp_ptr __gmp_p = __gmp_z->_mp_d; - mp_size_t __gmp_n = __gmp_z->_mp_size; - mp_limb_t __gmp_l = __gmp_p[0]; - /* This is a "#if" rather than a plain "if" so as to avoid gcc warnings - about "<< GMP_NUMB_BITS" exceeding the type size, and to avoid Borland - C++ 6.0 warnings about condition always true for something like - "__GMP_ULONG_MAX < GMP_NUMB_MASK". */ -#if GMP_NAIL_BITS == 0 || defined (_LONG_LONG_LIMB) - /* limb==long and no nails, or limb==longlong, one limb is enough */ - return (unsigned long)(__gmp_n != 0 ? __gmp_l : 0); -#else - /* limb==long and nails, need two limbs when available */ - __gmp_n = __GMP_ABS (__gmp_n); - if (__gmp_n <= 1) - return (__gmp_n != 0 ? __gmp_l : 0); - else - return __gmp_l + (__gmp_p[1] << GMP_NUMB_BITS); -#endif -} -#endif - -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_getlimbn) -#if ! defined (__GMP_FORCE_mpz_getlimbn) -__GMP_EXTERN_INLINE -#endif -mp_limb_t -mpz_getlimbn (mpz_srcptr __gmp_z, mp_size_t __gmp_n) __GMP_NOTHROW -{ - mp_limb_t __gmp_result = 0; - if (__GMP_LIKELY (__gmp_n >= 0 && __gmp_n < __GMP_ABS (__gmp_z->_mp_size))) - __gmp_result = __gmp_z->_mp_d[__gmp_n]; - return __gmp_result; -} -#endif - -#if defined (__GMP_EXTERN_INLINE) && ! defined (__GMP_FORCE_mpz_neg) -__GMP_EXTERN_INLINE void -mpz_neg (mpz_ptr __gmp_w, mpz_srcptr __gmp_u) -{ - if (__gmp_w != __gmp_u) - mpz_set (__gmp_w, __gmp_u); - __gmp_w->_mp_size = - __gmp_w->_mp_size; -} -#endif - -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_perfect_square_p) -#if ! defined (__GMP_FORCE_mpz_perfect_square_p) -__GMP_EXTERN_INLINE -#endif -int -mpz_perfect_square_p (mpz_srcptr __gmp_a) -{ - mp_size_t __gmp_asize; - int __gmp_result; - - __gmp_asize = __gmp_a->_mp_size; - __gmp_result = (__gmp_asize >= 0); /* zero is a square, negatives are not */ - if (__GMP_LIKELY (__gmp_asize > 0)) - __gmp_result = mpn_perfect_square_p (__gmp_a->_mp_d, __gmp_asize); - return __gmp_result; -} -#endif - -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_popcount) -#if ! defined (__GMP_FORCE_mpz_popcount) -__GMP_EXTERN_INLINE -#endif -mp_bitcnt_t -mpz_popcount (mpz_srcptr __gmp_u) __GMP_NOTHROW -{ - mp_size_t __gmp_usize; - mp_bitcnt_t __gmp_result; - - __gmp_usize = __gmp_u->_mp_size; - __gmp_result = (__gmp_usize < 0 ? __GMP_BITCNT_MAX : 0); - if (__GMP_LIKELY (__gmp_usize > 0)) - __gmp_result = mpn_popcount (__gmp_u->_mp_d, __gmp_usize); - return __gmp_result; -} -#endif - -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_set_q) -#if ! defined (__GMP_FORCE_mpz_set_q) -__GMP_EXTERN_INLINE -#endif -void -mpz_set_q (mpz_ptr __gmp_w, mpq_srcptr __gmp_u) -{ - mpz_tdiv_q (__gmp_w, mpq_numref (__gmp_u), mpq_denref (__gmp_u)); -} -#endif - -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_size) -#if ! defined (__GMP_FORCE_mpz_size) -__GMP_EXTERN_INLINE -#endif -size_t -mpz_size (mpz_srcptr __gmp_z) __GMP_NOTHROW -{ - return __GMP_ABS (__gmp_z->_mp_size); -} -#endif - - -/**************** mpq inlines ****************/ - -#if defined (__GMP_EXTERN_INLINE) && ! defined (__GMP_FORCE_mpq_abs) -__GMP_EXTERN_INLINE void -mpq_abs (mpq_ptr __gmp_w, mpq_srcptr __gmp_u) -{ - if (__gmp_w != __gmp_u) - mpq_set (__gmp_w, __gmp_u); - __gmp_w->_mp_num._mp_size = __GMP_ABS (__gmp_w->_mp_num._mp_size); -} -#endif - -#if defined (__GMP_EXTERN_INLINE) && ! defined (__GMP_FORCE_mpq_neg) -__GMP_EXTERN_INLINE void -mpq_neg (mpq_ptr __gmp_w, mpq_srcptr __gmp_u) -{ - if (__gmp_w != __gmp_u) - mpq_set (__gmp_w, __gmp_u); - __gmp_w->_mp_num._mp_size = - __gmp_w->_mp_num._mp_size; -} -#endif - - -/**************** mpn inlines ****************/ - -/* The comments with __GMPN_ADD_1 below apply here too. - - The test for FUNCTION returning 0 should predict well. If it's assumed - {yp,ysize} will usually have a random number of bits then the high limb - won't be full and a carry out will occur a good deal less than 50% of the - time. - - ysize==0 isn't a documented feature, but is used internally in a few - places. - - Producing cout last stops it using up a register during the main part of - the calculation, though gcc (as of 3.0) on an "if (mpn_add (...))" - doesn't seem able to move the true and false legs of the conditional up - to the two places cout is generated. */ - -#define __GMPN_AORS(cout, wp, xp, xsize, yp, ysize, FUNCTION, TEST) \ - do { \ - mp_size_t __gmp_i; \ - mp_limb_t __gmp_x; \ - \ - /* ASSERT ((ysize) >= 0); */ \ - /* ASSERT ((xsize) >= (ysize)); */ \ - /* ASSERT (MPN_SAME_OR_SEPARATE2_P (wp, xsize, xp, xsize)); */ \ - /* ASSERT (MPN_SAME_OR_SEPARATE2_P (wp, xsize, yp, ysize)); */ \ - \ - __gmp_i = (ysize); \ - if (__gmp_i != 0) \ - { \ - if (FUNCTION (wp, xp, yp, __gmp_i)) \ - { \ - do \ - { \ - if (__gmp_i >= (xsize)) \ - { \ - (cout) = 1; \ - goto __gmp_done; \ - } \ - __gmp_x = (xp)[__gmp_i]; \ - } \ - while (TEST); \ - } \ - } \ - if ((wp) != (xp)) \ - __GMPN_COPY_REST (wp, xp, xsize, __gmp_i); \ - (cout) = 0; \ - __gmp_done: \ - ; \ - } while (0) - -#define __GMPN_ADD(cout, wp, xp, xsize, yp, ysize) \ - __GMPN_AORS (cout, wp, xp, xsize, yp, ysize, mpn_add_n, \ - (((wp)[__gmp_i++] = (__gmp_x + 1) & GMP_NUMB_MASK) == 0)) -#define __GMPN_SUB(cout, wp, xp, xsize, yp, ysize) \ - __GMPN_AORS (cout, wp, xp, xsize, yp, ysize, mpn_sub_n, \ - (((wp)[__gmp_i++] = (__gmp_x - 1) & GMP_NUMB_MASK), __gmp_x == 0)) - - -/* The use of __gmp_i indexing is designed to ensure a compile time src==dst - remains nice and clear to the compiler, so that __GMPN_COPY_REST can - disappear, and the load/add/store gets a chance to become a - read-modify-write on CISC CPUs. - - Alternatives: - - Using a pair of pointers instead of indexing would be possible, but gcc - isn't able to recognise compile-time src==dst in that case, even when the - pointers are incremented more or less together. Other compilers would - very likely have similar difficulty. - - gcc could use "if (__builtin_constant_p(src==dst) && src==dst)" or - similar to detect a compile-time src==dst. This works nicely on gcc - 2.95.x, it's not good on gcc 3.0 where __builtin_constant_p(p==p) seems - to be always false, for a pointer p. But the current code form seems - good enough for src==dst anyway. - - gcc on x86 as usual doesn't give particularly good flags handling for the - carry/borrow detection. It's tempting to want some multi instruction asm - blocks to help it, and this was tried, but in truth there's only a few - instructions to save and any gain is all too easily lost by register - juggling setting up for the asm. */ - -#if GMP_NAIL_BITS == 0 -#define __GMPN_AORS_1(cout, dst, src, n, v, OP, CB) \ - do { \ - mp_size_t __gmp_i; \ - mp_limb_t __gmp_x, __gmp_r; \ - \ - /* ASSERT ((n) >= 1); */ \ - /* ASSERT (MPN_SAME_OR_SEPARATE_P (dst, src, n)); */ \ - \ - __gmp_x = (src)[0]; \ - __gmp_r = __gmp_x OP (v); \ - (dst)[0] = __gmp_r; \ - if (CB (__gmp_r, __gmp_x, (v))) \ - { \ - (cout) = 1; \ - for (__gmp_i = 1; __gmp_i < (n);) \ - { \ - __gmp_x = (src)[__gmp_i]; \ - __gmp_r = __gmp_x OP 1; \ - (dst)[__gmp_i] = __gmp_r; \ - ++__gmp_i; \ - if (!CB (__gmp_r, __gmp_x, 1)) \ - { \ - if ((src) != (dst)) \ - __GMPN_COPY_REST (dst, src, n, __gmp_i); \ - (cout) = 0; \ - break; \ - } \ - } \ - } \ - else \ - { \ - if ((src) != (dst)) \ - __GMPN_COPY_REST (dst, src, n, 1); \ - (cout) = 0; \ - } \ - } while (0) -#endif - -#if GMP_NAIL_BITS >= 1 -#define __GMPN_AORS_1(cout, dst, src, n, v, OP, CB) \ - do { \ - mp_size_t __gmp_i; \ - mp_limb_t __gmp_x, __gmp_r; \ - \ - /* ASSERT ((n) >= 1); */ \ - /* ASSERT (MPN_SAME_OR_SEPARATE_P (dst, src, n)); */ \ - \ - __gmp_x = (src)[0]; \ - __gmp_r = __gmp_x OP (v); \ - (dst)[0] = __gmp_r & GMP_NUMB_MASK; \ - if (__gmp_r >> GMP_NUMB_BITS != 0) \ - { \ - (cout) = 1; \ - for (__gmp_i = 1; __gmp_i < (n);) \ - { \ - __gmp_x = (src)[__gmp_i]; \ - __gmp_r = __gmp_x OP 1; \ - (dst)[__gmp_i] = __gmp_r & GMP_NUMB_MASK; \ - ++__gmp_i; \ - if (__gmp_r >> GMP_NUMB_BITS == 0) \ - { \ - if ((src) != (dst)) \ - __GMPN_COPY_REST (dst, src, n, __gmp_i); \ - (cout) = 0; \ - break; \ - } \ - } \ - } \ - else \ - { \ - if ((src) != (dst)) \ - __GMPN_COPY_REST (dst, src, n, 1); \ - (cout) = 0; \ - } \ - } while (0) -#endif - -#define __GMPN_ADDCB(r,x,y) ((r) < (y)) -#define __GMPN_SUBCB(r,x,y) ((x) < (y)) - -#define __GMPN_ADD_1(cout, dst, src, n, v) \ - __GMPN_AORS_1(cout, dst, src, n, v, +, __GMPN_ADDCB) -#define __GMPN_SUB_1(cout, dst, src, n, v) \ - __GMPN_AORS_1(cout, dst, src, n, v, -, __GMPN_SUBCB) - - -/* Compare {xp,size} and {yp,size}, setting "result" to positive, zero or - negative. size==0 is allowed. On random data usually only one limb will - need to be examined to get a result, so it's worth having it inline. */ -#define __GMPN_CMP(result, xp, yp, size) \ - do { \ - mp_size_t __gmp_i; \ - mp_limb_t __gmp_x, __gmp_y; \ - \ - /* ASSERT ((size) >= 0); */ \ - \ - (result) = 0; \ - __gmp_i = (size); \ - while (--__gmp_i >= 0) \ - { \ - __gmp_x = (xp)[__gmp_i]; \ - __gmp_y = (yp)[__gmp_i]; \ - if (__gmp_x != __gmp_y) \ - { \ - /* Cannot use __gmp_x - __gmp_y, may overflow an "int" */ \ - (result) = (__gmp_x > __gmp_y ? 1 : -1); \ - break; \ - } \ - } \ - } while (0) - - -#if defined (__GMPN_COPY) && ! defined (__GMPN_COPY_REST) -#define __GMPN_COPY_REST(dst, src, size, start) \ - do { \ - /* ASSERT ((start) >= 0); */ \ - /* ASSERT ((start) <= (size)); */ \ - __GMPN_COPY ((dst)+(start), (src)+(start), (size)-(start)); \ - } while (0) -#endif - -/* Copy {src,size} to {dst,size}, starting at "start". This is designed to - keep the indexing dst[j] and src[j] nice and simple for __GMPN_ADD_1, - __GMPN_ADD, etc. */ -#if ! defined (__GMPN_COPY_REST) -#define __GMPN_COPY_REST(dst, src, size, start) \ - do { \ - mp_size_t __gmp_j; \ - /* ASSERT ((size) >= 0); */ \ - /* ASSERT ((start) >= 0); */ \ - /* ASSERT ((start) <= (size)); */ \ - /* ASSERT (MPN_SAME_OR_SEPARATE_P (dst, src, size)); */ \ - for (__gmp_j = (start); __gmp_j < (size); __gmp_j++) \ - (dst)[__gmp_j] = (src)[__gmp_j]; \ - } while (0) -#endif - -/* Enhancement: Use some of the smarter code from gmp-impl.h. Maybe use - mpn_copyi if there's a native version, and if we don't mind demanding - binary compatibility for it (on targets which use it). */ - -#if ! defined (__GMPN_COPY) -#define __GMPN_COPY(dst, src, size) __GMPN_COPY_REST (dst, src, size, 0) -#endif - - -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpn_add) -#if ! defined (__GMP_FORCE_mpn_add) -__GMP_EXTERN_INLINE -#endif -mp_limb_t -mpn_add (mp_ptr __gmp_wp, mp_srcptr __gmp_xp, mp_size_t __gmp_xsize, mp_srcptr __gmp_yp, mp_size_t __gmp_ysize) -{ - mp_limb_t __gmp_c; - __GMPN_ADD (__gmp_c, __gmp_wp, __gmp_xp, __gmp_xsize, __gmp_yp, __gmp_ysize); - return __gmp_c; -} -#endif - -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpn_add_1) -#if ! defined (__GMP_FORCE_mpn_add_1) -__GMP_EXTERN_INLINE -#endif -mp_limb_t -mpn_add_1 (mp_ptr __gmp_dst, mp_srcptr __gmp_src, mp_size_t __gmp_size, mp_limb_t __gmp_n) __GMP_NOTHROW -{ - mp_limb_t __gmp_c; - __GMPN_ADD_1 (__gmp_c, __gmp_dst, __gmp_src, __gmp_size, __gmp_n); - return __gmp_c; -} -#endif - -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpn_cmp) -#if ! defined (__GMP_FORCE_mpn_cmp) -__GMP_EXTERN_INLINE -#endif -int -mpn_cmp (mp_srcptr __gmp_xp, mp_srcptr __gmp_yp, mp_size_t __gmp_size) __GMP_NOTHROW -{ - int __gmp_result; - __GMPN_CMP (__gmp_result, __gmp_xp, __gmp_yp, __gmp_size); - return __gmp_result; -} -#endif - -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpn_sub) -#if ! defined (__GMP_FORCE_mpn_sub) -__GMP_EXTERN_INLINE -#endif -mp_limb_t -mpn_sub (mp_ptr __gmp_wp, mp_srcptr __gmp_xp, mp_size_t __gmp_xsize, mp_srcptr __gmp_yp, mp_size_t __gmp_ysize) -{ - mp_limb_t __gmp_c; - __GMPN_SUB (__gmp_c, __gmp_wp, __gmp_xp, __gmp_xsize, __gmp_yp, __gmp_ysize); - return __gmp_c; -} -#endif - -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpn_sub_1) -#if ! defined (__GMP_FORCE_mpn_sub_1) -__GMP_EXTERN_INLINE -#endif -mp_limb_t -mpn_sub_1 (mp_ptr __gmp_dst, mp_srcptr __gmp_src, mp_size_t __gmp_size, mp_limb_t __gmp_n) __GMP_NOTHROW -{ - mp_limb_t __gmp_c; - __GMPN_SUB_1 (__gmp_c, __gmp_dst, __gmp_src, __gmp_size, __gmp_n); - return __gmp_c; -} -#endif - -#if defined (__cplusplus) -} -#endif - - -/* Allow faster testing for negative, zero, and positive. */ -#define mpz_sgn(Z) ((Z)->_mp_size < 0 ? -1 : (Z)->_mp_size > 0) -#define mpf_sgn(F) ((F)->_mp_size < 0 ? -1 : (F)->_mp_size > 0) -#define mpq_sgn(Q) ((Q)->_mp_num._mp_size < 0 ? -1 : (Q)->_mp_num._mp_size > 0) - -/* When using GCC, optimize certain common comparisons. */ -#if defined (__GNUC__) -#define mpz_cmp_ui(Z,UI) \ - (__builtin_constant_p (UI) && (UI) == 0 \ - ? mpz_sgn (Z) : _mpz_cmp_ui (Z,UI)) -#define mpz_cmp_si(Z,SI) \ - (__builtin_constant_p (SI) && (SI) == 0 ? mpz_sgn (Z) \ - : __builtin_constant_p (SI) && (SI) > 0 \ - ? _mpz_cmp_ui (Z, __GMP_CAST (unsigned long int, SI)) \ - : _mpz_cmp_si (Z,SI)) -#define mpq_cmp_ui(Q,NUI,DUI) \ - (__builtin_constant_p (NUI) && (NUI) == 0 \ - ? mpq_sgn (Q) : _mpq_cmp_ui (Q,NUI,DUI)) -#define mpq_cmp_si(q,n,d) \ - (__builtin_constant_p ((n) >= 0) && (n) >= 0 \ - ? mpq_cmp_ui (q, __GMP_CAST (unsigned long, n), d) \ - : _mpq_cmp_si (q, n, d)) -#else -#define mpz_cmp_ui(Z,UI) _mpz_cmp_ui (Z,UI) -#define mpz_cmp_si(Z,UI) _mpz_cmp_si (Z,UI) -#define mpq_cmp_ui(Q,NUI,DUI) _mpq_cmp_ui (Q,NUI,DUI) -#define mpq_cmp_si(q,n,d) _mpq_cmp_si(q,n,d) -#endif - - -/* Using "&" rather than "&&" means these can come out branch-free. Every - mpz_t has at least one limb allocated, so fetching the low limb is always - allowed. */ -#define mpz_odd_p(z) (((z)->_mp_size != 0) & __GMP_CAST (int, (z)->_mp_d[0])) -#define mpz_even_p(z) (! mpz_odd_p (z)) - - -/**************** C++ routines ****************/ - -#ifdef __cplusplus -__GMP_DECLSPEC_XX std::ostream& operator<< (std::ostream &, mpz_srcptr); -__GMP_DECLSPEC_XX std::ostream& operator<< (std::ostream &, mpq_srcptr); -__GMP_DECLSPEC_XX std::ostream& operator<< (std::ostream &, mpf_srcptr); -__GMP_DECLSPEC_XX std::istream& operator>> (std::istream &, mpz_ptr); -__GMP_DECLSPEC_XX std::istream& operator>> (std::istream &, mpq_ptr); -__GMP_DECLSPEC_XX std::istream& operator>> (std::istream &, mpf_ptr); -#endif - -/* Source-level compatibility with GMP 1. */ -#define mpz_mdiv mpz_fdiv_q -#define mpz_mdivmod mpz_fdiv_qr -#define mpz_mmod mpz_fdiv_r -#define mpz_mdiv_ui mpz_fdiv_q_ui -#define mpz_mdivmod_ui(q,r,n,d) \ - (((r) == 0) ? mpz_fdiv_q_ui (q,n,d) : mpz_fdiv_qr_ui (q,r,n,d)) -#define mpz_mmod_ui(r,n,d) \ - (((r) == 0) ? mpz_fdiv_ui (n,d) : mpz_fdiv_r_ui (r,n,d)) - -#define gmp_randinit(x,y,z) gmp_randinit_lc_2exp_size(x,z) - -typedef __mpz_struct MP_INT; /* gmp 1 source compatibility */ -typedef __mpq_struct MP_RAT; /* gmp 1 source compatibility */ - -#define mpz_div mpz_fdiv_q -#define mpz_divmod mpz_fdiv_qr -#define mpz_div_ui mpz_fdiv_q_ui -#define mpz_divmod_ui mpz_fdiv_qr_ui -#define mpz_div_2exp mpz_fdiv_q_2exp -#define mpz_mod_2exp mpz_fdiv_r_2exp - -enum -{ - GMP_ERROR_NONE = 0, - GMP_ERROR_UNSUPPORTED_ARGUMENT = 1, - GMP_ERROR_DIVISION_BY_ZERO = 2, - GMP_ERROR_SQRT_OF_NEGATIVE = 4, - GMP_ERROR_INVALID_ARGUMENT = 8 -}; - -/* Major version number is the value of __GNU_MP__ too, above and in mp.h. */ -#define __GNU_MP_VERSION 5 -#define __GNU_MP_VERSION_MINOR 0 -#define __GNU_MP_VERSION_PATCHLEVEL 2 -#define GMP_VERSION "5.0.2" - -#define __MPIR_VERSION 2 -#define __MPIR_VERSION_MINOR 4 -#define __MPIR_VERSION_PATCHLEVEL 0 -#if defined( _MSC_VER ) -#define _MSC_MPIR_VERSION "2.4.0" -#endif - -/* These are for programs like MPFR to use the same CC and CFLAGS as MPIR */ - -#if ! defined (__GMP_WITHIN_CONFIGURE) -/* No __GMP_CC here as --enable-gmpcompat option not selected */ - -#define __MPIR_CC "gcc -std=gnu99" -#define __MPIR_CFLAGS "-mmacosx-version-min=10.5" -#endif - -#define __GMP_H__ -#endif /* __GMP_H__ */ diff --git a/src/external/inc/macx64/mpir-2.4.0/mpirxx.h b/src/external/inc/macx64/mpir-2.4.0/mpirxx.h deleted file mode 100644 index 3ad1dcf6f..000000000 --- a/src/external/inc/macx64/mpir-2.4.0/mpirxx.h +++ /dev/null @@ -1,3403 +0,0 @@ -/* mpirxx.h -- C++ class wrapper for GMP types. -*- C++ -*- - -Copyright 2001, 2002, 2003, 2006, 2008 Free Software Foundation, Inc. - -Copyright 2009 William Hart - -This file is part of the GNU MP Library. - -The GNU MP Library is free software; you can redistribute it and/or modify -it under the terms of the GNU Lesser General Public License as published by -the Free Software Foundation; either version 3 of the License, or (at your -option) any later version. - -The GNU MP Library is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public -License for more details. - -You should have received a copy of the GNU Lesser General Public License -along with the GNU MP Library. If not, see http://www.gnu.org/licenses/. */ - -/* the C++ compiler must implement the following features: - - member templates - - partial specialization of templates - - namespace support - for g++, this means version 2.91 or higher - for other compilers, I don't know */ -#ifdef __GNUC__ -#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 91) -#error mpirxx.h requires g++ version 2.91 (egcs 1.1.2) or higher -#endif -#endif - -#ifndef __GMP_PLUSPLUS__ -#define __GMP_PLUSPLUS__ - -#include - -#include /* for strlen */ -#include -#include -#include -#include - - -/**************** Function objects ****************/ -/* Any evaluation of a __gmp_expr ends up calling one of these functions - all intermediate functions being inline, the evaluation should optimize - to a direct call to the relevant function, thus yielding no overhead - over the C interface. */ - -struct __gmp_unary_plus -{ - static void eval(mpz_ptr z, mpz_srcptr w) { mpz_set(z, w); } - static void eval(mpq_ptr q, mpq_srcptr r) { mpq_set(q, r); } - static void eval(mpf_ptr f, mpf_srcptr g) { mpf_set(f, g); } -}; - -struct __gmp_unary_minus -{ - static void eval(mpz_ptr z, mpz_srcptr w) { mpz_neg(z, w); } - static void eval(mpq_ptr q, mpq_srcptr r) { mpq_neg(q, r); } - static void eval(mpf_ptr f, mpf_srcptr g) { mpf_neg(f, g); } -}; - -struct __gmp_unary_com -{ - static void eval(mpz_ptr z, mpz_srcptr w) { mpz_com(z, w); } -}; - -struct __gmp_binary_plus -{ - static void eval(mpz_ptr z, mpz_srcptr w, mpz_srcptr v) - { mpz_add(z, w, v); } - - static void eval(mpz_ptr z, mpz_srcptr w, unsigned long int l) - { mpz_add_ui(z, w, l); } - static void eval(mpz_ptr z, unsigned long int l, mpz_srcptr w) - { mpz_add_ui(z, w, l); } - static void eval(mpz_ptr z, mpz_srcptr w, signed long int l) - { - if (l >= 0) - mpz_add_ui(z, w, l); - else - mpz_sub_ui(z, w, -l); - } - static void eval(mpz_ptr z, signed long int l, mpz_srcptr w) - { - if (l >= 0) - mpz_add_ui(z, w, l); - else - mpz_sub_ui(z, w, -l); - } - static void eval(mpz_ptr z, mpz_srcptr w, double d) - { - mpz_t temp; - mpz_init_set_d(temp, d); - mpz_add(z, w, temp); - mpz_clear(temp); - } - static void eval(mpz_ptr z, double d, mpz_srcptr w) - { - mpz_t temp; - mpz_init_set_d(temp, d); - mpz_add(z, temp, w); - mpz_clear(temp); - } - - static void eval(mpq_ptr q, mpq_srcptr r, mpq_srcptr s) - { mpq_add(q, r, s); } - - static void eval(mpq_ptr q, mpq_srcptr r, unsigned long int l) - { mpq_set(q, r); mpz_addmul_ui(mpq_numref(q), mpq_denref(q), l); } - static void eval(mpq_ptr q, unsigned long int l, mpq_srcptr r) - { mpq_set(q, r); mpz_addmul_ui(mpq_numref(q), mpq_denref(q), l); } - static void eval(mpq_ptr q, mpq_srcptr r, signed long int l) - { - mpq_set(q, r); - if (l >= 0) - mpz_addmul_ui(mpq_numref(q), mpq_denref(q), l); - else - mpz_submul_ui(mpq_numref(q), mpq_denref(q), -l); - } - static void eval(mpq_ptr q, signed long int l, mpq_srcptr r) - { - mpq_set(q, r); - if (l >= 0) - mpz_addmul_ui(mpq_numref(q), mpq_denref(q), l); - else - mpz_submul_ui(mpq_numref(q), mpq_denref(q), -l); - } - static void eval(mpq_ptr q, mpq_srcptr r, double d) - { - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - mpq_add(q, r, temp); - mpq_clear(temp); - } - static void eval(mpq_ptr q, double d, mpq_srcptr r) - { - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - mpq_add(q, temp, r); - mpq_clear(temp); - } - - static void eval(mpq_ptr q, mpq_srcptr r, mpz_srcptr z) - { mpq_set(q, r); mpz_addmul(mpq_numref(q), mpq_denref(q), z); } - static void eval(mpq_ptr q, mpz_srcptr z, mpq_srcptr r) - { mpq_set(q, r); mpz_addmul(mpq_numref(q), mpq_denref(q), z); } - - static void eval(mpf_ptr f, mpf_srcptr g, mpf_srcptr h) - { mpf_add(f, g, h); } - - static void eval(mpf_ptr f, mpf_srcptr g, unsigned long int l) - { mpf_add_ui(f, g, l); } - static void eval(mpf_ptr f, unsigned long int l, mpf_srcptr g) - { mpf_add_ui(f, g, l); } - static void eval(mpf_ptr f, mpf_srcptr g, signed long int l) - { - if (l >= 0) - mpf_add_ui(f, g, l); - else - mpf_sub_ui(f, g, -l); - } - static void eval(mpf_ptr f, signed long int l, mpf_srcptr g) - { - if (l >= 0) - mpf_add_ui(f, g, l); - else - mpf_sub_ui(f, g, -l); - } - static void eval(mpf_ptr f, mpf_srcptr g, double d) - { - mpf_t temp; - mpf_init2(temp, 8*sizeof(double)); - mpf_set_d(temp, d); - mpf_add(f, g, temp); - mpf_clear(temp); - } - static void eval(mpf_ptr f, double d, mpf_srcptr g) - { - mpf_t temp; - mpf_init2(temp, 8*sizeof(double)); - mpf_set_d(temp, d); - mpf_add(f, temp, g); - mpf_clear(temp); - } -}; - -struct __gmp_binary_minus -{ - static void eval(mpz_ptr z, mpz_srcptr w, mpz_srcptr v) - { mpz_sub(z, w, v); } - - static void eval(mpz_ptr z, mpz_srcptr w, unsigned long int l) - { mpz_sub_ui(z, w, l); } - static void eval(mpz_ptr z, unsigned long int l, mpz_srcptr w) - { mpz_ui_sub(z, l, w); } - static void eval(mpz_ptr z, mpz_srcptr w, signed long int l) - { - if (l >= 0) - mpz_sub_ui(z, w, l); - else - mpz_add_ui(z, w, -l); - } - static void eval(mpz_ptr z, signed long int l, mpz_srcptr w) - { - if (l >= 0) - mpz_ui_sub(z, l, w); - else - { - mpz_add_ui(z, w, -l); - mpz_neg(z, z); - } - } - static void eval(mpz_ptr z, mpz_srcptr w, double d) - { - mpz_t temp; - mpz_init_set_d(temp, d); - mpz_sub(z, w, temp); - mpz_clear(temp); - } - static void eval(mpz_ptr z, double d, mpz_srcptr w) - { - mpz_t temp; - mpz_init_set_d(temp, d); - mpz_sub(z, temp, w); - mpz_clear(temp); - } - - static void eval(mpq_ptr q, mpq_srcptr r, mpq_srcptr s) - { mpq_sub(q, r, s); } - - static void eval(mpq_ptr q, mpq_srcptr r, unsigned long int l) - { mpq_set(q, r); mpz_submul_ui(mpq_numref(q), mpq_denref(q), l); } - static void eval(mpq_ptr q, unsigned long int l, mpq_srcptr r) - { mpq_neg(q, r); mpz_addmul_ui(mpq_numref(q), mpq_denref(q), l); } - static void eval(mpq_ptr q, mpq_srcptr r, signed long int l) - { - mpq_set(q, r); - if (l >= 0) - mpz_submul_ui(mpq_numref(q), mpq_denref(q), l); - else - mpz_addmul_ui(mpq_numref(q), mpq_denref(q), -l); - } - static void eval(mpq_ptr q, signed long int l, mpq_srcptr r) - { - mpq_neg(q, r); - if (l >= 0) - mpz_addmul_ui(mpq_numref(q), mpq_denref(q), l); - else - mpz_submul_ui(mpq_numref(q), mpq_denref(q), -l); - } - static void eval(mpq_ptr q, mpq_srcptr r, double d) - { - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - mpq_sub(q, r, temp); - mpq_clear(temp); - } - static void eval(mpq_ptr q, double d, mpq_srcptr r) - { - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - mpq_sub(q, temp, r); - mpq_clear(temp); - } - - static void eval(mpq_ptr q, mpq_srcptr r, mpz_srcptr z) - { mpq_set(q, r); mpz_submul(mpq_numref(q), mpq_denref(q), z); } - static void eval(mpq_ptr q, mpz_srcptr z, mpq_srcptr r) - { mpq_neg(q, r); mpz_addmul(mpq_numref(q), mpq_denref(q), z); } - - static void eval(mpf_ptr f, mpf_srcptr g, mpf_srcptr h) - { mpf_sub(f, g, h); } - - static void eval(mpf_ptr f, mpf_srcptr g, unsigned long int l) - { mpf_sub_ui(f, g, l); } - static void eval(mpf_ptr f, unsigned long int l, mpf_srcptr g) - { mpf_ui_sub(f, l, g); } - static void eval(mpf_ptr f, mpf_srcptr g, signed long int l) - { - if (l >= 0) - mpf_sub_ui(f, g, l); - else - mpf_add_ui(f, g, -l); - } - static void eval(mpf_ptr f, signed long int l, mpf_srcptr g) - { - if (l >= 0) - mpf_sub_ui(f, g, l); - else - mpf_add_ui(f, g, -l); - mpf_neg(f, f); - } - static void eval(mpf_ptr f, mpf_srcptr g, double d) - { - mpf_t temp; - mpf_init2(temp, 8*sizeof(double)); - mpf_set_d(temp, d); - mpf_sub(f, g, temp); - mpf_clear(temp); - } - static void eval(mpf_ptr f, double d, mpf_srcptr g) - { - mpf_t temp; - mpf_init2(temp, 8*sizeof(double)); - mpf_set_d(temp, d); - mpf_sub(f, temp, g); - mpf_clear(temp); - } -}; - -struct __gmp_binary_multiplies -{ - static void eval(mpz_ptr z, mpz_srcptr w, mpz_srcptr v) - { mpz_mul(z, w, v); } - - static void eval(mpz_ptr z, mpz_srcptr w, unsigned long int l) - { mpz_mul_ui(z, w, l); } - static void eval(mpz_ptr z, unsigned long int l, mpz_srcptr w) - { mpz_mul_ui(z, w, l); } - static void eval(mpz_ptr z, mpz_srcptr w, signed long int l) - { mpz_mul_si (z, w, l); } - static void eval(mpz_ptr z, signed long int l, mpz_srcptr w) - { mpz_mul_si (z, w, l); } - static void eval(mpz_ptr z, mpz_srcptr w, double d) - { - mpz_t temp; - mpz_init_set_d(temp, d); - mpz_mul(z, w, temp); - mpz_clear(temp); - } - static void eval(mpz_ptr z, double d, mpz_srcptr w) - { - mpz_t temp; - mpz_init_set_d(temp, d); - mpz_mul(z, temp, w); - mpz_clear(temp); - } - - static void eval(mpq_ptr q, mpq_srcptr r, mpq_srcptr s) - { mpq_mul(q, r, s); } - - static void eval(mpq_ptr q, mpq_srcptr r, unsigned long int l) - { - mpq_t temp; - mpq_init(temp); - mpq_set_ui(temp, l, 1); - mpq_mul(q, r, temp); - mpq_clear(temp); - } - static void eval(mpq_ptr q, unsigned long int l, mpq_srcptr r) - { - mpq_t temp; - mpq_init(temp); - mpq_set_ui(temp, l, 1); - mpq_mul(q, temp, r); - mpq_clear(temp); - } - static void eval(mpq_ptr q, mpq_srcptr r, signed long int l) - { - mpq_t temp; - mpq_init(temp); - mpq_set_si(temp, l, 1); - mpq_mul(q, r, temp); - mpq_clear(temp); - } - static void eval(mpq_ptr q, signed long int l, mpq_srcptr r) - { - mpq_t temp; - mpq_init(temp); - mpq_set_si(temp, l, 1); - mpq_mul(q, temp, r); - mpq_clear(temp); - } - static void eval(mpq_ptr q, mpq_srcptr r, double d) - { - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - mpq_mul(q, r, temp); - mpq_clear(temp); - } - static void eval(mpq_ptr q, double d, mpq_srcptr r) - { - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - mpq_mul(q, temp, r); - mpq_clear(temp); - } - - static void eval(mpf_ptr f, mpf_srcptr g, mpf_srcptr h) - { mpf_mul(f, g, h); } - - static void eval(mpf_ptr f, mpf_srcptr g, unsigned long int l) - { mpf_mul_ui(f, g, l); } - static void eval(mpf_ptr f, unsigned long int l, mpf_srcptr g) - { mpf_mul_ui(f, g, l); } - static void eval(mpf_ptr f, mpf_srcptr g, signed long int l) - { - if (l >= 0) - mpf_mul_ui(f, g, l); - else - { - mpf_mul_ui(f, g, -l); - mpf_neg(f, f); - } - } - static void eval(mpf_ptr f, signed long int l, mpf_srcptr g) - { - if (l >= 0) - mpf_mul_ui(f, g, l); - else - { - mpf_mul_ui(f, g, -l); - mpf_neg(f, f); - } - } - static void eval(mpf_ptr f, mpf_srcptr g, double d) - { - mpf_t temp; - mpf_init2(temp, 8*sizeof(double)); - mpf_set_d(temp, d); - mpf_mul(f, g, temp); - mpf_clear(temp); - } - static void eval(mpf_ptr f, double d, mpf_srcptr g) - { - mpf_t temp; - mpf_init2(temp, 8*sizeof(double)); - mpf_set_d(temp, d); - mpf_mul(f, temp, g); - mpf_clear(temp); - } -}; - -struct __gmp_binary_divides -{ - static void eval(mpz_ptr z, mpz_srcptr w, mpz_srcptr v) - { mpz_tdiv_q(z, w, v); } - - static void eval(mpz_ptr z, mpz_srcptr w, unsigned long int l) - { mpz_tdiv_q_ui(z, w, l); } - static void eval(mpz_ptr z, unsigned long int l, mpz_srcptr w) - { - if (mpz_sgn(w) >= 0) - { - if (mpz_fits_ulong_p(w)) - mpz_set_ui(z, l / mpz_get_ui(w)); - else - mpz_set_ui(z, 0); - } - else - { - mpz_neg(z, w); - if (mpz_fits_ulong_p(z)) - { - mpz_set_ui(z, l / mpz_get_ui(z)); - mpz_neg(z, z); - } - else - mpz_set_ui(z, 0); - } - } - static void eval(mpz_ptr z, mpz_srcptr w, signed long int l) - { - if (l >= 0) - mpz_tdiv_q_ui(z, w, l); - else - { - mpz_tdiv_q_ui(z, w, -l); - mpz_neg(z, z); - } - } - static void eval(mpz_ptr z, signed long int l, mpz_srcptr w) - { - if (mpz_fits_slong_p(w)) - mpz_set_si(z, l / mpz_get_si(w)); - else - { - /* if w is bigger than a long then the quotient must be zero, unless - l==LONG_MIN and w==-LONG_MIN in which case the quotient is -1 */ - mpz_set_si (z, (mpz_cmpabs_ui (w, (l >= 0 ? l : -l)) == 0 ? -1 : 0)); - } - } - static void eval(mpz_ptr z, mpz_srcptr w, double d) - { - mpz_t temp; - mpz_init_set_d(temp, d); - mpz_tdiv_q(z, w, temp); - mpz_clear(temp); - } - static void eval(mpz_ptr z, double d, mpz_srcptr w) - { - mpz_t temp; - mpz_init_set_d(temp, d); - mpz_tdiv_q(z, temp, w); - mpz_clear(temp); - } - - static void eval(mpq_ptr q, mpq_srcptr r, mpq_srcptr s) - { mpq_div(q, r, s); } - - static void eval(mpq_ptr q, mpq_srcptr r, unsigned long int l) - { - mpq_t temp; - mpq_init(temp); - mpq_set_ui(temp, l, 1); - mpq_div(q, r, temp); - mpq_clear(temp); - } - static void eval(mpq_ptr q, unsigned long int l, mpq_srcptr r) - { - mpq_t temp; - mpq_init(temp); - mpq_set_ui(temp, l, 1); - mpq_div(q, temp, r); - mpq_clear(temp); - } - static void eval(mpq_ptr q, mpq_srcptr r, signed long int l) - { - mpq_t temp; - mpq_init(temp); - mpq_set_si(temp, l, 1); - mpq_div(q, r, temp); - mpq_clear(temp); - } - static void eval(mpq_ptr q, signed long int l, mpq_srcptr r) - { - mpq_t temp; - mpq_init(temp); - mpq_set_si(temp, l, 1); - mpq_div(q, temp, r); - mpq_clear(temp); - } - static void eval(mpq_ptr q, mpq_srcptr r, double d) - { - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - mpq_div(q, r, temp); - mpq_clear(temp); - } - static void eval(mpq_ptr q, double d, mpq_srcptr r) - { - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - mpq_div(q, temp, r); - mpq_clear(temp); - } - - static void eval(mpf_ptr f, mpf_srcptr g, mpf_srcptr h) - { mpf_div(f, g, h); } - - static void eval(mpf_ptr f, mpf_srcptr g, unsigned long int l) - { mpf_div_ui(f, g, l); } - static void eval(mpf_ptr f, unsigned long int l, mpf_srcptr g) - { mpf_ui_div(f, l, g); } - static void eval(mpf_ptr f, mpf_srcptr g, signed long int l) - { - if (l >= 0) - mpf_div_ui(f, g, l); - else - { - mpf_div_ui(f, g, -l); - mpf_neg(f, f); - } - } - static void eval(mpf_ptr f, signed long int l, mpf_srcptr g) - { - if (l >= 0) - mpf_ui_div(f, l, g); - else - { - mpf_ui_div(f, -l, g); - mpf_neg(f, f); - } - } - static void eval(mpf_ptr f, mpf_srcptr g, double d) - { - mpf_t temp; - mpf_init2(temp, 8*sizeof(double)); - mpf_set_d(temp, d); - mpf_div(f, g, temp); - mpf_clear(temp); - } - static void eval(mpf_ptr f, double d, mpf_srcptr g) - { - mpf_t temp; - mpf_init2(temp, 8*sizeof(double)); - mpf_set_d(temp, d); - mpf_div(f, temp, g); - mpf_clear(temp); - } -}; - -struct __gmp_binary_modulus -{ - static void eval(mpz_ptr z, mpz_srcptr w, mpz_srcptr v) - { mpz_tdiv_r(z, w, v); } - - static void eval(mpz_ptr z, mpz_srcptr w, unsigned long int l) - { mpz_tdiv_r_ui(z, w, l); } - static void eval(mpz_ptr z, unsigned long int l, mpz_srcptr w) - { - if (mpz_sgn(w) >= 0) - { - if (mpz_fits_ulong_p(w)) - mpz_set_ui(z, l % mpz_get_ui(w)); - else - mpz_set_ui(z, l); - } - else - { - mpz_neg(z, w); - if (mpz_fits_ulong_p(z)) - mpz_set_ui(z, l % mpz_get_ui(z)); - else - mpz_set_ui(z, l); - } - } - static void eval(mpz_ptr z, mpz_srcptr w, signed long int l) - { - mpz_tdiv_r_ui (z, w, (l >= 0 ? l : -l)); - } - static void eval(mpz_ptr z, signed long int l, mpz_srcptr w) - { - if (mpz_fits_slong_p(w)) - mpz_set_si(z, l % mpz_get_si(w)); - else - { - /* if w is bigger than a long then the remainder is l unchanged, - unless l==LONG_MIN and w==-LONG_MIN in which case it's 0 */ - mpz_set_si (z, mpz_cmpabs_ui (w, (l >= 0 ? l : -l)) == 0 ? 0 : l); - } - } - static void eval(mpz_ptr z, mpz_srcptr w, double d) - { - mpz_t temp; - mpz_init_set_d(temp, d); - mpz_tdiv_r(z, w, temp); - mpz_clear(temp); - } - static void eval(mpz_ptr z, double d, mpz_srcptr w) - { - mpz_t temp; - mpz_init_set_d(temp, d); - mpz_tdiv_r(z, temp, w); - mpz_clear(temp); - } -}; - -// Max allocations for plain types when converted to mpz_t -#define __GMP_DBL_LIMBS (2 + DBL_MAX_EXP / GMP_NUMB_BITS) -#define __GMP_ULI_LIMBS (1 + (8 * sizeof (long) - 1) / GMP_NUMB_BITS) - -#define __GMPXX_TMP_UI \ - mpz_t temp; \ - mp_limb_t limbs[__GMP_ULI_LIMBS]; \ - temp->_mp_d = limbs; \ - temp->_mp_alloc = __GMP_ULI_LIMBS; \ - mpz_set_ui (temp, l) -#define __GMPXX_TMP_SI \ - mpz_t temp; \ - mp_limb_t limbs[__GMP_ULI_LIMBS]; \ - temp->_mp_d = limbs; \ - temp->_mp_alloc = __GMP_ULI_LIMBS; \ - mpz_set_si (temp, l) -#define __GMPXX_TMP_D \ - mpz_t temp; \ - mp_limb_t limbs[__GMP_DBL_LIMBS]; \ - temp->_mp_d = limbs; \ - temp->_mp_alloc = __GMP_DBL_LIMBS; \ - mpz_set_d (temp, d) - -struct __gmp_binary_and -{ - static void eval(mpz_ptr z, mpz_srcptr w, mpz_srcptr v) - { mpz_and(z, w, v); } - - static void eval(mpz_ptr z, mpz_srcptr w, unsigned long int l) - { __GMPXX_TMP_UI; mpz_and (z, w, temp); } - static void eval(mpz_ptr z, unsigned long int l, mpz_srcptr w) - { __GMPXX_TMP_UI; mpz_and (z, w, temp); } - static void eval(mpz_ptr z, mpz_srcptr w, signed long int l) - { __GMPXX_TMP_SI; mpz_and (z, w, temp); } - static void eval(mpz_ptr z, signed long int l, mpz_srcptr w) - { __GMPXX_TMP_SI; mpz_and (z, w, temp); } - static void eval(mpz_ptr z, mpz_srcptr w, double d) - { __GMPXX_TMP_D; mpz_and (z, w, temp); } - static void eval(mpz_ptr z, double d, mpz_srcptr w) - { __GMPXX_TMP_D; mpz_and (z, w, temp); } -}; - -struct __gmp_binary_ior -{ - static void eval(mpz_ptr z, mpz_srcptr w, mpz_srcptr v) - { mpz_ior(z, w, v); } - static void eval(mpz_ptr z, mpz_srcptr w, unsigned long int l) - { __GMPXX_TMP_UI; mpz_ior (z, w, temp); } - static void eval(mpz_ptr z, unsigned long int l, mpz_srcptr w) - { __GMPXX_TMP_UI; mpz_ior (z, w, temp); } - static void eval(mpz_ptr z, mpz_srcptr w, signed long int l) - { __GMPXX_TMP_SI; mpz_ior (z, w, temp); } - static void eval(mpz_ptr z, signed long int l, mpz_srcptr w) - { __GMPXX_TMP_SI; mpz_ior (z, w, temp); } - static void eval(mpz_ptr z, mpz_srcptr w, double d) - { __GMPXX_TMP_D; mpz_ior (z, w, temp); } - static void eval(mpz_ptr z, double d, mpz_srcptr w) - { __GMPXX_TMP_D; mpz_ior (z, w, temp); } -}; - -struct __gmp_binary_xor -{ - static void eval(mpz_ptr z, mpz_srcptr w, mpz_srcptr v) - { mpz_xor(z, w, v); } - static void eval(mpz_ptr z, mpz_srcptr w, unsigned long int l) - { __GMPXX_TMP_UI; mpz_xor (z, w, temp); } - static void eval(mpz_ptr z, unsigned long int l, mpz_srcptr w) - { __GMPXX_TMP_UI; mpz_xor (z, w, temp); } - static void eval(mpz_ptr z, mpz_srcptr w, signed long int l) - { __GMPXX_TMP_SI; mpz_xor (z, w, temp); } - static void eval(mpz_ptr z, signed long int l, mpz_srcptr w) - { __GMPXX_TMP_SI; mpz_xor (z, w, temp); } - static void eval(mpz_ptr z, mpz_srcptr w, double d) - { __GMPXX_TMP_D; mpz_xor (z, w, temp); } - static void eval(mpz_ptr z, double d, mpz_srcptr w) - { __GMPXX_TMP_D; mpz_xor (z, w, temp); } -}; - -struct __gmp_binary_lshift -{ - static void eval(mpz_ptr z, mpz_srcptr w, unsigned long int l) - { mpz_mul_2exp(z, w, l); } - static void eval(mpq_ptr q, mpq_srcptr r, unsigned long int l) - { mpq_mul_2exp(q, r, l); } - static void eval(mpf_ptr f, mpf_srcptr g, unsigned long int l) - { mpf_mul_2exp(f, g, l); } -}; - -struct __gmp_binary_rshift -{ - static void eval(mpz_ptr z, mpz_srcptr w, unsigned long int l) - { mpz_fdiv_q_2exp(z, w, l); } - static void eval(mpq_ptr q, mpq_srcptr r, unsigned long int l) - { mpq_div_2exp(q, r, l); } - static void eval(mpf_ptr f, mpf_srcptr g, unsigned long int l) - { mpf_div_2exp(f, g, l); } -}; - -struct __gmp_binary_equal -{ - static bool eval(mpz_srcptr z, mpz_srcptr w) { return mpz_cmp(z, w) == 0; } - - static bool eval(mpz_srcptr z, unsigned long int l) - { return mpz_cmp_ui(z, l) == 0; } - static bool eval(unsigned long int l, mpz_srcptr z) - { return mpz_cmp_ui(z, l) == 0; } - static bool eval(mpz_srcptr z, signed long int l) - { return mpz_cmp_si(z, l) == 0; } - static bool eval(signed long int l, mpz_srcptr z) - { return mpz_cmp_si(z, l) == 0; } - static bool eval(mpz_srcptr z, double d) - { return mpz_cmp_d(z, d) == 0; } - static bool eval(double d, mpz_srcptr z) - { return mpz_cmp_d(z, d) == 0; } - - static bool eval(mpq_srcptr q, mpq_srcptr r) - { return mpq_equal(q, r) != 0; } - - static bool eval(mpq_srcptr q, unsigned long int l) - { return mpq_cmp_ui(q, l, 1) == 0; } - static bool eval(unsigned long int l, mpq_srcptr q) - { return mpq_cmp_ui(q, l, 1) == 0; } - static bool eval(mpq_srcptr q, signed long int l) - { return mpq_cmp_si(q, l, 1) == 0; } - static bool eval(signed long int l, mpq_srcptr q) - { return mpq_cmp_si(q, l, 1) == 0; } - static bool eval(mpq_srcptr q, double d) - { - bool b; - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - b = (mpq_equal(q, temp) != 0); - mpq_clear(temp); - return b; - } - static bool eval(double d, mpq_srcptr q) - { - bool b; - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - b = (mpq_equal(temp, q) != 0); - mpq_clear(temp); - return b; - } - - static bool eval(mpf_srcptr f, mpf_srcptr g) { return mpf_cmp(f, g) == 0; } - - static bool eval(mpf_srcptr f, unsigned long int l) - { return mpf_cmp_ui(f, l) == 0; } - static bool eval(unsigned long int l, mpf_srcptr f) - { return mpf_cmp_ui(f, l) == 0; } - static bool eval(mpf_srcptr f, signed long int l) - { return mpf_cmp_si(f, l) == 0; } - static bool eval(signed long int l, mpf_srcptr f) - { return mpf_cmp_si(f, l) == 0; } - static bool eval(mpf_srcptr f, double d) - { return mpf_cmp_d(f, d) == 0; } - static bool eval(double d, mpf_srcptr f) - { return mpf_cmp_d(f, d) == 0; } -}; - -struct __gmp_binary_not_equal -{ - static bool eval(mpz_srcptr z, mpz_srcptr w) { return mpz_cmp(z, w) != 0; } - - static bool eval(mpz_srcptr z, unsigned long int l) - { return mpz_cmp_ui(z, l) != 0; } - static bool eval(unsigned long int l, mpz_srcptr z) - { return mpz_cmp_ui(z, l) != 0; } - static bool eval(mpz_srcptr z, signed long int l) - { return mpz_cmp_si(z, l) != 0; } - static bool eval(signed long int l, mpz_srcptr z) - { return mpz_cmp_si(z, l) != 0; } - static bool eval(mpz_srcptr z, double d) - { return mpz_cmp_d(z, d) != 0; } - static bool eval(double d, mpz_srcptr z) - { return mpz_cmp_d(z, d) != 0; } - - static bool eval(mpq_srcptr q, mpq_srcptr r) - { return mpq_equal(q, r) == 0; } - - static bool eval(mpq_srcptr q, unsigned long int l) - { return mpq_cmp_ui(q, l, 1) != 0; } - static bool eval(unsigned long int l, mpq_srcptr q) - { return mpq_cmp_ui(q, l, 1) != 0; } - static bool eval(mpq_srcptr q, signed long int l) - { return mpq_cmp_si(q, l, 1) != 0; } - static bool eval(signed long int l, mpq_srcptr q) - { return mpq_cmp_si(q, l, 1) != 0; } - static bool eval(mpq_srcptr q, double d) - { - bool b; - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - b = (mpq_equal(q, temp) == 0); - mpq_clear(temp); - return b; - } - static bool eval(double d, mpq_srcptr q) - { - bool b; - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - b = (mpq_equal(temp, q) == 0); - mpq_clear(temp); - return b; - } - - static bool eval(mpf_srcptr f, mpf_srcptr g) { return mpf_cmp(f, g) != 0; } - - static bool eval(mpf_srcptr f, unsigned long int l) - { return mpf_cmp_ui(f, l) != 0; } - static bool eval(unsigned long int l, mpf_srcptr f) - { return mpf_cmp_ui(f, l) != 0; } - static bool eval(mpf_srcptr f, signed long int l) - { return mpf_cmp_si(f, l) != 0; } - static bool eval(signed long int l, mpf_srcptr f) - { return mpf_cmp_si(f, l) != 0; } - static bool eval(mpf_srcptr f, double d) - { return mpf_cmp_d(f, d) != 0; } - static bool eval(double d, mpf_srcptr f) - { return mpf_cmp_d(f, d) != 0; } -}; - -struct __gmp_binary_less -{ - static bool eval(mpz_srcptr z, mpz_srcptr w) { return mpz_cmp(z, w) < 0; } - - static bool eval(mpz_srcptr z, unsigned long int l) - { return mpz_cmp_ui(z, l) < 0; } - static bool eval(unsigned long int l, mpz_srcptr z) - { return mpz_cmp_ui(z, l) > 0; } - static bool eval(mpz_srcptr z, signed long int l) - { return mpz_cmp_si(z, l) < 0; } - static bool eval(signed long int l, mpz_srcptr z) - { return mpz_cmp_si(z, l) > 0; } - static bool eval(mpz_srcptr z, double d) - { return mpz_cmp_d(z, d) < 0; } - static bool eval(double d, mpz_srcptr z) - { return mpz_cmp_d(z, d) > 0; } - - static bool eval(mpq_srcptr q, mpq_srcptr r) { return mpq_cmp(q, r) < 0; } - - static bool eval(mpq_srcptr q, unsigned long int l) - { return mpq_cmp_ui(q, l, 1) < 0; } - static bool eval(unsigned long int l, mpq_srcptr q) - { return mpq_cmp_ui(q, l, 1) > 0; } - static bool eval(mpq_srcptr q, signed long int l) - { return mpq_cmp_si(q, l, 1) < 0; } - static bool eval(signed long int l, mpq_srcptr q) - { return mpq_cmp_si(q, l, 1) > 0; } - static bool eval(mpq_srcptr q, double d) - { - bool b; - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - b = (mpq_cmp(q, temp) < 0); - mpq_clear(temp); - return b; - } - static bool eval(double d, mpq_srcptr q) - { - bool b; - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - b = (mpq_cmp(temp, q) < 0); - mpq_clear(temp); - return b; - } - - static bool eval(mpf_srcptr f, mpf_srcptr g) { return mpf_cmp(f, g) < 0; } - - static bool eval(mpf_srcptr f, unsigned long int l) - { return mpf_cmp_ui(f, l) < 0; } - static bool eval(unsigned long int l, mpf_srcptr f) - { return mpf_cmp_ui(f, l) > 0; } - static bool eval(mpf_srcptr f, signed long int l) - { return mpf_cmp_si(f, l) < 0; } - static bool eval(signed long int l, mpf_srcptr f) - { return mpf_cmp_si(f, l) > 0; } - static bool eval(mpf_srcptr f, double d) - { return mpf_cmp_d(f, d) < 0; } - static bool eval(double d, mpf_srcptr f) - { return mpf_cmp_d(f, d) > 0; } -}; - -struct __gmp_binary_less_equal -{ - static bool eval(mpz_srcptr z, mpz_srcptr w) { return mpz_cmp(z, w) <= 0; } - - static bool eval(mpz_srcptr z, unsigned long int l) - { return mpz_cmp_ui(z, l) <= 0; } - static bool eval(unsigned long int l, mpz_srcptr z) - { return mpz_cmp_ui(z, l) >= 0; } - static bool eval(mpz_srcptr z, signed long int l) - { return mpz_cmp_si(z, l) <= 0; } - static bool eval(signed long int l, mpz_srcptr z) - { return mpz_cmp_si(z, l) >= 0; } - static bool eval(mpz_srcptr z, double d) - { return mpz_cmp_d(z, d) <= 0; } - static bool eval(double d, mpz_srcptr z) - { return mpz_cmp_d(z, d) >= 0; } - - static bool eval(mpq_srcptr q, mpq_srcptr r) { return mpq_cmp(q, r) <= 0; } - - static bool eval(mpq_srcptr q, unsigned long int l) - { return mpq_cmp_ui(q, l, 1) <= 0; } - static bool eval(unsigned long int l, mpq_srcptr q) - { return mpq_cmp_ui(q, l, 1) >= 0; } - static bool eval(mpq_srcptr q, signed long int l) - { return mpq_cmp_si(q, l, 1) <= 0; } - static bool eval(signed long int l, mpq_srcptr q) - { return mpq_cmp_si(q, l, 1) >= 0; } - static bool eval(mpq_srcptr q, double d) - { - bool b; - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - b = (mpq_cmp(q, temp) <= 0); - mpq_clear(temp); - return b; - } - static bool eval(double d, mpq_srcptr q) - { - bool b; - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - b = (mpq_cmp(temp, q) <= 0); - mpq_clear(temp); - return b; - } - - static bool eval(mpf_srcptr f, mpf_srcptr g) { return mpf_cmp(f, g) <= 0; } - - static bool eval(mpf_srcptr f, unsigned long int l) - { return mpf_cmp_ui(f, l) <= 0; } - static bool eval(unsigned long int l, mpf_srcptr f) - { return mpf_cmp_ui(f, l) >= 0; } - static bool eval(mpf_srcptr f, signed long int l) - { return mpf_cmp_si(f, l) <= 0; } - static bool eval(signed long int l, mpf_srcptr f) - { return mpf_cmp_si(f, l) >= 0; } - static bool eval(mpf_srcptr f, double d) - { return mpf_cmp_d(f, d) <= 0; } - static bool eval(double d, mpf_srcptr f) - { return mpf_cmp_d(f, d) >= 0; } -}; - -struct __gmp_binary_greater -{ - static bool eval(mpz_srcptr z, mpz_srcptr w) { return mpz_cmp(z, w) > 0; } - - static bool eval(mpz_srcptr z, unsigned long int l) - { return mpz_cmp_ui(z, l) > 0; } - static bool eval(unsigned long int l, mpz_srcptr z) - { return mpz_cmp_ui(z, l) < 0; } - static bool eval(mpz_srcptr z, signed long int l) - { return mpz_cmp_si(z, l) > 0; } - static bool eval(signed long int l, mpz_srcptr z) - { return mpz_cmp_si(z, l) < 0; } - static bool eval(mpz_srcptr z, double d) - { return mpz_cmp_d(z, d) > 0; } - static bool eval(double d, mpz_srcptr z) - { return mpz_cmp_d(z, d) < 0; } - - static bool eval(mpq_srcptr q, mpq_srcptr r) { return mpq_cmp(q, r) > 0; } - - static bool eval(mpq_srcptr q, unsigned long int l) - { return mpq_cmp_ui(q, l, 1) > 0; } - static bool eval(unsigned long int l, mpq_srcptr q) - { return mpq_cmp_ui(q, l, 1) < 0; } - static bool eval(mpq_srcptr q, signed long int l) - { return mpq_cmp_si(q, l, 1) > 0; } - static bool eval(signed long int l, mpq_srcptr q) - { return mpq_cmp_si(q, l, 1) < 0; } - static bool eval(mpq_srcptr q, double d) - { - bool b; - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - b = (mpq_cmp(q, temp) > 0); - mpq_clear(temp); - return b; - } - static bool eval(double d, mpq_srcptr q) - { - bool b; - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - b = (mpq_cmp(temp, q) > 0); - mpq_clear(temp); - return b; - } - - static bool eval(mpf_srcptr f, mpf_srcptr g) { return mpf_cmp(f, g) > 0; } - - static bool eval(mpf_srcptr f, unsigned long int l) - { return mpf_cmp_ui(f, l) > 0; } - static bool eval(unsigned long int l, mpf_srcptr f) - { return mpf_cmp_ui(f, l) < 0; } - static bool eval(mpf_srcptr f, signed long int l) - { return mpf_cmp_si(f, l) > 0; } - static bool eval(signed long int l, mpf_srcptr f) - { return mpf_cmp_si(f, l) < 0; } - static bool eval(mpf_srcptr f, double d) - { return mpf_cmp_d(f, d) > 0; } - static bool eval(double d, mpf_srcptr f) - { return mpf_cmp_d(f, d) < 0; } -}; - -struct __gmp_binary_greater_equal -{ - static bool eval(mpz_srcptr z, mpz_srcptr w) { return mpz_cmp(z, w) >= 0; } - - static bool eval(mpz_srcptr z, unsigned long int l) - { return mpz_cmp_ui(z, l) >= 0; } - static bool eval(unsigned long int l, mpz_srcptr z) - { return mpz_cmp_ui(z, l) <= 0; } - static bool eval(mpz_srcptr z, signed long int l) - { return mpz_cmp_si(z, l) >= 0; } - static bool eval(signed long int l, mpz_srcptr z) - { return mpz_cmp_si(z, l) <= 0; } - static bool eval(mpz_srcptr z, double d) - { return mpz_cmp_d(z, d) >= 0; } - static bool eval(double d, mpz_srcptr z) - { return mpz_cmp_d(z, d) <= 0; } - - static bool eval(mpq_srcptr q, mpq_srcptr r) { return mpq_cmp(q, r) >= 0; } - - static bool eval(mpq_srcptr q, unsigned long int l) - { return mpq_cmp_ui(q, l, 1) >= 0; } - static bool eval(unsigned long int l, mpq_srcptr q) - { return mpq_cmp_ui(q, l, 1) <= 0; } - static bool eval(mpq_srcptr q, signed long int l) - { return mpq_cmp_si(q, l, 1) >= 0; } - static bool eval(signed long int l, mpq_srcptr q) - { return mpq_cmp_si(q, l, 1) <= 0; } - static bool eval(mpq_srcptr q, double d) - { - bool b; - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - b = (mpq_cmp(q, temp) >= 0); - mpq_clear(temp); - return b; - } - static bool eval(double d, mpq_srcptr q) - { - bool b; - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - b = (mpq_cmp(temp, q) >= 0); - mpq_clear(temp); - return b; - } - - static bool eval(mpf_srcptr f, mpf_srcptr g) { return mpf_cmp(f, g) >= 0; } - - static bool eval(mpf_srcptr f, unsigned long int l) - { return mpf_cmp_ui(f, l) >= 0; } - static bool eval(unsigned long int l, mpf_srcptr f) - { return mpf_cmp_ui(f, l) <= 0; } - static bool eval(mpf_srcptr f, signed long int l) - { return mpf_cmp_si(f, l) >= 0; } - static bool eval(signed long int l, mpf_srcptr f) - { return mpf_cmp_si(f, l) <= 0; } - static bool eval(mpf_srcptr f, double d) - { return mpf_cmp_d(f, d) >= 0; } - static bool eval(double d, mpf_srcptr f) - { return mpf_cmp_d(f, d) <= 0; } -}; - -struct __gmp_unary_increment -{ - static void eval(mpz_ptr z) { mpz_add_ui(z, z, 1); } - static void eval(mpq_ptr q) - { mpz_add(mpq_numref(q), mpq_numref(q), mpq_denref(q)); } - static void eval(mpf_ptr f) { mpf_add_ui(f, f, 1); } -}; - -struct __gmp_unary_decrement -{ - static void eval(mpz_ptr z) { mpz_sub_ui(z, z, 1); } - static void eval(mpq_ptr q) - { mpz_sub(mpq_numref(q), mpq_numref(q), mpq_denref(q)); } - static void eval(mpf_ptr f) { mpf_sub_ui(f, f, 1); } -}; - -struct __gmp_abs_function -{ - static void eval(mpz_ptr z, mpz_srcptr w) { mpz_abs(z, w); } - static void eval(mpq_ptr q, mpq_srcptr r) { mpq_abs(q, r); } - static void eval(mpf_ptr f, mpf_srcptr g) { mpf_abs(f, g); } -}; - -struct __gmp_trunc_function -{ - static void eval(mpf_ptr f, mpf_srcptr g) { mpf_trunc(f, g); } -}; - -struct __gmp_floor_function -{ - static void eval(mpf_ptr f, mpf_srcptr g) { mpf_floor(f, g); } -}; - -struct __gmp_ceil_function -{ - static void eval(mpf_ptr f, mpf_srcptr g) { mpf_ceil(f, g); } -}; - -struct __gmp_sqrt_function -{ - static void eval(mpz_ptr z, mpz_srcptr w) { mpz_sqrt(z, w); } - static void eval(mpf_ptr f, mpf_srcptr g) { mpf_sqrt(f, g); } -}; - -struct __gmp_hypot_function -{ - static void eval(mpf_ptr f, mpf_srcptr g, mpf_srcptr h) - { - mpf_t temp; - mpf_init2(temp, mpf_get_prec(f)); - mpf_mul(temp, g, g); - mpf_mul(f, h, h); - mpf_add(f, f, temp); - mpf_sqrt(f, f); - mpf_clear(temp); - } - - static void eval(mpf_ptr f, mpf_srcptr g, unsigned long int l) - { - mpf_t temp; - mpf_init2(temp, mpf_get_prec(f)); - mpf_mul(temp, g, g); - mpf_set_ui(f, l); - mpf_mul(f, f, f); - mpf_add(f, f, temp); - mpf_sqrt(f, f); - mpf_clear(temp); - } - static void eval(mpf_ptr f, unsigned long int l, mpf_srcptr g) - { - mpf_t temp; - mpf_init2(temp, mpf_get_prec(f)); - mpf_mul(temp, g, g); - mpf_set_ui(f, l); - mpf_mul(f, f, f); - mpf_add(f, f, temp); - mpf_sqrt(f, f); - mpf_clear(temp); - } - static void eval(mpf_ptr f, mpf_srcptr g, signed long int l) - { - mpf_t temp; - mpf_init2(temp, mpf_get_prec(f)); - mpf_mul(temp, g, g); - mpf_set_si(f, l); - mpf_mul(f, f, f); - mpf_add(f, f, temp); - mpf_sqrt(f, f); - mpf_clear(temp); - } - static void eval(mpf_ptr f, signed long int l, mpf_srcptr g) - { - mpf_t temp; - mpf_init2(temp, mpf_get_prec(f)); - mpf_mul(temp, g, g); - mpf_set_si(f, l); - mpf_mul(f, f, f); - mpf_add(f, f, temp); - mpf_sqrt(f, f); - mpf_clear(temp); - } - static void eval(mpf_ptr f, mpf_srcptr g, double d) - { - mpf_t temp; - mpf_init2(temp, mpf_get_prec(f)); - mpf_mul(temp, g, g); - mpf_set_d(f, d); - mpf_mul(f, f, f); - mpf_add(f, f, temp); - mpf_sqrt(f, f); - mpf_clear(temp); - } - static void eval(mpf_ptr f, double d, mpf_srcptr g) - { - mpf_t temp; - mpf_init2(temp, mpf_get_prec(f)); - mpf_mul(temp, g, g); - mpf_set_d(f, d); - mpf_mul(f, f, f); - mpf_add(f, f, temp); - mpf_sqrt(f, f); - mpf_clear(temp); - } -}; - -struct __gmp_sgn_function -{ - static int eval(mpz_srcptr z) { return mpz_sgn(z); } - static int eval(mpq_srcptr q) { return mpq_sgn(q); } - static int eval(mpf_srcptr f) { return mpf_sgn(f); } -}; - -struct __gmp_cmp_function -{ - static int eval(mpz_srcptr z, mpz_srcptr w) { return mpz_cmp(z, w); } - - static int eval(mpz_srcptr z, unsigned long int l) - { return mpz_cmp_ui(z, l); } - static int eval(unsigned long int l, mpz_srcptr z) - { return -mpz_cmp_ui(z, l); } - static int eval(mpz_srcptr z, signed long int l) - { return mpz_cmp_si(z, l); } - static int eval(signed long int l, mpz_srcptr z) - { return -mpz_cmp_si(z, l); } - static int eval(mpz_srcptr z, double d) - { return mpz_cmp_d(z, d); } - static int eval(double d, mpz_srcptr z) - { return -mpz_cmp_d(z, d); } - - static int eval(mpq_srcptr q, mpq_srcptr r) { return mpq_cmp(q, r); } - - static int eval(mpq_srcptr q, unsigned long int l) - { return mpq_cmp_ui(q, l, 1); } - static int eval(unsigned long int l, mpq_srcptr q) - { return -mpq_cmp_ui(q, l, 1); } - static int eval(mpq_srcptr q, signed long int l) - { return mpq_cmp_si(q, l, 1); } - static int eval(signed long int l, mpq_srcptr q) - { return -mpq_cmp_si(q, l, 1); } - static int eval(mpq_srcptr q, double d) - { - int i; - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - i = mpq_cmp(q, temp); - mpq_clear(temp); - return i; - } - static int eval(double d, mpq_srcptr q) - { - int i; - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - i = mpq_cmp(temp, q); - mpq_clear(temp); - return i; - } - - static int eval(mpf_srcptr f, mpf_srcptr g) { return mpf_cmp(f, g); } - - static int eval(mpf_srcptr f, unsigned long int l) - { return mpf_cmp_ui(f, l); } - static int eval(unsigned long int l, mpf_srcptr f) - { return -mpf_cmp_ui(f, l); } - static int eval(mpf_srcptr f, signed long int l) - { return mpf_cmp_si(f, l); } - static int eval(signed long int l, mpf_srcptr f) - { return -mpf_cmp_si(f, l); } - static int eval(mpf_srcptr f, double d) - { return mpf_cmp_d(f, d); } - static int eval(double d, mpf_srcptr f) - { return -mpf_cmp_d(f, d); } -}; - -struct __gmp_rand_function -{ - static void eval(mpz_ptr z, gmp_randstate_t s, unsigned long int l) - { mpz_urandomb(z, s, l); } - static void eval(mpz_ptr z, gmp_randstate_t s, mpz_srcptr w) - { mpz_urandomm(z, s, w); } - static void eval(mpf_ptr f, gmp_randstate_t s, mp_bitcnt_t prec) - { mpf_urandomb(f, s, prec); } -}; - - -/**************** Auxiliary classes ****************/ - -/* this is much the same as gmp_allocated_string in gmp-impl.h - since gmp-impl.h is not publicly available, I redefine it here - I use a different name to avoid possible clashes */ -extern "C" { -struct __gmp_alloc_cstring_c -{ - void (*free_func) (void *, size_t); -}; -} - -struct __gmp_alloc_cstring : __gmp_alloc_cstring_c -{ - char *str; - __gmp_alloc_cstring(char *s) { str = s; } - ~__gmp_alloc_cstring() - { - mp_get_memory_functions (NULL, NULL, &free_func); - (*free_func) (str, std::strlen(str)+1); - } -}; - -// general expression template class -template -class __gmp_expr; - - -// templates for resolving expression types -template -struct __gmp_resolve_ref -{ - typedef T ref_type; -}; - -template -struct __gmp_resolve_ref<__gmp_expr > -{ - typedef const __gmp_expr & ref_type; -}; - - -template -struct __gmp_resolve_expr; - -template <> -struct __gmp_resolve_expr -{ - typedef mpz_t value_type; - typedef mpz_ptr ptr_type; -}; - -template <> -struct __gmp_resolve_expr -{ - typedef mpq_t value_type; - typedef mpq_ptr ptr_type; -}; - -template <> -struct __gmp_resolve_expr -{ - typedef mpf_t value_type; - typedef mpf_ptr ptr_type; -}; - -template <> -struct __gmp_resolve_expr -{ - typedef mpq_t value_type; -}; - -template <> -struct __gmp_resolve_expr -{ - typedef mpq_t value_type; -}; - -template <> -struct __gmp_resolve_expr -{ - typedef mpf_t value_type; -}; - -template <> -struct __gmp_resolve_expr -{ - typedef mpf_t value_type; -}; - -template <> -struct __gmp_resolve_expr -{ - typedef mpf_t value_type; -}; - -template <> -struct __gmp_resolve_expr -{ - typedef mpf_t value_type; -}; - - - -template -struct __gmp_resolve_temp -{ - typedef __gmp_expr temp_type; -}; - -template -struct __gmp_resolve_temp -{ - typedef const __gmp_expr & temp_type; -}; - - -// classes for evaluating unary and binary expressions -template -struct __gmp_unary_expr -{ - const T &val; - - __gmp_unary_expr(const T &v) : val(v) { } -private: - __gmp_unary_expr(); -}; - -template -struct __gmp_binary_expr -{ - typename __gmp_resolve_ref::ref_type val1; - typename __gmp_resolve_ref::ref_type val2; - - __gmp_binary_expr(const T &v1, const U &v2) : val1(v1), val2(v2) { } -private: - __gmp_binary_expr(); -}; - - -// functions for evaluating expressions -template -void __gmp_set_expr(mpz_ptr, const __gmp_expr &); -template -void __gmp_set_expr(mpq_ptr, const __gmp_expr &); -template -void __gmp_set_expr(mpf_ptr, const __gmp_expr &); - - -/**************** Macros for in-class declarations ****************/ -/* This is just repetitive code that is easier to maintain if it's written - only once */ - -#define __GMPP_DECLARE_COMPOUND_OPERATOR(fun) \ - template \ - __gmp_expr & fun(const __gmp_expr &); - -#define __GMPN_DECLARE_COMPOUND_OPERATOR(fun) \ - __gmp_expr & fun(signed char); \ - __gmp_expr & fun(unsigned char); \ - __gmp_expr & fun(signed int); \ - __gmp_expr & fun(unsigned int); \ - __gmp_expr & fun(signed short int); \ - __gmp_expr & fun(unsigned short int); \ - __gmp_expr & fun(signed long int); \ - __gmp_expr & fun(unsigned long int); \ - __gmp_expr & fun(float); \ - __gmp_expr & fun(double); \ - __gmp_expr & fun(long double); - -#define __GMP_DECLARE_COMPOUND_OPERATOR(fun) \ -__GMPP_DECLARE_COMPOUND_OPERATOR(fun) \ -__GMPN_DECLARE_COMPOUND_OPERATOR(fun) - -#define __GMP_DECLARE_COMPOUND_OPERATOR_UI(fun) \ - __gmp_expr & fun(unsigned long int); - -#define __GMP_DECLARE_INCREMENT_OPERATOR(fun) \ - inline __gmp_expr & fun(); \ - inline __gmp_expr fun(int); - - -/**************** mpz_class -- wrapper for mpz_t ****************/ - -template <> -class __gmp_expr -{ -private: - typedef mpz_t value_type; - value_type mp; -public: - mp_bitcnt_t get_prec() const { return mpf_get_default_prec(); } - - // constructors and destructor - __gmp_expr() { mpz_init(mp); } - - __gmp_expr(const __gmp_expr &z) { mpz_init_set(mp, z.mp); } - template - __gmp_expr(const __gmp_expr &expr) - { mpz_init(mp); __gmp_set_expr(mp, expr); } - - __gmp_expr(signed char c) { mpz_init_set_si(mp, c); } - __gmp_expr(unsigned char c) { mpz_init_set_ui(mp, c); } - - __gmp_expr(signed int i) { mpz_init_set_si(mp, i); } - __gmp_expr(unsigned int i) { mpz_init_set_ui(mp, i); } - - __gmp_expr(signed short int s) { mpz_init_set_si(mp, s); } - __gmp_expr(unsigned short int s) { mpz_init_set_ui(mp, s); } - - __gmp_expr(signed long int l) { mpz_init_set_si(mp, l); } - __gmp_expr(unsigned long int l) { mpz_init_set_ui(mp, l); } - - __gmp_expr(float f) { mpz_init_set_d(mp, f); } - __gmp_expr(double d) { mpz_init_set_d(mp, d); } - // __gmp_expr(long double ld) { mpz_init_set_d(mp, ld); } - - explicit __gmp_expr(const char *s) - { - if (mpz_init_set_str (mp, s, 0) != 0) - { - mpz_clear (mp); - throw std::invalid_argument ("mpz_set_str"); - } - } - __gmp_expr(const char *s, int base) - { - if (mpz_init_set_str (mp, s, base) != 0) - { - mpz_clear (mp); - throw std::invalid_argument ("mpz_set_str"); - } - } - explicit __gmp_expr(const std::string &s) - { - if (mpz_init_set_str (mp, s.c_str(), 0) != 0) - { - mpz_clear (mp); - throw std::invalid_argument ("mpz_set_str"); - } - } - __gmp_expr(const std::string &s, int base) - { - if (mpz_init_set_str(mp, s.c_str(), base) != 0) - { - mpz_clear (mp); - throw std::invalid_argument ("mpz_set_str"); - } - } - - explicit __gmp_expr(mpz_srcptr z) { mpz_init_set(mp, z); } - - ~__gmp_expr() { mpz_clear(mp); } - - // assignment operators - __gmp_expr & operator=(const __gmp_expr &z) - { mpz_set(mp, z.mp); return *this; } - template - __gmp_expr & operator=(const __gmp_expr &expr) - { __gmp_set_expr(mp, expr); return *this; } - - __gmp_expr & operator=(signed char c) { mpz_set_si(mp, c); return *this; } - __gmp_expr & operator=(unsigned char c) { mpz_set_ui(mp, c); return *this; } - - __gmp_expr & operator=(signed int i) { mpz_set_si(mp, i); return *this; } - __gmp_expr & operator=(unsigned int i) { mpz_set_ui(mp, i); return *this; } - - __gmp_expr & operator=(signed short int s) - { mpz_set_si(mp, s); return *this; } - __gmp_expr & operator=(unsigned short int s) - { mpz_set_ui(mp, s); return *this; } - - __gmp_expr & operator=(signed long int l) - { mpz_set_si(mp, l); return *this; } - __gmp_expr & operator=(unsigned long int l) - { mpz_set_ui(mp, l); return *this; } - - __gmp_expr & operator=(float f) { mpz_set_d(mp, f); return *this; } - __gmp_expr & operator=(double d) { mpz_set_d(mp, d); return *this; } - // __gmp_expr & operator=(long double ld) - // { mpz_set_ld(mp, ld); return *this; } - - __gmp_expr & operator=(const char *s) - { - if (mpz_set_str (mp, s, 0) != 0) - throw std::invalid_argument ("mpz_set_str"); - return *this; - } - __gmp_expr & operator=(const std::string &s) - { - if (mpz_set_str(mp, s.c_str(), 0) != 0) - throw std::invalid_argument ("mpz_set_str"); - return *this; - } - - // string input/output functions - int set_str(const char *s, int base) - { return mpz_set_str(mp, s, base); } - int set_str(const std::string &s, int base) - { return mpz_set_str(mp, s.c_str(), base); } - std::string get_str(int base = 10) const - { - __gmp_alloc_cstring temp(mpz_get_str(0, base, mp)); - return std::string(temp.str); - } - - // conversion functions - mpz_srcptr __get_mp() const { return mp; } - mpz_ptr __get_mp() { return mp; } - mpz_srcptr get_mpz_t() const { return mp; } - mpz_ptr get_mpz_t() { return mp; } - - signed long int get_si() const { return mpz_get_si(mp); } - unsigned long int get_ui() const { return mpz_get_ui(mp); } - double get_d() const { return mpz_get_d(mp); } - - // bool fits_schar_p() const { return mpz_fits_schar_p(mp); } - // bool fits_uchar_p() const { return mpz_fits_uchar_p(mp); } - bool fits_sint_p() const { return mpz_fits_sint_p(mp); } - bool fits_uint_p() const { return mpz_fits_uint_p(mp); } - bool fits_sshort_p() const { return mpz_fits_sshort_p(mp); } - bool fits_ushort_p() const { return mpz_fits_ushort_p(mp); } - bool fits_slong_p() const { return mpz_fits_slong_p(mp); } - bool fits_ulong_p() const { return mpz_fits_ulong_p(mp); } - // bool fits_float_p() const { return mpz_fits_float_p(mp); } - // bool fits_double_p() const { return mpz_fits_double_p(mp); } - // bool fits_ldouble_p() const { return mpz_fits_ldouble_p(mp); } - - // member operators - __GMP_DECLARE_COMPOUND_OPERATOR(operator+=) - __GMP_DECLARE_COMPOUND_OPERATOR(operator-=) - __GMP_DECLARE_COMPOUND_OPERATOR(operator*=) - __GMP_DECLARE_COMPOUND_OPERATOR(operator/=) - __GMP_DECLARE_COMPOUND_OPERATOR(operator%=) - - __GMPP_DECLARE_COMPOUND_OPERATOR(operator&=) - __GMPP_DECLARE_COMPOUND_OPERATOR(operator|=) - __GMPP_DECLARE_COMPOUND_OPERATOR(operator^=) - - __GMP_DECLARE_COMPOUND_OPERATOR_UI(operator<<=) - __GMP_DECLARE_COMPOUND_OPERATOR_UI(operator>>=) - - __GMP_DECLARE_INCREMENT_OPERATOR(operator++) - __GMP_DECLARE_INCREMENT_OPERATOR(operator--) -}; - -typedef __gmp_expr mpz_class; - - -/**************** mpq_class -- wrapper for mpq_t ****************/ - -template <> -class __gmp_expr -{ -private: - typedef mpq_t value_type; - value_type mp; -public: - mp_bitcnt_t get_prec() const { return mpf_get_default_prec(); } - void canonicalize() { mpq_canonicalize(mp); } - - // constructors and destructor - __gmp_expr() { mpq_init(mp); } - - __gmp_expr(const __gmp_expr &q) { mpq_init(mp); mpq_set(mp, q.mp); } - template - __gmp_expr(const __gmp_expr &expr) - { mpq_init(mp); __gmp_set_expr(mp, expr); } - - __gmp_expr(signed char c) { mpq_init(mp); mpq_set_si(mp, c, 1); } - __gmp_expr(unsigned char c) { mpq_init(mp); mpq_set_ui(mp, c, 1); } - - __gmp_expr(signed int i) { mpq_init(mp); mpq_set_si(mp, i, 1); } - __gmp_expr(unsigned int i) { mpq_init(mp); mpq_set_ui(mp, i, 1); } - - __gmp_expr(signed short int s) { mpq_init(mp); mpq_set_si(mp, s, 1); } - __gmp_expr(unsigned short int s) { mpq_init(mp); mpq_set_ui(mp, s, 1); } - - __gmp_expr(signed long int l) { mpq_init(mp); mpq_set_si(mp, l, 1); } - __gmp_expr(unsigned long int l) { mpq_init(mp); mpq_set_ui(mp, l, 1); } - - __gmp_expr(float f) { mpq_init(mp); mpq_set_d(mp, f); } - __gmp_expr(double d) { mpq_init(mp); mpq_set_d(mp, d); } - // __gmp_expr(long double ld) { mpq_init(mp); mpq_set_ld(mp, ld); } - - explicit __gmp_expr(const char *s) - { - mpq_init (mp); - if (mpq_set_str (mp, s, 0) != 0) - { - mpq_clear (mp); - throw std::invalid_argument ("mpq_set_str"); - } - } - __gmp_expr(const char *s, int base) - { - mpq_init (mp); - if (mpq_set_str(mp, s, base) != 0) - { - mpq_clear (mp); - throw std::invalid_argument ("mpq_set_str"); - } - } - explicit __gmp_expr(const std::string &s) - { - mpq_init (mp); - if (mpq_set_str (mp, s.c_str(), 0) != 0) - { - mpq_clear (mp); - throw std::invalid_argument ("mpq_set_str"); - } - } - __gmp_expr(const std::string &s, int base) - { - mpq_init(mp); - if (mpq_set_str (mp, s.c_str(), base) != 0) - { - mpq_clear (mp); - throw std::invalid_argument ("mpq_set_str"); - } - } - explicit __gmp_expr(mpq_srcptr q) { mpq_init(mp); mpq_set(mp, q); } - - __gmp_expr(const mpz_class &num, const mpz_class &den) - { - mpq_init(mp); - mpz_set(mpq_numref(mp), num.get_mpz_t()); - mpz_set(mpq_denref(mp), den.get_mpz_t()); - } - - ~__gmp_expr() { mpq_clear(mp); } - - // assignment operators - __gmp_expr & operator=(const __gmp_expr &q) - { mpq_set(mp, q.mp); return *this; } - template - __gmp_expr & operator=(const __gmp_expr &expr) - { __gmp_set_expr(mp, expr); return *this; } - - __gmp_expr & operator=(signed char c) - { mpq_set_si(mp, c, 1); return *this; } - __gmp_expr & operator=(unsigned char c) - { mpq_set_ui(mp, c, 1); return *this; } - - __gmp_expr & operator=(signed int i) { mpq_set_si(mp, i, 1); return *this; } - __gmp_expr & operator=(unsigned int i) - { mpq_set_ui(mp, i, 1); return *this; } - - __gmp_expr & operator=(signed short int s) - { mpq_set_si(mp, s, 1); return *this; } - __gmp_expr & operator=(unsigned short int s) - { mpq_set_ui(mp, s, 1); return *this; } - - __gmp_expr & operator=(signed long int l) - { mpq_set_si(mp, l, 1); return *this; } - __gmp_expr & operator=(unsigned long int l) - { mpq_set_ui(mp, l, 1); return *this; } - - __gmp_expr & operator=(float f) { mpq_set_d(mp, f); return *this; } - __gmp_expr & operator=(double d) { mpq_set_d(mp, d); return *this; } - // __gmp_expr & operator=(long double ld) - // { mpq_set_ld(mp, ld); return *this; } - - __gmp_expr & operator=(const char *s) - { - if (mpq_set_str (mp, s, 0) != 0) - throw std::invalid_argument ("mpq_set_str"); - return *this; - } - __gmp_expr & operator=(const std::string &s) - { - if (mpq_set_str(mp, s.c_str(), 0) != 0) - throw std::invalid_argument ("mpq_set_str"); - return *this; - } - - // string input/output functions - int set_str(const char *s, int base) - { return mpq_set_str(mp, s, base); } - int set_str(const std::string &s, int base) - { return mpq_set_str(mp, s.c_str(), base); } - std::string get_str(int base = 10) const - { - __gmp_alloc_cstring temp(mpq_get_str(0, base, mp)); - return std::string(temp.str); - } - - // conversion functions - - // casting a reference to an mpz_t to mpz_class & is a dirty hack, - // but works because the internal representation of mpz_class is - // exactly an mpz_t - const mpz_class & get_num() const - { return reinterpret_cast(*mpq_numref(mp)); } - mpz_class & get_num() - { return reinterpret_cast(*mpq_numref(mp)); } - const mpz_class & get_den() const - { return reinterpret_cast(*mpq_denref(mp)); } - mpz_class & get_den() - { return reinterpret_cast(*mpq_denref(mp)); } - - mpq_srcptr __get_mp() const { return mp; } - mpq_ptr __get_mp() { return mp; } - mpq_srcptr get_mpq_t() const { return mp; } - mpq_ptr get_mpq_t() { return mp; } - - mpz_srcptr get_num_mpz_t() const { return mpq_numref(mp); } - mpz_ptr get_num_mpz_t() { return mpq_numref(mp); } - mpz_srcptr get_den_mpz_t() const { return mpq_denref(mp); } - mpz_ptr get_den_mpz_t() { return mpq_denref(mp); } - - double get_d() const { return mpq_get_d(mp); } - - // compound assignments - __GMP_DECLARE_COMPOUND_OPERATOR(operator+=) - __GMP_DECLARE_COMPOUND_OPERATOR(operator-=) - __GMP_DECLARE_COMPOUND_OPERATOR(operator*=) - __GMP_DECLARE_COMPOUND_OPERATOR(operator/=) - - __GMP_DECLARE_COMPOUND_OPERATOR_UI(operator<<=) - __GMP_DECLARE_COMPOUND_OPERATOR_UI(operator>>=) - - __GMP_DECLARE_INCREMENT_OPERATOR(operator++) - __GMP_DECLARE_INCREMENT_OPERATOR(operator--) -}; - -typedef __gmp_expr mpq_class; - - -/**************** mpf_class -- wrapper for mpf_t ****************/ - -template <> -class __gmp_expr -{ -private: - typedef mpf_t value_type; - value_type mp; -public: - mp_bitcnt_t get_prec() const { return mpf_get_prec(mp); } - - void set_prec(mp_bitcnt_t prec) { mpf_set_prec(mp, prec); } - void set_prec_raw(mp_bitcnt_t prec) { mpf_set_prec_raw(mp, prec); } - - // constructors and destructor - __gmp_expr() { mpf_init(mp); } - - __gmp_expr(const __gmp_expr &f) - { mpf_init2(mp, f.get_prec()); mpf_set(mp, f.mp); } - __gmp_expr(const __gmp_expr &f, mp_bitcnt_t prec) - { mpf_init2(mp, prec); mpf_set(mp, f.mp); } - template - __gmp_expr(const __gmp_expr &expr) - { mpf_init2(mp, expr.get_prec()); __gmp_set_expr(mp, expr); } - template - __gmp_expr(const __gmp_expr &expr, mp_bitcnt_t prec) - { mpf_init2(mp, prec); __gmp_set_expr(mp, expr); } - - __gmp_expr(signed char c) { mpf_init_set_si(mp, c); } - __gmp_expr(signed char c, mp_bitcnt_t prec) - { mpf_init2(mp, prec); mpf_set_si(mp, c); } - __gmp_expr(unsigned char c) { mpf_init_set_ui(mp, c); } - __gmp_expr(unsigned char c, mp_bitcnt_t prec) - { mpf_init2(mp, prec); mpf_set_ui(mp, c); } - - __gmp_expr(signed int i) { mpf_init_set_si(mp, i); } - __gmp_expr(signed int i, mp_bitcnt_t prec) - { mpf_init2(mp, prec); mpf_set_si(mp, i); } - __gmp_expr(unsigned int i) { mpf_init_set_ui(mp, i); } - __gmp_expr(unsigned int i, mp_bitcnt_t prec) - { mpf_init2(mp, prec); mpf_set_ui(mp, i); } - - __gmp_expr(signed short int s) { mpf_init_set_si(mp, s); } - __gmp_expr(signed short int s, mp_bitcnt_t prec) - { mpf_init2(mp, prec); mpf_set_si(mp, s); } - __gmp_expr(unsigned short int s) { mpf_init_set_ui(mp, s); } - __gmp_expr(unsigned short int s, mp_bitcnt_t prec) - { mpf_init2(mp, prec); mpf_set_ui(mp, s); } - - __gmp_expr(signed long int l) { mpf_init_set_si(mp, l); } - __gmp_expr(signed long int l, mp_bitcnt_t prec) - { mpf_init2(mp, prec); mpf_set_si(mp, l); } - __gmp_expr(unsigned long int l) { mpf_init_set_ui(mp, l); } - __gmp_expr(unsigned long int l, mp_bitcnt_t prec) - { mpf_init2(mp, prec); mpf_set_ui(mp, l); } - - __gmp_expr(float f) { mpf_init_set_d(mp, f); } - __gmp_expr(float f, mp_bitcnt_t prec) - { mpf_init2(mp, prec); mpf_set_d(mp, f); } - __gmp_expr(double d) { mpf_init_set_d(mp, d); } - __gmp_expr(double d, mp_bitcnt_t prec) - { mpf_init2(mp, prec); mpf_set_d(mp, d); } - // __gmp_expr(long double ld) { mpf_init_set_d(mp, ld); } - // __gmp_expr(long double ld, mp_bitcnt_t prec) - // { mpf_init2(mp, prec); mpf_set_d(mp, ld); } - - explicit __gmp_expr(const char *s) - { - if (mpf_init_set_str (mp, s, 0) != 0) - { - mpf_clear (mp); - throw std::invalid_argument ("mpf_set_str"); - } - } - __gmp_expr(const char *s, mp_bitcnt_t prec, int base = 0) - { - mpf_init2(mp, prec); - if (mpf_set_str(mp, s, base) != 0) - { - mpf_clear (mp); - throw std::invalid_argument ("mpf_set_str"); - } - } - explicit __gmp_expr(const std::string &s) - { - if (mpf_init_set_str(mp, s.c_str(), 0) != 0) - { - mpf_clear (mp); - throw std::invalid_argument ("mpf_set_str"); - } - } - __gmp_expr(const std::string &s, mp_bitcnt_t prec, int base = 0) - { - mpf_init2(mp, prec); - if (mpf_set_str(mp, s.c_str(), base) != 0) - { - mpf_clear (mp); - throw std::invalid_argument ("mpf_set_str"); - } - } - - explicit __gmp_expr(mpf_srcptr f) - { mpf_init2(mp, mpf_get_prec(f)); mpf_set(mp, f); } - __gmp_expr(mpf_srcptr f, mp_bitcnt_t prec) - { mpf_init2(mp, prec); mpf_set(mp, f); } - - ~__gmp_expr() { mpf_clear(mp); } - - // assignment operators - __gmp_expr & operator=(const __gmp_expr &f) - { mpf_set(mp, f.mp); return *this; } - template - __gmp_expr & operator=(const __gmp_expr &expr) - { __gmp_set_expr(mp, expr); return *this; } - - __gmp_expr & operator=(signed char c) { mpf_set_si(mp, c); return *this; } - __gmp_expr & operator=(unsigned char c) { mpf_set_ui(mp, c); return *this; } - - __gmp_expr & operator=(signed int i) { mpf_set_si(mp, i); return *this; } - __gmp_expr & operator=(unsigned int i) { mpf_set_ui(mp, i); return *this; } - - __gmp_expr & operator=(signed short int s) - { mpf_set_si(mp, s); return *this; } - __gmp_expr & operator=(unsigned short int s) - { mpf_set_ui(mp, s); return *this; } - - __gmp_expr & operator=(signed long int l) - { mpf_set_si(mp, l); return *this; } - __gmp_expr & operator=(unsigned long int l) - { mpf_set_ui(mp, l); return *this; } - - __gmp_expr & operator=(float f) { mpf_set_d(mp, f); return *this; } - __gmp_expr & operator=(double d) { mpf_set_d(mp, d); return *this; } - // __gmp_expr & operator=(long double ld) - // { mpf_set_ld(mp, ld); return *this; } - - __gmp_expr & operator=(const char *s) - { - if (mpf_set_str (mp, s, 0) != 0) - throw std::invalid_argument ("mpf_set_str"); - return *this; - } - __gmp_expr & operator=(const std::string &s) - { - if (mpf_set_str(mp, s.c_str(), 0) != 0) - throw std::invalid_argument ("mpf_set_str"); - return *this; - } - - // string input/output functions - int set_str(const char *s, int base) - { return mpf_set_str(mp, s, base); } - int set_str(const std::string &s, int base) - { return mpf_set_str(mp, s.c_str(), base); } - std::string get_str(mp_exp_t &expo, int base = 10, size_t size = 0) const - { - __gmp_alloc_cstring temp(mpf_get_str(0, &expo, base, size, mp)); - return std::string(temp.str); - } - - // conversion functions - mpf_srcptr __get_mp() const { return mp; } - mpf_ptr __get_mp() { return mp; } - mpf_srcptr get_mpf_t() const { return mp; } - mpf_ptr get_mpf_t() { return mp; } - - signed long int get_si() const { return mpf_get_si(mp); } - unsigned long int get_ui() const { return mpf_get_ui(mp); } - double get_d() const { return mpf_get_d(mp); } - - // bool fits_schar_p() const { return mpf_fits_schar_p(mp); } - // bool fits_uchar_p() const { return mpf_fits_uchar_p(mp); } - bool fits_sint_p() const { return mpf_fits_sint_p(mp); } - bool fits_uint_p() const { return mpf_fits_uint_p(mp); } - bool fits_sshort_p() const { return mpf_fits_sshort_p(mp); } - bool fits_ushort_p() const { return mpf_fits_ushort_p(mp); } - bool fits_slong_p() const { return mpf_fits_slong_p(mp); } - bool fits_ulong_p() const { return mpf_fits_ulong_p(mp); } - // bool fits_float_p() const { return mpf_fits_float_p(mp); } - // bool fits_double_p() const { return mpf_fits_double_p(mp); } - // bool fits_ldouble_p() const { return mpf_fits_ldouble_p(mp); } - - // compound assignments - __GMP_DECLARE_COMPOUND_OPERATOR(operator+=) - __GMP_DECLARE_COMPOUND_OPERATOR(operator-=) - __GMP_DECLARE_COMPOUND_OPERATOR(operator*=) - __GMP_DECLARE_COMPOUND_OPERATOR(operator/=) - - __GMP_DECLARE_COMPOUND_OPERATOR_UI(operator<<=) - __GMP_DECLARE_COMPOUND_OPERATOR_UI(operator>>=) - - __GMP_DECLARE_INCREMENT_OPERATOR(operator++) - __GMP_DECLARE_INCREMENT_OPERATOR(operator--) -}; - -typedef __gmp_expr mpf_class; - - - -/**************** I/O operators ****************/ - -// these should (and will) be provided separately - -template -inline std::ostream & operator<< -(std::ostream &o, const __gmp_expr &expr) -{ - return o << expr.__get_mp(); -} - -template -inline std::ostream & operator<< -(std::ostream &o, const __gmp_expr &expr) -{ - __gmp_expr temp(expr); - return o << temp.__get_mp(); -} - - -template -inline std::istream & operator>>(std::istream &i, __gmp_expr &expr) -{ - return i >> expr.__get_mp(); -} - -inline std::istream & operator>>(std::istream &i, mpq_class &q) -{ - i >> q.get_mpq_t(); - // q.canonicalize(); // you might want to uncomment this - return i; -} - - -/**************** Functions for type conversion ****************/ - -template <> -inline void __gmp_set_expr(mpz_ptr z, const mpz_class &w) -{ - mpz_set(z, w.get_mpz_t()); -} - -template -inline void __gmp_set_expr(mpz_ptr z, const __gmp_expr &expr) -{ - expr.eval(z); -} - -template <> -inline void __gmp_set_expr(mpz_ptr z, const mpq_class &q) -{ - mpz_set_q(z, q.get_mpq_t()); -} - -template -inline void __gmp_set_expr(mpz_ptr z, const __gmp_expr &expr) -{ - mpq_class temp(expr); - mpz_set_q(z, temp.get_mpq_t()); -} - -template -inline void __gmp_set_expr(mpz_ptr z, const mpf_class &f) -{ - mpz_set_f(z, f.get_mpf_t()); -} - -template -inline void __gmp_set_expr(mpz_ptr z, const __gmp_expr &expr) -{ - mpf_class temp(expr); - mpz_set_f(z, temp.get_mpf_t()); -} - -template <> -inline void __gmp_set_expr(mpq_ptr q, const mpz_class &z) -{ - mpq_set_z(q, z.get_mpz_t()); -} - -template -inline void __gmp_set_expr(mpq_ptr q, const __gmp_expr &expr) -{ - mpz_class temp(expr); - mpq_set_z(q, temp.get_mpz_t()); -} - -template <> -inline void __gmp_set_expr(mpq_ptr q, const mpq_class &r) -{ - mpq_set(q, r.get_mpq_t()); -} - -template -inline void __gmp_set_expr(mpq_ptr q, const __gmp_expr &expr) -{ - expr.eval(q); -} - -template -inline void __gmp_set_expr(mpq_ptr q, const mpf_class &f) -{ - mpq_set_f(q, f.get_mpf_t()); -} - -template -inline void __gmp_set_expr(mpq_ptr q, const __gmp_expr &expr) -{ - mpf_class temp(expr); - mpq_set_f(q, temp.get_mpf_t()); -} - -template -inline void __gmp_set_expr(mpf_ptr f, const mpz_class &z) -{ - mpf_set_z(f, z.get_mpz_t()); -} - -template -inline void __gmp_set_expr(mpf_ptr f, const __gmp_expr &expr) -{ - mpz_class temp(expr); - mpf_set_z(f, temp.get_mpz_t()); -} - -template -inline void __gmp_set_expr(mpf_ptr f, const mpq_class &q) -{ - mpf_set_q(f, q.get_mpq_t()); -} - -template -inline void __gmp_set_expr(mpf_ptr f, const __gmp_expr &expr) -{ - mpq_class temp(expr); - mpf_set_q(f, temp.get_mpq_t()); -} - -template <> -inline void __gmp_set_expr(mpf_ptr f, const mpf_class &g) -{ - mpf_set(f, g.get_mpf_t()); -} - -template -inline void __gmp_set_expr(mpf_ptr f, const __gmp_expr &expr) -{ - expr.eval(f, mpf_get_prec(f)); -} - - -/**************** Specializations of __gmp_expr ****************/ -/* The eval() method of __gmp_expr evaluates the corresponding - expression and assigns the result to its argument, which is either an - mpz_t, mpq_t, or mpf_t as specified by the T argument. - Compound expressions are evaluated recursively (temporaries are created - to hold intermediate values), while for simple expressions the eval() - method of the appropriate function object (available as the Op argument - of either __gmp_unary_expr or __gmp_binary_expr) is - called. */ - - -/**************** Unary expressions ****************/ -/* cases: - - simple: argument is mp*_class, that is, __gmp_expr - - compound: argument is __gmp_expr (with U not equal to T) */ - - -// simple expressions - -template -class __gmp_expr, Op> > -{ -private: - typedef __gmp_expr val_type; - - __gmp_unary_expr expr; -public: - __gmp_expr(const val_type &val) : expr(val) { } - void eval(typename __gmp_resolve_expr::ptr_type p, - unsigned long int = 0) const - { Op::eval(p, expr.val.__get_mp()); } - const val_type & get_val() const { return expr.val; } - unsigned long int get_prec() const { return expr.val.get_prec(); } -}; - - -// compound expressions - -template -class __gmp_expr, Op> > -{ -private: - typedef __gmp_expr val_type; - - __gmp_unary_expr expr; -public: - __gmp_expr(const val_type &val) : expr(val) { } - void eval(typename __gmp_resolve_expr::ptr_type p) const - { __gmp_expr temp(expr.val); Op::eval(p, temp.__get_mp()); } - void eval(typename __gmp_resolve_expr::ptr_type p, - mp_bitcnt_t prec) const - { __gmp_expr temp(expr.val, prec); Op::eval(p, temp.__get_mp()); } - const val_type & get_val() const { return expr.val; } - unsigned long int get_prec() const { return expr.val.get_prec(); } -}; - - -/**************** Binary expressions ****************/ -/* simple: - - arguments are both mp*_class - - one argument is mp*_class, one is a built-in type - compound: - - one is mp*_class, one is __gmp_expr - - one is __gmp_expr, one is built-in - - both arguments are __gmp_expr<...> */ - - -// simple expressions - -template -class __gmp_expr -, __gmp_expr, Op> > -{ -private: - typedef __gmp_expr val1_type; - typedef __gmp_expr val2_type; - - __gmp_binary_expr expr; -public: - __gmp_expr(const val1_type &val1, const val2_type &val2) - : expr(val1, val2) { } - void eval(typename __gmp_resolve_expr::ptr_type p, - unsigned long int = 0) const - { Op::eval(p, expr.val1.__get_mp(), expr.val2.__get_mp()); } - const val1_type & get_val1() const { return expr.val1; } - const val2_type & get_val2() const { return expr.val2; } - unsigned long int get_prec() const - { - mp_bitcnt_t prec1 = expr.val1.get_prec(), - prec2 = expr.val2.get_prec(); - return (prec1 > prec2) ? prec1 : prec2; - } -}; - - -// simple expressions, T is a built-in numerical type - -template -class __gmp_expr, U, Op> > -{ -private: - typedef __gmp_expr val1_type; - typedef U val2_type; - - __gmp_binary_expr expr; -public: - __gmp_expr(const val1_type &val1, const val2_type &val2) - : expr(val1, val2) { } - void eval(typename __gmp_resolve_expr::ptr_type p, - unsigned long int = 0) const - { Op::eval(p, expr.val1.__get_mp(), expr.val2); } - const val1_type & get_val1() const { return expr.val1; } - const val2_type & get_val2() const { return expr.val2; } - unsigned long int get_prec() const { return expr.val1.get_prec(); } -}; - -template -class __gmp_expr, Op> > -{ -private: - typedef U val1_type; - typedef __gmp_expr val2_type; - - __gmp_binary_expr expr; -public: - __gmp_expr(const val1_type &val1, const val2_type &val2) - : expr(val1, val2) { } - void eval(typename __gmp_resolve_expr::ptr_type p, - unsigned long int = 0) const - { Op::eval(p, expr.val1, expr.val2.__get_mp()); } - const val1_type & get_val1() const { return expr.val1; } - const val2_type & get_val2() const { return expr.val2; } - unsigned long int get_prec() const { return expr.val2.get_prec(); } -}; - - -// compound expressions, one argument is a subexpression - -template -class __gmp_expr -, __gmp_expr, Op> > -{ -private: - typedef __gmp_expr val1_type; - typedef __gmp_expr val2_type; - - __gmp_binary_expr expr; -public: - __gmp_expr(const val1_type &val1, const val2_type &val2) - : expr(val1, val2) { } - void eval(typename __gmp_resolve_expr::ptr_type p) const - { - __gmp_expr temp(expr.val2); - Op::eval(p, expr.val1.__get_mp(), temp.__get_mp()); - } - void eval(typename __gmp_resolve_expr::ptr_type p, - mp_bitcnt_t prec) const - { - __gmp_expr temp(expr.val2, prec); - Op::eval(p, expr.val1.__get_mp(), temp.__get_mp()); - } - const val1_type & get_val1() const { return expr.val1; } - const val2_type & get_val2() const { return expr.val2; } - unsigned long int get_prec() const - { - mp_bitcnt_t prec1 = expr.val1.get_prec(), - prec2 = expr.val2.get_prec(); - return (prec1 > prec2) ? prec1 : prec2; - } -}; - -template -class __gmp_expr -, __gmp_expr, Op> > -{ -private: - typedef __gmp_expr val1_type; - typedef __gmp_expr val2_type; - - __gmp_binary_expr expr; -public: - __gmp_expr(const val1_type &val1, const val2_type &val2) - : expr(val1, val2) { } - void eval(typename __gmp_resolve_expr::ptr_type p) const - { - __gmp_expr temp(expr.val1); - Op::eval(p, temp.__get_mp(), expr.val2.__get_mp()); - } - void eval(typename __gmp_resolve_expr::ptr_type p, - mp_bitcnt_t prec) const - { - __gmp_expr temp(expr.val1, prec); - Op::eval(p, temp.__get_mp(), expr.val2.__get_mp()); - } - const val1_type & get_val1() const { return expr.val1; } - const val2_type & get_val2() const { return expr.val2; } - unsigned long int get_prec() const - { - mp_bitcnt_t prec1 = expr.val1.get_prec(), - prec2 = expr.val2.get_prec(); - return (prec1 > prec2) ? prec1 : prec2; - } -}; - -template -class __gmp_expr -, __gmp_expr, Op> > -{ -private: - typedef __gmp_expr val1_type; - typedef __gmp_expr val2_type; - - __gmp_binary_expr expr; -public: - __gmp_expr(const val1_type &val1, const val2_type &val2) - : expr(val1, val2) { } - void eval(typename __gmp_resolve_expr::ptr_type p) const - { - __gmp_expr temp(expr.val2); - Op::eval(p, expr.val1.__get_mp(), temp.__get_mp()); - } - void eval(typename __gmp_resolve_expr::ptr_type p, - mp_bitcnt_t prec) const - { - __gmp_expr temp(expr.val2, prec); - Op::eval(p, expr.val1.__get_mp(), temp.__get_mp()); - } - const val1_type & get_val1() const { return expr.val1; } - const val2_type & get_val2() const { return expr.val2; } - unsigned long int get_prec() const - { - mp_bitcnt_t prec1 = expr.val1.get_prec(), - prec2 = expr.val2.get_prec(); - return (prec1 > prec2) ? prec1 : prec2; - } -}; - -template -class __gmp_expr -, __gmp_expr, Op> > -{ -private: - typedef __gmp_expr val1_type; - typedef __gmp_expr val2_type; - - __gmp_binary_expr expr; -public: - __gmp_expr(const val1_type &val1, const val2_type &val2) - : expr(val1, val2) { } - void eval(typename __gmp_resolve_expr::ptr_type p) const - { - __gmp_expr temp(expr.val1); - Op::eval(p, temp.__get_mp(), expr.val2.__get_mp()); - } - void eval(typename __gmp_resolve_expr::ptr_type p, - mp_bitcnt_t prec) const - { - __gmp_expr temp(expr.val1, prec); - Op::eval(p, temp.__get_mp(), expr.val2.__get_mp()); - } - const val1_type & get_val1() const { return expr.val1; } - const val2_type & get_val2() const { return expr.val2; } - unsigned long int get_prec() const - { - mp_bitcnt_t prec1 = expr.val1.get_prec(), - prec2 = expr.val2.get_prec(); - return (prec1 > prec2) ? prec1 : prec2; - } -}; - - -// one argument is a subexpression, one is a built-in - -template -class __gmp_expr, V, Op> > -{ -private: - typedef __gmp_expr val1_type; - typedef V val2_type; - - __gmp_binary_expr expr; -public: - __gmp_expr(const val1_type &val1, const val2_type &val2) - : expr(val1, val2) { } - void eval(typename __gmp_resolve_expr::ptr_type p) const - { - __gmp_expr temp(expr.val1); - Op::eval(p, temp.__get_mp(), expr.val2); - } - void eval(typename __gmp_resolve_expr::ptr_type p, - mp_bitcnt_t prec) const - { - __gmp_expr temp(expr.val1, prec); - Op::eval(p, temp.__get_mp(), expr.val2); - } - const val1_type & get_val1() const { return expr.val1; } - const val2_type & get_val2() const { return expr.val2; } - unsigned long int get_prec() const { return expr.val1.get_prec(); } -}; - -template -class __gmp_expr, Op> > -{ -private: - typedef U val1_type; - typedef __gmp_expr val2_type; - - __gmp_binary_expr expr; -public: - __gmp_expr(const val1_type &val1, const val2_type &val2) - : expr(val1, val2) { } - void eval(typename __gmp_resolve_expr::ptr_type p) const - { - __gmp_expr temp(expr.val2); - Op::eval(p, expr.val1, temp.__get_mp()); - } - void eval(typename __gmp_resolve_expr::ptr_type p, - mp_bitcnt_t prec) const - { - __gmp_expr temp(expr.val2, prec); - Op::eval(p, expr.val1, temp.__get_mp()); - } - const val1_type & get_val1() const { return expr.val1; } - const val2_type & get_val2() const { return expr.val2; } - unsigned long int get_prec() const { return expr.val2.get_prec(); } -}; - - -// both arguments are subexpressions - -template -class __gmp_expr -, __gmp_expr, Op> > -{ -private: - typedef __gmp_expr val1_type; - typedef __gmp_expr val2_type; - - __gmp_binary_expr expr; -public: - __gmp_expr(const val1_type &val1, const val2_type &val2) - : expr(val1, val2) { } - void eval(typename __gmp_resolve_expr::ptr_type p) const - { - __gmp_expr temp1(expr.val1), temp2(expr.val2); - Op::eval(p, temp1.__get_mp(), temp2.__get_mp()); - } - void eval(typename __gmp_resolve_expr::ptr_type p, - mp_bitcnt_t prec) const - { - __gmp_expr temp1(expr.val1, prec), temp2(expr.val2, prec); - Op::eval(p, temp1.__get_mp(), temp2.__get_mp()); - } - const val1_type & get_val1() const { return expr.val1; } - const val2_type & get_val2() const { return expr.val2; } - unsigned long int get_prec() const - { - mp_bitcnt_t prec1 = expr.val1.get_prec(), - prec2 = expr.val2.get_prec(); - return (prec1 > prec2) ? prec1 : prec2; - } -}; - -template -class __gmp_expr -, __gmp_expr, Op> > -{ -private: - typedef __gmp_expr val1_type; - typedef __gmp_expr val2_type; - - __gmp_binary_expr expr; -public: - __gmp_expr(const val1_type &val1, const val2_type &val2) - : expr(val1, val2) { } - void eval(typename __gmp_resolve_expr::ptr_type p) const - { - __gmp_expr temp1(expr.val1), temp2(expr.val2); - Op::eval(p, temp1.__get_mp(), temp2.__get_mp()); - } - void eval(typename __gmp_resolve_expr::ptr_type p, - mp_bitcnt_t prec) const - { - __gmp_expr temp1(expr.val1, prec), temp2(expr.val2, prec); - Op::eval(p, temp1.__get_mp(), temp2.__get_mp()); - } - const val1_type & get_val1() const { return expr.val1; } - const val2_type & get_val2() const { return expr.val2; } - unsigned long int get_prec() const - { - mp_bitcnt_t prec1 = expr.val1.get_prec(), - prec2 = expr.val2.get_prec(); - return (prec1 > prec2) ? prec1 : prec2; - } -}; - -template -class __gmp_expr -, __gmp_expr, Op> > -{ -private: - typedef __gmp_expr val1_type; - typedef __gmp_expr val2_type; - - __gmp_binary_expr expr; -public: - __gmp_expr(const val1_type &val1, const val2_type &val2) - : expr(val1, val2) { } - void eval(typename __gmp_resolve_expr::ptr_type p) const - { - __gmp_expr temp1(expr.val1), temp2(expr.val2); - Op::eval(p, temp1.__get_mp(), temp2.__get_mp()); - } - void eval(typename __gmp_resolve_expr::ptr_type p, - mp_bitcnt_t prec) const - { - __gmp_expr temp1(expr.val1, prec), temp2(expr.val2, prec); - Op::eval(p, temp1.__get_mp(), temp2.__get_mp()); - } - const val1_type & get_val1() const { return expr.val1; } - const val2_type & get_val2() const { return expr.val2; } - unsigned long int get_prec() const - { - mp_bitcnt_t prec1 = expr.val1.get_prec(), - prec2 = expr.val2.get_prec(); - return (prec1 > prec2) ? prec1 : prec2; - } -}; - - -/**************** Special cases ****************/ - -/* Some operations (i.e., add and subtract) with mixed mpz/mpq arguments - can be done directly without first converting the mpz to mpq. - Appropriate specializations of __gmp_expr are required. */ - - -#define __GMPZQ_DEFINE_EXPR(eval_fun) \ - \ -template <> \ -class __gmp_expr > \ -{ \ -private: \ - typedef mpz_class val1_type; \ - typedef mpq_class val2_type; \ - \ - __gmp_binary_expr expr; \ -public: \ - __gmp_expr(const val1_type &val1, const val2_type &val2) \ - : expr(val1, val2) { } \ - void eval(mpq_ptr q) const \ - { eval_fun::eval(q, expr.val1.get_mpz_t(), expr.val2.get_mpq_t()); } \ - const val1_type & get_val1() const { return expr.val1; } \ - const val2_type & get_val2() const { return expr.val2; } \ - unsigned long int get_prec() const { return mpf_get_default_prec(); } \ -}; \ - \ -template <> \ -class __gmp_expr > \ -{ \ -private: \ - typedef mpq_class val1_type; \ - typedef mpz_class val2_type; \ - \ - __gmp_binary_expr expr; \ -public: \ - __gmp_expr(const val1_type &val1, const val2_type &val2) \ - : expr(val1, val2) { } \ - void eval(mpq_ptr q) const \ - { eval_fun::eval(q, expr.val1.get_mpq_t(), expr.val2.get_mpz_t()); } \ - const val1_type & get_val1() const { return expr.val1; } \ - const val2_type & get_val2() const { return expr.val2; } \ - unsigned long int get_prec() const { return mpf_get_default_prec(); } \ -}; \ - \ -template \ -class __gmp_expr \ -, eval_fun> > \ -{ \ -private: \ - typedef mpz_class val1_type; \ - typedef __gmp_expr val2_type; \ - \ - __gmp_binary_expr expr; \ -public: \ - __gmp_expr(const val1_type &val1, const val2_type &val2) \ - : expr(val1, val2) { } \ - void eval(mpq_ptr q) const \ - { \ - mpq_class temp(expr.val2); \ - eval_fun::eval(q, expr.val1.get_mpz_t(), temp.get_mpq_t()); \ - } \ - const val1_type & get_val1() const { return expr.val1; } \ - const val2_type & get_val2() const { return expr.val2; } \ - unsigned long int get_prec() const { return mpf_get_default_prec(); } \ -}; \ - \ -template \ -class __gmp_expr \ -, eval_fun> > \ -{ \ -private: \ - typedef mpq_class val1_type; \ - typedef __gmp_expr val2_type; \ - \ - __gmp_binary_expr expr; \ -public: \ - __gmp_expr(const val1_type &val1, const val2_type &val2) \ - : expr(val1, val2) { } \ - void eval(mpq_ptr q) const \ - { \ - mpz_class temp(expr.val2); \ - eval_fun::eval(q, expr.val1.get_mpq_t(), temp.get_mpz_t()); \ - } \ - const val1_type & get_val1() const { return expr.val1; } \ - const val2_type & get_val2() const { return expr.val2; } \ - unsigned long int get_prec() const { return mpf_get_default_prec(); } \ -}; \ - \ -template \ -class __gmp_expr \ -, mpq_class, eval_fun> > \ -{ \ -private: \ - typedef __gmp_expr val1_type; \ - typedef mpq_class val2_type; \ - \ - __gmp_binary_expr expr; \ -public: \ - __gmp_expr(const val1_type &val1, const val2_type &val2) \ - : expr(val1, val2) { } \ - void eval(mpq_ptr q) const \ - { \ - mpz_class temp(expr.val1); \ - eval_fun::eval(q, temp.get_mpz_t(), expr.val2.get_mpq_t()); \ - } \ - const val1_type & get_val1() const { return expr.val1; } \ - const val2_type & get_val2() const { return expr.val2; } \ - unsigned long int get_prec() const { return mpf_get_default_prec(); } \ -}; \ - \ -template \ -class __gmp_expr \ -, mpz_class, eval_fun> > \ -{ \ -private: \ - typedef __gmp_expr val1_type; \ - typedef mpz_class val2_type; \ - \ - __gmp_binary_expr expr; \ -public: \ - __gmp_expr(const val1_type &val1, const val2_type &val2) \ - : expr(val1, val2) { } \ - void eval(mpq_ptr q) const \ - { \ - mpq_class temp(expr.val1); \ - eval_fun::eval(q, temp.get_mpq_t(), expr.val2.get_mpz_t()); \ - } \ - const val1_type & get_val1() const { return expr.val1; } \ - const val2_type & get_val2() const { return expr.val2; } \ - unsigned long int get_prec() const { return mpf_get_default_prec(); } \ -}; \ - \ -template \ -class __gmp_expr, __gmp_expr, eval_fun> > \ -{ \ -private: \ - typedef __gmp_expr val1_type; \ - typedef __gmp_expr val2_type; \ - \ - __gmp_binary_expr expr; \ -public: \ - __gmp_expr(const val1_type &val1, const val2_type &val2) \ - : expr(val1, val2) { } \ - void eval(mpq_ptr q) const \ - { \ - mpz_class temp1(expr.val1); \ - mpq_class temp2(expr.val2); \ - eval_fun::eval(q, temp1.get_mpz_t(), temp2.get_mpq_t()); \ - } \ - const val1_type & get_val1() const { return expr.val1; } \ - const val2_type & get_val2() const { return expr.val2; } \ - unsigned long int get_prec() const { return mpf_get_default_prec(); } \ -}; \ - \ -template \ -class __gmp_expr, __gmp_expr, eval_fun> > \ -{ \ -private: \ - typedef __gmp_expr val1_type; \ - typedef __gmp_expr val2_type; \ - \ - __gmp_binary_expr expr; \ -public: \ - __gmp_expr(const val1_type &val1, const val2_type &val2) \ - : expr(val1, val2) { } \ - void eval(mpq_ptr q) const \ - { \ - mpq_class temp1(expr.val1); \ - mpz_class temp2(expr.val2); \ - eval_fun::eval(q, temp1.get_mpq_t(), temp2.get_mpz_t()); \ - } \ - const val1_type & get_val1() const { return expr.val1; } \ - const val2_type & get_val2() const { return expr.val2; } \ - unsigned long int get_prec() const { return mpf_get_default_prec(); } \ -}; - - -__GMPZQ_DEFINE_EXPR(__gmp_binary_plus) -__GMPZQ_DEFINE_EXPR(__gmp_binary_minus) - -/**************** Macros for defining functions ****************/ -/* Results of operators and functions are instances of __gmp_expr. - T determines the numerical type of the expression: it can be either - mpz_t, mpq_t, or mpf_t. When the arguments of a binary - expression have different numerical types, __gmp_resolve_expr is used - to determine the "larger" type. - U is either __gmp_unary_expr or __gmp_binary_expr, - where V and W are the arguments' types -- they can in turn be - expressions, thus allowing to build compound expressions to any - degree of complexity. - Op is a function object that must have an eval() method accepting - appropriate arguments. - Actual evaluation of a __gmp_expr object is done when it gets - assigned to an mp*_class ("lazy" evaluation): this is done by calling - its eval() method. */ - - -// non-member unary operators and functions - -#define __GMP_DEFINE_UNARY_FUNCTION(fun, eval_fun) \ - \ -template \ -inline __gmp_expr, eval_fun> > \ -fun(const __gmp_expr &expr) \ -{ \ - return __gmp_expr, eval_fun> >(expr); \ -} - -#define __GMP_DEFINE_UNARY_TYPE_FUNCTION(type, fun, eval_fun) \ - \ -template \ -inline type fun(const __gmp_expr &expr) \ -{ \ - typename __gmp_resolve_temp::temp_type temp(expr); \ - return eval_fun::eval(temp.__get_mp()); \ -} - - -// non-member binary operators and functions - -#define __GMPP_DEFINE_BINARY_FUNCTION(fun, eval_fun) \ - \ -template \ -inline __gmp_expr::value_type, \ -__gmp_binary_expr<__gmp_expr, __gmp_expr, eval_fun> > \ -fun(const __gmp_expr &expr1, const __gmp_expr &expr2) \ -{ \ - return __gmp_expr::value_type, \ - __gmp_binary_expr<__gmp_expr, __gmp_expr, eval_fun> > \ - (expr1, expr2); \ -} - -#define __GMPNN_DEFINE_BINARY_FUNCTION(fun, eval_fun, type, bigtype) \ - \ -template \ -inline __gmp_expr \ -, bigtype, eval_fun> > \ -fun(const __gmp_expr &expr, type t) \ -{ \ - return __gmp_expr \ - , bigtype, eval_fun> >(expr, t); \ -} \ - \ -template \ -inline __gmp_expr \ -, eval_fun> > \ -fun(type t, const __gmp_expr &expr) \ -{ \ - return __gmp_expr \ - , eval_fun> >(t, expr); \ -} - -#define __GMPNS_DEFINE_BINARY_FUNCTION(fun, eval_fun, type) \ -__GMPNN_DEFINE_BINARY_FUNCTION(fun, eval_fun, type, signed long int) - -#define __GMPNU_DEFINE_BINARY_FUNCTION(fun, eval_fun, type) \ -__GMPNN_DEFINE_BINARY_FUNCTION(fun, eval_fun, type, unsigned long int) - -#define __GMPND_DEFINE_BINARY_FUNCTION(fun, eval_fun, type) \ -__GMPNN_DEFINE_BINARY_FUNCTION(fun, eval_fun, type, double) - -#define __GMPNLD_DEFINE_BINARY_FUNCTION(fun, eval_fun, type) \ -__GMPNN_DEFINE_BINARY_FUNCTION(fun, eval_fun, type, long double) - -#define __GMPN_DEFINE_BINARY_FUNCTION(fun, eval_fun) \ -__GMPNS_DEFINE_BINARY_FUNCTION(fun, eval_fun, signed char) \ -__GMPNU_DEFINE_BINARY_FUNCTION(fun, eval_fun, unsigned char) \ -__GMPNS_DEFINE_BINARY_FUNCTION(fun, eval_fun, signed int) \ -__GMPNU_DEFINE_BINARY_FUNCTION(fun, eval_fun, unsigned int) \ -__GMPNS_DEFINE_BINARY_FUNCTION(fun, eval_fun, signed short int) \ -__GMPNU_DEFINE_BINARY_FUNCTION(fun, eval_fun, unsigned short int) \ -__GMPNS_DEFINE_BINARY_FUNCTION(fun, eval_fun, signed long int) \ -__GMPNU_DEFINE_BINARY_FUNCTION(fun, eval_fun, unsigned long int) \ -__GMPND_DEFINE_BINARY_FUNCTION(fun, eval_fun, float) \ -__GMPND_DEFINE_BINARY_FUNCTION(fun, eval_fun, double) \ -__GMPNLD_DEFINE_BINARY_FUNCTION(fun, eval_fun, long double) - -#define __GMP_DEFINE_BINARY_FUNCTION(fun, eval_fun) \ -__GMPP_DEFINE_BINARY_FUNCTION(fun, eval_fun) \ -__GMPN_DEFINE_BINARY_FUNCTION(fun, eval_fun) - - -#define __GMP_DEFINE_BINARY_FUNCTION_UI(fun, eval_fun) \ - \ -template \ -inline __gmp_expr \ -, unsigned long int, eval_fun> > \ -fun(const __gmp_expr &expr, unsigned long int l) \ -{ \ - return __gmp_expr, unsigned long int, eval_fun> >(expr, l); \ -} - - -#define __GMPP_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun) \ - \ -template \ -inline type fun(const __gmp_expr &expr1, \ - const __gmp_expr &expr2) \ -{ \ - typedef typename __gmp_resolve_expr::value_type eval_type; \ - typename __gmp_resolve_temp::temp_type temp1(expr1); \ - typename __gmp_resolve_temp::temp_type temp2(expr2); \ - return eval_fun::eval(temp1.__get_mp(), temp2.__get_mp()); \ -} - -#define __GMPNN_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, \ - type2, bigtype) \ - \ -template \ -inline type fun(const __gmp_expr &expr, type2 t) \ -{ \ - typename __gmp_resolve_temp::temp_type temp(expr); \ - return eval_fun::eval(temp.__get_mp(), static_cast(t)); \ -} \ - \ -template \ -inline type fun(type2 t, const __gmp_expr &expr) \ -{ \ - typename __gmp_resolve_temp::temp_type temp(expr); \ - return eval_fun::eval(static_cast(t), temp.__get_mp()); \ -} - -#define __GMPNS_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, type2) \ -__GMPNN_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, \ - type2, signed long int) - -#define __GMPNU_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, type2) \ -__GMPNN_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, \ - type2, unsigned long int) - -#define __GMPND_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, type2) \ -__GMPNN_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, type2, double) - -#define __GMPNLD_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, type2) \ -__GMPNN_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, type2, long double) - -#define __GMPN_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun) \ -__GMPNS_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, signed char) \ -__GMPNU_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, unsigned char) \ -__GMPNS_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, signed int) \ -__GMPNU_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, unsigned int) \ -__GMPNS_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, signed short int) \ -__GMPNU_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, unsigned short int) \ -__GMPNS_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, signed long int) \ -__GMPNU_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, unsigned long int) \ -__GMPND_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, float) \ -__GMPND_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, double) \ -__GMPNLD_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, long double) - -#define __GMP_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun) \ -__GMPP_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun) \ -__GMPN_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun) - - -// member operators - -#define __GMPP_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun) \ - \ -template \ -inline type##_class & type##_class::fun(const __gmp_expr &expr) \ -{ \ - __gmp_set_expr(mp, __gmp_expr, eval_fun> >(*this, expr)); \ - return *this; \ -} - -#define __GMPNN_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, \ - type2, bigtype) \ - \ -inline type##_class & type##_class::fun(type2 t) \ -{ \ - __gmp_set_expr(mp, __gmp_expr >(*this, t)); \ - return *this; \ -} - -#define __GMPNS_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, type2) \ -__GMPNN_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, \ - type2, signed long int) - -#define __GMPNU_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, type2) \ -__GMPNN_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, \ - type2, unsigned long int) - -#define __GMPND_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, type2) \ -__GMPNN_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, type2, double) - -#define __GMPNLD_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, type2) \ -__GMPNN_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, type2, long double) - -#define __GMPN_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun) \ -__GMPNS_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, signed char) \ -__GMPNU_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, unsigned char) \ -__GMPNS_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, signed int) \ -__GMPNU_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, unsigned int) \ -__GMPNS_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, signed short int) \ -__GMPNU_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, unsigned short int) \ -__GMPNS_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, signed long int) \ -__GMPNU_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, unsigned long int) \ -__GMPND_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, float) \ -__GMPND_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, double) \ -/* __GMPNLD_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, long double) */ - -#define __GMP_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun) \ -__GMPP_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun) \ -__GMPN_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun) - -#define __GMPZ_DEFINE_COMPOUND_OPERATOR(fun, eval_fun) \ -__GMP_DEFINE_COMPOUND_OPERATOR(mpz, fun, eval_fun) - -#define __GMPZZ_DEFINE_COMPOUND_OPERATOR(fun, eval_fun) \ -__GMPP_DEFINE_COMPOUND_OPERATOR(mpz, fun, eval_fun) - -#define __GMPQ_DEFINE_COMPOUND_OPERATOR(fun, eval_fun) \ -__GMP_DEFINE_COMPOUND_OPERATOR(mpq, fun, eval_fun) - -#define __GMPF_DEFINE_COMPOUND_OPERATOR(fun, eval_fun) \ -__GMP_DEFINE_COMPOUND_OPERATOR(mpf, fun, eval_fun) - - - -#define __GMP_DEFINE_COMPOUND_OPERATOR_UI(type, fun, eval_fun) \ - \ -inline type##_class & type##_class::fun(unsigned long int l) \ -{ \ - __gmp_set_expr(mp, __gmp_expr >(*this, l)); \ - return *this; \ -} - -#define __GMPZ_DEFINE_COMPOUND_OPERATOR_UI(fun, eval_fun) \ -__GMP_DEFINE_COMPOUND_OPERATOR_UI(mpz, fun, eval_fun) - -#define __GMPQ_DEFINE_COMPOUND_OPERATOR_UI(fun, eval_fun) \ -__GMP_DEFINE_COMPOUND_OPERATOR_UI(mpq, fun, eval_fun) - -#define __GMPF_DEFINE_COMPOUND_OPERATOR_UI(fun, eval_fun) \ -__GMP_DEFINE_COMPOUND_OPERATOR_UI(mpf, fun, eval_fun) - - - -#define __GMP_DEFINE_INCREMENT_OPERATOR(type, fun, eval_fun) \ - \ -inline type##_class & type##_class::fun() \ -{ \ - eval_fun::eval(mp); \ - return *this; \ -} \ - \ -inline type##_class type##_class::fun(int) \ -{ \ - type##_class temp(*this); \ - eval_fun::eval(mp); \ - return temp; \ -} - -#define __GMPZ_DEFINE_INCREMENT_OPERATOR(fun, eval_fun) \ -__GMP_DEFINE_INCREMENT_OPERATOR(mpz, fun, eval_fun) - -#define __GMPQ_DEFINE_INCREMENT_OPERATOR(fun, eval_fun) \ -__GMP_DEFINE_INCREMENT_OPERATOR(mpq, fun, eval_fun) - -#define __GMPF_DEFINE_INCREMENT_OPERATOR(fun, eval_fun) \ -__GMP_DEFINE_INCREMENT_OPERATOR(mpf, fun, eval_fun) - - - -/**************** Arithmetic operators and functions ****************/ - -// non-member operators and functions - -__GMP_DEFINE_UNARY_FUNCTION(operator+, __gmp_unary_plus) -__GMP_DEFINE_UNARY_FUNCTION(operator-, __gmp_unary_minus) -__GMP_DEFINE_UNARY_FUNCTION(operator~, __gmp_unary_com) - -__GMP_DEFINE_BINARY_FUNCTION(operator+, __gmp_binary_plus) -__GMP_DEFINE_BINARY_FUNCTION(operator-, __gmp_binary_minus) -__GMP_DEFINE_BINARY_FUNCTION(operator*, __gmp_binary_multiplies) -__GMP_DEFINE_BINARY_FUNCTION(operator/, __gmp_binary_divides) -__GMP_DEFINE_BINARY_FUNCTION(operator%, __gmp_binary_modulus) -__GMP_DEFINE_BINARY_FUNCTION(operator&, __gmp_binary_and) -__GMP_DEFINE_BINARY_FUNCTION(operator|, __gmp_binary_ior) -__GMP_DEFINE_BINARY_FUNCTION(operator^, __gmp_binary_xor) - -__GMP_DEFINE_BINARY_FUNCTION_UI(operator<<, __gmp_binary_lshift) -__GMP_DEFINE_BINARY_FUNCTION_UI(operator>>, __gmp_binary_rshift) - -__GMP_DEFINE_BINARY_TYPE_FUNCTION(bool, operator==, __gmp_binary_equal) -__GMP_DEFINE_BINARY_TYPE_FUNCTION(bool, operator!=, __gmp_binary_not_equal) -__GMP_DEFINE_BINARY_TYPE_FUNCTION(bool, operator<, __gmp_binary_less) -__GMP_DEFINE_BINARY_TYPE_FUNCTION(bool, operator<=, __gmp_binary_less_equal) -__GMP_DEFINE_BINARY_TYPE_FUNCTION(bool, operator>, __gmp_binary_greater) -__GMP_DEFINE_BINARY_TYPE_FUNCTION(bool, operator>=, \ - __gmp_binary_greater_equal) - -__GMP_DEFINE_UNARY_FUNCTION(abs, __gmp_abs_function) -__GMP_DEFINE_UNARY_FUNCTION(trunc, __gmp_trunc_function) -__GMP_DEFINE_UNARY_FUNCTION(floor, __gmp_floor_function) -__GMP_DEFINE_UNARY_FUNCTION(ceil, __gmp_ceil_function) -__GMP_DEFINE_UNARY_FUNCTION(sqrt, __gmp_sqrt_function) -__GMP_DEFINE_BINARY_FUNCTION(hypot, __gmp_hypot_function) - -__GMP_DEFINE_UNARY_TYPE_FUNCTION(int, sgn, __gmp_sgn_function) -__GMP_DEFINE_BINARY_TYPE_FUNCTION(int, cmp, __gmp_cmp_function) - -// member operators for mpz_class - -__GMPZ_DEFINE_COMPOUND_OPERATOR(operator+=, __gmp_binary_plus) -__GMPZ_DEFINE_COMPOUND_OPERATOR(operator-=, __gmp_binary_minus) -__GMPZ_DEFINE_COMPOUND_OPERATOR(operator*=, __gmp_binary_multiplies) -__GMPZ_DEFINE_COMPOUND_OPERATOR(operator/=, __gmp_binary_divides) -__GMPZ_DEFINE_COMPOUND_OPERATOR(operator%=, __gmp_binary_modulus) - -__GMPZZ_DEFINE_COMPOUND_OPERATOR(operator&=, __gmp_binary_and) -__GMPZZ_DEFINE_COMPOUND_OPERATOR(operator|=, __gmp_binary_ior) -__GMPZZ_DEFINE_COMPOUND_OPERATOR(operator^=, __gmp_binary_xor) - -__GMPZ_DEFINE_COMPOUND_OPERATOR_UI(operator<<=, __gmp_binary_lshift) -__GMPZ_DEFINE_COMPOUND_OPERATOR_UI(operator>>=, __gmp_binary_rshift) - -__GMPZ_DEFINE_INCREMENT_OPERATOR(operator++, __gmp_unary_increment) -__GMPZ_DEFINE_INCREMENT_OPERATOR(operator--, __gmp_unary_decrement) - -// member operators for mpq_class - -__GMPQ_DEFINE_COMPOUND_OPERATOR(operator+=, __gmp_binary_plus) -__GMPQ_DEFINE_COMPOUND_OPERATOR(operator-=, __gmp_binary_minus) -__GMPQ_DEFINE_COMPOUND_OPERATOR(operator*=, __gmp_binary_multiplies) -__GMPQ_DEFINE_COMPOUND_OPERATOR(operator/=, __gmp_binary_divides) - -__GMPQ_DEFINE_COMPOUND_OPERATOR_UI(operator<<=, __gmp_binary_lshift) -__GMPQ_DEFINE_COMPOUND_OPERATOR_UI(operator>>=, __gmp_binary_rshift) - -__GMPQ_DEFINE_INCREMENT_OPERATOR(operator++, __gmp_unary_increment) -__GMPQ_DEFINE_INCREMENT_OPERATOR(operator--, __gmp_unary_decrement) - -// member operators for mpf_class - -__GMPF_DEFINE_COMPOUND_OPERATOR(operator+=, __gmp_binary_plus) -__GMPF_DEFINE_COMPOUND_OPERATOR(operator-=, __gmp_binary_minus) -__GMPF_DEFINE_COMPOUND_OPERATOR(operator*=, __gmp_binary_multiplies) -__GMPF_DEFINE_COMPOUND_OPERATOR(operator/=, __gmp_binary_divides) - -__GMPF_DEFINE_COMPOUND_OPERATOR_UI(operator<<=, __gmp_binary_lshift) -__GMPF_DEFINE_COMPOUND_OPERATOR_UI(operator>>=, __gmp_binary_rshift) - -__GMPF_DEFINE_INCREMENT_OPERATOR(operator++, __gmp_unary_increment) -__GMPF_DEFINE_INCREMENT_OPERATOR(operator--, __gmp_unary_decrement) - - - -/**************** Class wrapper for gmp_randstate_t ****************/ - -class __gmp_urandomb_value { }; -class __gmp_urandomm_value { }; - -template <> -class __gmp_expr -{ -private: - __gmp_randstate_struct *state; - unsigned long int bits; -public: - __gmp_expr(gmp_randstate_t s, unsigned long int l) : state(s), bits(l) { } - void eval(mpz_ptr z) const { __gmp_rand_function::eval(z, state, bits); } - unsigned long int get_prec() const { return mpf_get_default_prec(); } -}; - -template <> -class __gmp_expr -{ -private: - __gmp_randstate_struct *state; - mpz_class range; -public: - __gmp_expr(gmp_randstate_t s, const mpz_class &z) : state(s), range(z) { } - void eval(mpz_ptr z) const - { __gmp_rand_function::eval(z, state, range.get_mpz_t()); } - unsigned long int get_prec() const { return mpf_get_default_prec(); } -}; - -template <> -class __gmp_expr -{ -private: - __gmp_randstate_struct *state; - unsigned long int bits; -public: - __gmp_expr(gmp_randstate_t s, unsigned long int l) : state(s), bits(l) { } - void eval(mpf_ptr f, mp_bitcnt_t prec) const - { __gmp_rand_function::eval(f, state, (bits>0) ? get_prec() : prec); } - unsigned long int get_prec() const - { - if (bits == 0) - return mpf_get_default_prec(); - else - return bits; - } -}; - -extern "C" { - typedef void __gmp_randinit_default_t (gmp_randstate_t); - typedef void __gmp_randinit_lc_2exp_t (gmp_randstate_t, mpz_srcptr, unsigned long int, mp_bitcnt_t); - typedef int __gmp_randinit_lc_2exp_size_t (gmp_randstate_t, mp_bitcnt_t); -} - -class gmp_randclass -{ -private: - gmp_randstate_t state; - - // copy construction and assignment not allowed - gmp_randclass(const gmp_randclass &); - void operator=(const gmp_randclass &); -public: - // constructors and destructor - gmp_randclass(gmp_randalg_t alg, unsigned long int size) - { - switch (alg) - { - case GMP_RAND_ALG_LC: // no other cases for now - default: - gmp_randinit_lc_2exp_size(state, size); - break; - } - } - - // gmp_randinit_default - gmp_randclass(__gmp_randinit_default_t* f) { f(state); } - - // gmp_randinit_lc_2exp - gmp_randclass(__gmp_randinit_lc_2exp_t* f, - mpz_class z, unsigned long int l1, unsigned long int l2) - { f(state, z.get_mpz_t(), l1, l2); } - - // gmp_randinit_lc_2exp_size - gmp_randclass(__gmp_randinit_lc_2exp_size_t* f, - unsigned long int size) - { - if (f (state, size) == 0) - throw std::length_error ("gmp_randinit_lc_2exp_size"); - } - - ~gmp_randclass() { gmp_randclear(state); } - - // initialize - void seed(); // choose a random seed some way (?) - void seed(unsigned long int s) { gmp_randseed_ui(state, s); } - void seed(const mpz_class &z) { gmp_randseed(state, z.get_mpz_t()); } - - // get random number - __gmp_expr get_z_bits(unsigned long int l) - { return __gmp_expr(state, l); } - __gmp_expr get_z_bits(const mpz_class &z) - { return get_z_bits(z.get_ui()); } - - __gmp_expr get_z_range(const mpz_class &z) - { return __gmp_expr(state, z); } - - __gmp_expr get_f(unsigned long int prec = 0) - { return __gmp_expr(state, prec); } -}; - - -/**************** #undef all private macros ****************/ - -#undef __GMPP_DECLARE_COMPOUND_OPERATOR -#undef __GMPN_DECLARE_COMPOUND_OPERATOR -#undef __GMP_DECLARE_COMPOUND_OPERATOR -#undef __GMP_DECLARE_COMPOUND_OPERATOR_UI -#undef __GMP_DECLARE_INCREMENT_OPERATOR - -#undef __GMPZQ_DEFINE_EXPR -#undef __GMP_DEFINE_TERNARY_EXPR - -#undef __GMP_DEFINE_UNARY_FUNCTION -#undef __GMP_DEFINE_UNARY_TYPE_FUNCTION - -#undef __GMPP_DEFINE_BINARY_FUNCTION -#undef __GMPNN_DEFINE_BINARY_FUNCTION -#undef __GMPNS_DEFINE_BINARY_FUNCTION -#undef __GMPNU_DEFINE_BINARY_FUNCTION -#undef __GMPND_DEFINE_BINARY_FUNCTION -#undef __GMPNLD_DEFINE_BINARY_FUNCTION -#undef __GMPN_DEFINE_BINARY_FUNCTION -#undef __GMP_DEFINE_BINARY_FUNCTION - -#undef __GMP_DEFINE_BINARY_FUNCTION_UI - -#undef __GMPP_DEFINE_BINARY_TYPE_FUNCTION -#undef __GMPNN_DEFINE_BINARY_TYPE_FUNCTION -#undef __GMPNS_DEFINE_BINARY_TYPE_FUNCTION -#undef __GMPNU_DEFINE_BINARY_TYPE_FUNCTION -#undef __GMPND_DEFINE_BINARY_TYPE_FUNCTION -#undef __GMPNLD_DEFINE_BINARY_TYPE_FUNCTION -#undef __GMPN_DEFINE_BINARY_TYPE_FUNCTION -#undef __GMP_DEFINE_BINARY_TYPE_FUNCTION - -#undef __GMPP_DECLARE_COMPOUND_OPERATOR -#undef __GMPN_DECLARE_COMPOUND_OPERATOR -#undef __GMP_DECLARE_COMPOUND_OPERATOR - -#undef __GMP_DECLARE_COMPOUND_OPERATOR_UI -#undef __GMP_DECLARE_INCREMENT_OPERATOR - -#undef __GMPZ_DEFINE_COMPOUND_OPERATOR -#undef __GMPZZ_DEFINE_COMPOUND_OPERATOR -#undef __GMPZN_DEFINE_COMPOUND_OPERATOR -#undef __GMPZNN_DEFINE_COMPOUND_OPERATOR -#undef __GMPZNS_DEFINE_COMPOUND_OPERATOR -#undef __GMPZNU_DEFINE_COMPOUND_OPERATOR -#undef __GMPZND_DEFINE_COMPOUND_OPERATOR -#undef __GMPZNLD_DEFINE_COMPOUND_OPERATOR - -#undef __GMPP_DEFINE_COMPOUND_OPERATOR -#undef __GMPNN_DEFINE_COMPOUND_OPERATOR -#undef __GMPNS_DEFINE_COMPOUND_OPERATOR -#undef __GMPNU_DEFINE_COMPOUND_OPERATOR -#undef __GMPND_DEFINE_COMPOUND_OPERATOR -#undef __GMPNLD_DEFINE_COMPOUND_OPERATOR -#undef __GMPN_DEFINE_COMPOUND_OPERATOR -#undef __GMP_DEFINE_COMPOUND_OPERATOR - -#undef __GMPZ_DEFINE_COMPOUND_OPERATOR -#undef __GMPZZ_DEFINE_COMPOUND_OPERATOR -#undef __GMPQ_DEFINE_COMPOUND_OPERATOR -#undef __GMPF_DEFINE_COMPOUND_OPERATOR - -#undef __GMP_DEFINE_COMPOUND_OPERATOR_UI -#undef __GMPZ_DEFINE_COMPOUND_OPERATOR_UI -#undef __GMPQ_DEFINE_COMPOUND_OPERATOR_UI -#undef __GMPF_DEFINE_COMPOUND_OPERATOR_UI - -#undef __GMP_DEFINE_INCREMENT_OPERATOR -#undef __GMPZ_DEFINE_INCREMENT_OPERATOR -#undef __GMPQ_DEFINE_INCREMENT_OPERATOR -#undef __GMPF_DEFINE_INCREMENT_OPERATOR - -#endif /* __GMP_PLUSPLUS__ */ diff --git a/src/external/inc/win32-gcc/mpir-2.2.1/mpir.h b/src/external/inc/win32-gcc/mpir-2.2.1/mpir.h deleted file mode 100644 index 8c92d5118..000000000 --- a/src/external/inc/win32-gcc/mpir-2.2.1/mpir.h +++ /dev/null @@ -1,2390 +0,0 @@ -/* Definitions for GNU multiple precision functions. -*- mode: c -*- - -Copyright 1991, 1993, 1994, 1995, 1996, 1997, 1999, 2000, 2001, 2002, 2003, -2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc. - -Copyright 2008 William Hart, Gonzalo Tornaria - -This file is part of the MPIR Library. - -The MPIR Library is free software; you can redistribute it and/or modify -it under the terms of the GNU Lesser General Public License as published by -the Free Software Foundation; either version 3 of the License, or (at your -option) any later version. - -The MPIR Library is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public -License for more details. - -You should have received a copy of the GNU Lesser General Public License -along with the GNU MP Library. If not, see http://www.gnu.org/licenses/. */ - -#ifndef __GMP_H__ - -#if defined (__cplusplus) -#include /* for std::istream, std::ostream, std::string */ -#include -#endif - - -/* Instantiated by configure. */ -#if ! defined (__GMP_WITHIN_CONFIGURE) -#define __GMP_BITS_PER_MP_LIMB 32 -#define __GMP_HAVE_HOST_CPU_FAMILY_power 0 -#define __GMP_HAVE_HOST_CPU_FAMILY_powerpc 0 -#define GMP_LIMB_BITS 32 -#define GMP_NAIL_BITS 0 -#endif -#define GMP_NUMB_BITS (GMP_LIMB_BITS - GMP_NAIL_BITS) -#define GMP_NUMB_MASK ((~ __GMP_CAST (mp_limb_t, 0)) >> GMP_NAIL_BITS) -#define GMP_NUMB_MAX GMP_NUMB_MASK -#define GMP_NAIL_MASK (~ GMP_NUMB_MASK) - - -/* The following (everything under ifndef __GNU_MP__) must be identical in - mpir.h and mp.h to allow both to be included in an application or during - the library build. */ -#ifndef __GNU_MP__ -#define __GNU_MP__ 4 - -#define __need_size_t /* tell gcc stddef.h we only want size_t */ -#if defined (__cplusplus) -#include /* for size_t */ -#else -#include /* for size_t */ -#endif -#undef __need_size_t - -/* Instantiated by configure. */ -#if ! defined (__GMP_WITHIN_CONFIGURE) -/* #undef _LONG_LONG_LIMB */ -#define __GMP_LIBGMP_DLL 0 -#endif - -/* #if defined(__GMP_WITHIN_CONFIGURE) && defined(_WIN64) */ -#ifdef __WIN64 -#define _LONG_LONG_LIMB 1 -#endif - - -/* __STDC__ - some ANSI compilers define this only to 0, hence the use of - "defined" and not "__STDC__-0". In particular Sun workshop C 5.0 - sets __STDC__ to 0, but requires "##" for token pasting. - - _AIX - gnu ansidecl.h asserts that all known AIX compilers are ANSI but - don't always define __STDC__. - - __DECC - current versions of DEC C (5.9 for instance) for alpha are ANSI, - but don't define __STDC__ in their default mode. Don't know if old - versions might have been K&R, but let's not worry about that unless - someone is still using one. - - _mips - gnu ansidecl.h says the RISC/OS MIPS compiler is ANSI in SVR4 - mode, but doesn't define __STDC__. - - _MSC_VER - Microsoft C is ANSI, but __STDC__ is undefined unless the /Za - option is given (in which case it's 1). - - _WIN32 - tested for by gnu ansidecl.h, no doubt on the assumption that - all w32 compilers are ansi. - - Note: This same set of tests is used by gen-psqr.c and - demos/expr/expr-impl.h, so if anything needs adding, then be sure to - update those too. */ - -#if defined (__STDC__) \ - || defined (__cplusplus) \ - || defined (_AIX) \ - || defined (__DECC) \ - || (defined (__mips) && defined (_SYSTYPE_SVR4)) \ - || defined (_MSC_VER) \ - || defined (_WIN32) -#define __GMP_HAVE_CONST 1 -#define __GMP_HAVE_PROTOTYPES 1 -#define __GMP_HAVE_TOKEN_PASTE 1 -#else -#define __GMP_HAVE_CONST 0 -#define __GMP_HAVE_PROTOTYPES 0 -#define __GMP_HAVE_TOKEN_PASTE 0 -#endif - - -#if __GMP_HAVE_CONST -#define __gmp_const const -#define __gmp_signed signed -#else -#define __gmp_const -#define __gmp_signed -#endif - - -/* __GMP_DECLSPEC supports Windows DLL versions of libmpir, and is empty in - all other circumstances. - - When compiling objects for libmpir, __GMP_DECLSPEC is an export directive, - or when compiling for an application it's an import directive. The two - cases are differentiated by __GMP_WITHIN_GMP defined by the GMP Makefiles - (and not defined from an application). - - __GMP_DECLSPEC_XX is similarly used for libmpirxx. __GMP_WITHIN_GMPXX - indicates when building libmpirxx, and in that case libmpirxx functions are - exports, but libmpir functions which might get called are imports. - - libmp.la uses __GMP_DECLSPEC, just as if it were libmpir.la. libmpir and - libmp don't call each other, so there's no conflict or confusion. - - Libtool DLL_EXPORT define is not used. - - There's no attempt to support GMP built both static and DLL. Doing so - would mean applications would have to tell us which of the two is going - to be used when linking, and that seems very tedious and error prone if - using GMP by hand, and equally tedious from a package since autoconf and - automake don't give much help. - - __GMP_DECLSPEC is required on all documented global functions and - variables, the various internals in gmp-impl.h etc can be left unadorned. - But internals used by the test programs or speed measuring programs - should have __GMP_DECLSPEC, and certainly constants or variables must - have it or the wrong address will be resolved. - - In gcc __declspec can go at either the start or end of a prototype. - - In Microsoft C __declspec must go at the start, or after the type like - void __declspec(...) *foo()". There's no __dllexport or anything to - guard against someone foolish #defining dllexport. _export used to be - available, but no longer. - - In Borland C _export still exists, but needs to go after the type, like - "void _export foo();". Would have to change the __GMP_DECLSPEC syntax to - make use of that. Probably more trouble than it's worth. */ - -#if defined (__GNUC__) -#define __GMP_DECLSPEC_EXPORT __declspec(__dllexport__) -#define __GMP_DECLSPEC_IMPORT __declspec(__dllimport__) -#endif -#if defined (_MSC_VER) || defined (__BORLANDC__) -#define __GMP_DECLSPEC_EXPORT __declspec(dllexport) -#define __GMP_DECLSPEC_IMPORT __declspec(dllimport) -#endif -#ifdef __WATCOMC__ -#define __GMP_DECLSPEC_EXPORT __export -#define __GMP_DECLSPEC_IMPORT __import -#endif -#ifdef __IBMC__ -#define __GMP_DECLSPEC_EXPORT _Export -#define __GMP_DECLSPEC_IMPORT _Import -#endif - -#if __GMP_LIBGMP_DLL -#if __GMP_WITHIN_GMP -/* compiling to go into a DLL libmpir */ -#define __GMP_DECLSPEC __GMP_DECLSPEC_EXPORT -#else -/* compiling to go into an application which will link to a DLL libmpir */ -#define __GMP_DECLSPEC __GMP_DECLSPEC_IMPORT -#endif -#else -/* all other cases */ -#define __GMP_DECLSPEC -#endif - - -#ifdef __GMP_SHORT_LIMB -typedef unsigned int mp_limb_t; -typedef int mp_limb_signed_t; -#else -#ifdef _LONG_LONG_LIMB -typedef unsigned long long int mp_limb_t; -typedef long long int mp_limb_signed_t; -#else -typedef unsigned long int mp_limb_t; -typedef long int mp_limb_signed_t; -#endif -#endif - -#ifdef _WIN64 -typedef unsigned long long int mp_bitcnt_t; -#else -typedef unsigned long int mp_bitcnt_t; -#endif - -/* For reference, note that the name __mpz_struct gets into C++ mangled - function names, which means although the "__" suggests an internal, we - must leave this name for binary compatibility. */ -typedef struct -{ - int _mp_alloc; /* Number of *limbs* allocated and pointed - to by the _mp_d field. */ - int _mp_size; /* abs(_mp_size) is the number of limbs the - last field points to. If _mp_size is - negative this is a negative number. */ - mp_limb_t *_mp_d; /* Pointer to the limbs. */ -} __mpz_struct; - -#endif /* __GNU_MP__ */ - -typedef __mpz_struct mpz_t[1]; - -typedef mp_limb_t * mp_ptr; -typedef __gmp_const mp_limb_t * mp_srcptr; -#if defined( _WIN64) -#define __GMP_MP_SIZE_T_INT 0 -typedef long long int mp_size_t; -typedef long int mp_exp_t; -#else -#define __GMP_MP_SIZE_T_INT 0 -typedef long int mp_size_t; -typedef long int mp_exp_t; -#endif - -typedef struct -{ - __mpz_struct _mp_num; - __mpz_struct _mp_den; -} __mpq_struct; - -typedef __mpq_struct mpq_t[1]; - -typedef struct -{ - int _mp_prec; /* Max precision, in number of `mp_limb_t's. - Set by mpf_init and modified by - mpf_set_prec. The area pointed to by the - _mp_d field contains `prec' + 1 limbs. */ - int _mp_size; /* abs(_mp_size) is the number of limbs the - last field points to. If _mp_size is - negative this is a negative number. */ - mp_exp_t _mp_exp; /* Exponent, in the base of `mp_limb_t'. */ - mp_limb_t *_mp_d; /* Pointer to the limbs. */ -} __mpf_struct; - -typedef __mpf_struct mpf_t[1]; - -/* Available random number generation algorithms. */ -typedef enum -{ - GMP_RAND_ALG_DEFAULT = 0, - GMP_RAND_ALG_LC = GMP_RAND_ALG_DEFAULT /* Linear congruential. */ -} gmp_randalg_t; - -/* Random state struct. */ -typedef struct -{ - mpz_t _mp_seed; /* _mp_d member points to state of the generator. */ - gmp_randalg_t _mp_alg; /* Currently unused. */ - union { - void *_mp_lc; /* Pointer to function pointers structure. */ - } _mp_algdata; -} __gmp_randstate_struct; -typedef __gmp_randstate_struct gmp_randstate_t[1]; - -/* Types for function declarations in gmp files. */ -/* ??? Should not pollute user name space with these ??? */ -typedef __gmp_const __mpz_struct *mpz_srcptr; -typedef __mpz_struct *mpz_ptr; -typedef __gmp_const __mpf_struct *mpf_srcptr; -typedef __mpf_struct *mpf_ptr; -typedef __gmp_const __mpq_struct *mpq_srcptr; -typedef __mpq_struct *mpq_ptr; - - -/* This is not wanted in mp.h, so put it outside the __GNU_MP__ common - section. */ -#if __GMP_LIBGMP_DLL -#if __GMP_WITHIN_GMPXX -/* compiling to go into a DLL libmpirxx */ -#define __GMP_DECLSPEC_XX __GMP_DECLSPEC_EXPORT -#else -/* compiling to go into a application which will link to a DLL libmpirxx */ -#define __GMP_DECLSPEC_XX __GMP_DECLSPEC_IMPORT -#endif -#else -/* all other cases */ -#define __GMP_DECLSPEC_XX -#endif - - -#if __GMP_HAVE_PROTOTYPES -#define __GMP_PROTO(x) x -#else -#define __GMP_PROTO(x) () -#endif - -#ifndef __MPN -#if __GMP_HAVE_TOKEN_PASTE -#define __MPN(x) __gmpn_##x -#else -#define __MPN(x) __gmpn_/**/x -#endif -#endif - -/* For reference, "defined(EOF)" cannot be used here. In g++ 2.95.4, - defines EOF but not FILE. */ -#if defined (FILE) \ - || defined (H_STDIO) \ - || defined (_H_STDIO) /* AIX */ \ - || defined (_STDIO_H) /* glibc, Sun, SCO */ \ - || defined (_STDIO_H_) /* BSD, OSF */ \ - || defined (__STDIO_H) /* Borland */ \ - || defined (__STDIO_H__) /* IRIX */ \ - || defined (_STDIO_INCLUDED) /* HPUX */ \ - || defined (_FILE_DEFINED) /* Microsoft */ \ - || defined (__STDIO__) /* Apple MPW MrC */ \ - || defined (_MSL_STDIO_H) /* Metrowerks */ \ - || defined (_STDIO_H_INCLUDED) /* QNX4 */ \ - || defined (_ISO_STDIO_ISO_H) /* Sun C++ */ -#define _GMP_H_HAVE_FILE 1 -#endif - -/* In ISO C, if a prototype involving "struct obstack *" is given without - that structure defined, then the struct is scoped down to just the - prototype, causing a conflict if it's subsequently defined for real. So - only give prototypes if we've got obstack.h. */ -#if defined (_OBSTACK_H) /* glibc */ -#define _GMP_H_HAVE_OBSTACK 1 -#endif - -/* The prototypes for gmp_vprintf etc are provided only if va_list is - available, via an application having included or . - Usually va_list is a typedef so can't be tested directly, but C99 - specifies that va_start is a macro (and it was normally a macro on past - systems too), so look for that. - - will define some sort of va_list for vprintf and vfprintf, but - let's not bother trying to use that since it's not standard and since - application uses for gmp_vprintf etc will almost certainly require the - whole or anyway. */ - -#ifdef va_start -#define _GMP_H_HAVE_VA_LIST 1 -#endif - -/* Test for gcc >= maj.min, as per __GNUC_PREREQ in glibc */ -#if defined (__GNUC__) && defined (__GNUC_MINOR__) -#define __GMP_GNUC_PREREQ(maj, min) \ - ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min)) -#else -#define __GMP_GNUC_PREREQ(maj, min) 0 -#endif - -/* "pure" is in gcc 2.96 and up, see "(gcc)Function Attributes". Basically - it means a function does nothing but examine its arguments and memory - (global or via arguments) to generate a return value, but changes nothing - and has no side-effects. __GMP_NO_ATTRIBUTE_CONST_PURE lets - tune/common.c etc turn this off when trying to write timing loops. */ -#if __GMP_GNUC_PREREQ (2,96) && ! defined (__GMP_NO_ATTRIBUTE_CONST_PURE) -#define __GMP_ATTRIBUTE_PURE __attribute__ ((__pure__)) -#else -#define __GMP_ATTRIBUTE_PURE -#endif - - -/* __GMP_CAST allows us to use static_cast in C++, so our macros are clean - to "g++ -Wold-style-cast". - - Casts in "extern inline" code within an extern "C" block don't induce - these warnings, so __GMP_CAST only needs to be used on documented - macros. */ - -#ifdef __cplusplus -#define __GMP_CAST(type, expr) (static_cast (expr)) -#else -#define __GMP_CAST(type, expr) ((type) (expr)) -#endif - - -/* An empty "throw ()" means the function doesn't throw any C++ exceptions, - this can save some stack frame info in applications. - - Currently it's given only on functions which never divide-by-zero etc, - don't allocate memory, and are expected to never need to allocate memory. - This leaves open the possibility of a C++ throw from a future GMP - exceptions scheme. - - mpz_set_ui etc are omitted to leave open the lazy allocation scheme - described in doc/tasks.html. mpz_get_d etc are omitted to leave open - exceptions for float overflows. - - Note that __GMP_NOTHROW must be given on any inlines the same as on their - prototypes (for g++ at least, where they're used together). Note also - that g++ 3.0 demands that __GMP_NOTHROW is before other attributes like - __GMP_ATTRIBUTE_PURE. */ - -#if defined (__cplusplus) -#define __GMP_NOTHROW throw () -#else -#define __GMP_NOTHROW -#endif - -/* PORTME: What other compilers have a useful "extern inline"? "static - inline" would be an acceptable substitute if the compiler (or linker) - discards unused statics. */ - -/* gcc has __inline__ in all modes, including strict ansi. Give a prototype - for an inline too, so as to correctly specify "dllimport" on windows, in - case the function is called rather than inlined. */ - -#ifdef __GNUC__ -#if defined(__APPLE_CC__) && (__APPLE_CC__ != 1) /* FSF GCC sets this flag to 1 on Apple machines */ - -#if ! (__APPLE_CC__ >= 5465 && __STDC_VERSION__ >= 199901L) -#define __GMP_EXTERN_INLINE extern __inline__ -#define __GMP_INLINE_PROTOTYPES 1 -#endif - -#else /*GNU CC*/ - -#if defined(__GNUC_STDC_INLINE__) || defined (__GNUC_GNU_INLINE__) -#define __GMP_EXTERN_INLINE extern __inline__ __attribute__((__gnu_inline__)) -#else -#define __GMP_EXTERN_INLINE extern __inline__ -#endif -#define __GMP_INLINE_PROTOTYPES 1 - -#endif -#endif - -/* DEC C (eg. version 5.9) supports "static __inline foo()", even in -std1 - strict ANSI mode. Inlining is done even when not optimizing (ie. -O0 - mode, which is the default), but an unnecessary local copy of foo is - emitted unless -O is used. "extern __inline" is accepted, but the - "extern" appears to be ignored, ie. it becomes a plain global function - but which is inlined within its file. Don't know if all old versions of - DEC C supported __inline, but as a start let's do the right thing for - current versions. */ -#ifdef __DECC -#define __GMP_EXTERN_INLINE static __inline -#endif - -/* SCO OpenUNIX 8 cc supports "static inline foo()" but not in -Xc strict - ANSI mode (__STDC__ is 1 in that mode). Inlining only actually takes - place under -O. Without -O "foo" seems to be emitted whether it's used - or not, which is wasteful. "extern inline foo()" isn't useful, the - "extern" is apparently ignored, so foo is inlined if possible but also - emitted as a global, which causes multiple definition errors when - building a shared libmpir. */ -#ifdef __SCO_VERSION__ -#if __SCO_VERSION__ > 400000000 && __STDC__ != 1 \ - && ! defined (__GMP_EXTERN_INLINE) -#define __GMP_EXTERN_INLINE static inline -#endif -#endif - -#if defined _MSC_VER -#define __GMP_EXTERN_INLINE static __inline -#endif - -/* C++ always has "inline" and since it's a normal feature the linker should - discard duplicate non-inlined copies, or if it doesn't then that's a - problem for everyone, not just GMP. */ -#if defined (__cplusplus) && ! defined (__GMP_EXTERN_INLINE) -#define __GMP_EXTERN_INLINE inline -#endif - -/* Don't do any inlining within a configure run, since if the compiler ends - up emitting copies of the code into the object file it can end up - demanding the various support routines (like mpn_popcount) for linking, - making the "alloca" test and perhaps others fail. And on hppa ia64 a - pre-release gcc 3.2 was seen not respecting the "extern" in "extern - __inline__", triggering this problem too. */ -#if defined (__GMP_WITHIN_CONFIGURE) && ! __GMP_WITHIN_CONFIGURE_INLINE -#undef __GMP_EXTERN_INLINE -#endif - -/* By default, don't give a prototype when there's going to be an inline - version. Note in particular that Cray C++ objects to the combination of - prototype and inline. */ -#ifdef __GMP_EXTERN_INLINE -#ifndef __GMP_INLINE_PROTOTYPES -#define __GMP_INLINE_PROTOTYPES 0 -#endif -#else -#define __GMP_INLINE_PROTOTYPES 1 -#endif - - -#define __GMP_ABS(x) ((x) >= 0 ? (x) : -(x)) -#define __GMP_MAX(h,i) ((h) > (i) ? (h) : (i)) - -/* __GMP_USHRT_MAX is not "~ (unsigned short) 0" because short is promoted - to int by "~". */ -#define __GMP_UINT_MAX (~ (unsigned) 0) -#define __GMP_ULONG_MAX (~ (unsigned long) 0) -#define __GMP_USHRT_MAX ((unsigned short) ~0) - - -/* __builtin_expect is in gcc 3.0, and not in 2.95. */ -#if __GMP_GNUC_PREREQ (3,0) -#define __GMP_LIKELY(cond) __builtin_expect ((cond) != 0, 1) -#define __GMP_UNLIKELY(cond) __builtin_expect ((cond) != 0, 0) -#else -#define __GMP_LIKELY(cond) (cond) -#define __GMP_UNLIKELY(cond) (cond) -#endif - -/* Allow direct user access to numerator and denominator of a mpq_t object. */ -#define mpq_numref(Q) (&((Q)->_mp_num)) -#define mpq_denref(Q) (&((Q)->_mp_den)) - - -#if defined (__cplusplus) -extern "C" { -using std::FILE; -#endif - -#define mp_set_memory_functions __gmp_set_memory_functions -__GMP_DECLSPEC void mp_set_memory_functions __GMP_PROTO ((void *(*) (size_t), - void *(*) (void *, size_t, size_t), - void (*) (void *, size_t))) __GMP_NOTHROW; - -#define mp_get_memory_functions __gmp_get_memory_functions -__GMP_DECLSPEC void mp_get_memory_functions __GMP_PROTO ((void *(**) (size_t), - void *(**) (void *, size_t, size_t), - void (**) (void *, size_t))) __GMP_NOTHROW; - -#define mp_bits_per_limb __gmp_bits_per_limb -__GMP_DECLSPEC extern __gmp_const int mp_bits_per_limb; - -#define gmp_errno __gmp_errno -__GMP_DECLSPEC extern int gmp_errno; - -#define gmp_version __gmp_version -__GMP_DECLSPEC extern __gmp_const char * __gmp_const gmp_version; - -#define mpir_version __mpir_version -__GMP_DECLSPEC extern __gmp_const char * __gmp_const mpir_version; - - -/**************** Random number routines. ****************/ - -#define gmp_randinit_default __gmp_randinit_default -__GMP_DECLSPEC void gmp_randinit_default __GMP_PROTO ((gmp_randstate_t)); - -#define gmp_randinit_lc_2exp __gmp_randinit_lc_2exp -__GMP_DECLSPEC void gmp_randinit_lc_2exp __GMP_PROTO ((gmp_randstate_t, - mpz_srcptr, unsigned long int, - mp_bitcnt_t)); - -#define gmp_randinit_lc_2exp_size __gmp_randinit_lc_2exp_size -__GMP_DECLSPEC int gmp_randinit_lc_2exp_size __GMP_PROTO ((gmp_randstate_t, mp_bitcnt_t)); - -#define gmp_randinit_mt __gmp_randinit_mt -__GMP_DECLSPEC void gmp_randinit_mt __GMP_PROTO ((gmp_randstate_t)); - -#define gmp_randinit_set __gmp_randinit_set -__GMP_DECLSPEC void gmp_randinit_set __GMP_PROTO ((gmp_randstate_t, __gmp_const __gmp_randstate_struct *)); - -#define gmp_randseed __gmp_randseed -__GMP_DECLSPEC void gmp_randseed __GMP_PROTO ((gmp_randstate_t, mpz_srcptr)); - -#define gmp_randseed_ui __gmp_randseed_ui -__GMP_DECLSPEC void gmp_randseed_ui __GMP_PROTO ((gmp_randstate_t, unsigned long int)); - -#define gmp_randclear __gmp_randclear -__GMP_DECLSPEC void gmp_randclear __GMP_PROTO ((gmp_randstate_t)); - -#define gmp_urandomb_ui __gmp_urandomb_ui -__GMP_DECLSPEC unsigned long gmp_urandomb_ui __GMP_PROTO ((gmp_randstate_t, unsigned long)); - -#define gmp_urandomm_ui __gmp_urandomm_ui -__GMP_DECLSPEC unsigned long gmp_urandomm_ui __GMP_PROTO ((gmp_randstate_t, unsigned long)); - - -/**************** Formatted output routines. ****************/ - -#define gmp_asprintf __gmp_asprintf -__GMP_DECLSPEC int gmp_asprintf __GMP_PROTO ((char **, __gmp_const char *, ...)); - -#define gmp_fprintf __gmp_fprintf -#ifdef _GMP_H_HAVE_FILE -__GMP_DECLSPEC int gmp_fprintf __GMP_PROTO ((FILE *, __gmp_const char *, ...)); -#endif - -#define gmp_obstack_printf __gmp_obstack_printf -#if defined (_GMP_H_HAVE_OBSTACK) -__GMP_DECLSPEC int gmp_obstack_printf __GMP_PROTO ((struct obstack *, __gmp_const char *, ...)); -#endif - -#define gmp_obstack_vprintf __gmp_obstack_vprintf -#if defined (_GMP_H_HAVE_OBSTACK) && defined (_GMP_H_HAVE_VA_LIST) -__GMP_DECLSPEC int gmp_obstack_vprintf __GMP_PROTO ((struct obstack *, __gmp_const char *, va_list)); -#endif - -#define gmp_printf __gmp_printf -__GMP_DECLSPEC int gmp_printf __GMP_PROTO ((__gmp_const char *, ...)); - -#define gmp_snprintf __gmp_snprintf -__GMP_DECLSPEC int gmp_snprintf __GMP_PROTO ((char *, size_t, __gmp_const char *, ...)); - -#define gmp_sprintf __gmp_sprintf -__GMP_DECLSPEC int gmp_sprintf __GMP_PROTO ((char *, __gmp_const char *, ...)); - -#define gmp_vasprintf __gmp_vasprintf -#if defined (_GMP_H_HAVE_VA_LIST) -__GMP_DECLSPEC int gmp_vasprintf __GMP_PROTO ((char **, __gmp_const char *, va_list)); -#endif - -#define gmp_vfprintf __gmp_vfprintf -#if defined (_GMP_H_HAVE_FILE) && defined (_GMP_H_HAVE_VA_LIST) -__GMP_DECLSPEC int gmp_vfprintf __GMP_PROTO ((FILE *, __gmp_const char *, va_list)); -#endif - -#define gmp_vprintf __gmp_vprintf -#if defined (_GMP_H_HAVE_VA_LIST) -__GMP_DECLSPEC int gmp_vprintf __GMP_PROTO ((__gmp_const char *, va_list)); -#endif - -#define gmp_vsnprintf __gmp_vsnprintf -#if defined (_GMP_H_HAVE_VA_LIST) -__GMP_DECLSPEC int gmp_vsnprintf __GMP_PROTO ((char *, size_t, __gmp_const char *, va_list)); -#endif - -#define gmp_vsprintf __gmp_vsprintf -#if defined (_GMP_H_HAVE_VA_LIST) -__GMP_DECLSPEC int gmp_vsprintf __GMP_PROTO ((char *, __gmp_const char *, va_list)); -#endif - - -/**************** Formatted input routines. ****************/ - -#define gmp_fscanf __gmp_fscanf -#ifdef _GMP_H_HAVE_FILE -__GMP_DECLSPEC int gmp_fscanf __GMP_PROTO ((FILE *, __gmp_const char *, ...)); -#endif - -#define gmp_scanf __gmp_scanf -__GMP_DECLSPEC int gmp_scanf __GMP_PROTO ((__gmp_const char *, ...)); - -#define gmp_sscanf __gmp_sscanf -__GMP_DECLSPEC int gmp_sscanf __GMP_PROTO ((__gmp_const char *, __gmp_const char *, ...)); - -#define gmp_vfscanf __gmp_vfscanf -#if defined (_GMP_H_HAVE_FILE) && defined (_GMP_H_HAVE_VA_LIST) -__GMP_DECLSPEC int gmp_vfscanf __GMP_PROTO ((FILE *, __gmp_const char *, va_list)); -#endif - -#define gmp_vscanf __gmp_vscanf -#if defined (_GMP_H_HAVE_VA_LIST) -__GMP_DECLSPEC int gmp_vscanf __GMP_PROTO ((__gmp_const char *, va_list)); -#endif - -#define gmp_vsscanf __gmp_vsscanf -#if defined (_GMP_H_HAVE_VA_LIST) -__GMP_DECLSPEC int gmp_vsscanf __GMP_PROTO ((__gmp_const char *, __gmp_const char *, va_list)); -#endif - - -/**************** Integer (i.e. Z) routines. ****************/ - -#define __GMP_BITS_PER_ULONG (8*sizeof(unsigned long)) - -#define _mpz_realloc __gmpz_realloc -#define mpz_realloc __gmpz_realloc -__GMP_DECLSPEC void *_mpz_realloc __GMP_PROTO ((mpz_ptr, mp_size_t)); - -#define mpz_abs __gmpz_abs -#define __GMP_MPZ_ABS_MIN_ALLOC(x,y) (__GMP_ABS(y->_mp_size)) -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_abs) -__GMP_DECLSPEC void mpz_abs __GMP_PROTO ((mpz_ptr, mpz_srcptr)); -#endif - -#define __GMP_MPZ_ADD_MIN_ALLOC(x,y,z) (__GMP_MAX(__GMP_ABS(y->_mp_size),__GMP_ABS(z->_mp_size))+1) -#define mpz_add __gmpz_add -__GMP_DECLSPEC void mpz_add __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define __GMP_MPZ_ADD_UI_MIN_ALLOC(x,y,z) (__GMP_MAX(__GMP_ABS(y->_mp_size),1+(__GMP_BITS_PER_ULONG-1)/GMP_NUMB_BITS)+1) -#define mpz_add_ui __gmpz_add_ui -__GMP_DECLSPEC void mpz_add_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_addmul __gmpz_addmul -__GMP_DECLSPEC void mpz_addmul __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_addmul_ui __gmpz_addmul_ui -__GMP_DECLSPEC void mpz_addmul_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_and __gmpz_and -__GMP_DECLSPEC void mpz_and __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_array_init __gmpz_array_init -__GMP_DECLSPEC void mpz_array_init __GMP_PROTO ((mpz_ptr, mp_size_t, mp_size_t)); - -#define mpz_bin_ui __gmpz_bin_ui -__GMP_DECLSPEC void mpz_bin_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_bin_uiui __gmpz_bin_uiui -__GMP_DECLSPEC void mpz_bin_uiui __GMP_PROTO ((mpz_ptr, unsigned long int, unsigned long int)); - -#define mpz_cdiv_q __gmpz_cdiv_q -__GMP_DECLSPEC void mpz_cdiv_q __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_cdiv_q_2exp __gmpz_cdiv_q_2exp -__GMP_DECLSPEC void mpz_cdiv_q_2exp __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long)); - -#define mpz_cdiv_q_ui __gmpz_cdiv_q_ui -__GMP_DECLSPEC unsigned long int mpz_cdiv_q_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_cdiv_qr __gmpz_cdiv_qr -__GMP_DECLSPEC void mpz_cdiv_qr __GMP_PROTO ((mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_cdiv_qr_ui __gmpz_cdiv_qr_ui -__GMP_DECLSPEC unsigned long int mpz_cdiv_qr_ui __GMP_PROTO ((mpz_ptr, mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_cdiv_r __gmpz_cdiv_r -__GMP_DECLSPEC void mpz_cdiv_r __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_cdiv_r_2exp __gmpz_cdiv_r_2exp -__GMP_DECLSPEC void mpz_cdiv_r_2exp __GMP_PROTO ((mpz_ptr, mpz_srcptr, mp_bitcnt_t)); - -#define mpz_cdiv_r_ui __gmpz_cdiv_r_ui -__GMP_DECLSPEC unsigned long int mpz_cdiv_r_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_cdiv_ui __gmpz_cdiv_ui -__GMP_DECLSPEC unsigned long int mpz_cdiv_ui __GMP_PROTO ((mpz_srcptr, unsigned long int)) __GMP_ATTRIBUTE_PURE; - -#define mpz_clear __gmpz_clear -__GMP_DECLSPEC void mpz_clear __GMP_PROTO ((mpz_ptr)); - -#define mpz_clears __gmpz_clears -__GMP_DECLSPEC void mpz_clears __GMP_PROTO ((mpz_ptr, ...)); - -#define mpz_clrbit __gmpz_clrbit -__GMP_DECLSPEC void mpz_clrbit __GMP_PROTO ((mpz_ptr, mp_bitcnt_t)); - -#define mpz_cmp __gmpz_cmp -__GMP_DECLSPEC int mpz_cmp __GMP_PROTO ((mpz_srcptr, mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpz_cmp_d __gmpz_cmp_d -__GMP_DECLSPEC int mpz_cmp_d __GMP_PROTO ((mpz_srcptr, double)) __GMP_ATTRIBUTE_PURE; - -#define _mpz_cmp_si __gmpz_cmp_si -__GMP_DECLSPEC int _mpz_cmp_si __GMP_PROTO ((mpz_srcptr, signed long int)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define _mpz_cmp_ui __gmpz_cmp_ui -__GMP_DECLSPEC int _mpz_cmp_ui __GMP_PROTO ((mpz_srcptr, unsigned long int)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpz_cmpabs __gmpz_cmpabs -__GMP_DECLSPEC int mpz_cmpabs __GMP_PROTO ((mpz_srcptr, mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpz_cmpabs_d __gmpz_cmpabs_d -__GMP_DECLSPEC int mpz_cmpabs_d __GMP_PROTO ((mpz_srcptr, double)) __GMP_ATTRIBUTE_PURE; - -#define mpz_cmpabs_ui __gmpz_cmpabs_ui -__GMP_DECLSPEC int mpz_cmpabs_ui __GMP_PROTO ((mpz_srcptr, unsigned long int)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpz_com __gmpz_com -__GMP_DECLSPEC void mpz_com __GMP_PROTO ((mpz_ptr, mpz_srcptr)); - -#define mpz_combit __gmpz_combit -__GMP_DECLSPEC void mpz_combit __GMP_PROTO ((mpz_ptr, mp_bitcnt_t)); - -#define mpz_congruent_p __gmpz_congruent_p -__GMP_DECLSPEC int mpz_congruent_p __GMP_PROTO ((mpz_srcptr, mpz_srcptr, mpz_srcptr)) __GMP_ATTRIBUTE_PURE; - -#define mpz_congruent_2exp_p __gmpz_congruent_2exp_p -__GMP_DECLSPEC int mpz_congruent_2exp_p __GMP_PROTO ((mpz_srcptr, mpz_srcptr, mp_bitcnt_t)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpz_congruent_ui_p __gmpz_congruent_ui_p -__GMP_DECLSPEC int mpz_congruent_ui_p __GMP_PROTO ((mpz_srcptr, unsigned long, unsigned long)) __GMP_ATTRIBUTE_PURE; - -#define mpz_divexact __gmpz_divexact -__GMP_DECLSPEC void mpz_divexact __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_divexact_ui __gmpz_divexact_ui -__GMP_DECLSPEC void mpz_divexact_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long)); - -#define mpz_divisible_p __gmpz_divisible_p -__GMP_DECLSPEC int mpz_divisible_p __GMP_PROTO ((mpz_srcptr, mpz_srcptr)) __GMP_ATTRIBUTE_PURE; - -#define mpz_divisible_ui_p __gmpz_divisible_ui_p -__GMP_DECLSPEC int mpz_divisible_ui_p __GMP_PROTO ((mpz_srcptr, unsigned long)) __GMP_ATTRIBUTE_PURE; - -#define mpz_divisible_2exp_p __gmpz_divisible_2exp_p -__GMP_DECLSPEC int mpz_divisible_2exp_p __GMP_PROTO ((mpz_srcptr, mp_bitcnt_t)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpz_dump __gmpz_dump -__GMP_DECLSPEC void mpz_dump __GMP_PROTO ((mpz_srcptr)); - -#define mpz_export __gmpz_export -__GMP_DECLSPEC void *mpz_export __GMP_PROTO ((void *, size_t *, int, size_t, int, size_t, mpz_srcptr)); - -#define mpz_fac_ui __gmpz_fac_ui -__GMP_DECLSPEC void mpz_fac_ui __GMP_PROTO ((mpz_ptr, unsigned long int)); - -#define mpz_fdiv_q __gmpz_fdiv_q -__GMP_DECLSPEC void mpz_fdiv_q __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_fdiv_q_2exp __gmpz_fdiv_q_2exp -__GMP_DECLSPEC void mpz_fdiv_q_2exp __GMP_PROTO ((mpz_ptr, mpz_srcptr, mp_bitcnt_t)); - -#define mpz_fdiv_q_ui __gmpz_fdiv_q_ui -__GMP_DECLSPEC unsigned long int mpz_fdiv_q_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_fdiv_qr __gmpz_fdiv_qr -__GMP_DECLSPEC void mpz_fdiv_qr __GMP_PROTO ((mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_fdiv_qr_ui __gmpz_fdiv_qr_ui -__GMP_DECLSPEC unsigned long int mpz_fdiv_qr_ui __GMP_PROTO ((mpz_ptr, mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_fdiv_r __gmpz_fdiv_r -__GMP_DECLSPEC void mpz_fdiv_r __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_fdiv_r_2exp __gmpz_fdiv_r_2exp -__GMP_DECLSPEC void mpz_fdiv_r_2exp __GMP_PROTO ((mpz_ptr, mpz_srcptr, mp_bitcnt_t)); - -#define mpz_fdiv_r_ui __gmpz_fdiv_r_ui -__GMP_DECLSPEC unsigned long int mpz_fdiv_r_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_fdiv_ui __gmpz_fdiv_ui -__GMP_DECLSPEC unsigned long int mpz_fdiv_ui __GMP_PROTO ((mpz_srcptr, unsigned long int)) __GMP_ATTRIBUTE_PURE; - -#define mpz_fib_ui __gmpz_fib_ui -__GMP_DECLSPEC void mpz_fib_ui __GMP_PROTO ((mpz_ptr, unsigned long int)); - -#define mpz_fib2_ui __gmpz_fib2_ui -__GMP_DECLSPEC void mpz_fib2_ui __GMP_PROTO ((mpz_ptr, mpz_ptr, unsigned long int)); - -#define mpz_fits_sint_p __gmpz_fits_sint_p -__GMP_DECLSPEC int mpz_fits_sint_p __GMP_PROTO ((mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpz_fits_slong_p __gmpz_fits_slong_p -__GMP_DECLSPEC int mpz_fits_slong_p __GMP_PROTO ((mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpz_fits_sshort_p __gmpz_fits_sshort_p -__GMP_DECLSPEC int mpz_fits_sshort_p __GMP_PROTO ((mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpz_fits_uint_p __gmpz_fits_uint_p -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_fits_uint_p) -__GMP_DECLSPEC int mpz_fits_uint_p __GMP_PROTO ((mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#endif - -#define mpz_fits_ulong_p __gmpz_fits_ulong_p -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_fits_ulong_p) -__GMP_DECLSPEC int mpz_fits_ulong_p __GMP_PROTO ((mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#endif - -#define mpz_fits_ushort_p __gmpz_fits_ushort_p -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_fits_ushort_p) -__GMP_DECLSPEC int mpz_fits_ushort_p __GMP_PROTO ((mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#endif - -#define mpz_gcd __gmpz_gcd -__GMP_DECLSPEC void mpz_gcd __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_gcd_ui __gmpz_gcd_ui -__GMP_DECLSPEC unsigned long int mpz_gcd_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_gcdext __gmpz_gcdext -__GMP_DECLSPEC void mpz_gcdext __GMP_PROTO ((mpz_ptr, mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_get_d __gmpz_get_d -__GMP_DECLSPEC double mpz_get_d __GMP_PROTO ((mpz_srcptr)) __GMP_ATTRIBUTE_PURE; - -#define mpz_get_d_2exp __gmpz_get_d_2exp -__GMP_DECLSPEC double mpz_get_d_2exp __GMP_PROTO ((signed long int *, mpz_srcptr)); - -#define mpz_get_si __gmpz_get_si -__GMP_DECLSPEC /* signed */ long int mpz_get_si __GMP_PROTO ((mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpz_get_str __gmpz_get_str -__GMP_DECLSPEC char *mpz_get_str __GMP_PROTO ((char *, int, mpz_srcptr)); - -#define mpz_get_ui __gmpz_get_ui -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_get_ui) -__GMP_DECLSPEC unsigned long int mpz_get_ui __GMP_PROTO ((mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#endif - -#define mpz_getlimbn __gmpz_getlimbn -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_getlimbn) -__GMP_DECLSPEC mp_limb_t mpz_getlimbn __GMP_PROTO ((mpz_srcptr, mp_size_t)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#endif - -#define mpz_hamdist __gmpz_hamdist -__GMP_DECLSPEC mp_bitcnt_t mpz_hamdist __GMP_PROTO ((mpz_srcptr, mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpz_import __gmpz_import -__GMP_DECLSPEC void mpz_import __GMP_PROTO ((mpz_ptr, size_t, int, size_t, int, size_t, __gmp_const void *)); - -#define mpz_init __gmpz_init -__GMP_DECLSPEC void mpz_init __GMP_PROTO ((mpz_ptr)); - -#define mpz_init2 __gmpz_init2 -__GMP_DECLSPEC void mpz_init2 __GMP_PROTO ((mpz_ptr, mp_bitcnt_t)); - -#define mpz_inits __gmpz_inits -__GMP_DECLSPEC void mpz_inits __GMP_PROTO ((mpz_ptr, ...)); - -#define mpz_init_set __gmpz_init_set -__GMP_DECLSPEC void mpz_init_set __GMP_PROTO ((mpz_ptr, mpz_srcptr)); - -#define mpz_init_set_d __gmpz_init_set_d -__GMP_DECLSPEC void mpz_init_set_d __GMP_PROTO ((mpz_ptr, double)); - -#define mpz_init_set_si __gmpz_init_set_si -__GMP_DECLSPEC void mpz_init_set_si __GMP_PROTO ((mpz_ptr, signed long int)); - -#define mpz_init_set_str __gmpz_init_set_str -__GMP_DECLSPEC int mpz_init_set_str __GMP_PROTO ((mpz_ptr, __gmp_const char *, int)); - -#define mpz_init_set_ui __gmpz_init_set_ui -__GMP_DECLSPEC void mpz_init_set_ui __GMP_PROTO ((mpz_ptr, unsigned long int)); - -#define mpz_inp_raw __gmpz_inp_raw -#ifdef _GMP_H_HAVE_FILE -__GMP_DECLSPEC size_t mpz_inp_raw __GMP_PROTO ((mpz_ptr, FILE *)); -#endif - -#define mpz_inp_str __gmpz_inp_str -#ifdef _GMP_H_HAVE_FILE -__GMP_DECLSPEC size_t mpz_inp_str __GMP_PROTO ((mpz_ptr, FILE *, int)); -#endif - -#define mpz_invert __gmpz_invert -__GMP_DECLSPEC int mpz_invert __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_ior __gmpz_ior -__GMP_DECLSPEC void mpz_ior __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_jacobi __gmpz_jacobi -__GMP_DECLSPEC int mpz_jacobi __GMP_PROTO ((mpz_srcptr, mpz_srcptr)) __GMP_ATTRIBUTE_PURE; - -#define mpz_kronecker mpz_jacobi /* alias */ - -#define mpz_kronecker_si __gmpz_kronecker_si -__GMP_DECLSPEC int mpz_kronecker_si __GMP_PROTO ((mpz_srcptr, long)) __GMP_ATTRIBUTE_PURE; - -#define mpz_kronecker_ui __gmpz_kronecker_ui -__GMP_DECLSPEC int mpz_kronecker_ui __GMP_PROTO ((mpz_srcptr, unsigned long)) __GMP_ATTRIBUTE_PURE; - -#define mpz_si_kronecker __gmpz_si_kronecker -__GMP_DECLSPEC int mpz_si_kronecker __GMP_PROTO ((long, mpz_srcptr)) __GMP_ATTRIBUTE_PURE; - -#define mpz_ui_kronecker __gmpz_ui_kronecker -__GMP_DECLSPEC int mpz_ui_kronecker __GMP_PROTO ((unsigned long, mpz_srcptr)) __GMP_ATTRIBUTE_PURE; - -#define mpz_lcm __gmpz_lcm -__GMP_DECLSPEC void mpz_lcm __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_lcm_ui __gmpz_lcm_ui -__GMP_DECLSPEC void mpz_lcm_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long)); - -#define mpz_legendre mpz_jacobi /* alias */ - -#define mpz_lucnum_ui __gmpz_lucnum_ui -__GMP_DECLSPEC void mpz_lucnum_ui __GMP_PROTO ((mpz_ptr, unsigned long int)); - -#define mpz_lucnum2_ui __gmpz_lucnum2_ui -__GMP_DECLSPEC void mpz_lucnum2_ui __GMP_PROTO ((mpz_ptr, mpz_ptr, unsigned long int)); - -#define mpz_millerrabin __gmpz_millerrabin -__GMP_DECLSPEC int mpz_millerrabin __GMP_PROTO ((mpz_srcptr, int)) __GMP_ATTRIBUTE_PURE; - -#define mpz_mod __gmpz_mod -__GMP_DECLSPEC void mpz_mod __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_mod_ui mpz_fdiv_r_ui /* same as fdiv_r because divisor unsigned */ - -#define __GMP_MPZ_MUL_MIN_ALLOC(x,y,z) (__GMP_ABS(y->_mp_size)+__GMP_ABS(z->_mp_size)+1) -#define mpz_mul __gmpz_mul -__GMP_DECLSPEC void mpz_mul __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_mul_2exp __gmpz_mul_2exp -__GMP_DECLSPEC void mpz_mul_2exp __GMP_PROTO ((mpz_ptr, mpz_srcptr, mp_bitcnt_t)); - -#define __GMP_MPZ_MUL_SI_MIN_ALLOC(x,y,z) (__GMP_ABS(y->_mp_size)+(__GMP_BITS_PER_ULONG-1)/GMP_NUMB_BITS+1) -#define mpz_mul_si __gmpz_mul_si -__GMP_DECLSPEC void mpz_mul_si __GMP_PROTO ((mpz_ptr, mpz_srcptr, long int)); - -#define __GMP_MPZ_MUL_UI_MIN_ALLOC(x,y,z) (__GMP_ABS(y->_mp_size)+(__GMP_BITS_PER_ULONG-1)/GMP_NUMB_BITS+1) -#define mpz_mul_ui __gmpz_mul_ui -__GMP_DECLSPEC void mpz_mul_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_neg __gmpz_neg -#define __GMP_MPZ_NEG_MIN_ALLOC(x,y) (__GMP_ABS(y->_mp_size)) -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_neg) -__GMP_DECLSPEC void mpz_neg __GMP_PROTO ((mpz_ptr, mpz_srcptr)); -#endif - -#define mpz_nextprime __gmpz_nextprime -__GMP_DECLSPEC void mpz_nextprime __GMP_PROTO ((mpz_ptr, mpz_srcptr)); - -#define mpz_next_likely_prime __gmpz_next_likely_prime -__GMP_DECLSPEC void mpz_next_likely_prime __GMP_PROTO ((mpz_ptr, mpz_srcptr,gmp_randstate_t)); - -#define mpz_out_raw __gmpz_out_raw -#ifdef _GMP_H_HAVE_FILE -__GMP_DECLSPEC size_t mpz_out_raw __GMP_PROTO ((FILE *, mpz_srcptr)); -#endif - -#define mpz_out_str __gmpz_out_str -#ifdef _GMP_H_HAVE_FILE -__GMP_DECLSPEC size_t mpz_out_str __GMP_PROTO ((FILE *, int, mpz_srcptr)); -#endif - -#define mpz_perfect_power_p __gmpz_perfect_power_p -__GMP_DECLSPEC int mpz_perfect_power_p __GMP_PROTO ((mpz_srcptr)) __GMP_ATTRIBUTE_PURE; - -#define mpz_perfect_square_p __gmpz_perfect_square_p -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_perfect_square_p) -__GMP_DECLSPEC int mpz_perfect_square_p __GMP_PROTO ((mpz_srcptr)) __GMP_ATTRIBUTE_PURE; -#endif - -#define mpz_popcount __gmpz_popcount -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_popcount) -__GMP_DECLSPEC mp_bitcnt_t mpz_popcount __GMP_PROTO ((mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#endif - -#define mpz_pow_ui __gmpz_pow_ui -__GMP_DECLSPEC void mpz_pow_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_powm __gmpz_powm -__GMP_DECLSPEC void mpz_powm __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_powm_ui __gmpz_powm_ui -__GMP_DECLSPEC void mpz_powm_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int, mpz_srcptr)); - -#define mpz_probab_prime_p __gmpz_probab_prime_p -__GMP_DECLSPEC int mpz_probab_prime_p __GMP_PROTO ((mpz_srcptr, int)) __GMP_ATTRIBUTE_PURE; - -#define mpz_probable_prime_p __gmpz_probable_prime_p -__GMP_DECLSPEC int mpz_probable_prime_p __GMP_PROTO ((mpz_srcptr,gmp_randstate_t, int,unsigned long)); - -#define mpz_likely_prime_p __gmpz_likely_prime_p -__GMP_DECLSPEC int mpz_likely_prime_p __GMP_PROTO ((mpz_srcptr,gmp_randstate_t, unsigned long)); - -#define mpz_realloc2 __gmpz_realloc2 -__GMP_DECLSPEC void mpz_realloc2 __GMP_PROTO ((mpz_ptr, mp_bitcnt_t)); - -#define mpz_remove __gmpz_remove -__GMP_DECLSPEC unsigned long int mpz_remove __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_root __gmpz_root -__GMP_DECLSPEC int mpz_root __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_nthroot __gmpz_nthroot -__GMP_DECLSPEC void mpz_nthroot __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_rootrem __gmpz_rootrem -__GMP_DECLSPEC void mpz_rootrem __GMP_PROTO ((mpz_ptr,mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_rrandomb __gmpz_rrandomb -__GMP_DECLSPEC void mpz_rrandomb __GMP_PROTO ((mpz_ptr, gmp_randstate_t, mp_bitcnt_t)); - -#define mpz_scan0 __gmpz_scan0 -__GMP_DECLSPEC mp_bitcnt_t mpz_scan0 __GMP_PROTO ((mpz_srcptr, mp_bitcnt_t)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpz_scan1 __gmpz_scan1 -__GMP_DECLSPEC mp_bitcnt_t mpz_scan1 __GMP_PROTO ((mpz_srcptr, mp_bitcnt_t)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define __GMP_MPZ_SET_MIN_ALLOC(x,y) __GMP_ABS(y->_mp_size) -#define mpz_set __gmpz_set -__GMP_DECLSPEC void mpz_set __GMP_PROTO ((mpz_ptr, mpz_srcptr)); - -#define mpz_set_d __gmpz_set_d -__GMP_DECLSPEC void mpz_set_d __GMP_PROTO ((mpz_ptr, double)); - -#define mpz_set_f __gmpz_set_f -__GMP_DECLSPEC void mpz_set_f __GMP_PROTO ((mpz_ptr, mpf_srcptr)); - -#define mpz_set_q __gmpz_set_q -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_set_q) -__GMP_DECLSPEC void mpz_set_q __GMP_PROTO ((mpz_ptr, mpq_srcptr)); -#endif - -#define __GMP_MPZ_SET_SI_MIN_ALLOC(x,y) (1+(__GMP_BITS_PER_ULONG-1)/GMP_NUMB_BITS) -#define mpz_set_si __gmpz_set_si -__GMP_DECLSPEC void mpz_set_si __GMP_PROTO ((mpz_ptr, signed long int)); - -#define mpz_set_str __gmpz_set_str -__GMP_DECLSPEC int mpz_set_str __GMP_PROTO ((mpz_ptr, __gmp_const char *, int)); - -#define __GMP_MPZ_SET_UI_MIN_ALLOC(x,y) (1+(__GMP_BITS_PER_ULONG-1)/GMP_NUMB_BITS) -#define mpz_set_ui __gmpz_set_ui -__GMP_DECLSPEC void mpz_set_ui __GMP_PROTO ((mpz_ptr, unsigned long int)); - -#define mpz_setbit __gmpz_setbit -__GMP_DECLSPEC void mpz_setbit __GMP_PROTO ((mpz_ptr, mp_bitcnt_t)); - -#define mpz_size __gmpz_size -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_size) -__GMP_DECLSPEC size_t mpz_size __GMP_PROTO ((mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#endif - -#define mpz_sizeinbase __gmpz_sizeinbase -__GMP_DECLSPEC size_t mpz_sizeinbase __GMP_PROTO ((mpz_srcptr, int)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpz_sqrt __gmpz_sqrt -__GMP_DECLSPEC void mpz_sqrt __GMP_PROTO ((mpz_ptr, mpz_srcptr)); - -#define mpz_sqrtrem __gmpz_sqrtrem -__GMP_DECLSPEC void mpz_sqrtrem __GMP_PROTO ((mpz_ptr, mpz_ptr, mpz_srcptr)); - -#define __GMP_MPZ_SUB_MIN_ALLOC(x,y,z) (__GMP_MAX(__GMP_ABS(y->_mp_size),__GMP_ABS(z->_mp_size))+1) -#define mpz_sub __gmpz_sub -__GMP_DECLSPEC void mpz_sub __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define __GMP_MPZ_SUB_UI_MIN_ALLOC(x,y,z) (__GMP_MAX(__GMP_ABS(y->_mp_size),1+(__GMP_BITS_PER_ULONG-1)/GMP_NUMB_BITS)+1) -#define mpz_sub_ui __gmpz_sub_ui -__GMP_DECLSPEC void mpz_sub_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); - -#define __GMP_MPZ_UI_SUB_MIN_ALLOC(x,y,z) (__GMP_MAX(__GMP_ABS(z->_mp_size),1+(__GMP_BITS_PER_ULONG-1)/GMP_NUMB_BITS)+1) -#define mpz_ui_sub __gmpz_ui_sub -__GMP_DECLSPEC void mpz_ui_sub __GMP_PROTO ((mpz_ptr, unsigned long int, mpz_srcptr)); - -#define mpz_submul __gmpz_submul -__GMP_DECLSPEC void mpz_submul __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_submul_ui __gmpz_submul_ui -__GMP_DECLSPEC void mpz_submul_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_swap __gmpz_swap -__GMP_DECLSPEC void mpz_swap __GMP_PROTO ((mpz_ptr, mpz_ptr)) __GMP_NOTHROW; - -#define mpz_tdiv_ui __gmpz_tdiv_ui -__GMP_DECLSPEC unsigned long int mpz_tdiv_ui __GMP_PROTO ((mpz_srcptr, unsigned long int)) __GMP_ATTRIBUTE_PURE; - -#define mpz_tdiv_q __gmpz_tdiv_q -__GMP_DECLSPEC void mpz_tdiv_q __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_tdiv_q_2exp __gmpz_tdiv_q_2exp -__GMP_DECLSPEC void mpz_tdiv_q_2exp __GMP_PROTO ((mpz_ptr, mpz_srcptr, mp_bitcnt_t)); - -#define mpz_tdiv_q_ui __gmpz_tdiv_q_ui -__GMP_DECLSPEC unsigned long int mpz_tdiv_q_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_tdiv_qr __gmpz_tdiv_qr -__GMP_DECLSPEC void mpz_tdiv_qr __GMP_PROTO ((mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_tdiv_qr_ui __gmpz_tdiv_qr_ui -__GMP_DECLSPEC unsigned long int mpz_tdiv_qr_ui __GMP_PROTO ((mpz_ptr, mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_tdiv_r __gmpz_tdiv_r -__GMP_DECLSPEC void mpz_tdiv_r __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - -#define mpz_tdiv_r_2exp __gmpz_tdiv_r_2exp -__GMP_DECLSPEC void mpz_tdiv_r_2exp __GMP_PROTO ((mpz_ptr, mpz_srcptr, mp_bitcnt_t)); - -#define mpz_tdiv_r_ui __gmpz_tdiv_r_ui -__GMP_DECLSPEC unsigned long int mpz_tdiv_r_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); - -#define mpz_tstbit __gmpz_tstbit -__GMP_DECLSPEC int mpz_tstbit __GMP_PROTO ((mpz_srcptr, mp_bitcnt_t)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpz_ui_pow_ui __gmpz_ui_pow_ui -__GMP_DECLSPEC void mpz_ui_pow_ui __GMP_PROTO ((mpz_ptr, unsigned long int, unsigned long int)); - -#define mpz_urandomb __gmpz_urandomb -__GMP_DECLSPEC void mpz_urandomb __GMP_PROTO ((mpz_ptr, gmp_randstate_t, mp_bitcnt_t)); - -#define mpz_urandomm __gmpz_urandomm -__GMP_DECLSPEC void mpz_urandomm __GMP_PROTO ((mpz_ptr, gmp_randstate_t, mpz_srcptr)); - -#define mpz_xor __gmpz_xor -#define mpz_eor __gmpz_xor -__GMP_DECLSPEC void mpz_xor __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); - - -/**************** Rational (i.e. Q) routines. ****************/ - -#define mpq_abs __gmpq_abs -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpq_abs) -__GMP_DECLSPEC void mpq_abs __GMP_PROTO ((mpq_ptr, mpq_srcptr)); -#endif - -#define mpq_add __gmpq_add -__GMP_DECLSPEC void mpq_add __GMP_PROTO ((mpq_ptr, mpq_srcptr, mpq_srcptr)); - -#define mpq_canonicalize __gmpq_canonicalize -__GMP_DECLSPEC void mpq_canonicalize __GMP_PROTO ((mpq_ptr)); - -#define mpq_clear __gmpq_clear -__GMP_DECLSPEC void mpq_clear __GMP_PROTO ((mpq_ptr)); - -#define mpq_clears __gmpq_clears -__GMP_DECLSPEC void mpq_clears __GMP_PROTO ((mpq_ptr, ...)); - -#define mpq_cmp __gmpq_cmp -__GMP_DECLSPEC int mpq_cmp __GMP_PROTO ((mpq_srcptr, mpq_srcptr)) __GMP_ATTRIBUTE_PURE; - -#define _mpq_cmp_si __gmpq_cmp_si -__GMP_DECLSPEC int _mpq_cmp_si __GMP_PROTO ((mpq_srcptr, long, unsigned long)) __GMP_ATTRIBUTE_PURE; - -#define _mpq_cmp_ui __gmpq_cmp_ui -__GMP_DECLSPEC int _mpq_cmp_ui __GMP_PROTO ((mpq_srcptr, unsigned long int, unsigned long int)) __GMP_ATTRIBUTE_PURE; - -#define mpq_div __gmpq_div -__GMP_DECLSPEC void mpq_div __GMP_PROTO ((mpq_ptr, mpq_srcptr, mpq_srcptr)); - -#define mpq_div_2exp __gmpq_div_2exp -__GMP_DECLSPEC void mpq_div_2exp __GMP_PROTO ((mpq_ptr, mpq_srcptr, mp_bitcnt_t)); - -#define mpq_equal __gmpq_equal -__GMP_DECLSPEC int mpq_equal __GMP_PROTO ((mpq_srcptr, mpq_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpq_get_num __gmpq_get_num -__GMP_DECLSPEC void mpq_get_num __GMP_PROTO ((mpz_ptr, mpq_srcptr)); - -#define mpq_get_den __gmpq_get_den -__GMP_DECLSPEC void mpq_get_den __GMP_PROTO ((mpz_ptr, mpq_srcptr)); - -#define mpq_get_d __gmpq_get_d -__GMP_DECLSPEC double mpq_get_d __GMP_PROTO ((mpq_srcptr)) __GMP_ATTRIBUTE_PURE; - -#define mpq_get_str __gmpq_get_str -__GMP_DECLSPEC char *mpq_get_str __GMP_PROTO ((char *, int, mpq_srcptr)); - -#define mpq_init __gmpq_init -__GMP_DECLSPEC void mpq_init __GMP_PROTO ((mpq_ptr)); - -#define mpq_inits __gmpq_inits -__GMP_DECLSPEC void mpq_inits __GMP_PROTO ((mpq_ptr, ...)); - -#define mpq_inp_str __gmpq_inp_str -#ifdef _GMP_H_HAVE_FILE -__GMP_DECLSPEC size_t mpq_inp_str __GMP_PROTO ((mpq_ptr, FILE *, int)); -#endif - -#define mpq_inv __gmpq_inv -__GMP_DECLSPEC void mpq_inv __GMP_PROTO ((mpq_ptr, mpq_srcptr)); - -#define mpq_mul __gmpq_mul -__GMP_DECLSPEC void mpq_mul __GMP_PROTO ((mpq_ptr, mpq_srcptr, mpq_srcptr)); - -#define mpq_mul_2exp __gmpq_mul_2exp -__GMP_DECLSPEC void mpq_mul_2exp __GMP_PROTO ((mpq_ptr, mpq_srcptr, mp_bitcnt_t)); - -#define mpq_neg __gmpq_neg -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpq_neg) -__GMP_DECLSPEC void mpq_neg __GMP_PROTO ((mpq_ptr, mpq_srcptr)); -#endif - -#define mpq_out_str __gmpq_out_str -#ifdef _GMP_H_HAVE_FILE -__GMP_DECLSPEC size_t mpq_out_str __GMP_PROTO ((FILE *, int, mpq_srcptr)); -#endif - -#define mpq_set __gmpq_set -__GMP_DECLSPEC void mpq_set __GMP_PROTO ((mpq_ptr, mpq_srcptr)); - -#define mpq_set_d __gmpq_set_d -__GMP_DECLSPEC void mpq_set_d __GMP_PROTO ((mpq_ptr, double)); - -#define mpq_set_den __gmpq_set_den -__GMP_DECLSPEC void mpq_set_den __GMP_PROTO ((mpq_ptr, mpz_srcptr)); - -#define mpq_set_f __gmpq_set_f -__GMP_DECLSPEC void mpq_set_f __GMP_PROTO ((mpq_ptr, mpf_srcptr)); - -#define mpq_set_num __gmpq_set_num -__GMP_DECLSPEC void mpq_set_num __GMP_PROTO ((mpq_ptr, mpz_srcptr)); - -#define mpq_set_si __gmpq_set_si -__GMP_DECLSPEC void mpq_set_si __GMP_PROTO ((mpq_ptr, signed long int, unsigned long int)); - -#define mpq_set_str __gmpq_set_str -__GMP_DECLSPEC int mpq_set_str __GMP_PROTO ((mpq_ptr, __gmp_const char *, int)); - -#define mpq_set_ui __gmpq_set_ui -__GMP_DECLSPEC void mpq_set_ui __GMP_PROTO ((mpq_ptr, unsigned long int, unsigned long int)); - -#define mpq_set_z __gmpq_set_z -__GMP_DECLSPEC void mpq_set_z __GMP_PROTO ((mpq_ptr, mpz_srcptr)); - -#define mpq_sub __gmpq_sub -__GMP_DECLSPEC void mpq_sub __GMP_PROTO ((mpq_ptr, mpq_srcptr, mpq_srcptr)); - -#define mpq_swap __gmpq_swap -__GMP_DECLSPEC void mpq_swap __GMP_PROTO ((mpq_ptr, mpq_ptr)) __GMP_NOTHROW; - - -/**************** Float (i.e. F) routines. ****************/ - -#define mpf_abs __gmpf_abs -__GMP_DECLSPEC void mpf_abs __GMP_PROTO ((mpf_ptr, mpf_srcptr)); - -#define mpf_add __gmpf_add -__GMP_DECLSPEC void mpf_add __GMP_PROTO ((mpf_ptr, mpf_srcptr, mpf_srcptr)); - -#define mpf_add_ui __gmpf_add_ui -__GMP_DECLSPEC void mpf_add_ui __GMP_PROTO ((mpf_ptr, mpf_srcptr, unsigned long int)); -#define mpf_ceil __gmpf_ceil -__GMP_DECLSPEC void mpf_ceil __GMP_PROTO ((mpf_ptr, mpf_srcptr)); - -#define mpf_clear __gmpf_clear -__GMP_DECLSPEC void mpf_clear __GMP_PROTO ((mpf_ptr)); - -#define mpf_clears __gmpf_clears -__GMP_DECLSPEC void mpf_clears __GMP_PROTO ((mpf_ptr, ...)); - -#define mpf_cmp __gmpf_cmp -__GMP_DECLSPEC int mpf_cmp __GMP_PROTO ((mpf_srcptr, mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpf_cmp_d __gmpf_cmp_d -__GMP_DECLSPEC int mpf_cmp_d __GMP_PROTO ((mpf_srcptr, double)) __GMP_ATTRIBUTE_PURE; - -#define mpf_cmp_si __gmpf_cmp_si -__GMP_DECLSPEC int mpf_cmp_si __GMP_PROTO ((mpf_srcptr, signed long int)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpf_cmp_ui __gmpf_cmp_ui -__GMP_DECLSPEC int mpf_cmp_ui __GMP_PROTO ((mpf_srcptr, unsigned long int)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpf_div __gmpf_div -__GMP_DECLSPEC void mpf_div __GMP_PROTO ((mpf_ptr, mpf_srcptr, mpf_srcptr)); - -#define mpf_div_2exp __gmpf_div_2exp -__GMP_DECLSPEC void mpf_div_2exp __GMP_PROTO ((mpf_ptr, mpf_srcptr, mp_bitcnt_t)); - -#define mpf_div_ui __gmpf_div_ui -__GMP_DECLSPEC void mpf_div_ui __GMP_PROTO ((mpf_ptr, mpf_srcptr, unsigned long int)); - -#define mpf_dump __gmpf_dump -__GMP_DECLSPEC void mpf_dump __GMP_PROTO ((mpf_srcptr)); - -#define mpf_eq __gmpf_eq -__GMP_DECLSPEC int mpf_eq __GMP_PROTO ((mpf_srcptr, mpf_srcptr, unsigned long int)) __GMP_ATTRIBUTE_PURE; - -#define mpf_fits_sint_p __gmpf_fits_sint_p -__GMP_DECLSPEC int mpf_fits_sint_p __GMP_PROTO ((mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpf_fits_slong_p __gmpf_fits_slong_p -__GMP_DECLSPEC int mpf_fits_slong_p __GMP_PROTO ((mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpf_fits_sshort_p __gmpf_fits_sshort_p -__GMP_DECLSPEC int mpf_fits_sshort_p __GMP_PROTO ((mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpf_fits_uint_p __gmpf_fits_uint_p -__GMP_DECLSPEC int mpf_fits_uint_p __GMP_PROTO ((mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpf_fits_ulong_p __gmpf_fits_ulong_p -__GMP_DECLSPEC int mpf_fits_ulong_p __GMP_PROTO ((mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpf_fits_ushort_p __gmpf_fits_ushort_p -__GMP_DECLSPEC int mpf_fits_ushort_p __GMP_PROTO ((mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpf_floor __gmpf_floor -__GMP_DECLSPEC void mpf_floor __GMP_PROTO ((mpf_ptr, mpf_srcptr)); - -#define mpf_get_d __gmpf_get_d -__GMP_DECLSPEC double mpf_get_d __GMP_PROTO ((mpf_srcptr)) __GMP_ATTRIBUTE_PURE; - -#define mpf_get_d_2exp __gmpf_get_d_2exp -__GMP_DECLSPEC double mpf_get_d_2exp __GMP_PROTO ((signed long int *, mpf_srcptr)); - -#define mpf_get_default_prec __gmpf_get_default_prec -__GMP_DECLSPEC mp_bitcnt_t mpf_get_default_prec __GMP_PROTO ((void)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpf_get_prec __gmpf_get_prec -__GMP_DECLSPEC mp_bitcnt_t mpf_get_prec __GMP_PROTO ((mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpf_get_si __gmpf_get_si -__GMP_DECLSPEC long mpf_get_si __GMP_PROTO ((mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpf_get_str __gmpf_get_str -__GMP_DECLSPEC char *mpf_get_str __GMP_PROTO ((char *, mp_exp_t *, int, size_t, mpf_srcptr)); - -#define mpf_get_ui __gmpf_get_ui -__GMP_DECLSPEC unsigned long mpf_get_ui __GMP_PROTO ((mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpf_init __gmpf_init -__GMP_DECLSPEC void mpf_init __GMP_PROTO ((mpf_ptr)); - -#define mpf_init2 __gmpf_init2 -__GMP_DECLSPEC void mpf_init2 __GMP_PROTO ((mpf_ptr, mp_bitcnt_t)); - -#define mpf_inits __gmpf_inits -__GMP_DECLSPEC void mpf_inits __GMP_PROTO ((mpf_ptr, ...)); - -#define mpf_init_set __gmpf_init_set -__GMP_DECLSPEC void mpf_init_set __GMP_PROTO ((mpf_ptr, mpf_srcptr)); - -#define mpf_init_set_d __gmpf_init_set_d -__GMP_DECLSPEC void mpf_init_set_d __GMP_PROTO ((mpf_ptr, double)); - -#define mpf_init_set_si __gmpf_init_set_si -__GMP_DECLSPEC void mpf_init_set_si __GMP_PROTO ((mpf_ptr, signed long int)); - -#define mpf_init_set_str __gmpf_init_set_str -__GMP_DECLSPEC int mpf_init_set_str __GMP_PROTO ((mpf_ptr, __gmp_const char *, int)); - -#define mpf_init_set_ui __gmpf_init_set_ui -__GMP_DECLSPEC void mpf_init_set_ui __GMP_PROTO ((mpf_ptr, unsigned long int)); - -#define mpf_inp_str __gmpf_inp_str -#ifdef _GMP_H_HAVE_FILE -__GMP_DECLSPEC size_t mpf_inp_str __GMP_PROTO ((mpf_ptr, FILE *, int)); -#endif - -#define mpf_integer_p __gmpf_integer_p -__GMP_DECLSPEC int mpf_integer_p __GMP_PROTO ((mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpf_mul __gmpf_mul -__GMP_DECLSPEC void mpf_mul __GMP_PROTO ((mpf_ptr, mpf_srcptr, mpf_srcptr)); - -#define mpf_mul_2exp __gmpf_mul_2exp -__GMP_DECLSPEC void mpf_mul_2exp __GMP_PROTO ((mpf_ptr, mpf_srcptr, mp_bitcnt_t)); - -#define mpf_mul_ui __gmpf_mul_ui -__GMP_DECLSPEC void mpf_mul_ui __GMP_PROTO ((mpf_ptr, mpf_srcptr, unsigned long int)); - -#define mpf_neg __gmpf_neg -__GMP_DECLSPEC void mpf_neg __GMP_PROTO ((mpf_ptr, mpf_srcptr)); - -#define mpf_out_str __gmpf_out_str -#ifdef _GMP_H_HAVE_FILE -__GMP_DECLSPEC size_t mpf_out_str __GMP_PROTO ((FILE *, int, size_t, mpf_srcptr)); -#endif - -#define mpf_pow_ui __gmpf_pow_ui -__GMP_DECLSPEC void mpf_pow_ui __GMP_PROTO ((mpf_ptr, mpf_srcptr, unsigned long int)); - -#define mpf_random2 __gmpf_random2 -__GMP_DECLSPEC void mpf_random2 __GMP_PROTO ((mpf_ptr, mp_size_t, mp_exp_t)); - -#define mpf_rrandomb __gmpf_rrandomb -__GMP_DECLSPEC void mpf_rrandomb __GMP_PROTO ((mpf_ptr, gmp_randstate_t, mp_size_t, mp_exp_t)); - -#define mpf_reldiff __gmpf_reldiff -__GMP_DECLSPEC void mpf_reldiff __GMP_PROTO ((mpf_ptr, mpf_srcptr, mpf_srcptr)); - -#define mpf_set __gmpf_set -__GMP_DECLSPEC void mpf_set __GMP_PROTO ((mpf_ptr, mpf_srcptr)); - -#define mpf_set_d __gmpf_set_d -__GMP_DECLSPEC void mpf_set_d __GMP_PROTO ((mpf_ptr, double)); - -#define mpf_set_default_prec __gmpf_set_default_prec -__GMP_DECLSPEC void mpf_set_default_prec __GMP_PROTO ((mp_bitcnt_t)) __GMP_NOTHROW; - -#define mpf_set_prec __gmpf_set_prec -__GMP_DECLSPEC void mpf_set_prec __GMP_PROTO ((mpf_ptr, mp_bitcnt_t)); - -#define mpf_set_prec_raw __gmpf_set_prec_raw -__GMP_DECLSPEC void mpf_set_prec_raw __GMP_PROTO ((mpf_ptr, mp_bitcnt_t)) __GMP_NOTHROW; - -#define mpf_set_q __gmpf_set_q -__GMP_DECLSPEC void mpf_set_q __GMP_PROTO ((mpf_ptr, mpq_srcptr)); - -#define mpf_set_si __gmpf_set_si -__GMP_DECLSPEC void mpf_set_si __GMP_PROTO ((mpf_ptr, signed long int)); - -#define mpf_set_str __gmpf_set_str -__GMP_DECLSPEC int mpf_set_str __GMP_PROTO ((mpf_ptr, __gmp_const char *, int)); - -#define mpf_set_ui __gmpf_set_ui -__GMP_DECLSPEC void mpf_set_ui __GMP_PROTO ((mpf_ptr, unsigned long int)); - -#define mpf_set_z __gmpf_set_z -__GMP_DECLSPEC void mpf_set_z __GMP_PROTO ((mpf_ptr, mpz_srcptr)); - -#define mpf_size __gmpf_size -__GMP_DECLSPEC size_t mpf_size __GMP_PROTO ((mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpf_sqrt __gmpf_sqrt -__GMP_DECLSPEC void mpf_sqrt __GMP_PROTO ((mpf_ptr, mpf_srcptr)); - -#define mpf_sqrt_ui __gmpf_sqrt_ui -__GMP_DECLSPEC void mpf_sqrt_ui __GMP_PROTO ((mpf_ptr, unsigned long int)); - -#define mpf_sub __gmpf_sub -__GMP_DECLSPEC void mpf_sub __GMP_PROTO ((mpf_ptr, mpf_srcptr, mpf_srcptr)); - -#define mpf_sub_ui __gmpf_sub_ui -__GMP_DECLSPEC void mpf_sub_ui __GMP_PROTO ((mpf_ptr, mpf_srcptr, unsigned long int)); - -#define mpf_swap __gmpf_swap -__GMP_DECLSPEC void mpf_swap __GMP_PROTO ((mpf_ptr, mpf_ptr)) __GMP_NOTHROW; - -#define mpf_trunc __gmpf_trunc -__GMP_DECLSPEC void mpf_trunc __GMP_PROTO ((mpf_ptr, mpf_srcptr)); - -#define mpf_ui_div __gmpf_ui_div -__GMP_DECLSPEC void mpf_ui_div __GMP_PROTO ((mpf_ptr, unsigned long int, mpf_srcptr)); - -#define mpf_ui_sub __gmpf_ui_sub -__GMP_DECLSPEC void mpf_ui_sub __GMP_PROTO ((mpf_ptr, unsigned long int, mpf_srcptr)); - -#define mpf_urandomb __gmpf_urandomb -__GMP_DECLSPEC void mpf_urandomb __GMP_PROTO ((mpf_t, gmp_randstate_t, mp_bitcnt_t)); - - -/************ Low level positive-integer (i.e. N) routines. ************/ - -/* This is ugly, but we need to make user calls reach the prefixed function. */ - -#define mpn_add __MPN(add) -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpn_add) -__GMP_DECLSPEC mp_limb_t mpn_add __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_srcptr,mp_size_t)); -#endif - -#define mpn_add_1 __MPN(add_1) -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpn_add_1) -__GMP_DECLSPEC mp_limb_t mpn_add_1 __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_limb_t)) __GMP_NOTHROW; -#endif - -#define mpn_add_n __MPN(add_n) -__GMP_DECLSPEC mp_limb_t mpn_add_n __GMP_PROTO ((mp_ptr, mp_srcptr, mp_srcptr, mp_size_t)); - -#define mpn_addmul_1 __MPN(addmul_1) -__GMP_DECLSPEC mp_limb_t mpn_addmul_1 __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_limb_t)); - -#define mpn_bdivmod __MPN(bdivmod) -__GMP_DECLSPEC mp_limb_t mpn_bdivmod __GMP_PROTO ((mp_ptr, mp_ptr, mp_size_t, mp_srcptr, mp_size_t, unsigned long int)); - -#define mpn_divrem __MPN(divrem) -__GMP_DECLSPEC mp_limb_t mpn_divrem __GMP_PROTO ((mp_ptr, mp_size_t, mp_ptr, mp_size_t, mp_srcptr, mp_size_t)); - -#define mpn_mulmod_2expp1 __MPN(mulmod_2expp1) -__GMP_DECLSPEC int mpn_mulmod_2expp1 __GMP_PROTO ((mp_ptr, mp_srcptr, mp_srcptr,int,unsigned long, mp_ptr)); - -#define mpn_mulmod_2expm1 __MPN(mulmod_2expm1) -__GMP_DECLSPEC void mpn_mulmod_2expm1 __GMP_PROTO ((mp_ptr, mp_ptr, mp_ptr,unsigned long, mp_ptr)); - -#define mpn_cmp __MPN(cmp) -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpn_cmp) -__GMP_DECLSPEC int mpn_cmp __GMP_PROTO ((mp_srcptr, mp_srcptr, mp_size_t)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#endif - -#define mpn_divexact_by3(dst,src,size) \ - mpn_divexact_by3c (dst, src, size, __GMP_CAST (mp_limb_t, 0)) - -#define mpn_divexact_by3c __MPN(divexact_by3c) -__GMP_DECLSPEC mp_limb_t mpn_divexact_by3c __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_limb_t)); - -#define mpn_divmod_1(qp,np,nsize,dlimb) \ - mpn_divrem_1 (qp, __GMP_CAST (mp_size_t, 0), np, nsize, dlimb) - -#define mpn_divrem_1 __MPN(divrem_1) -__GMP_DECLSPEC mp_limb_t mpn_divrem_1 __GMP_PROTO ((mp_ptr, mp_size_t, mp_srcptr, mp_size_t, mp_limb_t)); - -#define mpn_divrem_2 __MPN(divrem_2) -__GMP_DECLSPEC mp_limb_t mpn_divrem_2 __GMP_PROTO ((mp_ptr, mp_size_t, mp_ptr, mp_size_t, mp_srcptr)); - -#define mpn_invert __MPN(invert) -__GMP_DECLSPEC void mpn_invert __GMP_PROTO ((mp_ptr xp, mp_srcptr ap, mp_size_t n)); - -#define mpn_sb_divappr_q __MPN(sb_divappr_q) -__GMP_DECLSPEC mp_limb_t mpn_sb_divappr_q __GMP_PROTO ((mp_ptr qp, mp_ptr np, mp_size_t nn, - mp_srcptr dp, mp_size_t dn, mp_limb_t dip)); - -#define mpn_dc_divappr_q_n __MPN(dc_divappr_q_n) -__GMP_DECLSPEC mp_limb_t mpn_dc_divappr_q_n __GMP_PROTO ((mp_ptr qp, mp_ptr np, mp_srcptr dp, mp_size_t n, - mp_limb_t dip, mp_ptr tp)); - -#define mpn_dc_bdiv_q_n __MPN(dc_bdiv_q_n) -__GMP_DECLSPEC void mpn_dc_bdiv_q_n __GMP_PROTO ((mp_ptr qp, mp_ptr wp, mp_ptr np, mp_srcptr dp, mp_size_t n, - mp_limb_t dinv, mp_ptr scratch)); - -#define mpn_inv_divappr_q_n __MPN(inv_divappr_q_n) -__GMP_DECLSPEC mp_limb_t mpn_inv_divappr_q_n __GMP_PROTO ((mp_ptr qp, mp_ptr np, mp_srcptr dp, mp_size_t n, - mp_srcptr dip)); - -#define mpn_dc_divappr_q __MPN(dc_divappr_q) -__GMP_DECLSPEC mp_limb_t mpn_dc_divappr_q __GMP_PROTO ((mp_ptr qp, mp_ptr np, mp_size_t nn, mp_srcptr dp, mp_size_t n, - mp_limb_t dinv)); - -#define mpn_dc_div_q __MPN(dc_div_q) -__GMP_DECLSPEC mp_limb_t mpn_dc_div_q __GMP_PROTO ((mp_ptr qp, mp_ptr np, mp_size_t nn, - mp_srcptr dp, mp_size_t dn, mp_limb_t dinv)); - -#define mpn_inv_divappr_q __MPN(inv_divappr_q) -__GMP_DECLSPEC mp_limb_t mpn_inv_divappr_q __GMP_PROTO ((mp_ptr qp, mp_ptr np, mp_size_t nn, mp_srcptr dp, mp_size_t n, - mp_srcptr dinv)); - -#define mpn_inv_div_q __MPN(inv_div_q) -__GMP_DECLSPEC mp_limb_t mpn_inv_div_q __GMP_PROTO ((mp_ptr qp, mp_ptr np, mp_size_t nn, - mp_srcptr dp, mp_size_t dn, mp_srcptr dinv)); - -#define mpn_inv_div_qr __MPN(inv_div_qr) -__GMP_DECLSPEC mp_limb_t mpn_inv_div_qr __GMP_PROTO ((mp_ptr qp, mp_ptr np, mp_size_t nn, - mp_srcptr dp, mp_size_t dn, mp_srcptr dinv)); - -#define mpn_inv_div_qr_n __MPN(inv_div_qr_n) -__GMP_DECLSPEC mp_limb_t mpn_inv_div_qr_n __GMP_PROTO ((mp_ptr qp, mp_ptr np, - mp_srcptr dp, mp_size_t dn, mp_srcptr dinv)); - -#define mpn_dc_div_qr __MPN(dc_div_qr) -__GMP_DECLSPEC mp_limb_t mpn_dc_div_qr __GMP_PROTO ((mp_ptr qp, mp_ptr np, mp_size_t nn, - mp_srcptr dp, mp_size_t dn, mp_limb_t dinv)); - -#define mpn_dc_div_qr_n __MPN(dc_div_qr_n) -__GMP_DECLSPEC mp_limb_t mpn_dc_div_qr_n __GMP_PROTO ((mp_ptr qp, mp_ptr np, mp_srcptr dp, mp_size_t n, - mp_limb_t dinv, mp_ptr tp)); - -#define mpn_sb_div_q __MPN(sb_div_q) -__GMP_DECLSPEC mp_limb_t mpn_sb_div_q __GMP_PROTO ((mp_ptr qp, mp_ptr np, mp_size_t nn, - mp_srcptr dp, mp_size_t dn, mp_limb_t dinv)); - -#define mpn_sb_bdiv_q __MPN(sb_bdiv_q) -__GMP_DECLSPEC void mpn_sb_bdiv_q __GMP_PROTO ((mp_ptr qp, mp_ptr wp, mp_ptr np, mp_size_t nn, - mp_srcptr dp, mp_size_t dn, mp_limb_t dinv)); - -#define mpn_dc_bdiv_q __MPN(dc_bdiv_q) -__GMP_DECLSPEC void mpn_dc_bdiv_q __GMP_PROTO ((mp_ptr qp, mp_ptr np, mp_size_t nn, - mp_srcptr dp, mp_size_t dn, mp_limb_t dinv)); - -#define mpn_dc_bdiv_qr __MPN(dc_bdiv_qr) -__GMP_DECLSPEC mp_limb_t mpn_dc_bdiv_qr __GMP_PROTO ((mp_ptr qp, mp_ptr np, mp_size_t nn, - mp_srcptr dp, mp_size_t dn, mp_limb_t dinv)); - -#define mpn_dc_bdiv_qr_n __MPN(dc_bdiv_qr_n) -__GMP_DECLSPEC mp_limb_t mpn_dc_bdiv_qr_n __GMP_PROTO ((mp_ptr qp, mp_ptr np, - mp_srcptr dp, mp_size_t n, mp_limb_t dinv, mp_ptr tp)); - -#define mpn_sb_div_qr __MPN(sb_div_qr) -__GMP_DECLSPEC mp_limb_t mpn_sb_div_qr __GMP_PROTO ((mp_ptr qp, mp_ptr np, mp_size_t nn, - mp_srcptr dp, mp_size_t dn, mp_limb_t dinv)); - -#define mpn_sb_bdiv_qr __MPN(sb_bdiv_qr) -__GMP_DECLSPEC mp_limb_t mpn_sb_bdiv_qr __GMP_PROTO ((mp_ptr qp, mp_ptr np, mp_size_t nn, - mp_srcptr dp, mp_size_t dn, mp_limb_t dinv)); - -#define mpn_tdiv_q __MPN(tdiv_q) -__GMP_DECLSPEC void mpn_tdiv_q __GMP_PROTO ((mp_ptr qp, mp_srcptr np, mp_size_t nn, - mp_srcptr dp, mp_size_t dn)); - -#define mpn_divexact __MPN(divexact) -__GMP_DECLSPEC void mpn_divexact __GMP_PROTO ((mp_ptr qp, - mp_srcptr np, mp_size_t nn, mp_srcptr dp, mp_size_t dn)); - -#define mpn_redc_1 __MPN(redc_1) -__GMP_DECLSPEC void mpn_redc_1 __GMP_PROTO ((mp_ptr, mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);) - -#define mpn_gcd __MPN(gcd) -__GMP_DECLSPEC mp_size_t mpn_gcd __GMP_PROTO ((mp_ptr, mp_ptr, mp_size_t, mp_ptr, mp_size_t)); - -#define mpn_gcd_1 __MPN(gcd_1) -__GMP_DECLSPEC mp_limb_t mpn_gcd_1 __GMP_PROTO ((mp_srcptr, mp_size_t, mp_limb_t)) __GMP_ATTRIBUTE_PURE; - -#define mpn_gcdext __MPN(gcdext) -__GMP_DECLSPEC mp_size_t mpn_gcdext __GMP_PROTO ((mp_ptr, mp_ptr, mp_size_t *, mp_ptr, mp_size_t, mp_ptr, mp_size_t)); - -#define mpn_get_str __MPN(get_str) -__GMP_DECLSPEC size_t mpn_get_str __GMP_PROTO ((unsigned char *, int, mp_ptr, mp_size_t)); - -#define mpn_hamdist __MPN(hamdist) -__GMP_DECLSPEC mp_bitcnt_t mpn_hamdist __GMP_PROTO ((mp_srcptr, mp_srcptr, mp_size_t)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpn_lshift __MPN(lshift) -__GMP_DECLSPEC mp_limb_t mpn_lshift __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, unsigned int)); - -#define mpn_mod_1 __MPN(mod_1) -__GMP_DECLSPEC mp_limb_t mpn_mod_1 __GMP_PROTO ((mp_srcptr, mp_size_t, mp_limb_t)) __GMP_ATTRIBUTE_PURE; - -#define mpn_mul __MPN(mul) -__GMP_DECLSPEC mp_limb_t mpn_mul __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t)); - -#define mpn_mul_1 __MPN(mul_1) -__GMP_DECLSPEC mp_limb_t mpn_mul_1 __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_limb_t)); - -#define mpn_mul_n __MPN(mul_n) -__GMP_DECLSPEC void mpn_mul_n __GMP_PROTO ((mp_ptr, mp_srcptr, mp_srcptr, mp_size_t)); - -#define mpn_sqr __MPN(sqr) -__GMP_DECLSPEC void mpn_sqr __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t)); - -#define mpn_neg_n __MPN(neg_n) -#define mpn_neg __MPN(neg_n) -__GMP_DECLSPEC mp_limb_t mpn_neg_n __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t)); - -#define mpn_com_n __MPN(com_n) -#define mpn_com __MPN(com_n) -__GMP_DECLSPEC void mpn_com_n __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t)); - -#define mpn_perfect_square_p __MPN(perfect_square_p) -__GMP_DECLSPEC int mpn_perfect_square_p __GMP_PROTO ((mp_srcptr, mp_size_t)) __GMP_ATTRIBUTE_PURE; - -#define mpn_popcount __MPN(popcount) -__GMP_DECLSPEC mp_bitcnt_t mpn_popcount __GMP_PROTO ((mp_srcptr, mp_size_t)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; - -#define mpn_pow_1 __MPN(pow_1) -__GMP_DECLSPEC mp_size_t mpn_pow_1 __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_limb_t, mp_ptr)); - -/* undocumented now, but retained here for upward compatibility */ -#define mpn_preinv_mod_1 __MPN(preinv_mod_1) -__GMP_DECLSPEC mp_limb_t mpn_preinv_mod_1 __GMP_PROTO ((mp_srcptr, mp_size_t, mp_limb_t, mp_limb_t)) __GMP_ATTRIBUTE_PURE; - -#define mpn_random __MPN(random) -__GMP_DECLSPEC void mpn_random __GMP_PROTO ((mp_ptr, mp_size_t)); - -#define mpn_random2 __MPN(random2) -__GMP_DECLSPEC void mpn_random2 __GMP_PROTO ((mp_ptr, mp_size_t)); - -#define mpn_urandomb __MPN(urandomb) -__GMP_DECLSPEC void mpn_urandomb __GMP_PROTO ((mp_ptr, gmp_randstate_t, unsigned long)); - -#define mpn_urandomm __MPN(urandomm) -__GMP_DECLSPEC void mpn_urandomm __GMP_PROTO ((mp_ptr, gmp_randstate_t, mp_srcptr, mp_size_t)); - -#define mpn_randomb __MPN(randomb) -__GMP_DECLSPEC void mpn_randomb __GMP_PROTO ((mp_ptr, gmp_randstate_t, mp_size_t)); - -#define mpn_rrandom __MPN(rrandom) -__GMP_DECLSPEC void mpn_rrandom __GMP_PROTO ((mp_ptr, gmp_randstate_t, mp_size_t)); - -#define mpn_rshift __MPN(rshift) -__GMP_DECLSPEC mp_limb_t mpn_rshift __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, unsigned int)); - -#define mpn_scan0 __MPN(scan0) -__GMP_DECLSPEC mp_bitcnt_t mpn_scan0 __GMP_PROTO ((mp_srcptr, mp_bitcnt_t)) __GMP_ATTRIBUTE_PURE; - -#define mpn_scan1 __MPN(scan1) -__GMP_DECLSPEC mp_bitcnt_t mpn_scan1 __GMP_PROTO ((mp_srcptr, mp_bitcnt_t)) __GMP_ATTRIBUTE_PURE; - -#define mpn_set_str __MPN(set_str) -__GMP_DECLSPEC mp_size_t mpn_set_str __GMP_PROTO ((mp_ptr, __gmp_const unsigned char *, size_t, int)); - -#define mpn_sqrtrem __MPN(sqrtrem) -__GMP_DECLSPEC mp_size_t mpn_sqrtrem __GMP_PROTO ((mp_ptr, mp_ptr, mp_srcptr, mp_size_t)); - -#define mpn_sub __MPN(sub) -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpn_sub) -__GMP_DECLSPEC mp_limb_t mpn_sub __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_srcptr,mp_size_t)); -#endif - -#define mpn_sub_1 __MPN(sub_1) -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpn_sub_1) -__GMP_DECLSPEC mp_limb_t mpn_sub_1 __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_limb_t)) __GMP_NOTHROW; -#endif - -#define mpn_sub_n __MPN(sub_n) -__GMP_DECLSPEC mp_limb_t mpn_sub_n __GMP_PROTO ((mp_ptr, mp_srcptr, mp_srcptr, mp_size_t)); - -#define mpn_submul_1 __MPN(submul_1) -__GMP_DECLSPEC mp_limb_t mpn_submul_1 __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_limb_t)); - -#define mpn_tdiv_qr __MPN(tdiv_qr) -__GMP_DECLSPEC void mpn_tdiv_qr __GMP_PROTO ((mp_ptr, mp_ptr, mp_size_t, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t)); - -#define mpn_and_n __MPN(and_n) -__GMP_DECLSPEC void mpn_and_n __GMP_PROTO ((mp_ptr, mp_srcptr, mp_srcptr, mp_size_t)); -#define mpn_andn_n __MPN(andn_n) -__GMP_DECLSPEC void mpn_andn_n __GMP_PROTO ((mp_ptr, mp_srcptr, mp_srcptr, mp_size_t)); -#define mpn_nand_n __MPN(nand_n) -__GMP_DECLSPEC void mpn_nand_n __GMP_PROTO ((mp_ptr, mp_srcptr, mp_srcptr, mp_size_t)); -#define mpn_ior_n __MPN(ior_n) -__GMP_DECLSPEC void mpn_ior_n __GMP_PROTO ((mp_ptr, mp_srcptr, mp_srcptr, mp_size_t)); -#define mpn_iorn_n __MPN(iorn_n) -__GMP_DECLSPEC void mpn_iorn_n __GMP_PROTO ((mp_ptr, mp_srcptr, mp_srcptr, mp_size_t)); -#define mpn_nior_n __MPN(nior_n) -__GMP_DECLSPEC void mpn_nior_n __GMP_PROTO ((mp_ptr, mp_srcptr, mp_srcptr, mp_size_t)); -#define mpn_xor_n __MPN(xor_n) -__GMP_DECLSPEC void mpn_xor_n __GMP_PROTO ((mp_ptr, mp_srcptr, mp_srcptr, mp_size_t)); -#define mpn_xnor_n __MPN(xnor_n) -__GMP_DECLSPEC void mpn_xnor_n __GMP_PROTO ((mp_ptr, mp_srcptr, mp_srcptr, mp_size_t)); - -#define mpn_copyi __MPN(copyi) -__GMP_DECLSPEC void mpn_copyi __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t)); -#define mpn_copyd __MPN(copyd) -__GMP_DECLSPEC void mpn_copyd __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t)); -#define mpn_zero __MPN(zero) -__GMP_DECLSPEC void mpn_zero __GMP_PROTO ((mp_ptr, mp_size_t)); - -/**************** mpz inlines ****************/ - -/* The following are provided as inlines where possible, but always exist as - library functions too, for binary compatibility. - - Within gmp itself this inlining generally isn't relied on, since it - doesn't get done for all compilers, whereas if something is worth - inlining then it's worth arranging always. - - There are two styles of inlining here. When the same bit of code is - wanted for the inline as for the library version, then __GMP_FORCE_foo - arranges for that code to be emitted and the __GMP_EXTERN_INLINE - directive suppressed, eg. mpz_fits_uint_p. When a different bit of code - is wanted for the inline than for the library version, then - __GMP_FORCE_foo arranges the inline to be suppressed, eg. mpz_abs. */ - -#if defined (__GMP_EXTERN_INLINE) && ! defined (__GMP_FORCE_mpz_abs) -__GMP_EXTERN_INLINE void -mpz_abs (mpz_ptr __gmp_w, mpz_srcptr __gmp_u) -{ - if (__gmp_w != __gmp_u) - mpz_set (__gmp_w, __gmp_u); - __gmp_w->_mp_size = __GMP_ABS (__gmp_w->_mp_size); -} -#endif - -#if GMP_NAIL_BITS == 0 -#define __GMPZ_FITS_UTYPE_P(z,maxval) \ - mp_size_t __gmp_n = z->_mp_size; \ - mp_ptr __gmp_p = z->_mp_d; \ - return (__gmp_n == 0 || (__gmp_n == 1 && __gmp_p[0] <= maxval)); -#else -#define __GMPZ_FITS_UTYPE_P(z,maxval) \ - mp_size_t __gmp_n = z->_mp_size; \ - mp_ptr __gmp_p = z->_mp_d; \ - return (__gmp_n == 0 || (__gmp_n == 1 && __gmp_p[0] <= maxval) \ - || (__gmp_n == 2 && __gmp_p[1] <= ((mp_limb_t) maxval >> GMP_NUMB_BITS))); -#endif - -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_fits_uint_p) -#if ! defined (__GMP_FORCE_mpz_fits_uint_p) -__GMP_EXTERN_INLINE -#endif -int -mpz_fits_uint_p (mpz_srcptr __gmp_z) __GMP_NOTHROW -{ - __GMPZ_FITS_UTYPE_P (__gmp_z, __GMP_UINT_MAX); -} -#endif - -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_fits_ulong_p) -#if ! defined (__GMP_FORCE_mpz_fits_ulong_p) -__GMP_EXTERN_INLINE -#endif -int -mpz_fits_ulong_p (mpz_srcptr __gmp_z) __GMP_NOTHROW -{ - __GMPZ_FITS_UTYPE_P (__gmp_z, __GMP_ULONG_MAX); -} -#endif - -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_fits_ushort_p) -#if ! defined (__GMP_FORCE_mpz_fits_ushort_p) -__GMP_EXTERN_INLINE -#endif -int -mpz_fits_ushort_p (mpz_srcptr __gmp_z) __GMP_NOTHROW -{ - __GMPZ_FITS_UTYPE_P (__gmp_z, __GMP_USHRT_MAX); -} -#endif - -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_get_ui) -#if ! defined (__GMP_FORCE_mpz_get_ui) -__GMP_EXTERN_INLINE -#endif -unsigned long -mpz_get_ui (mpz_srcptr __gmp_z) __GMP_NOTHROW -{ - mp_ptr __gmp_p = __gmp_z->_mp_d; - mp_size_t __gmp_n = __gmp_z->_mp_size; - mp_limb_t __gmp_l = __gmp_p[0]; - /* This is a "#if" rather than a plain "if" so as to avoid gcc warnings - about "<< GMP_NUMB_BITS" exceeding the type size, and to avoid Borland - C++ 6.0 warnings about condition always true for something like - "__GMP_ULONG_MAX < GMP_NUMB_MASK". */ -#if GMP_NAIL_BITS == 0 || defined (_LONG_LONG_LIMB) - /* limb==long and no nails, or limb==longlong, one limb is enough */ - return (unsigned long)(__gmp_n != 0 ? __gmp_l : 0); -#else - /* limb==long and nails, need two limbs when available */ - __gmp_n = __GMP_ABS (__gmp_n); - if (__gmp_n <= 1) - return (__gmp_n != 0 ? __gmp_l : 0); - else - return __gmp_l + (__gmp_p[1] << GMP_NUMB_BITS); -#endif -} -#endif - -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_getlimbn) -#if ! defined (__GMP_FORCE_mpz_getlimbn) -__GMP_EXTERN_INLINE -#endif -mp_limb_t -mpz_getlimbn (mpz_srcptr __gmp_z, mp_size_t __gmp_n) __GMP_NOTHROW -{ - mp_limb_t __gmp_result = 0; - if (__GMP_LIKELY (__gmp_n >= 0 && __gmp_n < __GMP_ABS (__gmp_z->_mp_size))) - __gmp_result = __gmp_z->_mp_d[__gmp_n]; - return __gmp_result; -} -#endif - -#if defined (__GMP_EXTERN_INLINE) && ! defined (__GMP_FORCE_mpz_neg) -__GMP_EXTERN_INLINE void -mpz_neg (mpz_ptr __gmp_w, mpz_srcptr __gmp_u) -{ - if (__gmp_w != __gmp_u) - mpz_set (__gmp_w, __gmp_u); - __gmp_w->_mp_size = - __gmp_w->_mp_size; -} -#endif - -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_perfect_square_p) -#if ! defined (__GMP_FORCE_mpz_perfect_square_p) -__GMP_EXTERN_INLINE -#endif -int -mpz_perfect_square_p (mpz_srcptr __gmp_a) -{ - mp_size_t __gmp_asize; - int __gmp_result; - - __gmp_asize = __gmp_a->_mp_size; - __gmp_result = (__gmp_asize >= 0); /* zero is a square, negatives are not */ - if (__GMP_LIKELY (__gmp_asize > 0)) - __gmp_result = mpn_perfect_square_p (__gmp_a->_mp_d, __gmp_asize); - return __gmp_result; -} -#endif - -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_popcount) -#if ! defined (__GMP_FORCE_mpz_popcount) -__GMP_EXTERN_INLINE -#endif -mp_bitcnt_t -mpz_popcount (mpz_srcptr __gmp_u) __GMP_NOTHROW -{ - mp_size_t __gmp_usize; - mp_bitcnt_t __gmp_result; - - __gmp_usize = __gmp_u->_mp_size; - __gmp_result = (__gmp_usize < 0 ? __GMP_ULONG_MAX : 0); - if (__GMP_LIKELY (__gmp_usize > 0)) - __gmp_result = mpn_popcount (__gmp_u->_mp_d, __gmp_usize); - return __gmp_result; -} -#endif - -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_set_q) -#if ! defined (__GMP_FORCE_mpz_set_q) -__GMP_EXTERN_INLINE -#endif -void -mpz_set_q (mpz_ptr __gmp_w, mpq_srcptr __gmp_u) -{ - mpz_tdiv_q (__gmp_w, mpq_numref (__gmp_u), mpq_denref (__gmp_u)); -} -#endif - -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_size) -#if ! defined (__GMP_FORCE_mpz_size) -__GMP_EXTERN_INLINE -#endif -size_t -mpz_size (mpz_srcptr __gmp_z) __GMP_NOTHROW -{ - return __GMP_ABS (__gmp_z->_mp_size); -} -#endif - - -/**************** mpq inlines ****************/ - -#if defined (__GMP_EXTERN_INLINE) && ! defined (__GMP_FORCE_mpq_abs) -__GMP_EXTERN_INLINE void -mpq_abs (mpq_ptr __gmp_w, mpq_srcptr __gmp_u) -{ - if (__gmp_w != __gmp_u) - mpq_set (__gmp_w, __gmp_u); - __gmp_w->_mp_num._mp_size = __GMP_ABS (__gmp_w->_mp_num._mp_size); -} -#endif - -#if defined (__GMP_EXTERN_INLINE) && ! defined (__GMP_FORCE_mpq_neg) -__GMP_EXTERN_INLINE void -mpq_neg (mpq_ptr __gmp_w, mpq_srcptr __gmp_u) -{ - if (__gmp_w != __gmp_u) - mpq_set (__gmp_w, __gmp_u); - __gmp_w->_mp_num._mp_size = - __gmp_w->_mp_num._mp_size; -} -#endif - - -/**************** mpn inlines ****************/ - -/* The comments with __GMPN_ADD_1 below apply here too. - - The test for FUNCTION returning 0 should predict well. If it's assumed - {yp,ysize} will usually have a random number of bits then the high limb - won't be full and a carry out will occur a good deal less than 50% of the - time. - - ysize==0 isn't a documented feature, but is used internally in a few - places. - - Producing cout last stops it using up a register during the main part of - the calculation, though gcc (as of 3.0) on an "if (mpn_add (...))" - doesn't seem able to move the true and false legs of the conditional up - to the two places cout is generated. */ - -#define __GMPN_AORS(cout, wp, xp, xsize, yp, ysize, FUNCTION, TEST) \ - do { \ - mp_size_t __gmp_i; \ - mp_limb_t __gmp_x; \ - \ - /* ASSERT ((ysize) >= 0); */ \ - /* ASSERT ((xsize) >= (ysize)); */ \ - /* ASSERT (MPN_SAME_OR_SEPARATE2_P (wp, xsize, xp, xsize)); */ \ - /* ASSERT (MPN_SAME_OR_SEPARATE2_P (wp, xsize, yp, ysize)); */ \ - \ - __gmp_i = (ysize); \ - if (__gmp_i != 0) \ - { \ - if (FUNCTION (wp, xp, yp, __gmp_i)) \ - { \ - do \ - { \ - if (__gmp_i >= (xsize)) \ - { \ - (cout) = 1; \ - goto __gmp_done; \ - } \ - __gmp_x = (xp)[__gmp_i]; \ - } \ - while (TEST); \ - } \ - } \ - if ((wp) != (xp)) \ - __GMPN_COPY_REST (wp, xp, xsize, __gmp_i); \ - (cout) = 0; \ - __gmp_done: \ - ; \ - } while (0) - -#define __GMPN_ADD(cout, wp, xp, xsize, yp, ysize) \ - __GMPN_AORS (cout, wp, xp, xsize, yp, ysize, mpn_add_n, \ - (((wp)[__gmp_i++] = (__gmp_x + 1) & GMP_NUMB_MASK) == 0)) -#define __GMPN_SUB(cout, wp, xp, xsize, yp, ysize) \ - __GMPN_AORS (cout, wp, xp, xsize, yp, ysize, mpn_sub_n, \ - (((wp)[__gmp_i++] = (__gmp_x - 1) & GMP_NUMB_MASK), __gmp_x == 0)) - - -/* The use of __gmp_i indexing is designed to ensure a compile time src==dst - remains nice and clear to the compiler, so that __GMPN_COPY_REST can - disappear, and the load/add/store gets a chance to become a - read-modify-write on CISC CPUs. - - Alternatives: - - Using a pair of pointers instead of indexing would be possible, but gcc - isn't able to recognise compile-time src==dst in that case, even when the - pointers are incremented more or less together. Other compilers would - very likely have similar difficulty. - - gcc could use "if (__builtin_constant_p(src==dst) && src==dst)" or - similar to detect a compile-time src==dst. This works nicely on gcc - 2.95.x, it's not good on gcc 3.0 where __builtin_constant_p(p==p) seems - to be always false, for a pointer p. But the current code form seems - good enough for src==dst anyway. - - gcc on x86 as usual doesn't give particularly good flags handling for the - carry/borrow detection. It's tempting to want some multi instruction asm - blocks to help it, and this was tried, but in truth there's only a few - instructions to save and any gain is all too easily lost by register - juggling setting up for the asm. */ - -#if GMP_NAIL_BITS == 0 -#define __GMPN_AORS_1(cout, dst, src, n, v, OP, CB) \ - do { \ - mp_size_t __gmp_i; \ - mp_limb_t __gmp_x, __gmp_r; \ - \ - /* ASSERT ((n) >= 1); */ \ - /* ASSERT (MPN_SAME_OR_SEPARATE_P (dst, src, n)); */ \ - \ - __gmp_x = (src)[0]; \ - __gmp_r = __gmp_x OP (v); \ - (dst)[0] = __gmp_r; \ - if (CB (__gmp_r, __gmp_x, (v))) \ - { \ - (cout) = 1; \ - for (__gmp_i = 1; __gmp_i < (n);) \ - { \ - __gmp_x = (src)[__gmp_i]; \ - __gmp_r = __gmp_x OP 1; \ - (dst)[__gmp_i] = __gmp_r; \ - ++__gmp_i; \ - if (!CB (__gmp_r, __gmp_x, 1)) \ - { \ - if ((src) != (dst)) \ - __GMPN_COPY_REST (dst, src, n, __gmp_i); \ - (cout) = 0; \ - break; \ - } \ - } \ - } \ - else \ - { \ - if ((src) != (dst)) \ - __GMPN_COPY_REST (dst, src, n, 1); \ - (cout) = 0; \ - } \ - } while (0) -#endif - -#if GMP_NAIL_BITS >= 1 -#define __GMPN_AORS_1(cout, dst, src, n, v, OP, CB) \ - do { \ - mp_size_t __gmp_i; \ - mp_limb_t __gmp_x, __gmp_r; \ - \ - /* ASSERT ((n) >= 1); */ \ - /* ASSERT (MPN_SAME_OR_SEPARATE_P (dst, src, n)); */ \ - \ - __gmp_x = (src)[0]; \ - __gmp_r = __gmp_x OP (v); \ - (dst)[0] = __gmp_r & GMP_NUMB_MASK; \ - if (__gmp_r >> GMP_NUMB_BITS != 0) \ - { \ - (cout) = 1; \ - for (__gmp_i = 1; __gmp_i < (n);) \ - { \ - __gmp_x = (src)[__gmp_i]; \ - __gmp_r = __gmp_x OP 1; \ - (dst)[__gmp_i] = __gmp_r & GMP_NUMB_MASK; \ - ++__gmp_i; \ - if (__gmp_r >> GMP_NUMB_BITS == 0) \ - { \ - if ((src) != (dst)) \ - __GMPN_COPY_REST (dst, src, n, __gmp_i); \ - (cout) = 0; \ - break; \ - } \ - } \ - } \ - else \ - { \ - if ((src) != (dst)) \ - __GMPN_COPY_REST (dst, src, n, 1); \ - (cout) = 0; \ - } \ - } while (0) -#endif - -#define __GMPN_ADDCB(r,x,y) ((r) < (y)) -#define __GMPN_SUBCB(r,x,y) ((x) < (y)) - -#define __GMPN_ADD_1(cout, dst, src, n, v) \ - __GMPN_AORS_1(cout, dst, src, n, v, +, __GMPN_ADDCB) -#define __GMPN_SUB_1(cout, dst, src, n, v) \ - __GMPN_AORS_1(cout, dst, src, n, v, -, __GMPN_SUBCB) - - -/* Compare {xp,size} and {yp,size}, setting "result" to positive, zero or - negative. size==0 is allowed. On random data usually only one limb will - need to be examined to get a result, so it's worth having it inline. */ -#define __GMPN_CMP(result, xp, yp, size) \ - do { \ - mp_size_t __gmp_i; \ - mp_limb_t __gmp_x, __gmp_y; \ - \ - /* ASSERT ((size) >= 0); */ \ - \ - (result) = 0; \ - __gmp_i = (size); \ - while (--__gmp_i >= 0) \ - { \ - __gmp_x = (xp)[__gmp_i]; \ - __gmp_y = (yp)[__gmp_i]; \ - if (__gmp_x != __gmp_y) \ - { \ - /* Cannot use __gmp_x - __gmp_y, may overflow an "int" */ \ - (result) = (__gmp_x > __gmp_y ? 1 : -1); \ - break; \ - } \ - } \ - } while (0) - - -#if defined (__GMPN_COPY) && ! defined (__GMPN_COPY_REST) -#define __GMPN_COPY_REST(dst, src, size, start) \ - do { \ - /* ASSERT ((start) >= 0); */ \ - /* ASSERT ((start) <= (size)); */ \ - __GMPN_COPY ((dst)+(start), (src)+(start), (size)-(start)); \ - } while (0) -#endif - -/* Copy {src,size} to {dst,size}, starting at "start". This is designed to - keep the indexing dst[j] and src[j] nice and simple for __GMPN_ADD_1, - __GMPN_ADD, etc. */ -#if ! defined (__GMPN_COPY_REST) -#define __GMPN_COPY_REST(dst, src, size, start) \ - do { \ - mp_size_t __gmp_j; \ - /* ASSERT ((size) >= 0); */ \ - /* ASSERT ((start) >= 0); */ \ - /* ASSERT ((start) <= (size)); */ \ - /* ASSERT (MPN_SAME_OR_SEPARATE_P (dst, src, size)); */ \ - for (__gmp_j = (start); __gmp_j < (size); __gmp_j++) \ - (dst)[__gmp_j] = (src)[__gmp_j]; \ - } while (0) -#endif - -/* Enhancement: Use some of the smarter code from gmp-impl.h. Maybe use - mpn_copyi if there's a native version, and if we don't mind demanding - binary compatibility for it (on targets which use it). */ - -#if ! defined (__GMPN_COPY) -#define __GMPN_COPY(dst, src, size) __GMPN_COPY_REST (dst, src, size, 0) -#endif - - -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpn_add) -#if ! defined (__GMP_FORCE_mpn_add) -__GMP_EXTERN_INLINE -#endif -mp_limb_t -mpn_add (mp_ptr __gmp_wp, mp_srcptr __gmp_xp, mp_size_t __gmp_xsize, mp_srcptr __gmp_yp, mp_size_t __gmp_ysize) -{ - mp_limb_t __gmp_c; - __GMPN_ADD (__gmp_c, __gmp_wp, __gmp_xp, __gmp_xsize, __gmp_yp, __gmp_ysize); - return __gmp_c; -} -#endif - -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpn_add_1) -#if ! defined (__GMP_FORCE_mpn_add_1) -__GMP_EXTERN_INLINE -#endif -mp_limb_t -mpn_add_1 (mp_ptr __gmp_dst, mp_srcptr __gmp_src, mp_size_t __gmp_size, mp_limb_t __gmp_n) __GMP_NOTHROW -{ - mp_limb_t __gmp_c; - __GMPN_ADD_1 (__gmp_c, __gmp_dst, __gmp_src, __gmp_size, __gmp_n); - return __gmp_c; -} -#endif - -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpn_cmp) -#if ! defined (__GMP_FORCE_mpn_cmp) -__GMP_EXTERN_INLINE -#endif -int -mpn_cmp (mp_srcptr __gmp_xp, mp_srcptr __gmp_yp, mp_size_t __gmp_size) __GMP_NOTHROW -{ - int __gmp_result; - __GMPN_CMP (__gmp_result, __gmp_xp, __gmp_yp, __gmp_size); - return __gmp_result; -} -#endif - -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpn_sub) -#if ! defined (__GMP_FORCE_mpn_sub) -__GMP_EXTERN_INLINE -#endif -mp_limb_t -mpn_sub (mp_ptr __gmp_wp, mp_srcptr __gmp_xp, mp_size_t __gmp_xsize, mp_srcptr __gmp_yp, mp_size_t __gmp_ysize) -{ - mp_limb_t __gmp_c; - __GMPN_SUB (__gmp_c, __gmp_wp, __gmp_xp, __gmp_xsize, __gmp_yp, __gmp_ysize); - return __gmp_c; -} -#endif - -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpn_sub_1) -#if ! defined (__GMP_FORCE_mpn_sub_1) -__GMP_EXTERN_INLINE -#endif -mp_limb_t -mpn_sub_1 (mp_ptr __gmp_dst, mp_srcptr __gmp_src, mp_size_t __gmp_size, mp_limb_t __gmp_n) __GMP_NOTHROW -{ - mp_limb_t __gmp_c; - __GMPN_SUB_1 (__gmp_c, __gmp_dst, __gmp_src, __gmp_size, __gmp_n); - return __gmp_c; -} -#endif - -#if defined (__cplusplus) -} -#endif - - -/* Allow faster testing for negative, zero, and positive. */ -#define mpz_sgn(Z) ((Z)->_mp_size < 0 ? -1 : (Z)->_mp_size > 0) -#define mpf_sgn(F) ((F)->_mp_size < 0 ? -1 : (F)->_mp_size > 0) -#define mpq_sgn(Q) ((Q)->_mp_num._mp_size < 0 ? -1 : (Q)->_mp_num._mp_size > 0) - -/* When using GCC, optimize certain common comparisons. */ -#if defined (__GNUC__) -#define mpz_cmp_ui(Z,UI) \ - (__builtin_constant_p (UI) && (UI) == 0 \ - ? mpz_sgn (Z) : _mpz_cmp_ui (Z,UI)) -#define mpz_cmp_si(Z,SI) \ - (__builtin_constant_p (SI) && (SI) == 0 ? mpz_sgn (Z) \ - : __builtin_constant_p (SI) && (SI) > 0 \ - ? _mpz_cmp_ui (Z, __GMP_CAST (unsigned long int, SI)) \ - : _mpz_cmp_si (Z,SI)) -#define mpq_cmp_ui(Q,NUI,DUI) \ - (__builtin_constant_p (NUI) && (NUI) == 0 \ - ? mpq_sgn (Q) : _mpq_cmp_ui (Q,NUI,DUI)) -#define mpq_cmp_si(q,n,d) \ - (__builtin_constant_p ((n) >= 0) && (n) >= 0 \ - ? mpq_cmp_ui (q, __GMP_CAST (unsigned long, n), d) \ - : _mpq_cmp_si (q, n, d)) -#else -#define mpz_cmp_ui(Z,UI) _mpz_cmp_ui (Z,UI) -#define mpz_cmp_si(Z,UI) _mpz_cmp_si (Z,UI) -#define mpq_cmp_ui(Q,NUI,DUI) _mpq_cmp_ui (Q,NUI,DUI) -#define mpq_cmp_si(q,n,d) _mpq_cmp_si(q,n,d) -#endif - - -/* Using "&" rather than "&&" means these can come out branch-free. Every - mpz_t has at least one limb allocated, so fetching the low limb is always - allowed. */ -#define mpz_odd_p(z) (((z)->_mp_size != 0) & __GMP_CAST (int, (z)->_mp_d[0])) -#define mpz_even_p(z) (! mpz_odd_p (z)) - - -/**************** C++ routines ****************/ - -#ifdef __cplusplus -__GMP_DECLSPEC_XX std::ostream& operator<< (std::ostream &, mpz_srcptr); -__GMP_DECLSPEC_XX std::ostream& operator<< (std::ostream &, mpq_srcptr); -__GMP_DECLSPEC_XX std::ostream& operator<< (std::ostream &, mpf_srcptr); -__GMP_DECLSPEC_XX std::istream& operator>> (std::istream &, mpz_ptr); -__GMP_DECLSPEC_XX std::istream& operator>> (std::istream &, mpq_ptr); -__GMP_DECLSPEC_XX std::istream& operator>> (std::istream &, mpf_ptr); -#endif - -/* Source-level compatibility with GMP 1. */ -#define mpz_mdiv mpz_fdiv_q -#define mpz_mdivmod mpz_fdiv_qr -#define mpz_mmod mpz_fdiv_r -#define mpz_mdiv_ui mpz_fdiv_q_ui -#define mpz_mdivmod_ui(q,r,n,d) \ - (((r) == 0) ? mpz_fdiv_q_ui (q,n,d) : mpz_fdiv_qr_ui (q,r,n,d)) -#define mpz_mmod_ui(r,n,d) \ - (((r) == 0) ? mpz_fdiv_ui (n,d) : mpz_fdiv_r_ui (r,n,d)) - -#define gmp_randinit(x,y,z) gmp_randinit_lc_2exp_size(x,z) - -typedef __mpz_struct MP_INT; /* gmp 1 source compatibility */ -typedef __mpq_struct MP_RAT; /* gmp 1 source compatibility */ - -#define mpz_div mpz_fdiv_q -#define mpz_divmod mpz_fdiv_qr -#define mpz_div_ui mpz_fdiv_q_ui -#define mpz_divmod_ui mpz_fdiv_qr_ui -#define mpz_div_2exp mpz_fdiv_q_2exp -#define mpz_mod_2exp mpz_fdiv_r_2exp - -enum -{ - GMP_ERROR_NONE = 0, - GMP_ERROR_UNSUPPORTED_ARGUMENT = 1, - GMP_ERROR_DIVISION_BY_ZERO = 2, - GMP_ERROR_SQRT_OF_NEGATIVE = 4, - GMP_ERROR_INVALID_ARGUMENT = 8 -}; - -/* Major version number is the value of __GNU_MP__ too, above and in mp.h. */ -#define __GNU_MP_VERSION 5 -#define __GNU_MP_VERSION_MINOR 0 -#define __GNU_MP_VERSION_PATCHLEVEL 1 -#define GMP_VERSION "5.0.1" - -#define __MPIR_VERSION 2 -#define __MPIR_VERSION_MINOR 2 -#define __MPIR_VERSION_PATCHLEVEL 1 -#if defined( _MSC_VER ) -#define _MSC_MPIR_VERSION "2.2.1" -#endif - -/* These are for programs like MPFR to use the same CC and CFLAGS as MPIR */ - -#if ! defined (__GMP_WITHIN_CONFIGURE) -#define __GMP_CC "gcc" -#define __GMP_CFLAGS "-m32 -O2 -fomit-frame-pointer -mtune=core2 -march=core2 -mno-cygwin" -#define __MPIR_CC "gcc -std=gnu99" -#define __MPIR_CFLAGS "-m32 -O2 -fomit-frame-pointer -mtune=core2 -march=core2 -mno-cygwin" -#endif - -#define __GMP_H__ -#endif /* __GMP_H__ */ diff --git a/src/external/inc/win32-gcc/mpir-2.2.1/mpirxx.h b/src/external/inc/win32-gcc/mpir-2.2.1/mpirxx.h deleted file mode 100644 index 3ad1dcf6f..000000000 --- a/src/external/inc/win32-gcc/mpir-2.2.1/mpirxx.h +++ /dev/null @@ -1,3403 +0,0 @@ -/* mpirxx.h -- C++ class wrapper for GMP types. -*- C++ -*- - -Copyright 2001, 2002, 2003, 2006, 2008 Free Software Foundation, Inc. - -Copyright 2009 William Hart - -This file is part of the GNU MP Library. - -The GNU MP Library is free software; you can redistribute it and/or modify -it under the terms of the GNU Lesser General Public License as published by -the Free Software Foundation; either version 3 of the License, or (at your -option) any later version. - -The GNU MP Library is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public -License for more details. - -You should have received a copy of the GNU Lesser General Public License -along with the GNU MP Library. If not, see http://www.gnu.org/licenses/. */ - -/* the C++ compiler must implement the following features: - - member templates - - partial specialization of templates - - namespace support - for g++, this means version 2.91 or higher - for other compilers, I don't know */ -#ifdef __GNUC__ -#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 91) -#error mpirxx.h requires g++ version 2.91 (egcs 1.1.2) or higher -#endif -#endif - -#ifndef __GMP_PLUSPLUS__ -#define __GMP_PLUSPLUS__ - -#include - -#include /* for strlen */ -#include -#include -#include -#include - - -/**************** Function objects ****************/ -/* Any evaluation of a __gmp_expr ends up calling one of these functions - all intermediate functions being inline, the evaluation should optimize - to a direct call to the relevant function, thus yielding no overhead - over the C interface. */ - -struct __gmp_unary_plus -{ - static void eval(mpz_ptr z, mpz_srcptr w) { mpz_set(z, w); } - static void eval(mpq_ptr q, mpq_srcptr r) { mpq_set(q, r); } - static void eval(mpf_ptr f, mpf_srcptr g) { mpf_set(f, g); } -}; - -struct __gmp_unary_minus -{ - static void eval(mpz_ptr z, mpz_srcptr w) { mpz_neg(z, w); } - static void eval(mpq_ptr q, mpq_srcptr r) { mpq_neg(q, r); } - static void eval(mpf_ptr f, mpf_srcptr g) { mpf_neg(f, g); } -}; - -struct __gmp_unary_com -{ - static void eval(mpz_ptr z, mpz_srcptr w) { mpz_com(z, w); } -}; - -struct __gmp_binary_plus -{ - static void eval(mpz_ptr z, mpz_srcptr w, mpz_srcptr v) - { mpz_add(z, w, v); } - - static void eval(mpz_ptr z, mpz_srcptr w, unsigned long int l) - { mpz_add_ui(z, w, l); } - static void eval(mpz_ptr z, unsigned long int l, mpz_srcptr w) - { mpz_add_ui(z, w, l); } - static void eval(mpz_ptr z, mpz_srcptr w, signed long int l) - { - if (l >= 0) - mpz_add_ui(z, w, l); - else - mpz_sub_ui(z, w, -l); - } - static void eval(mpz_ptr z, signed long int l, mpz_srcptr w) - { - if (l >= 0) - mpz_add_ui(z, w, l); - else - mpz_sub_ui(z, w, -l); - } - static void eval(mpz_ptr z, mpz_srcptr w, double d) - { - mpz_t temp; - mpz_init_set_d(temp, d); - mpz_add(z, w, temp); - mpz_clear(temp); - } - static void eval(mpz_ptr z, double d, mpz_srcptr w) - { - mpz_t temp; - mpz_init_set_d(temp, d); - mpz_add(z, temp, w); - mpz_clear(temp); - } - - static void eval(mpq_ptr q, mpq_srcptr r, mpq_srcptr s) - { mpq_add(q, r, s); } - - static void eval(mpq_ptr q, mpq_srcptr r, unsigned long int l) - { mpq_set(q, r); mpz_addmul_ui(mpq_numref(q), mpq_denref(q), l); } - static void eval(mpq_ptr q, unsigned long int l, mpq_srcptr r) - { mpq_set(q, r); mpz_addmul_ui(mpq_numref(q), mpq_denref(q), l); } - static void eval(mpq_ptr q, mpq_srcptr r, signed long int l) - { - mpq_set(q, r); - if (l >= 0) - mpz_addmul_ui(mpq_numref(q), mpq_denref(q), l); - else - mpz_submul_ui(mpq_numref(q), mpq_denref(q), -l); - } - static void eval(mpq_ptr q, signed long int l, mpq_srcptr r) - { - mpq_set(q, r); - if (l >= 0) - mpz_addmul_ui(mpq_numref(q), mpq_denref(q), l); - else - mpz_submul_ui(mpq_numref(q), mpq_denref(q), -l); - } - static void eval(mpq_ptr q, mpq_srcptr r, double d) - { - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - mpq_add(q, r, temp); - mpq_clear(temp); - } - static void eval(mpq_ptr q, double d, mpq_srcptr r) - { - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - mpq_add(q, temp, r); - mpq_clear(temp); - } - - static void eval(mpq_ptr q, mpq_srcptr r, mpz_srcptr z) - { mpq_set(q, r); mpz_addmul(mpq_numref(q), mpq_denref(q), z); } - static void eval(mpq_ptr q, mpz_srcptr z, mpq_srcptr r) - { mpq_set(q, r); mpz_addmul(mpq_numref(q), mpq_denref(q), z); } - - static void eval(mpf_ptr f, mpf_srcptr g, mpf_srcptr h) - { mpf_add(f, g, h); } - - static void eval(mpf_ptr f, mpf_srcptr g, unsigned long int l) - { mpf_add_ui(f, g, l); } - static void eval(mpf_ptr f, unsigned long int l, mpf_srcptr g) - { mpf_add_ui(f, g, l); } - static void eval(mpf_ptr f, mpf_srcptr g, signed long int l) - { - if (l >= 0) - mpf_add_ui(f, g, l); - else - mpf_sub_ui(f, g, -l); - } - static void eval(mpf_ptr f, signed long int l, mpf_srcptr g) - { - if (l >= 0) - mpf_add_ui(f, g, l); - else - mpf_sub_ui(f, g, -l); - } - static void eval(mpf_ptr f, mpf_srcptr g, double d) - { - mpf_t temp; - mpf_init2(temp, 8*sizeof(double)); - mpf_set_d(temp, d); - mpf_add(f, g, temp); - mpf_clear(temp); - } - static void eval(mpf_ptr f, double d, mpf_srcptr g) - { - mpf_t temp; - mpf_init2(temp, 8*sizeof(double)); - mpf_set_d(temp, d); - mpf_add(f, temp, g); - mpf_clear(temp); - } -}; - -struct __gmp_binary_minus -{ - static void eval(mpz_ptr z, mpz_srcptr w, mpz_srcptr v) - { mpz_sub(z, w, v); } - - static void eval(mpz_ptr z, mpz_srcptr w, unsigned long int l) - { mpz_sub_ui(z, w, l); } - static void eval(mpz_ptr z, unsigned long int l, mpz_srcptr w) - { mpz_ui_sub(z, l, w); } - static void eval(mpz_ptr z, mpz_srcptr w, signed long int l) - { - if (l >= 0) - mpz_sub_ui(z, w, l); - else - mpz_add_ui(z, w, -l); - } - static void eval(mpz_ptr z, signed long int l, mpz_srcptr w) - { - if (l >= 0) - mpz_ui_sub(z, l, w); - else - { - mpz_add_ui(z, w, -l); - mpz_neg(z, z); - } - } - static void eval(mpz_ptr z, mpz_srcptr w, double d) - { - mpz_t temp; - mpz_init_set_d(temp, d); - mpz_sub(z, w, temp); - mpz_clear(temp); - } - static void eval(mpz_ptr z, double d, mpz_srcptr w) - { - mpz_t temp; - mpz_init_set_d(temp, d); - mpz_sub(z, temp, w); - mpz_clear(temp); - } - - static void eval(mpq_ptr q, mpq_srcptr r, mpq_srcptr s) - { mpq_sub(q, r, s); } - - static void eval(mpq_ptr q, mpq_srcptr r, unsigned long int l) - { mpq_set(q, r); mpz_submul_ui(mpq_numref(q), mpq_denref(q), l); } - static void eval(mpq_ptr q, unsigned long int l, mpq_srcptr r) - { mpq_neg(q, r); mpz_addmul_ui(mpq_numref(q), mpq_denref(q), l); } - static void eval(mpq_ptr q, mpq_srcptr r, signed long int l) - { - mpq_set(q, r); - if (l >= 0) - mpz_submul_ui(mpq_numref(q), mpq_denref(q), l); - else - mpz_addmul_ui(mpq_numref(q), mpq_denref(q), -l); - } - static void eval(mpq_ptr q, signed long int l, mpq_srcptr r) - { - mpq_neg(q, r); - if (l >= 0) - mpz_addmul_ui(mpq_numref(q), mpq_denref(q), l); - else - mpz_submul_ui(mpq_numref(q), mpq_denref(q), -l); - } - static void eval(mpq_ptr q, mpq_srcptr r, double d) - { - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - mpq_sub(q, r, temp); - mpq_clear(temp); - } - static void eval(mpq_ptr q, double d, mpq_srcptr r) - { - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - mpq_sub(q, temp, r); - mpq_clear(temp); - } - - static void eval(mpq_ptr q, mpq_srcptr r, mpz_srcptr z) - { mpq_set(q, r); mpz_submul(mpq_numref(q), mpq_denref(q), z); } - static void eval(mpq_ptr q, mpz_srcptr z, mpq_srcptr r) - { mpq_neg(q, r); mpz_addmul(mpq_numref(q), mpq_denref(q), z); } - - static void eval(mpf_ptr f, mpf_srcptr g, mpf_srcptr h) - { mpf_sub(f, g, h); } - - static void eval(mpf_ptr f, mpf_srcptr g, unsigned long int l) - { mpf_sub_ui(f, g, l); } - static void eval(mpf_ptr f, unsigned long int l, mpf_srcptr g) - { mpf_ui_sub(f, l, g); } - static void eval(mpf_ptr f, mpf_srcptr g, signed long int l) - { - if (l >= 0) - mpf_sub_ui(f, g, l); - else - mpf_add_ui(f, g, -l); - } - static void eval(mpf_ptr f, signed long int l, mpf_srcptr g) - { - if (l >= 0) - mpf_sub_ui(f, g, l); - else - mpf_add_ui(f, g, -l); - mpf_neg(f, f); - } - static void eval(mpf_ptr f, mpf_srcptr g, double d) - { - mpf_t temp; - mpf_init2(temp, 8*sizeof(double)); - mpf_set_d(temp, d); - mpf_sub(f, g, temp); - mpf_clear(temp); - } - static void eval(mpf_ptr f, double d, mpf_srcptr g) - { - mpf_t temp; - mpf_init2(temp, 8*sizeof(double)); - mpf_set_d(temp, d); - mpf_sub(f, temp, g); - mpf_clear(temp); - } -}; - -struct __gmp_binary_multiplies -{ - static void eval(mpz_ptr z, mpz_srcptr w, mpz_srcptr v) - { mpz_mul(z, w, v); } - - static void eval(mpz_ptr z, mpz_srcptr w, unsigned long int l) - { mpz_mul_ui(z, w, l); } - static void eval(mpz_ptr z, unsigned long int l, mpz_srcptr w) - { mpz_mul_ui(z, w, l); } - static void eval(mpz_ptr z, mpz_srcptr w, signed long int l) - { mpz_mul_si (z, w, l); } - static void eval(mpz_ptr z, signed long int l, mpz_srcptr w) - { mpz_mul_si (z, w, l); } - static void eval(mpz_ptr z, mpz_srcptr w, double d) - { - mpz_t temp; - mpz_init_set_d(temp, d); - mpz_mul(z, w, temp); - mpz_clear(temp); - } - static void eval(mpz_ptr z, double d, mpz_srcptr w) - { - mpz_t temp; - mpz_init_set_d(temp, d); - mpz_mul(z, temp, w); - mpz_clear(temp); - } - - static void eval(mpq_ptr q, mpq_srcptr r, mpq_srcptr s) - { mpq_mul(q, r, s); } - - static void eval(mpq_ptr q, mpq_srcptr r, unsigned long int l) - { - mpq_t temp; - mpq_init(temp); - mpq_set_ui(temp, l, 1); - mpq_mul(q, r, temp); - mpq_clear(temp); - } - static void eval(mpq_ptr q, unsigned long int l, mpq_srcptr r) - { - mpq_t temp; - mpq_init(temp); - mpq_set_ui(temp, l, 1); - mpq_mul(q, temp, r); - mpq_clear(temp); - } - static void eval(mpq_ptr q, mpq_srcptr r, signed long int l) - { - mpq_t temp; - mpq_init(temp); - mpq_set_si(temp, l, 1); - mpq_mul(q, r, temp); - mpq_clear(temp); - } - static void eval(mpq_ptr q, signed long int l, mpq_srcptr r) - { - mpq_t temp; - mpq_init(temp); - mpq_set_si(temp, l, 1); - mpq_mul(q, temp, r); - mpq_clear(temp); - } - static void eval(mpq_ptr q, mpq_srcptr r, double d) - { - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - mpq_mul(q, r, temp); - mpq_clear(temp); - } - static void eval(mpq_ptr q, double d, mpq_srcptr r) - { - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - mpq_mul(q, temp, r); - mpq_clear(temp); - } - - static void eval(mpf_ptr f, mpf_srcptr g, mpf_srcptr h) - { mpf_mul(f, g, h); } - - static void eval(mpf_ptr f, mpf_srcptr g, unsigned long int l) - { mpf_mul_ui(f, g, l); } - static void eval(mpf_ptr f, unsigned long int l, mpf_srcptr g) - { mpf_mul_ui(f, g, l); } - static void eval(mpf_ptr f, mpf_srcptr g, signed long int l) - { - if (l >= 0) - mpf_mul_ui(f, g, l); - else - { - mpf_mul_ui(f, g, -l); - mpf_neg(f, f); - } - } - static void eval(mpf_ptr f, signed long int l, mpf_srcptr g) - { - if (l >= 0) - mpf_mul_ui(f, g, l); - else - { - mpf_mul_ui(f, g, -l); - mpf_neg(f, f); - } - } - static void eval(mpf_ptr f, mpf_srcptr g, double d) - { - mpf_t temp; - mpf_init2(temp, 8*sizeof(double)); - mpf_set_d(temp, d); - mpf_mul(f, g, temp); - mpf_clear(temp); - } - static void eval(mpf_ptr f, double d, mpf_srcptr g) - { - mpf_t temp; - mpf_init2(temp, 8*sizeof(double)); - mpf_set_d(temp, d); - mpf_mul(f, temp, g); - mpf_clear(temp); - } -}; - -struct __gmp_binary_divides -{ - static void eval(mpz_ptr z, mpz_srcptr w, mpz_srcptr v) - { mpz_tdiv_q(z, w, v); } - - static void eval(mpz_ptr z, mpz_srcptr w, unsigned long int l) - { mpz_tdiv_q_ui(z, w, l); } - static void eval(mpz_ptr z, unsigned long int l, mpz_srcptr w) - { - if (mpz_sgn(w) >= 0) - { - if (mpz_fits_ulong_p(w)) - mpz_set_ui(z, l / mpz_get_ui(w)); - else - mpz_set_ui(z, 0); - } - else - { - mpz_neg(z, w); - if (mpz_fits_ulong_p(z)) - { - mpz_set_ui(z, l / mpz_get_ui(z)); - mpz_neg(z, z); - } - else - mpz_set_ui(z, 0); - } - } - static void eval(mpz_ptr z, mpz_srcptr w, signed long int l) - { - if (l >= 0) - mpz_tdiv_q_ui(z, w, l); - else - { - mpz_tdiv_q_ui(z, w, -l); - mpz_neg(z, z); - } - } - static void eval(mpz_ptr z, signed long int l, mpz_srcptr w) - { - if (mpz_fits_slong_p(w)) - mpz_set_si(z, l / mpz_get_si(w)); - else - { - /* if w is bigger than a long then the quotient must be zero, unless - l==LONG_MIN and w==-LONG_MIN in which case the quotient is -1 */ - mpz_set_si (z, (mpz_cmpabs_ui (w, (l >= 0 ? l : -l)) == 0 ? -1 : 0)); - } - } - static void eval(mpz_ptr z, mpz_srcptr w, double d) - { - mpz_t temp; - mpz_init_set_d(temp, d); - mpz_tdiv_q(z, w, temp); - mpz_clear(temp); - } - static void eval(mpz_ptr z, double d, mpz_srcptr w) - { - mpz_t temp; - mpz_init_set_d(temp, d); - mpz_tdiv_q(z, temp, w); - mpz_clear(temp); - } - - static void eval(mpq_ptr q, mpq_srcptr r, mpq_srcptr s) - { mpq_div(q, r, s); } - - static void eval(mpq_ptr q, mpq_srcptr r, unsigned long int l) - { - mpq_t temp; - mpq_init(temp); - mpq_set_ui(temp, l, 1); - mpq_div(q, r, temp); - mpq_clear(temp); - } - static void eval(mpq_ptr q, unsigned long int l, mpq_srcptr r) - { - mpq_t temp; - mpq_init(temp); - mpq_set_ui(temp, l, 1); - mpq_div(q, temp, r); - mpq_clear(temp); - } - static void eval(mpq_ptr q, mpq_srcptr r, signed long int l) - { - mpq_t temp; - mpq_init(temp); - mpq_set_si(temp, l, 1); - mpq_div(q, r, temp); - mpq_clear(temp); - } - static void eval(mpq_ptr q, signed long int l, mpq_srcptr r) - { - mpq_t temp; - mpq_init(temp); - mpq_set_si(temp, l, 1); - mpq_div(q, temp, r); - mpq_clear(temp); - } - static void eval(mpq_ptr q, mpq_srcptr r, double d) - { - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - mpq_div(q, r, temp); - mpq_clear(temp); - } - static void eval(mpq_ptr q, double d, mpq_srcptr r) - { - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - mpq_div(q, temp, r); - mpq_clear(temp); - } - - static void eval(mpf_ptr f, mpf_srcptr g, mpf_srcptr h) - { mpf_div(f, g, h); } - - static void eval(mpf_ptr f, mpf_srcptr g, unsigned long int l) - { mpf_div_ui(f, g, l); } - static void eval(mpf_ptr f, unsigned long int l, mpf_srcptr g) - { mpf_ui_div(f, l, g); } - static void eval(mpf_ptr f, mpf_srcptr g, signed long int l) - { - if (l >= 0) - mpf_div_ui(f, g, l); - else - { - mpf_div_ui(f, g, -l); - mpf_neg(f, f); - } - } - static void eval(mpf_ptr f, signed long int l, mpf_srcptr g) - { - if (l >= 0) - mpf_ui_div(f, l, g); - else - { - mpf_ui_div(f, -l, g); - mpf_neg(f, f); - } - } - static void eval(mpf_ptr f, mpf_srcptr g, double d) - { - mpf_t temp; - mpf_init2(temp, 8*sizeof(double)); - mpf_set_d(temp, d); - mpf_div(f, g, temp); - mpf_clear(temp); - } - static void eval(mpf_ptr f, double d, mpf_srcptr g) - { - mpf_t temp; - mpf_init2(temp, 8*sizeof(double)); - mpf_set_d(temp, d); - mpf_div(f, temp, g); - mpf_clear(temp); - } -}; - -struct __gmp_binary_modulus -{ - static void eval(mpz_ptr z, mpz_srcptr w, mpz_srcptr v) - { mpz_tdiv_r(z, w, v); } - - static void eval(mpz_ptr z, mpz_srcptr w, unsigned long int l) - { mpz_tdiv_r_ui(z, w, l); } - static void eval(mpz_ptr z, unsigned long int l, mpz_srcptr w) - { - if (mpz_sgn(w) >= 0) - { - if (mpz_fits_ulong_p(w)) - mpz_set_ui(z, l % mpz_get_ui(w)); - else - mpz_set_ui(z, l); - } - else - { - mpz_neg(z, w); - if (mpz_fits_ulong_p(z)) - mpz_set_ui(z, l % mpz_get_ui(z)); - else - mpz_set_ui(z, l); - } - } - static void eval(mpz_ptr z, mpz_srcptr w, signed long int l) - { - mpz_tdiv_r_ui (z, w, (l >= 0 ? l : -l)); - } - static void eval(mpz_ptr z, signed long int l, mpz_srcptr w) - { - if (mpz_fits_slong_p(w)) - mpz_set_si(z, l % mpz_get_si(w)); - else - { - /* if w is bigger than a long then the remainder is l unchanged, - unless l==LONG_MIN and w==-LONG_MIN in which case it's 0 */ - mpz_set_si (z, mpz_cmpabs_ui (w, (l >= 0 ? l : -l)) == 0 ? 0 : l); - } - } - static void eval(mpz_ptr z, mpz_srcptr w, double d) - { - mpz_t temp; - mpz_init_set_d(temp, d); - mpz_tdiv_r(z, w, temp); - mpz_clear(temp); - } - static void eval(mpz_ptr z, double d, mpz_srcptr w) - { - mpz_t temp; - mpz_init_set_d(temp, d); - mpz_tdiv_r(z, temp, w); - mpz_clear(temp); - } -}; - -// Max allocations for plain types when converted to mpz_t -#define __GMP_DBL_LIMBS (2 + DBL_MAX_EXP / GMP_NUMB_BITS) -#define __GMP_ULI_LIMBS (1 + (8 * sizeof (long) - 1) / GMP_NUMB_BITS) - -#define __GMPXX_TMP_UI \ - mpz_t temp; \ - mp_limb_t limbs[__GMP_ULI_LIMBS]; \ - temp->_mp_d = limbs; \ - temp->_mp_alloc = __GMP_ULI_LIMBS; \ - mpz_set_ui (temp, l) -#define __GMPXX_TMP_SI \ - mpz_t temp; \ - mp_limb_t limbs[__GMP_ULI_LIMBS]; \ - temp->_mp_d = limbs; \ - temp->_mp_alloc = __GMP_ULI_LIMBS; \ - mpz_set_si (temp, l) -#define __GMPXX_TMP_D \ - mpz_t temp; \ - mp_limb_t limbs[__GMP_DBL_LIMBS]; \ - temp->_mp_d = limbs; \ - temp->_mp_alloc = __GMP_DBL_LIMBS; \ - mpz_set_d (temp, d) - -struct __gmp_binary_and -{ - static void eval(mpz_ptr z, mpz_srcptr w, mpz_srcptr v) - { mpz_and(z, w, v); } - - static void eval(mpz_ptr z, mpz_srcptr w, unsigned long int l) - { __GMPXX_TMP_UI; mpz_and (z, w, temp); } - static void eval(mpz_ptr z, unsigned long int l, mpz_srcptr w) - { __GMPXX_TMP_UI; mpz_and (z, w, temp); } - static void eval(mpz_ptr z, mpz_srcptr w, signed long int l) - { __GMPXX_TMP_SI; mpz_and (z, w, temp); } - static void eval(mpz_ptr z, signed long int l, mpz_srcptr w) - { __GMPXX_TMP_SI; mpz_and (z, w, temp); } - static void eval(mpz_ptr z, mpz_srcptr w, double d) - { __GMPXX_TMP_D; mpz_and (z, w, temp); } - static void eval(mpz_ptr z, double d, mpz_srcptr w) - { __GMPXX_TMP_D; mpz_and (z, w, temp); } -}; - -struct __gmp_binary_ior -{ - static void eval(mpz_ptr z, mpz_srcptr w, mpz_srcptr v) - { mpz_ior(z, w, v); } - static void eval(mpz_ptr z, mpz_srcptr w, unsigned long int l) - { __GMPXX_TMP_UI; mpz_ior (z, w, temp); } - static void eval(mpz_ptr z, unsigned long int l, mpz_srcptr w) - { __GMPXX_TMP_UI; mpz_ior (z, w, temp); } - static void eval(mpz_ptr z, mpz_srcptr w, signed long int l) - { __GMPXX_TMP_SI; mpz_ior (z, w, temp); } - static void eval(mpz_ptr z, signed long int l, mpz_srcptr w) - { __GMPXX_TMP_SI; mpz_ior (z, w, temp); } - static void eval(mpz_ptr z, mpz_srcptr w, double d) - { __GMPXX_TMP_D; mpz_ior (z, w, temp); } - static void eval(mpz_ptr z, double d, mpz_srcptr w) - { __GMPXX_TMP_D; mpz_ior (z, w, temp); } -}; - -struct __gmp_binary_xor -{ - static void eval(mpz_ptr z, mpz_srcptr w, mpz_srcptr v) - { mpz_xor(z, w, v); } - static void eval(mpz_ptr z, mpz_srcptr w, unsigned long int l) - { __GMPXX_TMP_UI; mpz_xor (z, w, temp); } - static void eval(mpz_ptr z, unsigned long int l, mpz_srcptr w) - { __GMPXX_TMP_UI; mpz_xor (z, w, temp); } - static void eval(mpz_ptr z, mpz_srcptr w, signed long int l) - { __GMPXX_TMP_SI; mpz_xor (z, w, temp); } - static void eval(mpz_ptr z, signed long int l, mpz_srcptr w) - { __GMPXX_TMP_SI; mpz_xor (z, w, temp); } - static void eval(mpz_ptr z, mpz_srcptr w, double d) - { __GMPXX_TMP_D; mpz_xor (z, w, temp); } - static void eval(mpz_ptr z, double d, mpz_srcptr w) - { __GMPXX_TMP_D; mpz_xor (z, w, temp); } -}; - -struct __gmp_binary_lshift -{ - static void eval(mpz_ptr z, mpz_srcptr w, unsigned long int l) - { mpz_mul_2exp(z, w, l); } - static void eval(mpq_ptr q, mpq_srcptr r, unsigned long int l) - { mpq_mul_2exp(q, r, l); } - static void eval(mpf_ptr f, mpf_srcptr g, unsigned long int l) - { mpf_mul_2exp(f, g, l); } -}; - -struct __gmp_binary_rshift -{ - static void eval(mpz_ptr z, mpz_srcptr w, unsigned long int l) - { mpz_fdiv_q_2exp(z, w, l); } - static void eval(mpq_ptr q, mpq_srcptr r, unsigned long int l) - { mpq_div_2exp(q, r, l); } - static void eval(mpf_ptr f, mpf_srcptr g, unsigned long int l) - { mpf_div_2exp(f, g, l); } -}; - -struct __gmp_binary_equal -{ - static bool eval(mpz_srcptr z, mpz_srcptr w) { return mpz_cmp(z, w) == 0; } - - static bool eval(mpz_srcptr z, unsigned long int l) - { return mpz_cmp_ui(z, l) == 0; } - static bool eval(unsigned long int l, mpz_srcptr z) - { return mpz_cmp_ui(z, l) == 0; } - static bool eval(mpz_srcptr z, signed long int l) - { return mpz_cmp_si(z, l) == 0; } - static bool eval(signed long int l, mpz_srcptr z) - { return mpz_cmp_si(z, l) == 0; } - static bool eval(mpz_srcptr z, double d) - { return mpz_cmp_d(z, d) == 0; } - static bool eval(double d, mpz_srcptr z) - { return mpz_cmp_d(z, d) == 0; } - - static bool eval(mpq_srcptr q, mpq_srcptr r) - { return mpq_equal(q, r) != 0; } - - static bool eval(mpq_srcptr q, unsigned long int l) - { return mpq_cmp_ui(q, l, 1) == 0; } - static bool eval(unsigned long int l, mpq_srcptr q) - { return mpq_cmp_ui(q, l, 1) == 0; } - static bool eval(mpq_srcptr q, signed long int l) - { return mpq_cmp_si(q, l, 1) == 0; } - static bool eval(signed long int l, mpq_srcptr q) - { return mpq_cmp_si(q, l, 1) == 0; } - static bool eval(mpq_srcptr q, double d) - { - bool b; - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - b = (mpq_equal(q, temp) != 0); - mpq_clear(temp); - return b; - } - static bool eval(double d, mpq_srcptr q) - { - bool b; - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - b = (mpq_equal(temp, q) != 0); - mpq_clear(temp); - return b; - } - - static bool eval(mpf_srcptr f, mpf_srcptr g) { return mpf_cmp(f, g) == 0; } - - static bool eval(mpf_srcptr f, unsigned long int l) - { return mpf_cmp_ui(f, l) == 0; } - static bool eval(unsigned long int l, mpf_srcptr f) - { return mpf_cmp_ui(f, l) == 0; } - static bool eval(mpf_srcptr f, signed long int l) - { return mpf_cmp_si(f, l) == 0; } - static bool eval(signed long int l, mpf_srcptr f) - { return mpf_cmp_si(f, l) == 0; } - static bool eval(mpf_srcptr f, double d) - { return mpf_cmp_d(f, d) == 0; } - static bool eval(double d, mpf_srcptr f) - { return mpf_cmp_d(f, d) == 0; } -}; - -struct __gmp_binary_not_equal -{ - static bool eval(mpz_srcptr z, mpz_srcptr w) { return mpz_cmp(z, w) != 0; } - - static bool eval(mpz_srcptr z, unsigned long int l) - { return mpz_cmp_ui(z, l) != 0; } - static bool eval(unsigned long int l, mpz_srcptr z) - { return mpz_cmp_ui(z, l) != 0; } - static bool eval(mpz_srcptr z, signed long int l) - { return mpz_cmp_si(z, l) != 0; } - static bool eval(signed long int l, mpz_srcptr z) - { return mpz_cmp_si(z, l) != 0; } - static bool eval(mpz_srcptr z, double d) - { return mpz_cmp_d(z, d) != 0; } - static bool eval(double d, mpz_srcptr z) - { return mpz_cmp_d(z, d) != 0; } - - static bool eval(mpq_srcptr q, mpq_srcptr r) - { return mpq_equal(q, r) == 0; } - - static bool eval(mpq_srcptr q, unsigned long int l) - { return mpq_cmp_ui(q, l, 1) != 0; } - static bool eval(unsigned long int l, mpq_srcptr q) - { return mpq_cmp_ui(q, l, 1) != 0; } - static bool eval(mpq_srcptr q, signed long int l) - { return mpq_cmp_si(q, l, 1) != 0; } - static bool eval(signed long int l, mpq_srcptr q) - { return mpq_cmp_si(q, l, 1) != 0; } - static bool eval(mpq_srcptr q, double d) - { - bool b; - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - b = (mpq_equal(q, temp) == 0); - mpq_clear(temp); - return b; - } - static bool eval(double d, mpq_srcptr q) - { - bool b; - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - b = (mpq_equal(temp, q) == 0); - mpq_clear(temp); - return b; - } - - static bool eval(mpf_srcptr f, mpf_srcptr g) { return mpf_cmp(f, g) != 0; } - - static bool eval(mpf_srcptr f, unsigned long int l) - { return mpf_cmp_ui(f, l) != 0; } - static bool eval(unsigned long int l, mpf_srcptr f) - { return mpf_cmp_ui(f, l) != 0; } - static bool eval(mpf_srcptr f, signed long int l) - { return mpf_cmp_si(f, l) != 0; } - static bool eval(signed long int l, mpf_srcptr f) - { return mpf_cmp_si(f, l) != 0; } - static bool eval(mpf_srcptr f, double d) - { return mpf_cmp_d(f, d) != 0; } - static bool eval(double d, mpf_srcptr f) - { return mpf_cmp_d(f, d) != 0; } -}; - -struct __gmp_binary_less -{ - static bool eval(mpz_srcptr z, mpz_srcptr w) { return mpz_cmp(z, w) < 0; } - - static bool eval(mpz_srcptr z, unsigned long int l) - { return mpz_cmp_ui(z, l) < 0; } - static bool eval(unsigned long int l, mpz_srcptr z) - { return mpz_cmp_ui(z, l) > 0; } - static bool eval(mpz_srcptr z, signed long int l) - { return mpz_cmp_si(z, l) < 0; } - static bool eval(signed long int l, mpz_srcptr z) - { return mpz_cmp_si(z, l) > 0; } - static bool eval(mpz_srcptr z, double d) - { return mpz_cmp_d(z, d) < 0; } - static bool eval(double d, mpz_srcptr z) - { return mpz_cmp_d(z, d) > 0; } - - static bool eval(mpq_srcptr q, mpq_srcptr r) { return mpq_cmp(q, r) < 0; } - - static bool eval(mpq_srcptr q, unsigned long int l) - { return mpq_cmp_ui(q, l, 1) < 0; } - static bool eval(unsigned long int l, mpq_srcptr q) - { return mpq_cmp_ui(q, l, 1) > 0; } - static bool eval(mpq_srcptr q, signed long int l) - { return mpq_cmp_si(q, l, 1) < 0; } - static bool eval(signed long int l, mpq_srcptr q) - { return mpq_cmp_si(q, l, 1) > 0; } - static bool eval(mpq_srcptr q, double d) - { - bool b; - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - b = (mpq_cmp(q, temp) < 0); - mpq_clear(temp); - return b; - } - static bool eval(double d, mpq_srcptr q) - { - bool b; - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - b = (mpq_cmp(temp, q) < 0); - mpq_clear(temp); - return b; - } - - static bool eval(mpf_srcptr f, mpf_srcptr g) { return mpf_cmp(f, g) < 0; } - - static bool eval(mpf_srcptr f, unsigned long int l) - { return mpf_cmp_ui(f, l) < 0; } - static bool eval(unsigned long int l, mpf_srcptr f) - { return mpf_cmp_ui(f, l) > 0; } - static bool eval(mpf_srcptr f, signed long int l) - { return mpf_cmp_si(f, l) < 0; } - static bool eval(signed long int l, mpf_srcptr f) - { return mpf_cmp_si(f, l) > 0; } - static bool eval(mpf_srcptr f, double d) - { return mpf_cmp_d(f, d) < 0; } - static bool eval(double d, mpf_srcptr f) - { return mpf_cmp_d(f, d) > 0; } -}; - -struct __gmp_binary_less_equal -{ - static bool eval(mpz_srcptr z, mpz_srcptr w) { return mpz_cmp(z, w) <= 0; } - - static bool eval(mpz_srcptr z, unsigned long int l) - { return mpz_cmp_ui(z, l) <= 0; } - static bool eval(unsigned long int l, mpz_srcptr z) - { return mpz_cmp_ui(z, l) >= 0; } - static bool eval(mpz_srcptr z, signed long int l) - { return mpz_cmp_si(z, l) <= 0; } - static bool eval(signed long int l, mpz_srcptr z) - { return mpz_cmp_si(z, l) >= 0; } - static bool eval(mpz_srcptr z, double d) - { return mpz_cmp_d(z, d) <= 0; } - static bool eval(double d, mpz_srcptr z) - { return mpz_cmp_d(z, d) >= 0; } - - static bool eval(mpq_srcptr q, mpq_srcptr r) { return mpq_cmp(q, r) <= 0; } - - static bool eval(mpq_srcptr q, unsigned long int l) - { return mpq_cmp_ui(q, l, 1) <= 0; } - static bool eval(unsigned long int l, mpq_srcptr q) - { return mpq_cmp_ui(q, l, 1) >= 0; } - static bool eval(mpq_srcptr q, signed long int l) - { return mpq_cmp_si(q, l, 1) <= 0; } - static bool eval(signed long int l, mpq_srcptr q) - { return mpq_cmp_si(q, l, 1) >= 0; } - static bool eval(mpq_srcptr q, double d) - { - bool b; - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - b = (mpq_cmp(q, temp) <= 0); - mpq_clear(temp); - return b; - } - static bool eval(double d, mpq_srcptr q) - { - bool b; - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - b = (mpq_cmp(temp, q) <= 0); - mpq_clear(temp); - return b; - } - - static bool eval(mpf_srcptr f, mpf_srcptr g) { return mpf_cmp(f, g) <= 0; } - - static bool eval(mpf_srcptr f, unsigned long int l) - { return mpf_cmp_ui(f, l) <= 0; } - static bool eval(unsigned long int l, mpf_srcptr f) - { return mpf_cmp_ui(f, l) >= 0; } - static bool eval(mpf_srcptr f, signed long int l) - { return mpf_cmp_si(f, l) <= 0; } - static bool eval(signed long int l, mpf_srcptr f) - { return mpf_cmp_si(f, l) >= 0; } - static bool eval(mpf_srcptr f, double d) - { return mpf_cmp_d(f, d) <= 0; } - static bool eval(double d, mpf_srcptr f) - { return mpf_cmp_d(f, d) >= 0; } -}; - -struct __gmp_binary_greater -{ - static bool eval(mpz_srcptr z, mpz_srcptr w) { return mpz_cmp(z, w) > 0; } - - static bool eval(mpz_srcptr z, unsigned long int l) - { return mpz_cmp_ui(z, l) > 0; } - static bool eval(unsigned long int l, mpz_srcptr z) - { return mpz_cmp_ui(z, l) < 0; } - static bool eval(mpz_srcptr z, signed long int l) - { return mpz_cmp_si(z, l) > 0; } - static bool eval(signed long int l, mpz_srcptr z) - { return mpz_cmp_si(z, l) < 0; } - static bool eval(mpz_srcptr z, double d) - { return mpz_cmp_d(z, d) > 0; } - static bool eval(double d, mpz_srcptr z) - { return mpz_cmp_d(z, d) < 0; } - - static bool eval(mpq_srcptr q, mpq_srcptr r) { return mpq_cmp(q, r) > 0; } - - static bool eval(mpq_srcptr q, unsigned long int l) - { return mpq_cmp_ui(q, l, 1) > 0; } - static bool eval(unsigned long int l, mpq_srcptr q) - { return mpq_cmp_ui(q, l, 1) < 0; } - static bool eval(mpq_srcptr q, signed long int l) - { return mpq_cmp_si(q, l, 1) > 0; } - static bool eval(signed long int l, mpq_srcptr q) - { return mpq_cmp_si(q, l, 1) < 0; } - static bool eval(mpq_srcptr q, double d) - { - bool b; - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - b = (mpq_cmp(q, temp) > 0); - mpq_clear(temp); - return b; - } - static bool eval(double d, mpq_srcptr q) - { - bool b; - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - b = (mpq_cmp(temp, q) > 0); - mpq_clear(temp); - return b; - } - - static bool eval(mpf_srcptr f, mpf_srcptr g) { return mpf_cmp(f, g) > 0; } - - static bool eval(mpf_srcptr f, unsigned long int l) - { return mpf_cmp_ui(f, l) > 0; } - static bool eval(unsigned long int l, mpf_srcptr f) - { return mpf_cmp_ui(f, l) < 0; } - static bool eval(mpf_srcptr f, signed long int l) - { return mpf_cmp_si(f, l) > 0; } - static bool eval(signed long int l, mpf_srcptr f) - { return mpf_cmp_si(f, l) < 0; } - static bool eval(mpf_srcptr f, double d) - { return mpf_cmp_d(f, d) > 0; } - static bool eval(double d, mpf_srcptr f) - { return mpf_cmp_d(f, d) < 0; } -}; - -struct __gmp_binary_greater_equal -{ - static bool eval(mpz_srcptr z, mpz_srcptr w) { return mpz_cmp(z, w) >= 0; } - - static bool eval(mpz_srcptr z, unsigned long int l) - { return mpz_cmp_ui(z, l) >= 0; } - static bool eval(unsigned long int l, mpz_srcptr z) - { return mpz_cmp_ui(z, l) <= 0; } - static bool eval(mpz_srcptr z, signed long int l) - { return mpz_cmp_si(z, l) >= 0; } - static bool eval(signed long int l, mpz_srcptr z) - { return mpz_cmp_si(z, l) <= 0; } - static bool eval(mpz_srcptr z, double d) - { return mpz_cmp_d(z, d) >= 0; } - static bool eval(double d, mpz_srcptr z) - { return mpz_cmp_d(z, d) <= 0; } - - static bool eval(mpq_srcptr q, mpq_srcptr r) { return mpq_cmp(q, r) >= 0; } - - static bool eval(mpq_srcptr q, unsigned long int l) - { return mpq_cmp_ui(q, l, 1) >= 0; } - static bool eval(unsigned long int l, mpq_srcptr q) - { return mpq_cmp_ui(q, l, 1) <= 0; } - static bool eval(mpq_srcptr q, signed long int l) - { return mpq_cmp_si(q, l, 1) >= 0; } - static bool eval(signed long int l, mpq_srcptr q) - { return mpq_cmp_si(q, l, 1) <= 0; } - static bool eval(mpq_srcptr q, double d) - { - bool b; - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - b = (mpq_cmp(q, temp) >= 0); - mpq_clear(temp); - return b; - } - static bool eval(double d, mpq_srcptr q) - { - bool b; - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - b = (mpq_cmp(temp, q) >= 0); - mpq_clear(temp); - return b; - } - - static bool eval(mpf_srcptr f, mpf_srcptr g) { return mpf_cmp(f, g) >= 0; } - - static bool eval(mpf_srcptr f, unsigned long int l) - { return mpf_cmp_ui(f, l) >= 0; } - static bool eval(unsigned long int l, mpf_srcptr f) - { return mpf_cmp_ui(f, l) <= 0; } - static bool eval(mpf_srcptr f, signed long int l) - { return mpf_cmp_si(f, l) >= 0; } - static bool eval(signed long int l, mpf_srcptr f) - { return mpf_cmp_si(f, l) <= 0; } - static bool eval(mpf_srcptr f, double d) - { return mpf_cmp_d(f, d) >= 0; } - static bool eval(double d, mpf_srcptr f) - { return mpf_cmp_d(f, d) <= 0; } -}; - -struct __gmp_unary_increment -{ - static void eval(mpz_ptr z) { mpz_add_ui(z, z, 1); } - static void eval(mpq_ptr q) - { mpz_add(mpq_numref(q), mpq_numref(q), mpq_denref(q)); } - static void eval(mpf_ptr f) { mpf_add_ui(f, f, 1); } -}; - -struct __gmp_unary_decrement -{ - static void eval(mpz_ptr z) { mpz_sub_ui(z, z, 1); } - static void eval(mpq_ptr q) - { mpz_sub(mpq_numref(q), mpq_numref(q), mpq_denref(q)); } - static void eval(mpf_ptr f) { mpf_sub_ui(f, f, 1); } -}; - -struct __gmp_abs_function -{ - static void eval(mpz_ptr z, mpz_srcptr w) { mpz_abs(z, w); } - static void eval(mpq_ptr q, mpq_srcptr r) { mpq_abs(q, r); } - static void eval(mpf_ptr f, mpf_srcptr g) { mpf_abs(f, g); } -}; - -struct __gmp_trunc_function -{ - static void eval(mpf_ptr f, mpf_srcptr g) { mpf_trunc(f, g); } -}; - -struct __gmp_floor_function -{ - static void eval(mpf_ptr f, mpf_srcptr g) { mpf_floor(f, g); } -}; - -struct __gmp_ceil_function -{ - static void eval(mpf_ptr f, mpf_srcptr g) { mpf_ceil(f, g); } -}; - -struct __gmp_sqrt_function -{ - static void eval(mpz_ptr z, mpz_srcptr w) { mpz_sqrt(z, w); } - static void eval(mpf_ptr f, mpf_srcptr g) { mpf_sqrt(f, g); } -}; - -struct __gmp_hypot_function -{ - static void eval(mpf_ptr f, mpf_srcptr g, mpf_srcptr h) - { - mpf_t temp; - mpf_init2(temp, mpf_get_prec(f)); - mpf_mul(temp, g, g); - mpf_mul(f, h, h); - mpf_add(f, f, temp); - mpf_sqrt(f, f); - mpf_clear(temp); - } - - static void eval(mpf_ptr f, mpf_srcptr g, unsigned long int l) - { - mpf_t temp; - mpf_init2(temp, mpf_get_prec(f)); - mpf_mul(temp, g, g); - mpf_set_ui(f, l); - mpf_mul(f, f, f); - mpf_add(f, f, temp); - mpf_sqrt(f, f); - mpf_clear(temp); - } - static void eval(mpf_ptr f, unsigned long int l, mpf_srcptr g) - { - mpf_t temp; - mpf_init2(temp, mpf_get_prec(f)); - mpf_mul(temp, g, g); - mpf_set_ui(f, l); - mpf_mul(f, f, f); - mpf_add(f, f, temp); - mpf_sqrt(f, f); - mpf_clear(temp); - } - static void eval(mpf_ptr f, mpf_srcptr g, signed long int l) - { - mpf_t temp; - mpf_init2(temp, mpf_get_prec(f)); - mpf_mul(temp, g, g); - mpf_set_si(f, l); - mpf_mul(f, f, f); - mpf_add(f, f, temp); - mpf_sqrt(f, f); - mpf_clear(temp); - } - static void eval(mpf_ptr f, signed long int l, mpf_srcptr g) - { - mpf_t temp; - mpf_init2(temp, mpf_get_prec(f)); - mpf_mul(temp, g, g); - mpf_set_si(f, l); - mpf_mul(f, f, f); - mpf_add(f, f, temp); - mpf_sqrt(f, f); - mpf_clear(temp); - } - static void eval(mpf_ptr f, mpf_srcptr g, double d) - { - mpf_t temp; - mpf_init2(temp, mpf_get_prec(f)); - mpf_mul(temp, g, g); - mpf_set_d(f, d); - mpf_mul(f, f, f); - mpf_add(f, f, temp); - mpf_sqrt(f, f); - mpf_clear(temp); - } - static void eval(mpf_ptr f, double d, mpf_srcptr g) - { - mpf_t temp; - mpf_init2(temp, mpf_get_prec(f)); - mpf_mul(temp, g, g); - mpf_set_d(f, d); - mpf_mul(f, f, f); - mpf_add(f, f, temp); - mpf_sqrt(f, f); - mpf_clear(temp); - } -}; - -struct __gmp_sgn_function -{ - static int eval(mpz_srcptr z) { return mpz_sgn(z); } - static int eval(mpq_srcptr q) { return mpq_sgn(q); } - static int eval(mpf_srcptr f) { return mpf_sgn(f); } -}; - -struct __gmp_cmp_function -{ - static int eval(mpz_srcptr z, mpz_srcptr w) { return mpz_cmp(z, w); } - - static int eval(mpz_srcptr z, unsigned long int l) - { return mpz_cmp_ui(z, l); } - static int eval(unsigned long int l, mpz_srcptr z) - { return -mpz_cmp_ui(z, l); } - static int eval(mpz_srcptr z, signed long int l) - { return mpz_cmp_si(z, l); } - static int eval(signed long int l, mpz_srcptr z) - { return -mpz_cmp_si(z, l); } - static int eval(mpz_srcptr z, double d) - { return mpz_cmp_d(z, d); } - static int eval(double d, mpz_srcptr z) - { return -mpz_cmp_d(z, d); } - - static int eval(mpq_srcptr q, mpq_srcptr r) { return mpq_cmp(q, r); } - - static int eval(mpq_srcptr q, unsigned long int l) - { return mpq_cmp_ui(q, l, 1); } - static int eval(unsigned long int l, mpq_srcptr q) - { return -mpq_cmp_ui(q, l, 1); } - static int eval(mpq_srcptr q, signed long int l) - { return mpq_cmp_si(q, l, 1); } - static int eval(signed long int l, mpq_srcptr q) - { return -mpq_cmp_si(q, l, 1); } - static int eval(mpq_srcptr q, double d) - { - int i; - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - i = mpq_cmp(q, temp); - mpq_clear(temp); - return i; - } - static int eval(double d, mpq_srcptr q) - { - int i; - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - i = mpq_cmp(temp, q); - mpq_clear(temp); - return i; - } - - static int eval(mpf_srcptr f, mpf_srcptr g) { return mpf_cmp(f, g); } - - static int eval(mpf_srcptr f, unsigned long int l) - { return mpf_cmp_ui(f, l); } - static int eval(unsigned long int l, mpf_srcptr f) - { return -mpf_cmp_ui(f, l); } - static int eval(mpf_srcptr f, signed long int l) - { return mpf_cmp_si(f, l); } - static int eval(signed long int l, mpf_srcptr f) - { return -mpf_cmp_si(f, l); } - static int eval(mpf_srcptr f, double d) - { return mpf_cmp_d(f, d); } - static int eval(double d, mpf_srcptr f) - { return -mpf_cmp_d(f, d); } -}; - -struct __gmp_rand_function -{ - static void eval(mpz_ptr z, gmp_randstate_t s, unsigned long int l) - { mpz_urandomb(z, s, l); } - static void eval(mpz_ptr z, gmp_randstate_t s, mpz_srcptr w) - { mpz_urandomm(z, s, w); } - static void eval(mpf_ptr f, gmp_randstate_t s, mp_bitcnt_t prec) - { mpf_urandomb(f, s, prec); } -}; - - -/**************** Auxiliary classes ****************/ - -/* this is much the same as gmp_allocated_string in gmp-impl.h - since gmp-impl.h is not publicly available, I redefine it here - I use a different name to avoid possible clashes */ -extern "C" { -struct __gmp_alloc_cstring_c -{ - void (*free_func) (void *, size_t); -}; -} - -struct __gmp_alloc_cstring : __gmp_alloc_cstring_c -{ - char *str; - __gmp_alloc_cstring(char *s) { str = s; } - ~__gmp_alloc_cstring() - { - mp_get_memory_functions (NULL, NULL, &free_func); - (*free_func) (str, std::strlen(str)+1); - } -}; - -// general expression template class -template -class __gmp_expr; - - -// templates for resolving expression types -template -struct __gmp_resolve_ref -{ - typedef T ref_type; -}; - -template -struct __gmp_resolve_ref<__gmp_expr > -{ - typedef const __gmp_expr & ref_type; -}; - - -template -struct __gmp_resolve_expr; - -template <> -struct __gmp_resolve_expr -{ - typedef mpz_t value_type; - typedef mpz_ptr ptr_type; -}; - -template <> -struct __gmp_resolve_expr -{ - typedef mpq_t value_type; - typedef mpq_ptr ptr_type; -}; - -template <> -struct __gmp_resolve_expr -{ - typedef mpf_t value_type; - typedef mpf_ptr ptr_type; -}; - -template <> -struct __gmp_resolve_expr -{ - typedef mpq_t value_type; -}; - -template <> -struct __gmp_resolve_expr -{ - typedef mpq_t value_type; -}; - -template <> -struct __gmp_resolve_expr -{ - typedef mpf_t value_type; -}; - -template <> -struct __gmp_resolve_expr -{ - typedef mpf_t value_type; -}; - -template <> -struct __gmp_resolve_expr -{ - typedef mpf_t value_type; -}; - -template <> -struct __gmp_resolve_expr -{ - typedef mpf_t value_type; -}; - - - -template -struct __gmp_resolve_temp -{ - typedef __gmp_expr temp_type; -}; - -template -struct __gmp_resolve_temp -{ - typedef const __gmp_expr & temp_type; -}; - - -// classes for evaluating unary and binary expressions -template -struct __gmp_unary_expr -{ - const T &val; - - __gmp_unary_expr(const T &v) : val(v) { } -private: - __gmp_unary_expr(); -}; - -template -struct __gmp_binary_expr -{ - typename __gmp_resolve_ref::ref_type val1; - typename __gmp_resolve_ref::ref_type val2; - - __gmp_binary_expr(const T &v1, const U &v2) : val1(v1), val2(v2) { } -private: - __gmp_binary_expr(); -}; - - -// functions for evaluating expressions -template -void __gmp_set_expr(mpz_ptr, const __gmp_expr &); -template -void __gmp_set_expr(mpq_ptr, const __gmp_expr &); -template -void __gmp_set_expr(mpf_ptr, const __gmp_expr &); - - -/**************** Macros for in-class declarations ****************/ -/* This is just repetitive code that is easier to maintain if it's written - only once */ - -#define __GMPP_DECLARE_COMPOUND_OPERATOR(fun) \ - template \ - __gmp_expr & fun(const __gmp_expr &); - -#define __GMPN_DECLARE_COMPOUND_OPERATOR(fun) \ - __gmp_expr & fun(signed char); \ - __gmp_expr & fun(unsigned char); \ - __gmp_expr & fun(signed int); \ - __gmp_expr & fun(unsigned int); \ - __gmp_expr & fun(signed short int); \ - __gmp_expr & fun(unsigned short int); \ - __gmp_expr & fun(signed long int); \ - __gmp_expr & fun(unsigned long int); \ - __gmp_expr & fun(float); \ - __gmp_expr & fun(double); \ - __gmp_expr & fun(long double); - -#define __GMP_DECLARE_COMPOUND_OPERATOR(fun) \ -__GMPP_DECLARE_COMPOUND_OPERATOR(fun) \ -__GMPN_DECLARE_COMPOUND_OPERATOR(fun) - -#define __GMP_DECLARE_COMPOUND_OPERATOR_UI(fun) \ - __gmp_expr & fun(unsigned long int); - -#define __GMP_DECLARE_INCREMENT_OPERATOR(fun) \ - inline __gmp_expr & fun(); \ - inline __gmp_expr fun(int); - - -/**************** mpz_class -- wrapper for mpz_t ****************/ - -template <> -class __gmp_expr -{ -private: - typedef mpz_t value_type; - value_type mp; -public: - mp_bitcnt_t get_prec() const { return mpf_get_default_prec(); } - - // constructors and destructor - __gmp_expr() { mpz_init(mp); } - - __gmp_expr(const __gmp_expr &z) { mpz_init_set(mp, z.mp); } - template - __gmp_expr(const __gmp_expr &expr) - { mpz_init(mp); __gmp_set_expr(mp, expr); } - - __gmp_expr(signed char c) { mpz_init_set_si(mp, c); } - __gmp_expr(unsigned char c) { mpz_init_set_ui(mp, c); } - - __gmp_expr(signed int i) { mpz_init_set_si(mp, i); } - __gmp_expr(unsigned int i) { mpz_init_set_ui(mp, i); } - - __gmp_expr(signed short int s) { mpz_init_set_si(mp, s); } - __gmp_expr(unsigned short int s) { mpz_init_set_ui(mp, s); } - - __gmp_expr(signed long int l) { mpz_init_set_si(mp, l); } - __gmp_expr(unsigned long int l) { mpz_init_set_ui(mp, l); } - - __gmp_expr(float f) { mpz_init_set_d(mp, f); } - __gmp_expr(double d) { mpz_init_set_d(mp, d); } - // __gmp_expr(long double ld) { mpz_init_set_d(mp, ld); } - - explicit __gmp_expr(const char *s) - { - if (mpz_init_set_str (mp, s, 0) != 0) - { - mpz_clear (mp); - throw std::invalid_argument ("mpz_set_str"); - } - } - __gmp_expr(const char *s, int base) - { - if (mpz_init_set_str (mp, s, base) != 0) - { - mpz_clear (mp); - throw std::invalid_argument ("mpz_set_str"); - } - } - explicit __gmp_expr(const std::string &s) - { - if (mpz_init_set_str (mp, s.c_str(), 0) != 0) - { - mpz_clear (mp); - throw std::invalid_argument ("mpz_set_str"); - } - } - __gmp_expr(const std::string &s, int base) - { - if (mpz_init_set_str(mp, s.c_str(), base) != 0) - { - mpz_clear (mp); - throw std::invalid_argument ("mpz_set_str"); - } - } - - explicit __gmp_expr(mpz_srcptr z) { mpz_init_set(mp, z); } - - ~__gmp_expr() { mpz_clear(mp); } - - // assignment operators - __gmp_expr & operator=(const __gmp_expr &z) - { mpz_set(mp, z.mp); return *this; } - template - __gmp_expr & operator=(const __gmp_expr &expr) - { __gmp_set_expr(mp, expr); return *this; } - - __gmp_expr & operator=(signed char c) { mpz_set_si(mp, c); return *this; } - __gmp_expr & operator=(unsigned char c) { mpz_set_ui(mp, c); return *this; } - - __gmp_expr & operator=(signed int i) { mpz_set_si(mp, i); return *this; } - __gmp_expr & operator=(unsigned int i) { mpz_set_ui(mp, i); return *this; } - - __gmp_expr & operator=(signed short int s) - { mpz_set_si(mp, s); return *this; } - __gmp_expr & operator=(unsigned short int s) - { mpz_set_ui(mp, s); return *this; } - - __gmp_expr & operator=(signed long int l) - { mpz_set_si(mp, l); return *this; } - __gmp_expr & operator=(unsigned long int l) - { mpz_set_ui(mp, l); return *this; } - - __gmp_expr & operator=(float f) { mpz_set_d(mp, f); return *this; } - __gmp_expr & operator=(double d) { mpz_set_d(mp, d); return *this; } - // __gmp_expr & operator=(long double ld) - // { mpz_set_ld(mp, ld); return *this; } - - __gmp_expr & operator=(const char *s) - { - if (mpz_set_str (mp, s, 0) != 0) - throw std::invalid_argument ("mpz_set_str"); - return *this; - } - __gmp_expr & operator=(const std::string &s) - { - if (mpz_set_str(mp, s.c_str(), 0) != 0) - throw std::invalid_argument ("mpz_set_str"); - return *this; - } - - // string input/output functions - int set_str(const char *s, int base) - { return mpz_set_str(mp, s, base); } - int set_str(const std::string &s, int base) - { return mpz_set_str(mp, s.c_str(), base); } - std::string get_str(int base = 10) const - { - __gmp_alloc_cstring temp(mpz_get_str(0, base, mp)); - return std::string(temp.str); - } - - // conversion functions - mpz_srcptr __get_mp() const { return mp; } - mpz_ptr __get_mp() { return mp; } - mpz_srcptr get_mpz_t() const { return mp; } - mpz_ptr get_mpz_t() { return mp; } - - signed long int get_si() const { return mpz_get_si(mp); } - unsigned long int get_ui() const { return mpz_get_ui(mp); } - double get_d() const { return mpz_get_d(mp); } - - // bool fits_schar_p() const { return mpz_fits_schar_p(mp); } - // bool fits_uchar_p() const { return mpz_fits_uchar_p(mp); } - bool fits_sint_p() const { return mpz_fits_sint_p(mp); } - bool fits_uint_p() const { return mpz_fits_uint_p(mp); } - bool fits_sshort_p() const { return mpz_fits_sshort_p(mp); } - bool fits_ushort_p() const { return mpz_fits_ushort_p(mp); } - bool fits_slong_p() const { return mpz_fits_slong_p(mp); } - bool fits_ulong_p() const { return mpz_fits_ulong_p(mp); } - // bool fits_float_p() const { return mpz_fits_float_p(mp); } - // bool fits_double_p() const { return mpz_fits_double_p(mp); } - // bool fits_ldouble_p() const { return mpz_fits_ldouble_p(mp); } - - // member operators - __GMP_DECLARE_COMPOUND_OPERATOR(operator+=) - __GMP_DECLARE_COMPOUND_OPERATOR(operator-=) - __GMP_DECLARE_COMPOUND_OPERATOR(operator*=) - __GMP_DECLARE_COMPOUND_OPERATOR(operator/=) - __GMP_DECLARE_COMPOUND_OPERATOR(operator%=) - - __GMPP_DECLARE_COMPOUND_OPERATOR(operator&=) - __GMPP_DECLARE_COMPOUND_OPERATOR(operator|=) - __GMPP_DECLARE_COMPOUND_OPERATOR(operator^=) - - __GMP_DECLARE_COMPOUND_OPERATOR_UI(operator<<=) - __GMP_DECLARE_COMPOUND_OPERATOR_UI(operator>>=) - - __GMP_DECLARE_INCREMENT_OPERATOR(operator++) - __GMP_DECLARE_INCREMENT_OPERATOR(operator--) -}; - -typedef __gmp_expr mpz_class; - - -/**************** mpq_class -- wrapper for mpq_t ****************/ - -template <> -class __gmp_expr -{ -private: - typedef mpq_t value_type; - value_type mp; -public: - mp_bitcnt_t get_prec() const { return mpf_get_default_prec(); } - void canonicalize() { mpq_canonicalize(mp); } - - // constructors and destructor - __gmp_expr() { mpq_init(mp); } - - __gmp_expr(const __gmp_expr &q) { mpq_init(mp); mpq_set(mp, q.mp); } - template - __gmp_expr(const __gmp_expr &expr) - { mpq_init(mp); __gmp_set_expr(mp, expr); } - - __gmp_expr(signed char c) { mpq_init(mp); mpq_set_si(mp, c, 1); } - __gmp_expr(unsigned char c) { mpq_init(mp); mpq_set_ui(mp, c, 1); } - - __gmp_expr(signed int i) { mpq_init(mp); mpq_set_si(mp, i, 1); } - __gmp_expr(unsigned int i) { mpq_init(mp); mpq_set_ui(mp, i, 1); } - - __gmp_expr(signed short int s) { mpq_init(mp); mpq_set_si(mp, s, 1); } - __gmp_expr(unsigned short int s) { mpq_init(mp); mpq_set_ui(mp, s, 1); } - - __gmp_expr(signed long int l) { mpq_init(mp); mpq_set_si(mp, l, 1); } - __gmp_expr(unsigned long int l) { mpq_init(mp); mpq_set_ui(mp, l, 1); } - - __gmp_expr(float f) { mpq_init(mp); mpq_set_d(mp, f); } - __gmp_expr(double d) { mpq_init(mp); mpq_set_d(mp, d); } - // __gmp_expr(long double ld) { mpq_init(mp); mpq_set_ld(mp, ld); } - - explicit __gmp_expr(const char *s) - { - mpq_init (mp); - if (mpq_set_str (mp, s, 0) != 0) - { - mpq_clear (mp); - throw std::invalid_argument ("mpq_set_str"); - } - } - __gmp_expr(const char *s, int base) - { - mpq_init (mp); - if (mpq_set_str(mp, s, base) != 0) - { - mpq_clear (mp); - throw std::invalid_argument ("mpq_set_str"); - } - } - explicit __gmp_expr(const std::string &s) - { - mpq_init (mp); - if (mpq_set_str (mp, s.c_str(), 0) != 0) - { - mpq_clear (mp); - throw std::invalid_argument ("mpq_set_str"); - } - } - __gmp_expr(const std::string &s, int base) - { - mpq_init(mp); - if (mpq_set_str (mp, s.c_str(), base) != 0) - { - mpq_clear (mp); - throw std::invalid_argument ("mpq_set_str"); - } - } - explicit __gmp_expr(mpq_srcptr q) { mpq_init(mp); mpq_set(mp, q); } - - __gmp_expr(const mpz_class &num, const mpz_class &den) - { - mpq_init(mp); - mpz_set(mpq_numref(mp), num.get_mpz_t()); - mpz_set(mpq_denref(mp), den.get_mpz_t()); - } - - ~__gmp_expr() { mpq_clear(mp); } - - // assignment operators - __gmp_expr & operator=(const __gmp_expr &q) - { mpq_set(mp, q.mp); return *this; } - template - __gmp_expr & operator=(const __gmp_expr &expr) - { __gmp_set_expr(mp, expr); return *this; } - - __gmp_expr & operator=(signed char c) - { mpq_set_si(mp, c, 1); return *this; } - __gmp_expr & operator=(unsigned char c) - { mpq_set_ui(mp, c, 1); return *this; } - - __gmp_expr & operator=(signed int i) { mpq_set_si(mp, i, 1); return *this; } - __gmp_expr & operator=(unsigned int i) - { mpq_set_ui(mp, i, 1); return *this; } - - __gmp_expr & operator=(signed short int s) - { mpq_set_si(mp, s, 1); return *this; } - __gmp_expr & operator=(unsigned short int s) - { mpq_set_ui(mp, s, 1); return *this; } - - __gmp_expr & operator=(signed long int l) - { mpq_set_si(mp, l, 1); return *this; } - __gmp_expr & operator=(unsigned long int l) - { mpq_set_ui(mp, l, 1); return *this; } - - __gmp_expr & operator=(float f) { mpq_set_d(mp, f); return *this; } - __gmp_expr & operator=(double d) { mpq_set_d(mp, d); return *this; } - // __gmp_expr & operator=(long double ld) - // { mpq_set_ld(mp, ld); return *this; } - - __gmp_expr & operator=(const char *s) - { - if (mpq_set_str (mp, s, 0) != 0) - throw std::invalid_argument ("mpq_set_str"); - return *this; - } - __gmp_expr & operator=(const std::string &s) - { - if (mpq_set_str(mp, s.c_str(), 0) != 0) - throw std::invalid_argument ("mpq_set_str"); - return *this; - } - - // string input/output functions - int set_str(const char *s, int base) - { return mpq_set_str(mp, s, base); } - int set_str(const std::string &s, int base) - { return mpq_set_str(mp, s.c_str(), base); } - std::string get_str(int base = 10) const - { - __gmp_alloc_cstring temp(mpq_get_str(0, base, mp)); - return std::string(temp.str); - } - - // conversion functions - - // casting a reference to an mpz_t to mpz_class & is a dirty hack, - // but works because the internal representation of mpz_class is - // exactly an mpz_t - const mpz_class & get_num() const - { return reinterpret_cast(*mpq_numref(mp)); } - mpz_class & get_num() - { return reinterpret_cast(*mpq_numref(mp)); } - const mpz_class & get_den() const - { return reinterpret_cast(*mpq_denref(mp)); } - mpz_class & get_den() - { return reinterpret_cast(*mpq_denref(mp)); } - - mpq_srcptr __get_mp() const { return mp; } - mpq_ptr __get_mp() { return mp; } - mpq_srcptr get_mpq_t() const { return mp; } - mpq_ptr get_mpq_t() { return mp; } - - mpz_srcptr get_num_mpz_t() const { return mpq_numref(mp); } - mpz_ptr get_num_mpz_t() { return mpq_numref(mp); } - mpz_srcptr get_den_mpz_t() const { return mpq_denref(mp); } - mpz_ptr get_den_mpz_t() { return mpq_denref(mp); } - - double get_d() const { return mpq_get_d(mp); } - - // compound assignments - __GMP_DECLARE_COMPOUND_OPERATOR(operator+=) - __GMP_DECLARE_COMPOUND_OPERATOR(operator-=) - __GMP_DECLARE_COMPOUND_OPERATOR(operator*=) - __GMP_DECLARE_COMPOUND_OPERATOR(operator/=) - - __GMP_DECLARE_COMPOUND_OPERATOR_UI(operator<<=) - __GMP_DECLARE_COMPOUND_OPERATOR_UI(operator>>=) - - __GMP_DECLARE_INCREMENT_OPERATOR(operator++) - __GMP_DECLARE_INCREMENT_OPERATOR(operator--) -}; - -typedef __gmp_expr mpq_class; - - -/**************** mpf_class -- wrapper for mpf_t ****************/ - -template <> -class __gmp_expr -{ -private: - typedef mpf_t value_type; - value_type mp; -public: - mp_bitcnt_t get_prec() const { return mpf_get_prec(mp); } - - void set_prec(mp_bitcnt_t prec) { mpf_set_prec(mp, prec); } - void set_prec_raw(mp_bitcnt_t prec) { mpf_set_prec_raw(mp, prec); } - - // constructors and destructor - __gmp_expr() { mpf_init(mp); } - - __gmp_expr(const __gmp_expr &f) - { mpf_init2(mp, f.get_prec()); mpf_set(mp, f.mp); } - __gmp_expr(const __gmp_expr &f, mp_bitcnt_t prec) - { mpf_init2(mp, prec); mpf_set(mp, f.mp); } - template - __gmp_expr(const __gmp_expr &expr) - { mpf_init2(mp, expr.get_prec()); __gmp_set_expr(mp, expr); } - template - __gmp_expr(const __gmp_expr &expr, mp_bitcnt_t prec) - { mpf_init2(mp, prec); __gmp_set_expr(mp, expr); } - - __gmp_expr(signed char c) { mpf_init_set_si(mp, c); } - __gmp_expr(signed char c, mp_bitcnt_t prec) - { mpf_init2(mp, prec); mpf_set_si(mp, c); } - __gmp_expr(unsigned char c) { mpf_init_set_ui(mp, c); } - __gmp_expr(unsigned char c, mp_bitcnt_t prec) - { mpf_init2(mp, prec); mpf_set_ui(mp, c); } - - __gmp_expr(signed int i) { mpf_init_set_si(mp, i); } - __gmp_expr(signed int i, mp_bitcnt_t prec) - { mpf_init2(mp, prec); mpf_set_si(mp, i); } - __gmp_expr(unsigned int i) { mpf_init_set_ui(mp, i); } - __gmp_expr(unsigned int i, mp_bitcnt_t prec) - { mpf_init2(mp, prec); mpf_set_ui(mp, i); } - - __gmp_expr(signed short int s) { mpf_init_set_si(mp, s); } - __gmp_expr(signed short int s, mp_bitcnt_t prec) - { mpf_init2(mp, prec); mpf_set_si(mp, s); } - __gmp_expr(unsigned short int s) { mpf_init_set_ui(mp, s); } - __gmp_expr(unsigned short int s, mp_bitcnt_t prec) - { mpf_init2(mp, prec); mpf_set_ui(mp, s); } - - __gmp_expr(signed long int l) { mpf_init_set_si(mp, l); } - __gmp_expr(signed long int l, mp_bitcnt_t prec) - { mpf_init2(mp, prec); mpf_set_si(mp, l); } - __gmp_expr(unsigned long int l) { mpf_init_set_ui(mp, l); } - __gmp_expr(unsigned long int l, mp_bitcnt_t prec) - { mpf_init2(mp, prec); mpf_set_ui(mp, l); } - - __gmp_expr(float f) { mpf_init_set_d(mp, f); } - __gmp_expr(float f, mp_bitcnt_t prec) - { mpf_init2(mp, prec); mpf_set_d(mp, f); } - __gmp_expr(double d) { mpf_init_set_d(mp, d); } - __gmp_expr(double d, mp_bitcnt_t prec) - { mpf_init2(mp, prec); mpf_set_d(mp, d); } - // __gmp_expr(long double ld) { mpf_init_set_d(mp, ld); } - // __gmp_expr(long double ld, mp_bitcnt_t prec) - // { mpf_init2(mp, prec); mpf_set_d(mp, ld); } - - explicit __gmp_expr(const char *s) - { - if (mpf_init_set_str (mp, s, 0) != 0) - { - mpf_clear (mp); - throw std::invalid_argument ("mpf_set_str"); - } - } - __gmp_expr(const char *s, mp_bitcnt_t prec, int base = 0) - { - mpf_init2(mp, prec); - if (mpf_set_str(mp, s, base) != 0) - { - mpf_clear (mp); - throw std::invalid_argument ("mpf_set_str"); - } - } - explicit __gmp_expr(const std::string &s) - { - if (mpf_init_set_str(mp, s.c_str(), 0) != 0) - { - mpf_clear (mp); - throw std::invalid_argument ("mpf_set_str"); - } - } - __gmp_expr(const std::string &s, mp_bitcnt_t prec, int base = 0) - { - mpf_init2(mp, prec); - if (mpf_set_str(mp, s.c_str(), base) != 0) - { - mpf_clear (mp); - throw std::invalid_argument ("mpf_set_str"); - } - } - - explicit __gmp_expr(mpf_srcptr f) - { mpf_init2(mp, mpf_get_prec(f)); mpf_set(mp, f); } - __gmp_expr(mpf_srcptr f, mp_bitcnt_t prec) - { mpf_init2(mp, prec); mpf_set(mp, f); } - - ~__gmp_expr() { mpf_clear(mp); } - - // assignment operators - __gmp_expr & operator=(const __gmp_expr &f) - { mpf_set(mp, f.mp); return *this; } - template - __gmp_expr & operator=(const __gmp_expr &expr) - { __gmp_set_expr(mp, expr); return *this; } - - __gmp_expr & operator=(signed char c) { mpf_set_si(mp, c); return *this; } - __gmp_expr & operator=(unsigned char c) { mpf_set_ui(mp, c); return *this; } - - __gmp_expr & operator=(signed int i) { mpf_set_si(mp, i); return *this; } - __gmp_expr & operator=(unsigned int i) { mpf_set_ui(mp, i); return *this; } - - __gmp_expr & operator=(signed short int s) - { mpf_set_si(mp, s); return *this; } - __gmp_expr & operator=(unsigned short int s) - { mpf_set_ui(mp, s); return *this; } - - __gmp_expr & operator=(signed long int l) - { mpf_set_si(mp, l); return *this; } - __gmp_expr & operator=(unsigned long int l) - { mpf_set_ui(mp, l); return *this; } - - __gmp_expr & operator=(float f) { mpf_set_d(mp, f); return *this; } - __gmp_expr & operator=(double d) { mpf_set_d(mp, d); return *this; } - // __gmp_expr & operator=(long double ld) - // { mpf_set_ld(mp, ld); return *this; } - - __gmp_expr & operator=(const char *s) - { - if (mpf_set_str (mp, s, 0) != 0) - throw std::invalid_argument ("mpf_set_str"); - return *this; - } - __gmp_expr & operator=(const std::string &s) - { - if (mpf_set_str(mp, s.c_str(), 0) != 0) - throw std::invalid_argument ("mpf_set_str"); - return *this; - } - - // string input/output functions - int set_str(const char *s, int base) - { return mpf_set_str(mp, s, base); } - int set_str(const std::string &s, int base) - { return mpf_set_str(mp, s.c_str(), base); } - std::string get_str(mp_exp_t &expo, int base = 10, size_t size = 0) const - { - __gmp_alloc_cstring temp(mpf_get_str(0, &expo, base, size, mp)); - return std::string(temp.str); - } - - // conversion functions - mpf_srcptr __get_mp() const { return mp; } - mpf_ptr __get_mp() { return mp; } - mpf_srcptr get_mpf_t() const { return mp; } - mpf_ptr get_mpf_t() { return mp; } - - signed long int get_si() const { return mpf_get_si(mp); } - unsigned long int get_ui() const { return mpf_get_ui(mp); } - double get_d() const { return mpf_get_d(mp); } - - // bool fits_schar_p() const { return mpf_fits_schar_p(mp); } - // bool fits_uchar_p() const { return mpf_fits_uchar_p(mp); } - bool fits_sint_p() const { return mpf_fits_sint_p(mp); } - bool fits_uint_p() const { return mpf_fits_uint_p(mp); } - bool fits_sshort_p() const { return mpf_fits_sshort_p(mp); } - bool fits_ushort_p() const { return mpf_fits_ushort_p(mp); } - bool fits_slong_p() const { return mpf_fits_slong_p(mp); } - bool fits_ulong_p() const { return mpf_fits_ulong_p(mp); } - // bool fits_float_p() const { return mpf_fits_float_p(mp); } - // bool fits_double_p() const { return mpf_fits_double_p(mp); } - // bool fits_ldouble_p() const { return mpf_fits_ldouble_p(mp); } - - // compound assignments - __GMP_DECLARE_COMPOUND_OPERATOR(operator+=) - __GMP_DECLARE_COMPOUND_OPERATOR(operator-=) - __GMP_DECLARE_COMPOUND_OPERATOR(operator*=) - __GMP_DECLARE_COMPOUND_OPERATOR(operator/=) - - __GMP_DECLARE_COMPOUND_OPERATOR_UI(operator<<=) - __GMP_DECLARE_COMPOUND_OPERATOR_UI(operator>>=) - - __GMP_DECLARE_INCREMENT_OPERATOR(operator++) - __GMP_DECLARE_INCREMENT_OPERATOR(operator--) -}; - -typedef __gmp_expr mpf_class; - - - -/**************** I/O operators ****************/ - -// these should (and will) be provided separately - -template -inline std::ostream & operator<< -(std::ostream &o, const __gmp_expr &expr) -{ - return o << expr.__get_mp(); -} - -template -inline std::ostream & operator<< -(std::ostream &o, const __gmp_expr &expr) -{ - __gmp_expr temp(expr); - return o << temp.__get_mp(); -} - - -template -inline std::istream & operator>>(std::istream &i, __gmp_expr &expr) -{ - return i >> expr.__get_mp(); -} - -inline std::istream & operator>>(std::istream &i, mpq_class &q) -{ - i >> q.get_mpq_t(); - // q.canonicalize(); // you might want to uncomment this - return i; -} - - -/**************** Functions for type conversion ****************/ - -template <> -inline void __gmp_set_expr(mpz_ptr z, const mpz_class &w) -{ - mpz_set(z, w.get_mpz_t()); -} - -template -inline void __gmp_set_expr(mpz_ptr z, const __gmp_expr &expr) -{ - expr.eval(z); -} - -template <> -inline void __gmp_set_expr(mpz_ptr z, const mpq_class &q) -{ - mpz_set_q(z, q.get_mpq_t()); -} - -template -inline void __gmp_set_expr(mpz_ptr z, const __gmp_expr &expr) -{ - mpq_class temp(expr); - mpz_set_q(z, temp.get_mpq_t()); -} - -template -inline void __gmp_set_expr(mpz_ptr z, const mpf_class &f) -{ - mpz_set_f(z, f.get_mpf_t()); -} - -template -inline void __gmp_set_expr(mpz_ptr z, const __gmp_expr &expr) -{ - mpf_class temp(expr); - mpz_set_f(z, temp.get_mpf_t()); -} - -template <> -inline void __gmp_set_expr(mpq_ptr q, const mpz_class &z) -{ - mpq_set_z(q, z.get_mpz_t()); -} - -template -inline void __gmp_set_expr(mpq_ptr q, const __gmp_expr &expr) -{ - mpz_class temp(expr); - mpq_set_z(q, temp.get_mpz_t()); -} - -template <> -inline void __gmp_set_expr(mpq_ptr q, const mpq_class &r) -{ - mpq_set(q, r.get_mpq_t()); -} - -template -inline void __gmp_set_expr(mpq_ptr q, const __gmp_expr &expr) -{ - expr.eval(q); -} - -template -inline void __gmp_set_expr(mpq_ptr q, const mpf_class &f) -{ - mpq_set_f(q, f.get_mpf_t()); -} - -template -inline void __gmp_set_expr(mpq_ptr q, const __gmp_expr &expr) -{ - mpf_class temp(expr); - mpq_set_f(q, temp.get_mpf_t()); -} - -template -inline void __gmp_set_expr(mpf_ptr f, const mpz_class &z) -{ - mpf_set_z(f, z.get_mpz_t()); -} - -template -inline void __gmp_set_expr(mpf_ptr f, const __gmp_expr &expr) -{ - mpz_class temp(expr); - mpf_set_z(f, temp.get_mpz_t()); -} - -template -inline void __gmp_set_expr(mpf_ptr f, const mpq_class &q) -{ - mpf_set_q(f, q.get_mpq_t()); -} - -template -inline void __gmp_set_expr(mpf_ptr f, const __gmp_expr &expr) -{ - mpq_class temp(expr); - mpf_set_q(f, temp.get_mpq_t()); -} - -template <> -inline void __gmp_set_expr(mpf_ptr f, const mpf_class &g) -{ - mpf_set(f, g.get_mpf_t()); -} - -template -inline void __gmp_set_expr(mpf_ptr f, const __gmp_expr &expr) -{ - expr.eval(f, mpf_get_prec(f)); -} - - -/**************** Specializations of __gmp_expr ****************/ -/* The eval() method of __gmp_expr evaluates the corresponding - expression and assigns the result to its argument, which is either an - mpz_t, mpq_t, or mpf_t as specified by the T argument. - Compound expressions are evaluated recursively (temporaries are created - to hold intermediate values), while for simple expressions the eval() - method of the appropriate function object (available as the Op argument - of either __gmp_unary_expr or __gmp_binary_expr) is - called. */ - - -/**************** Unary expressions ****************/ -/* cases: - - simple: argument is mp*_class, that is, __gmp_expr - - compound: argument is __gmp_expr (with U not equal to T) */ - - -// simple expressions - -template -class __gmp_expr, Op> > -{ -private: - typedef __gmp_expr val_type; - - __gmp_unary_expr expr; -public: - __gmp_expr(const val_type &val) : expr(val) { } - void eval(typename __gmp_resolve_expr::ptr_type p, - unsigned long int = 0) const - { Op::eval(p, expr.val.__get_mp()); } - const val_type & get_val() const { return expr.val; } - unsigned long int get_prec() const { return expr.val.get_prec(); } -}; - - -// compound expressions - -template -class __gmp_expr, Op> > -{ -private: - typedef __gmp_expr val_type; - - __gmp_unary_expr expr; -public: - __gmp_expr(const val_type &val) : expr(val) { } - void eval(typename __gmp_resolve_expr::ptr_type p) const - { __gmp_expr temp(expr.val); Op::eval(p, temp.__get_mp()); } - void eval(typename __gmp_resolve_expr::ptr_type p, - mp_bitcnt_t prec) const - { __gmp_expr temp(expr.val, prec); Op::eval(p, temp.__get_mp()); } - const val_type & get_val() const { return expr.val; } - unsigned long int get_prec() const { return expr.val.get_prec(); } -}; - - -/**************** Binary expressions ****************/ -/* simple: - - arguments are both mp*_class - - one argument is mp*_class, one is a built-in type - compound: - - one is mp*_class, one is __gmp_expr - - one is __gmp_expr, one is built-in - - both arguments are __gmp_expr<...> */ - - -// simple expressions - -template -class __gmp_expr -, __gmp_expr, Op> > -{ -private: - typedef __gmp_expr val1_type; - typedef __gmp_expr val2_type; - - __gmp_binary_expr expr; -public: - __gmp_expr(const val1_type &val1, const val2_type &val2) - : expr(val1, val2) { } - void eval(typename __gmp_resolve_expr::ptr_type p, - unsigned long int = 0) const - { Op::eval(p, expr.val1.__get_mp(), expr.val2.__get_mp()); } - const val1_type & get_val1() const { return expr.val1; } - const val2_type & get_val2() const { return expr.val2; } - unsigned long int get_prec() const - { - mp_bitcnt_t prec1 = expr.val1.get_prec(), - prec2 = expr.val2.get_prec(); - return (prec1 > prec2) ? prec1 : prec2; - } -}; - - -// simple expressions, T is a built-in numerical type - -template -class __gmp_expr, U, Op> > -{ -private: - typedef __gmp_expr val1_type; - typedef U val2_type; - - __gmp_binary_expr expr; -public: - __gmp_expr(const val1_type &val1, const val2_type &val2) - : expr(val1, val2) { } - void eval(typename __gmp_resolve_expr::ptr_type p, - unsigned long int = 0) const - { Op::eval(p, expr.val1.__get_mp(), expr.val2); } - const val1_type & get_val1() const { return expr.val1; } - const val2_type & get_val2() const { return expr.val2; } - unsigned long int get_prec() const { return expr.val1.get_prec(); } -}; - -template -class __gmp_expr, Op> > -{ -private: - typedef U val1_type; - typedef __gmp_expr val2_type; - - __gmp_binary_expr expr; -public: - __gmp_expr(const val1_type &val1, const val2_type &val2) - : expr(val1, val2) { } - void eval(typename __gmp_resolve_expr::ptr_type p, - unsigned long int = 0) const - { Op::eval(p, expr.val1, expr.val2.__get_mp()); } - const val1_type & get_val1() const { return expr.val1; } - const val2_type & get_val2() const { return expr.val2; } - unsigned long int get_prec() const { return expr.val2.get_prec(); } -}; - - -// compound expressions, one argument is a subexpression - -template -class __gmp_expr -, __gmp_expr, Op> > -{ -private: - typedef __gmp_expr val1_type; - typedef __gmp_expr val2_type; - - __gmp_binary_expr expr; -public: - __gmp_expr(const val1_type &val1, const val2_type &val2) - : expr(val1, val2) { } - void eval(typename __gmp_resolve_expr::ptr_type p) const - { - __gmp_expr temp(expr.val2); - Op::eval(p, expr.val1.__get_mp(), temp.__get_mp()); - } - void eval(typename __gmp_resolve_expr::ptr_type p, - mp_bitcnt_t prec) const - { - __gmp_expr temp(expr.val2, prec); - Op::eval(p, expr.val1.__get_mp(), temp.__get_mp()); - } - const val1_type & get_val1() const { return expr.val1; } - const val2_type & get_val2() const { return expr.val2; } - unsigned long int get_prec() const - { - mp_bitcnt_t prec1 = expr.val1.get_prec(), - prec2 = expr.val2.get_prec(); - return (prec1 > prec2) ? prec1 : prec2; - } -}; - -template -class __gmp_expr -, __gmp_expr, Op> > -{ -private: - typedef __gmp_expr val1_type; - typedef __gmp_expr val2_type; - - __gmp_binary_expr expr; -public: - __gmp_expr(const val1_type &val1, const val2_type &val2) - : expr(val1, val2) { } - void eval(typename __gmp_resolve_expr::ptr_type p) const - { - __gmp_expr temp(expr.val1); - Op::eval(p, temp.__get_mp(), expr.val2.__get_mp()); - } - void eval(typename __gmp_resolve_expr::ptr_type p, - mp_bitcnt_t prec) const - { - __gmp_expr temp(expr.val1, prec); - Op::eval(p, temp.__get_mp(), expr.val2.__get_mp()); - } - const val1_type & get_val1() const { return expr.val1; } - const val2_type & get_val2() const { return expr.val2; } - unsigned long int get_prec() const - { - mp_bitcnt_t prec1 = expr.val1.get_prec(), - prec2 = expr.val2.get_prec(); - return (prec1 > prec2) ? prec1 : prec2; - } -}; - -template -class __gmp_expr -, __gmp_expr, Op> > -{ -private: - typedef __gmp_expr val1_type; - typedef __gmp_expr val2_type; - - __gmp_binary_expr expr; -public: - __gmp_expr(const val1_type &val1, const val2_type &val2) - : expr(val1, val2) { } - void eval(typename __gmp_resolve_expr::ptr_type p) const - { - __gmp_expr temp(expr.val2); - Op::eval(p, expr.val1.__get_mp(), temp.__get_mp()); - } - void eval(typename __gmp_resolve_expr::ptr_type p, - mp_bitcnt_t prec) const - { - __gmp_expr temp(expr.val2, prec); - Op::eval(p, expr.val1.__get_mp(), temp.__get_mp()); - } - const val1_type & get_val1() const { return expr.val1; } - const val2_type & get_val2() const { return expr.val2; } - unsigned long int get_prec() const - { - mp_bitcnt_t prec1 = expr.val1.get_prec(), - prec2 = expr.val2.get_prec(); - return (prec1 > prec2) ? prec1 : prec2; - } -}; - -template -class __gmp_expr -, __gmp_expr, Op> > -{ -private: - typedef __gmp_expr val1_type; - typedef __gmp_expr val2_type; - - __gmp_binary_expr expr; -public: - __gmp_expr(const val1_type &val1, const val2_type &val2) - : expr(val1, val2) { } - void eval(typename __gmp_resolve_expr::ptr_type p) const - { - __gmp_expr temp(expr.val1); - Op::eval(p, temp.__get_mp(), expr.val2.__get_mp()); - } - void eval(typename __gmp_resolve_expr::ptr_type p, - mp_bitcnt_t prec) const - { - __gmp_expr temp(expr.val1, prec); - Op::eval(p, temp.__get_mp(), expr.val2.__get_mp()); - } - const val1_type & get_val1() const { return expr.val1; } - const val2_type & get_val2() const { return expr.val2; } - unsigned long int get_prec() const - { - mp_bitcnt_t prec1 = expr.val1.get_prec(), - prec2 = expr.val2.get_prec(); - return (prec1 > prec2) ? prec1 : prec2; - } -}; - - -// one argument is a subexpression, one is a built-in - -template -class __gmp_expr, V, Op> > -{ -private: - typedef __gmp_expr val1_type; - typedef V val2_type; - - __gmp_binary_expr expr; -public: - __gmp_expr(const val1_type &val1, const val2_type &val2) - : expr(val1, val2) { } - void eval(typename __gmp_resolve_expr::ptr_type p) const - { - __gmp_expr temp(expr.val1); - Op::eval(p, temp.__get_mp(), expr.val2); - } - void eval(typename __gmp_resolve_expr::ptr_type p, - mp_bitcnt_t prec) const - { - __gmp_expr temp(expr.val1, prec); - Op::eval(p, temp.__get_mp(), expr.val2); - } - const val1_type & get_val1() const { return expr.val1; } - const val2_type & get_val2() const { return expr.val2; } - unsigned long int get_prec() const { return expr.val1.get_prec(); } -}; - -template -class __gmp_expr, Op> > -{ -private: - typedef U val1_type; - typedef __gmp_expr val2_type; - - __gmp_binary_expr expr; -public: - __gmp_expr(const val1_type &val1, const val2_type &val2) - : expr(val1, val2) { } - void eval(typename __gmp_resolve_expr::ptr_type p) const - { - __gmp_expr temp(expr.val2); - Op::eval(p, expr.val1, temp.__get_mp()); - } - void eval(typename __gmp_resolve_expr::ptr_type p, - mp_bitcnt_t prec) const - { - __gmp_expr temp(expr.val2, prec); - Op::eval(p, expr.val1, temp.__get_mp()); - } - const val1_type & get_val1() const { return expr.val1; } - const val2_type & get_val2() const { return expr.val2; } - unsigned long int get_prec() const { return expr.val2.get_prec(); } -}; - - -// both arguments are subexpressions - -template -class __gmp_expr -, __gmp_expr, Op> > -{ -private: - typedef __gmp_expr val1_type; - typedef __gmp_expr val2_type; - - __gmp_binary_expr expr; -public: - __gmp_expr(const val1_type &val1, const val2_type &val2) - : expr(val1, val2) { } - void eval(typename __gmp_resolve_expr::ptr_type p) const - { - __gmp_expr temp1(expr.val1), temp2(expr.val2); - Op::eval(p, temp1.__get_mp(), temp2.__get_mp()); - } - void eval(typename __gmp_resolve_expr::ptr_type p, - mp_bitcnt_t prec) const - { - __gmp_expr temp1(expr.val1, prec), temp2(expr.val2, prec); - Op::eval(p, temp1.__get_mp(), temp2.__get_mp()); - } - const val1_type & get_val1() const { return expr.val1; } - const val2_type & get_val2() const { return expr.val2; } - unsigned long int get_prec() const - { - mp_bitcnt_t prec1 = expr.val1.get_prec(), - prec2 = expr.val2.get_prec(); - return (prec1 > prec2) ? prec1 : prec2; - } -}; - -template -class __gmp_expr -, __gmp_expr, Op> > -{ -private: - typedef __gmp_expr val1_type; - typedef __gmp_expr val2_type; - - __gmp_binary_expr expr; -public: - __gmp_expr(const val1_type &val1, const val2_type &val2) - : expr(val1, val2) { } - void eval(typename __gmp_resolve_expr::ptr_type p) const - { - __gmp_expr temp1(expr.val1), temp2(expr.val2); - Op::eval(p, temp1.__get_mp(), temp2.__get_mp()); - } - void eval(typename __gmp_resolve_expr::ptr_type p, - mp_bitcnt_t prec) const - { - __gmp_expr temp1(expr.val1, prec), temp2(expr.val2, prec); - Op::eval(p, temp1.__get_mp(), temp2.__get_mp()); - } - const val1_type & get_val1() const { return expr.val1; } - const val2_type & get_val2() const { return expr.val2; } - unsigned long int get_prec() const - { - mp_bitcnt_t prec1 = expr.val1.get_prec(), - prec2 = expr.val2.get_prec(); - return (prec1 > prec2) ? prec1 : prec2; - } -}; - -template -class __gmp_expr -, __gmp_expr, Op> > -{ -private: - typedef __gmp_expr val1_type; - typedef __gmp_expr val2_type; - - __gmp_binary_expr expr; -public: - __gmp_expr(const val1_type &val1, const val2_type &val2) - : expr(val1, val2) { } - void eval(typename __gmp_resolve_expr::ptr_type p) const - { - __gmp_expr temp1(expr.val1), temp2(expr.val2); - Op::eval(p, temp1.__get_mp(), temp2.__get_mp()); - } - void eval(typename __gmp_resolve_expr::ptr_type p, - mp_bitcnt_t prec) const - { - __gmp_expr temp1(expr.val1, prec), temp2(expr.val2, prec); - Op::eval(p, temp1.__get_mp(), temp2.__get_mp()); - } - const val1_type & get_val1() const { return expr.val1; } - const val2_type & get_val2() const { return expr.val2; } - unsigned long int get_prec() const - { - mp_bitcnt_t prec1 = expr.val1.get_prec(), - prec2 = expr.val2.get_prec(); - return (prec1 > prec2) ? prec1 : prec2; - } -}; - - -/**************** Special cases ****************/ - -/* Some operations (i.e., add and subtract) with mixed mpz/mpq arguments - can be done directly without first converting the mpz to mpq. - Appropriate specializations of __gmp_expr are required. */ - - -#define __GMPZQ_DEFINE_EXPR(eval_fun) \ - \ -template <> \ -class __gmp_expr > \ -{ \ -private: \ - typedef mpz_class val1_type; \ - typedef mpq_class val2_type; \ - \ - __gmp_binary_expr expr; \ -public: \ - __gmp_expr(const val1_type &val1, const val2_type &val2) \ - : expr(val1, val2) { } \ - void eval(mpq_ptr q) const \ - { eval_fun::eval(q, expr.val1.get_mpz_t(), expr.val2.get_mpq_t()); } \ - const val1_type & get_val1() const { return expr.val1; } \ - const val2_type & get_val2() const { return expr.val2; } \ - unsigned long int get_prec() const { return mpf_get_default_prec(); } \ -}; \ - \ -template <> \ -class __gmp_expr > \ -{ \ -private: \ - typedef mpq_class val1_type; \ - typedef mpz_class val2_type; \ - \ - __gmp_binary_expr expr; \ -public: \ - __gmp_expr(const val1_type &val1, const val2_type &val2) \ - : expr(val1, val2) { } \ - void eval(mpq_ptr q) const \ - { eval_fun::eval(q, expr.val1.get_mpq_t(), expr.val2.get_mpz_t()); } \ - const val1_type & get_val1() const { return expr.val1; } \ - const val2_type & get_val2() const { return expr.val2; } \ - unsigned long int get_prec() const { return mpf_get_default_prec(); } \ -}; \ - \ -template \ -class __gmp_expr \ -, eval_fun> > \ -{ \ -private: \ - typedef mpz_class val1_type; \ - typedef __gmp_expr val2_type; \ - \ - __gmp_binary_expr expr; \ -public: \ - __gmp_expr(const val1_type &val1, const val2_type &val2) \ - : expr(val1, val2) { } \ - void eval(mpq_ptr q) const \ - { \ - mpq_class temp(expr.val2); \ - eval_fun::eval(q, expr.val1.get_mpz_t(), temp.get_mpq_t()); \ - } \ - const val1_type & get_val1() const { return expr.val1; } \ - const val2_type & get_val2() const { return expr.val2; } \ - unsigned long int get_prec() const { return mpf_get_default_prec(); } \ -}; \ - \ -template \ -class __gmp_expr \ -, eval_fun> > \ -{ \ -private: \ - typedef mpq_class val1_type; \ - typedef __gmp_expr val2_type; \ - \ - __gmp_binary_expr expr; \ -public: \ - __gmp_expr(const val1_type &val1, const val2_type &val2) \ - : expr(val1, val2) { } \ - void eval(mpq_ptr q) const \ - { \ - mpz_class temp(expr.val2); \ - eval_fun::eval(q, expr.val1.get_mpq_t(), temp.get_mpz_t()); \ - } \ - const val1_type & get_val1() const { return expr.val1; } \ - const val2_type & get_val2() const { return expr.val2; } \ - unsigned long int get_prec() const { return mpf_get_default_prec(); } \ -}; \ - \ -template \ -class __gmp_expr \ -, mpq_class, eval_fun> > \ -{ \ -private: \ - typedef __gmp_expr val1_type; \ - typedef mpq_class val2_type; \ - \ - __gmp_binary_expr expr; \ -public: \ - __gmp_expr(const val1_type &val1, const val2_type &val2) \ - : expr(val1, val2) { } \ - void eval(mpq_ptr q) const \ - { \ - mpz_class temp(expr.val1); \ - eval_fun::eval(q, temp.get_mpz_t(), expr.val2.get_mpq_t()); \ - } \ - const val1_type & get_val1() const { return expr.val1; } \ - const val2_type & get_val2() const { return expr.val2; } \ - unsigned long int get_prec() const { return mpf_get_default_prec(); } \ -}; \ - \ -template \ -class __gmp_expr \ -, mpz_class, eval_fun> > \ -{ \ -private: \ - typedef __gmp_expr val1_type; \ - typedef mpz_class val2_type; \ - \ - __gmp_binary_expr expr; \ -public: \ - __gmp_expr(const val1_type &val1, const val2_type &val2) \ - : expr(val1, val2) { } \ - void eval(mpq_ptr q) const \ - { \ - mpq_class temp(expr.val1); \ - eval_fun::eval(q, temp.get_mpq_t(), expr.val2.get_mpz_t()); \ - } \ - const val1_type & get_val1() const { return expr.val1; } \ - const val2_type & get_val2() const { return expr.val2; } \ - unsigned long int get_prec() const { return mpf_get_default_prec(); } \ -}; \ - \ -template \ -class __gmp_expr, __gmp_expr, eval_fun> > \ -{ \ -private: \ - typedef __gmp_expr val1_type; \ - typedef __gmp_expr val2_type; \ - \ - __gmp_binary_expr expr; \ -public: \ - __gmp_expr(const val1_type &val1, const val2_type &val2) \ - : expr(val1, val2) { } \ - void eval(mpq_ptr q) const \ - { \ - mpz_class temp1(expr.val1); \ - mpq_class temp2(expr.val2); \ - eval_fun::eval(q, temp1.get_mpz_t(), temp2.get_mpq_t()); \ - } \ - const val1_type & get_val1() const { return expr.val1; } \ - const val2_type & get_val2() const { return expr.val2; } \ - unsigned long int get_prec() const { return mpf_get_default_prec(); } \ -}; \ - \ -template \ -class __gmp_expr, __gmp_expr, eval_fun> > \ -{ \ -private: \ - typedef __gmp_expr val1_type; \ - typedef __gmp_expr val2_type; \ - \ - __gmp_binary_expr expr; \ -public: \ - __gmp_expr(const val1_type &val1, const val2_type &val2) \ - : expr(val1, val2) { } \ - void eval(mpq_ptr q) const \ - { \ - mpq_class temp1(expr.val1); \ - mpz_class temp2(expr.val2); \ - eval_fun::eval(q, temp1.get_mpq_t(), temp2.get_mpz_t()); \ - } \ - const val1_type & get_val1() const { return expr.val1; } \ - const val2_type & get_val2() const { return expr.val2; } \ - unsigned long int get_prec() const { return mpf_get_default_prec(); } \ -}; - - -__GMPZQ_DEFINE_EXPR(__gmp_binary_plus) -__GMPZQ_DEFINE_EXPR(__gmp_binary_minus) - -/**************** Macros for defining functions ****************/ -/* Results of operators and functions are instances of __gmp_expr. - T determines the numerical type of the expression: it can be either - mpz_t, mpq_t, or mpf_t. When the arguments of a binary - expression have different numerical types, __gmp_resolve_expr is used - to determine the "larger" type. - U is either __gmp_unary_expr or __gmp_binary_expr, - where V and W are the arguments' types -- they can in turn be - expressions, thus allowing to build compound expressions to any - degree of complexity. - Op is a function object that must have an eval() method accepting - appropriate arguments. - Actual evaluation of a __gmp_expr object is done when it gets - assigned to an mp*_class ("lazy" evaluation): this is done by calling - its eval() method. */ - - -// non-member unary operators and functions - -#define __GMP_DEFINE_UNARY_FUNCTION(fun, eval_fun) \ - \ -template \ -inline __gmp_expr, eval_fun> > \ -fun(const __gmp_expr &expr) \ -{ \ - return __gmp_expr, eval_fun> >(expr); \ -} - -#define __GMP_DEFINE_UNARY_TYPE_FUNCTION(type, fun, eval_fun) \ - \ -template \ -inline type fun(const __gmp_expr &expr) \ -{ \ - typename __gmp_resolve_temp::temp_type temp(expr); \ - return eval_fun::eval(temp.__get_mp()); \ -} - - -// non-member binary operators and functions - -#define __GMPP_DEFINE_BINARY_FUNCTION(fun, eval_fun) \ - \ -template \ -inline __gmp_expr::value_type, \ -__gmp_binary_expr<__gmp_expr, __gmp_expr, eval_fun> > \ -fun(const __gmp_expr &expr1, const __gmp_expr &expr2) \ -{ \ - return __gmp_expr::value_type, \ - __gmp_binary_expr<__gmp_expr, __gmp_expr, eval_fun> > \ - (expr1, expr2); \ -} - -#define __GMPNN_DEFINE_BINARY_FUNCTION(fun, eval_fun, type, bigtype) \ - \ -template \ -inline __gmp_expr \ -, bigtype, eval_fun> > \ -fun(const __gmp_expr &expr, type t) \ -{ \ - return __gmp_expr \ - , bigtype, eval_fun> >(expr, t); \ -} \ - \ -template \ -inline __gmp_expr \ -, eval_fun> > \ -fun(type t, const __gmp_expr &expr) \ -{ \ - return __gmp_expr \ - , eval_fun> >(t, expr); \ -} - -#define __GMPNS_DEFINE_BINARY_FUNCTION(fun, eval_fun, type) \ -__GMPNN_DEFINE_BINARY_FUNCTION(fun, eval_fun, type, signed long int) - -#define __GMPNU_DEFINE_BINARY_FUNCTION(fun, eval_fun, type) \ -__GMPNN_DEFINE_BINARY_FUNCTION(fun, eval_fun, type, unsigned long int) - -#define __GMPND_DEFINE_BINARY_FUNCTION(fun, eval_fun, type) \ -__GMPNN_DEFINE_BINARY_FUNCTION(fun, eval_fun, type, double) - -#define __GMPNLD_DEFINE_BINARY_FUNCTION(fun, eval_fun, type) \ -__GMPNN_DEFINE_BINARY_FUNCTION(fun, eval_fun, type, long double) - -#define __GMPN_DEFINE_BINARY_FUNCTION(fun, eval_fun) \ -__GMPNS_DEFINE_BINARY_FUNCTION(fun, eval_fun, signed char) \ -__GMPNU_DEFINE_BINARY_FUNCTION(fun, eval_fun, unsigned char) \ -__GMPNS_DEFINE_BINARY_FUNCTION(fun, eval_fun, signed int) \ -__GMPNU_DEFINE_BINARY_FUNCTION(fun, eval_fun, unsigned int) \ -__GMPNS_DEFINE_BINARY_FUNCTION(fun, eval_fun, signed short int) \ -__GMPNU_DEFINE_BINARY_FUNCTION(fun, eval_fun, unsigned short int) \ -__GMPNS_DEFINE_BINARY_FUNCTION(fun, eval_fun, signed long int) \ -__GMPNU_DEFINE_BINARY_FUNCTION(fun, eval_fun, unsigned long int) \ -__GMPND_DEFINE_BINARY_FUNCTION(fun, eval_fun, float) \ -__GMPND_DEFINE_BINARY_FUNCTION(fun, eval_fun, double) \ -__GMPNLD_DEFINE_BINARY_FUNCTION(fun, eval_fun, long double) - -#define __GMP_DEFINE_BINARY_FUNCTION(fun, eval_fun) \ -__GMPP_DEFINE_BINARY_FUNCTION(fun, eval_fun) \ -__GMPN_DEFINE_BINARY_FUNCTION(fun, eval_fun) - - -#define __GMP_DEFINE_BINARY_FUNCTION_UI(fun, eval_fun) \ - \ -template \ -inline __gmp_expr \ -, unsigned long int, eval_fun> > \ -fun(const __gmp_expr &expr, unsigned long int l) \ -{ \ - return __gmp_expr, unsigned long int, eval_fun> >(expr, l); \ -} - - -#define __GMPP_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun) \ - \ -template \ -inline type fun(const __gmp_expr &expr1, \ - const __gmp_expr &expr2) \ -{ \ - typedef typename __gmp_resolve_expr::value_type eval_type; \ - typename __gmp_resolve_temp::temp_type temp1(expr1); \ - typename __gmp_resolve_temp::temp_type temp2(expr2); \ - return eval_fun::eval(temp1.__get_mp(), temp2.__get_mp()); \ -} - -#define __GMPNN_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, \ - type2, bigtype) \ - \ -template \ -inline type fun(const __gmp_expr &expr, type2 t) \ -{ \ - typename __gmp_resolve_temp::temp_type temp(expr); \ - return eval_fun::eval(temp.__get_mp(), static_cast(t)); \ -} \ - \ -template \ -inline type fun(type2 t, const __gmp_expr &expr) \ -{ \ - typename __gmp_resolve_temp::temp_type temp(expr); \ - return eval_fun::eval(static_cast(t), temp.__get_mp()); \ -} - -#define __GMPNS_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, type2) \ -__GMPNN_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, \ - type2, signed long int) - -#define __GMPNU_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, type2) \ -__GMPNN_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, \ - type2, unsigned long int) - -#define __GMPND_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, type2) \ -__GMPNN_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, type2, double) - -#define __GMPNLD_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, type2) \ -__GMPNN_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, type2, long double) - -#define __GMPN_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun) \ -__GMPNS_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, signed char) \ -__GMPNU_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, unsigned char) \ -__GMPNS_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, signed int) \ -__GMPNU_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, unsigned int) \ -__GMPNS_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, signed short int) \ -__GMPNU_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, unsigned short int) \ -__GMPNS_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, signed long int) \ -__GMPNU_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, unsigned long int) \ -__GMPND_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, float) \ -__GMPND_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, double) \ -__GMPNLD_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, long double) - -#define __GMP_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun) \ -__GMPP_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun) \ -__GMPN_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun) - - -// member operators - -#define __GMPP_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun) \ - \ -template \ -inline type##_class & type##_class::fun(const __gmp_expr &expr) \ -{ \ - __gmp_set_expr(mp, __gmp_expr, eval_fun> >(*this, expr)); \ - return *this; \ -} - -#define __GMPNN_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, \ - type2, bigtype) \ - \ -inline type##_class & type##_class::fun(type2 t) \ -{ \ - __gmp_set_expr(mp, __gmp_expr >(*this, t)); \ - return *this; \ -} - -#define __GMPNS_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, type2) \ -__GMPNN_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, \ - type2, signed long int) - -#define __GMPNU_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, type2) \ -__GMPNN_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, \ - type2, unsigned long int) - -#define __GMPND_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, type2) \ -__GMPNN_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, type2, double) - -#define __GMPNLD_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, type2) \ -__GMPNN_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, type2, long double) - -#define __GMPN_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun) \ -__GMPNS_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, signed char) \ -__GMPNU_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, unsigned char) \ -__GMPNS_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, signed int) \ -__GMPNU_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, unsigned int) \ -__GMPNS_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, signed short int) \ -__GMPNU_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, unsigned short int) \ -__GMPNS_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, signed long int) \ -__GMPNU_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, unsigned long int) \ -__GMPND_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, float) \ -__GMPND_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, double) \ -/* __GMPNLD_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, long double) */ - -#define __GMP_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun) \ -__GMPP_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun) \ -__GMPN_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun) - -#define __GMPZ_DEFINE_COMPOUND_OPERATOR(fun, eval_fun) \ -__GMP_DEFINE_COMPOUND_OPERATOR(mpz, fun, eval_fun) - -#define __GMPZZ_DEFINE_COMPOUND_OPERATOR(fun, eval_fun) \ -__GMPP_DEFINE_COMPOUND_OPERATOR(mpz, fun, eval_fun) - -#define __GMPQ_DEFINE_COMPOUND_OPERATOR(fun, eval_fun) \ -__GMP_DEFINE_COMPOUND_OPERATOR(mpq, fun, eval_fun) - -#define __GMPF_DEFINE_COMPOUND_OPERATOR(fun, eval_fun) \ -__GMP_DEFINE_COMPOUND_OPERATOR(mpf, fun, eval_fun) - - - -#define __GMP_DEFINE_COMPOUND_OPERATOR_UI(type, fun, eval_fun) \ - \ -inline type##_class & type##_class::fun(unsigned long int l) \ -{ \ - __gmp_set_expr(mp, __gmp_expr >(*this, l)); \ - return *this; \ -} - -#define __GMPZ_DEFINE_COMPOUND_OPERATOR_UI(fun, eval_fun) \ -__GMP_DEFINE_COMPOUND_OPERATOR_UI(mpz, fun, eval_fun) - -#define __GMPQ_DEFINE_COMPOUND_OPERATOR_UI(fun, eval_fun) \ -__GMP_DEFINE_COMPOUND_OPERATOR_UI(mpq, fun, eval_fun) - -#define __GMPF_DEFINE_COMPOUND_OPERATOR_UI(fun, eval_fun) \ -__GMP_DEFINE_COMPOUND_OPERATOR_UI(mpf, fun, eval_fun) - - - -#define __GMP_DEFINE_INCREMENT_OPERATOR(type, fun, eval_fun) \ - \ -inline type##_class & type##_class::fun() \ -{ \ - eval_fun::eval(mp); \ - return *this; \ -} \ - \ -inline type##_class type##_class::fun(int) \ -{ \ - type##_class temp(*this); \ - eval_fun::eval(mp); \ - return temp; \ -} - -#define __GMPZ_DEFINE_INCREMENT_OPERATOR(fun, eval_fun) \ -__GMP_DEFINE_INCREMENT_OPERATOR(mpz, fun, eval_fun) - -#define __GMPQ_DEFINE_INCREMENT_OPERATOR(fun, eval_fun) \ -__GMP_DEFINE_INCREMENT_OPERATOR(mpq, fun, eval_fun) - -#define __GMPF_DEFINE_INCREMENT_OPERATOR(fun, eval_fun) \ -__GMP_DEFINE_INCREMENT_OPERATOR(mpf, fun, eval_fun) - - - -/**************** Arithmetic operators and functions ****************/ - -// non-member operators and functions - -__GMP_DEFINE_UNARY_FUNCTION(operator+, __gmp_unary_plus) -__GMP_DEFINE_UNARY_FUNCTION(operator-, __gmp_unary_minus) -__GMP_DEFINE_UNARY_FUNCTION(operator~, __gmp_unary_com) - -__GMP_DEFINE_BINARY_FUNCTION(operator+, __gmp_binary_plus) -__GMP_DEFINE_BINARY_FUNCTION(operator-, __gmp_binary_minus) -__GMP_DEFINE_BINARY_FUNCTION(operator*, __gmp_binary_multiplies) -__GMP_DEFINE_BINARY_FUNCTION(operator/, __gmp_binary_divides) -__GMP_DEFINE_BINARY_FUNCTION(operator%, __gmp_binary_modulus) -__GMP_DEFINE_BINARY_FUNCTION(operator&, __gmp_binary_and) -__GMP_DEFINE_BINARY_FUNCTION(operator|, __gmp_binary_ior) -__GMP_DEFINE_BINARY_FUNCTION(operator^, __gmp_binary_xor) - -__GMP_DEFINE_BINARY_FUNCTION_UI(operator<<, __gmp_binary_lshift) -__GMP_DEFINE_BINARY_FUNCTION_UI(operator>>, __gmp_binary_rshift) - -__GMP_DEFINE_BINARY_TYPE_FUNCTION(bool, operator==, __gmp_binary_equal) -__GMP_DEFINE_BINARY_TYPE_FUNCTION(bool, operator!=, __gmp_binary_not_equal) -__GMP_DEFINE_BINARY_TYPE_FUNCTION(bool, operator<, __gmp_binary_less) -__GMP_DEFINE_BINARY_TYPE_FUNCTION(bool, operator<=, __gmp_binary_less_equal) -__GMP_DEFINE_BINARY_TYPE_FUNCTION(bool, operator>, __gmp_binary_greater) -__GMP_DEFINE_BINARY_TYPE_FUNCTION(bool, operator>=, \ - __gmp_binary_greater_equal) - -__GMP_DEFINE_UNARY_FUNCTION(abs, __gmp_abs_function) -__GMP_DEFINE_UNARY_FUNCTION(trunc, __gmp_trunc_function) -__GMP_DEFINE_UNARY_FUNCTION(floor, __gmp_floor_function) -__GMP_DEFINE_UNARY_FUNCTION(ceil, __gmp_ceil_function) -__GMP_DEFINE_UNARY_FUNCTION(sqrt, __gmp_sqrt_function) -__GMP_DEFINE_BINARY_FUNCTION(hypot, __gmp_hypot_function) - -__GMP_DEFINE_UNARY_TYPE_FUNCTION(int, sgn, __gmp_sgn_function) -__GMP_DEFINE_BINARY_TYPE_FUNCTION(int, cmp, __gmp_cmp_function) - -// member operators for mpz_class - -__GMPZ_DEFINE_COMPOUND_OPERATOR(operator+=, __gmp_binary_plus) -__GMPZ_DEFINE_COMPOUND_OPERATOR(operator-=, __gmp_binary_minus) -__GMPZ_DEFINE_COMPOUND_OPERATOR(operator*=, __gmp_binary_multiplies) -__GMPZ_DEFINE_COMPOUND_OPERATOR(operator/=, __gmp_binary_divides) -__GMPZ_DEFINE_COMPOUND_OPERATOR(operator%=, __gmp_binary_modulus) - -__GMPZZ_DEFINE_COMPOUND_OPERATOR(operator&=, __gmp_binary_and) -__GMPZZ_DEFINE_COMPOUND_OPERATOR(operator|=, __gmp_binary_ior) -__GMPZZ_DEFINE_COMPOUND_OPERATOR(operator^=, __gmp_binary_xor) - -__GMPZ_DEFINE_COMPOUND_OPERATOR_UI(operator<<=, __gmp_binary_lshift) -__GMPZ_DEFINE_COMPOUND_OPERATOR_UI(operator>>=, __gmp_binary_rshift) - -__GMPZ_DEFINE_INCREMENT_OPERATOR(operator++, __gmp_unary_increment) -__GMPZ_DEFINE_INCREMENT_OPERATOR(operator--, __gmp_unary_decrement) - -// member operators for mpq_class - -__GMPQ_DEFINE_COMPOUND_OPERATOR(operator+=, __gmp_binary_plus) -__GMPQ_DEFINE_COMPOUND_OPERATOR(operator-=, __gmp_binary_minus) -__GMPQ_DEFINE_COMPOUND_OPERATOR(operator*=, __gmp_binary_multiplies) -__GMPQ_DEFINE_COMPOUND_OPERATOR(operator/=, __gmp_binary_divides) - -__GMPQ_DEFINE_COMPOUND_OPERATOR_UI(operator<<=, __gmp_binary_lshift) -__GMPQ_DEFINE_COMPOUND_OPERATOR_UI(operator>>=, __gmp_binary_rshift) - -__GMPQ_DEFINE_INCREMENT_OPERATOR(operator++, __gmp_unary_increment) -__GMPQ_DEFINE_INCREMENT_OPERATOR(operator--, __gmp_unary_decrement) - -// member operators for mpf_class - -__GMPF_DEFINE_COMPOUND_OPERATOR(operator+=, __gmp_binary_plus) -__GMPF_DEFINE_COMPOUND_OPERATOR(operator-=, __gmp_binary_minus) -__GMPF_DEFINE_COMPOUND_OPERATOR(operator*=, __gmp_binary_multiplies) -__GMPF_DEFINE_COMPOUND_OPERATOR(operator/=, __gmp_binary_divides) - -__GMPF_DEFINE_COMPOUND_OPERATOR_UI(operator<<=, __gmp_binary_lshift) -__GMPF_DEFINE_COMPOUND_OPERATOR_UI(operator>>=, __gmp_binary_rshift) - -__GMPF_DEFINE_INCREMENT_OPERATOR(operator++, __gmp_unary_increment) -__GMPF_DEFINE_INCREMENT_OPERATOR(operator--, __gmp_unary_decrement) - - - -/**************** Class wrapper for gmp_randstate_t ****************/ - -class __gmp_urandomb_value { }; -class __gmp_urandomm_value { }; - -template <> -class __gmp_expr -{ -private: - __gmp_randstate_struct *state; - unsigned long int bits; -public: - __gmp_expr(gmp_randstate_t s, unsigned long int l) : state(s), bits(l) { } - void eval(mpz_ptr z) const { __gmp_rand_function::eval(z, state, bits); } - unsigned long int get_prec() const { return mpf_get_default_prec(); } -}; - -template <> -class __gmp_expr -{ -private: - __gmp_randstate_struct *state; - mpz_class range; -public: - __gmp_expr(gmp_randstate_t s, const mpz_class &z) : state(s), range(z) { } - void eval(mpz_ptr z) const - { __gmp_rand_function::eval(z, state, range.get_mpz_t()); } - unsigned long int get_prec() const { return mpf_get_default_prec(); } -}; - -template <> -class __gmp_expr -{ -private: - __gmp_randstate_struct *state; - unsigned long int bits; -public: - __gmp_expr(gmp_randstate_t s, unsigned long int l) : state(s), bits(l) { } - void eval(mpf_ptr f, mp_bitcnt_t prec) const - { __gmp_rand_function::eval(f, state, (bits>0) ? get_prec() : prec); } - unsigned long int get_prec() const - { - if (bits == 0) - return mpf_get_default_prec(); - else - return bits; - } -}; - -extern "C" { - typedef void __gmp_randinit_default_t (gmp_randstate_t); - typedef void __gmp_randinit_lc_2exp_t (gmp_randstate_t, mpz_srcptr, unsigned long int, mp_bitcnt_t); - typedef int __gmp_randinit_lc_2exp_size_t (gmp_randstate_t, mp_bitcnt_t); -} - -class gmp_randclass -{ -private: - gmp_randstate_t state; - - // copy construction and assignment not allowed - gmp_randclass(const gmp_randclass &); - void operator=(const gmp_randclass &); -public: - // constructors and destructor - gmp_randclass(gmp_randalg_t alg, unsigned long int size) - { - switch (alg) - { - case GMP_RAND_ALG_LC: // no other cases for now - default: - gmp_randinit_lc_2exp_size(state, size); - break; - } - } - - // gmp_randinit_default - gmp_randclass(__gmp_randinit_default_t* f) { f(state); } - - // gmp_randinit_lc_2exp - gmp_randclass(__gmp_randinit_lc_2exp_t* f, - mpz_class z, unsigned long int l1, unsigned long int l2) - { f(state, z.get_mpz_t(), l1, l2); } - - // gmp_randinit_lc_2exp_size - gmp_randclass(__gmp_randinit_lc_2exp_size_t* f, - unsigned long int size) - { - if (f (state, size) == 0) - throw std::length_error ("gmp_randinit_lc_2exp_size"); - } - - ~gmp_randclass() { gmp_randclear(state); } - - // initialize - void seed(); // choose a random seed some way (?) - void seed(unsigned long int s) { gmp_randseed_ui(state, s); } - void seed(const mpz_class &z) { gmp_randseed(state, z.get_mpz_t()); } - - // get random number - __gmp_expr get_z_bits(unsigned long int l) - { return __gmp_expr(state, l); } - __gmp_expr get_z_bits(const mpz_class &z) - { return get_z_bits(z.get_ui()); } - - __gmp_expr get_z_range(const mpz_class &z) - { return __gmp_expr(state, z); } - - __gmp_expr get_f(unsigned long int prec = 0) - { return __gmp_expr(state, prec); } -}; - - -/**************** #undef all private macros ****************/ - -#undef __GMPP_DECLARE_COMPOUND_OPERATOR -#undef __GMPN_DECLARE_COMPOUND_OPERATOR -#undef __GMP_DECLARE_COMPOUND_OPERATOR -#undef __GMP_DECLARE_COMPOUND_OPERATOR_UI -#undef __GMP_DECLARE_INCREMENT_OPERATOR - -#undef __GMPZQ_DEFINE_EXPR -#undef __GMP_DEFINE_TERNARY_EXPR - -#undef __GMP_DEFINE_UNARY_FUNCTION -#undef __GMP_DEFINE_UNARY_TYPE_FUNCTION - -#undef __GMPP_DEFINE_BINARY_FUNCTION -#undef __GMPNN_DEFINE_BINARY_FUNCTION -#undef __GMPNS_DEFINE_BINARY_FUNCTION -#undef __GMPNU_DEFINE_BINARY_FUNCTION -#undef __GMPND_DEFINE_BINARY_FUNCTION -#undef __GMPNLD_DEFINE_BINARY_FUNCTION -#undef __GMPN_DEFINE_BINARY_FUNCTION -#undef __GMP_DEFINE_BINARY_FUNCTION - -#undef __GMP_DEFINE_BINARY_FUNCTION_UI - -#undef __GMPP_DEFINE_BINARY_TYPE_FUNCTION -#undef __GMPNN_DEFINE_BINARY_TYPE_FUNCTION -#undef __GMPNS_DEFINE_BINARY_TYPE_FUNCTION -#undef __GMPNU_DEFINE_BINARY_TYPE_FUNCTION -#undef __GMPND_DEFINE_BINARY_TYPE_FUNCTION -#undef __GMPNLD_DEFINE_BINARY_TYPE_FUNCTION -#undef __GMPN_DEFINE_BINARY_TYPE_FUNCTION -#undef __GMP_DEFINE_BINARY_TYPE_FUNCTION - -#undef __GMPP_DECLARE_COMPOUND_OPERATOR -#undef __GMPN_DECLARE_COMPOUND_OPERATOR -#undef __GMP_DECLARE_COMPOUND_OPERATOR - -#undef __GMP_DECLARE_COMPOUND_OPERATOR_UI -#undef __GMP_DECLARE_INCREMENT_OPERATOR - -#undef __GMPZ_DEFINE_COMPOUND_OPERATOR -#undef __GMPZZ_DEFINE_COMPOUND_OPERATOR -#undef __GMPZN_DEFINE_COMPOUND_OPERATOR -#undef __GMPZNN_DEFINE_COMPOUND_OPERATOR -#undef __GMPZNS_DEFINE_COMPOUND_OPERATOR -#undef __GMPZNU_DEFINE_COMPOUND_OPERATOR -#undef __GMPZND_DEFINE_COMPOUND_OPERATOR -#undef __GMPZNLD_DEFINE_COMPOUND_OPERATOR - -#undef __GMPP_DEFINE_COMPOUND_OPERATOR -#undef __GMPNN_DEFINE_COMPOUND_OPERATOR -#undef __GMPNS_DEFINE_COMPOUND_OPERATOR -#undef __GMPNU_DEFINE_COMPOUND_OPERATOR -#undef __GMPND_DEFINE_COMPOUND_OPERATOR -#undef __GMPNLD_DEFINE_COMPOUND_OPERATOR -#undef __GMPN_DEFINE_COMPOUND_OPERATOR -#undef __GMP_DEFINE_COMPOUND_OPERATOR - -#undef __GMPZ_DEFINE_COMPOUND_OPERATOR -#undef __GMPZZ_DEFINE_COMPOUND_OPERATOR -#undef __GMPQ_DEFINE_COMPOUND_OPERATOR -#undef __GMPF_DEFINE_COMPOUND_OPERATOR - -#undef __GMP_DEFINE_COMPOUND_OPERATOR_UI -#undef __GMPZ_DEFINE_COMPOUND_OPERATOR_UI -#undef __GMPQ_DEFINE_COMPOUND_OPERATOR_UI -#undef __GMPF_DEFINE_COMPOUND_OPERATOR_UI - -#undef __GMP_DEFINE_INCREMENT_OPERATOR -#undef __GMPZ_DEFINE_INCREMENT_OPERATOR -#undef __GMPQ_DEFINE_INCREMENT_OPERATOR -#undef __GMPF_DEFINE_INCREMENT_OPERATOR - -#endif /* __GMP_PLUSPLUS__ */ diff --git a/src/external/inc/win32-msvc/mpir-2.2.1_x64/config.h b/src/external/inc/win32-msvc/mpir-2.2.1_x64/config.h deleted file mode 100644 index 79363aa2e..000000000 --- a/src/external/inc/win32-msvc/mpir-2.2.1_x64/config.h +++ /dev/null @@ -1,519 +0,0 @@ -/* Templates for defines setup by configure. - -Copyright 2000, 2001, 2002 Free Software Foundation, Inc. - -This file is part of the GNU MP Library. - -The GNU MP Library is free software; you can redistribute it and/or modify -it under the terms of the GNU Lesser General Public License as published by -the Free Software Foundation; either version 2.1 of the License, or (at your -option) any later version. - -The GNU MP Library is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public -License for more details. - -You should have received a copy of the GNU Lesser General Public License -along with the GNU MP Library; see the file COPYING.LIB. If not, write to -the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, -MA 02111-1307, USA. */ - -/* Define one (and only one) of these for the CPU host. - Only hosts that are going to be tested for need to be in this list, - not everything that can possibly be selected. - */ -#undef HAVE_HOST_CPU_alpha -#undef HAVE_HOST_CPU_alphaev5 -#undef HAVE_HOST_CPU_alphaev6 -#undef HAVE_HOST_CPU_alphaev67 - -#undef HAVE_HOST_CPU_m68k -#undef HAVE_HOST_CPU_m68000 -#undef HAVE_HOST_CPU_m68010 -#undef HAVE_HOST_CPU_m68020 -#undef HAVE_HOST_CPU_m68030 -#undef HAVE_HOST_CPU_m68040 -#undef HAVE_HOST_CPU_m68060 -#undef HAVE_HOST_CPU_m68302 -#undef HAVE_HOST_CPU_m68360 - -#undef HAVE_HOST_CPU_powerpc604 -#undef HAVE_HOST_CPU_powerpc604e -#undef HAVE_HOST_CPU_powerpc750 -#undef HAVE_HOST_CPU_powerpc7400 - -#undef HAVE_HOST_CPU_sparc -#undef HAVE_HOST_CPU_sparcv8 -#undef HAVE_HOST_CPU_supersparc -#undef HAVE_HOST_CPU_sparclite -#undef HAVE_HOST_CPU_microsparc -#undef HAVE_HOST_CPU_ultrasparc1 -#undef HAVE_HOST_CPU_ultrasparc2 -#undef HAVE_HOST_CPU_sparc64 - -#undef HAVE_HOST_CPU_hppa1_0 -#undef HAVE_HOST_CPU_hppa1_1 -#undef HAVE_HOST_CPU_hppa2_0n -#undef HAVE_HOST_CPU_hppa2_0w - -#undef HAVE_HOST_CPU_i386 -#undef HAVE_HOST_CPU_i486 -#undef HAVE_HOST_CPU_i586 -#undef HAVE_HOST_CPU_i686 -#undef HAVE_HOST_CPU_pentium -#undef HAVE_HOST_CPU_pentiummmx -#undef HAVE_HOST_CPU_pentiumpro -#undef HAVE_HOST_CPU_pentium2 -#undef HAVE_HOST_CPU_pentium3 -#undef HAVE_HOST_CPU_k5 -#undef HAVE_HOST_CPU_k6 -#undef HAVE_HOST_CPU_k62 -#undef HAVE_HOST_CPU_k63 -#undef HAVE_HOST_CPU_athlon - -/* a dummy to make autoheader happy */ -#undef HAVE_HOST_CPU_ - -/* Define one (and only one) of these for the CPU host family. - Only hosts that are going to be tested for need to be in this list, - not everything that can possibly be selected. - */ -#undef HAVE_HOST_CPU_FAMILY_power -#undef HAVE_HOST_CPU_FAMILY_powerpc -#define HAVE_HOST_CPU_FAMILY_x86 1 - -/* Define if we have native implementation of function. - (use just one of the three following defines) -*/ - -#undef HAVE_NATIVE_mpn_add -#undef HAVE_NATIVE_mpn_add_1 -#undef HAVE_NATIVE_mpn_addmul_2 -#undef HAVE_NATIVE_mpn_addmul_3 -#undef HAVE_NATIVE_mpn_addmul_4 -#undef HAVE_NATIVE_mpn_addsub_n -#undef HAVE_NATIVE_mpn_addsub_nc -#undef HAVE_NATIVE_mpn_and_n -#undef HAVE_NATIVE_mpn_andn_n -#undef HAVE_NATIVE_mpn_bdivmod -#undef HAVE_NATIVE_mpn_cmp -#undef HAVE_NATIVE_mpn_com_n -#undef HAVE_NATIVE_mpn_divrem -#undef HAVE_NATIVE_mpn_divrem_2 -#undef HAVE_NATIVE_mpn_divrem_newton -#undef HAVE_NATIVE_mpn_divrem_classic -#undef HAVE_NATIVE_mpn_dump -#undef HAVE_NATIVE_mpn_gcd -#undef HAVE_NATIVE_mpn_gcd_1 -#undef HAVE_NATIVE_mpn_gcd_finda -#undef HAVE_NATIVE_mpn_gcdext -#undef HAVE_NATIVE_mpn_get_str -#undef HAVE_NATIVE_mpn_invert_limb -#undef HAVE_NATIVE_mpn_ior_n -#undef HAVE_NATIVE_mpn_iorn_n -#undef HAVE_NATIVE_mpn_mul -#undef HAVE_NATIVE_mpn_mul_2 -#undef HAVE_NATIVE_mpn_mul_3 -#undef HAVE_NATIVE_mpn_mul_4 -#undef HAVE_NATIVE_mpn_mul_n -#undef HAVE_NATIVE_mpn_nand_n -#undef HAVE_NATIVE_mpn_nior_n -#undef HAVE_NATIVE_mpn_perfect_square_p -#undef HAVE_NATIVE_mpn_preinv_mod_1 -#undef HAVE_NATIVE_mpn_random2 -#undef HAVE_NATIVE_mpn_random -#undef HAVE_NATIVE_mpn_rawrandom -#undef HAVE_NATIVE_mpn_scan0 -#undef HAVE_NATIVE_mpn_scan1 -#undef HAVE_NATIVE_mpn_set_str -#undef HAVE_NATIVE_mpn_sqrtrem -#undef HAVE_NATIVE_mpn_sqr_diagonal -#undef HAVE_NATIVE_mpn_sub -#undef HAVE_NATIVE_mpn_sub_1 -#undef HAVE_NATIVE_mpn_udiv_w_sdiv -#undef HAVE_NATIVE_mpn_xor_n -#undef HAVE_NATIVE_mpn_xnor_n - -#undef HAVE_NATIVE_mpn_add_n -#undef HAVE_NATIVE_mpn_add_nc -#undef HAVE_NATIVE_mpn_sub_n -#undef HAVE_NATIVE_mpn_sub_nc - -#undef HAVE_NATIVE_mpn_addmul_1 -#undef HAVE_NATIVE_mpn_addmul_1c -#undef HAVE_NATIVE_mpn_submul_1 -#undef HAVE_NATIVE_mpn_submul_1c - -#undef HAVE_NATIVE_mpn_copyd -#undef HAVE_NATIVE_mpn_copyi - -#undef HAVE_NATIVE_mpn_divexact_1 -#undef HAVE_NATIVE_mpn_divexact_by3c -#undef HAVE_NATIVE_mpn_divrem_1 -#undef HAVE_NATIVE_mpn_divrem_1c - -#undef HAVE_NATIVE_mpn_hamdist -#undef HAVE_NATIVE_mpn_popcount - -#undef HAVE_NATIVE_mpn_lshift -#undef HAVE_NATIVE_mpn_rshift - -#undef HAVE_NATIVE_mpn_mod_1 -#undef HAVE_NATIVE_mpn_mod_1c -#undef HAVE_NATIVE_mpn_modexact_1_odd -#undef HAVE_NATIVE_mpn_modexact_1c_odd - -#undef HAVE_NATIVE_mpn_mul_1 -#undef HAVE_NATIVE_mpn_mul_1c -#undef HAVE_NATIVE_mpn_mul_basecase -#undef HAVE_NATIVE_mpn_sqr_basecase - -#undef HAVE_NATIVE_mpn_umul_ppmm -#undef HAVE_NATIVE_mpn_udiv_qrnnd - -/* For the generic C code */ - -#define HAVE_NATIVE_mpn_add_n 1 -#define HAVE_NATIVE_mpn_sub_n 1 - -/* a dummy to make autoheader happy */ -#undef HAVE_NATIVE_ - - -/* The gmp-mparam.h to update when tuning. */ -#undef GMP_MPARAM_H_SUGGEST - -/* Define if you have the `alarm' function. */ -#undef HAVE_ALARM - -/* Define if alloca() works (via gmp-impl.h). */ -#define HAVE_ALLOCA 1 - -/* Define if you have and it should be used (not on Ultrix). */ -#undef HAVE_ALLOCA_H - -/* Define if the compiler accepts gcc style __attribute__ ((const)) */ -#undef HAVE_ATTRIBUTE_CONST - -/* Define if the compiler accepts gcc style __attribute__ ((malloc)) */ -#undef HAVE_ATTRIBUTE_MALLOC - -/* Define if the compiler accepts gcc style __attribute__ ((mode (XX))) */ -#undef HAVE_ATTRIBUTE_MODE - -/* Define if the compiler accepts gcc style __attribute__ ((noreturn)) */ -#undef HAVE_ATTRIBUTE_NORETURN - -/* Define if tests/libtests has calling conventions checking for the CPU */ -#undef HAVE_CALLING_CONVENTIONS - -/* Define if you have the `clock' function. */ -#define HAVE_CLOCK 1 - -/* Define if you have the `clock_gettime' function. */ -#undef HAVE_CLOCK_GETTIME - -/* Define if you have the `cputime' function. */ -#undef HAVE_CPUTIME - -/* Define to 1 if you have the declaration of `fgetc', and to 0 if you don't. - */ -#define HAVE_DECL_FGETC 1 - -/* Define to 1 if you have the declaration of `fscanf', and to 0 if you don't. - */ -#define HAVE_DECL_FSCANF 1 - -/* Define to 1 if you have the declaration of `optarg', and to 0 if you don't. - */ -#define HAVE_DECL_OPTARG 0 - -/* Define to 1 if you have the declaration of `ungetc', and to 0 if you don't. - */ -#define HAVE_DECL_UNGETC 1 - -/* Define to 1 if you have the declaration of `vfprintf', and to 0 if you - don't. */ -#define HAVE_DECL_VFPRINTF 1 - -/* Define if denormalized floats work. */ -#define HAVE_DENORMS 1 - -/* Define if you have the header file. */ -#undef HAVE_DLFCN_H - -/* Define one (and only one) of the following for the format of a `double'. - If your format is not among these choices, or you don't know what it is, - then leave all of them undefined. - "IEEE_LITTLE_SWAPPED" means little endian, but with the two 4-byte halves - swapped, as used by ARM CPUs in little endian mode. */ -#undef HAVE_DOUBLE_IEEE_BIG_ENDIAN -#define HAVE_DOUBLE_IEEE_LITTLE_ENDIAN 1 -#undef HAVE_DOUBLE_IEEE_LITTLE_SWAPPED -#undef HAVE_DOUBLE_VAX_D -#undef HAVE_DOUBLE_VAX_G -#undef HAVE_DOUBLE_CRAY_CFP - -/* Define if you have the header file. */ -#define HAVE_FCNTL_H 1 - -/* Define if you have the header file. */ -#undef HAVE_FPU_CONTROL_H - -/* Define if you have the `getpagesize' function. */ -#undef HAVE_GETPAGESIZE - -/* Define if you have the `getrusage' function. */ -#undef HAVE_GETRUSAGE - -/* Define if you have the `gettimeofday' function. */ -#undef HAVE_GETTIMEOFDAY - -/* Define if 0/0, 1/0, -1/0 and sqrt(-1) work to generate NaN/infinities. */ -#define HAVE_INFS 1 - -/* Define if the system has the type `intmax_t'. */ -#undef HAVE_INTMAX_T - -/* Define if you have the header file. */ -#undef HAVE_INTTYPES_H - -/* Define one (just one) of the following for the endiannes of `mp_limb_t'. - If the endianness is not a simple big or little, or you don't know what - it is, then leave both of these undefined. */ -#undef HAVE_LIMB_BIG_ENDIAN -#define HAVE_LIMB_LITTLE_ENDIAN 1 - -#define HAVE_STD__LOCALE 1 - -/* Define if you have the `localeconv' function. */ -#define HAVE_LOCALECONV 1 - -/* Define if you have the header file. */ -#define HAVE_LOCALE_H 1 - -/* Define if the system has the type `long double'. */ -#define HAVE_LONG_DOUBLE 1 - -/* Define if the system has the type `long long'. */ -#define HAVE_LONG_LONG 1 - -/* Define if you have the `lrand48' function. */ -#undef HAVE_LRAND48 - -/* Define if you have the header file. */ -#define HAVE_MEMORY_H 1 - -/* Define if you have the `memset' function. */ -#define HAVE_MEMSET 1 - -/* Define if you have the `mmap' function. */ -#undef HAVE_MMAP - -/* Define if you have the `mprotect' function. */ -#undef HAVE_MPROTECT - -/* Define if you have the `obstack_vprintf' function. */ -#undef HAVE_OBSTACK_VPRINTF - -/* Define if you have the `popen' function. */ -#undef HAVE_POPEN - -/* Define if you have the `processor_info' function. */ -#undef HAVE_PROCESSOR_INFO - -/* Define if the system has the type `ptrdiff_t'. */ -#define HAVE_PTRDIFF_T 1 - -/* Define if the system has the type `quad_t'. */ -#undef HAVE_QUAD_T - -#define HAVE_RAISE 1 - -/* Define if you have the `read_real_time' function. */ -#undef HAVE_READ_REAL_TIME - -/* Define if you have the `sigaction' function. */ -#undef HAVE_SIGACTION - -/* Define if you have the `sigaltstack' function. */ -#undef HAVE_SIGALTSTACK - -/* Define if you have the `sigstack' function. */ -#undef HAVE_SIGSTACK - -/* Tune directory speed_cyclecounter, undef=none, 1=32bits, 2=64bits) */ -#define HAVE_SPEED_CYCLECOUNTER 2 - -/* Define if the system has the type `stack_t'. */ -#undef HAVE_STACK_T - -/* Define if exists and works */ -#define HAVE_STDARG 1 - -/* Define if you have the header file. */ -#undef HAVE_STDINT_H - -/* Define if you have the header file. */ -#define HAVE_STDLIB_H 1 - -/* Define if you have the `strcasecmp' function. */ -#undef HAVE_STRCASECMP - -/* Define if you have the `strchr' function. */ -#define HAVE_STRCHR 1 - -/* Define if cpp supports the ANSI # stringizing operator. */ -#define HAVE_STRINGIZE 1 - -/* Define if you have the header file. */ -#undef HAVE_STRINGS_H - -/* Define if you have the header file. */ -#define HAVE_STRING_H 1 - -/* Define if you have the `strnlen' function. */ -#define HAVE_STRNLEN 1 - -/* Define if you have the `strtoul' function. */ -#define HAVE_STRTOUL 1 - -/* Define if you have the `sysconf' function. */ -#undef HAVE_SYSCONF - -/* Define if you have the `sysctl' function. */ -#undef HAVE_SYSCTL - -/* Define if you have the `sysctlbyname' function. */ -#undef HAVE_SYSCTLBYNAME - -/* Define if you have the `syssgi' function. */ -#undef HAVE_SYSSGI - -/* Define if you have the header file. */ -#undef HAVE_SYS_MMAN_H - -/* Define if you have the header file. */ -#undef HAVE_SYS_PARAM_H - -/* Define if you have the header file. */ -#undef HAVE_SYS_PROCESSOR_H - -/* Define if you have the header file. */ -#undef HAVE_SYS_RESOURCE_H - -/* Define if you have the header file. */ -#define HAVE_SYS_STAT_H 1 - -/* Define if you have the header file. */ -#undef HAVE_SYS_SYSCTL_H - -/* Define if you have the header file. */ -#undef HAVE_SYS_SYSSGI_H - -/* Define if you have the header file. */ -#undef HAVE_SYS_SYSTEMCFG_H - -/* Define if you have the header file. */ -#undef HAVE_SYS_TIMES_H - -/* Define if you have the header file. */ -#undef HAVE_SYS_TIME_H - -/* Define if you have the header file. */ -#define HAVE_SYS_TYPES_H 1 - -/* Define if you have the `times' function. */ -#undef HAVE_TIMES - -/* Define if you have the header file. */ -#undef HAVE_UNISTD_H - -/* Define if you have vsnprintf and it works properly. */ -#undef HAVE_VSNPRINTF - -/* Assembler local label prefix */ -#undef LSYM_PREFIX - -/* Define if you have the `fesetround' function via the header file. - */ -#undef MPFR_HAVE_FESETROUND - -#define HAVE_SSTREAM 1 - -/* Name of package */ -#define PACKAGE "mpir" - -/* Define if compiler has function prototypes */ -#define PROTOTYPES 1 - -/* Define as the return type of signal handlers (`int' or `void'). */ -#define RETSIGTYPE void - -/* The size of a `unsigned long', as computed by sizeof. */ -#define SIZEOF_UNSIGNED_LONG 4 - -/* Define if sscanf requires writable inputs */ -#undef SSCANF_WRITABLE_INPUT - -/* Define if you have the ANSI C header files. */ -#define STDC_HEADERS 1 - -/* Define if you can safely include both and . */ -#undef TIME_WITH_SYS_TIME - -/* Maximum size the tune program can test for KARATSUBA_SQR_THRESHOLD */ -#define TUNE_KARATSUBA_SQR_MAX 67 - -/* ./configure --enable-assert option, to enable some ASSERT()s */ -#undef WANT_ASSERT - -/* ./configure --enable-fft option, to enable FFTs for multiplication */ -#define WANT_FFT 1 - -/* Define to 1 if --enable-profiling=gprof */ -#undef WANT_PROFILING_GPROF - -/* Define to 1 if --enable-profiling=prof */ -#undef WANT_PROFILING_PROF - -/* --enable-alloca=yes */ -#define WANT_TMP_ALLOCA 1 - -/* --enable-alloca=debug */ -#undef WANT_TMP_DEBUG - -/* --enable-alloca=malloc-notreentrant */ -#undef WANT_TMP_NOTREENTRANT - -/* --enable-alloca=malloc-reentrant */ -#undef WANT_TMP_REENTRANT - -/* Define if your processor stores words with the most significant byte first - (like Motorola and SPARC, unlike Intel and VAX). */ -#undef WORDS_BIGENDIAN - -/* Define if `lex' declares `yytext' as a `char *' by default, not a `char[]'. - */ -#undef YYTEXT_POINTER - -/* Define as `__inline' if that's what the C compiler calls it, or to nothing - if it is not supported. */ -#ifndef __cplusplus -#define inline __inline -#endif - -/* Define to empty if the keyword `volatile' does not work. Warning: valid - code using `volatile' can become incorrect without. Disable with care. */ -#undef volatile - -#ifdef _MSC_VER -#define access _access -#define strcasecmp _stricmp -#define strncasecmp _strnicmp -#define alloca _alloca -#define HAVE_STRCASECMP 1 -#define HAVE_STRNCASECMP 1 -#define va_copy(d, s) (d) = (s) -#endif diff --git a/src/external/inc/win32-msvc/mpir-2.2.1_x64/gmp-mparam.h b/src/external/inc/win32-msvc/mpir-2.2.1_x64/gmp-mparam.h deleted file mode 100644 index 454f44106..000000000 --- a/src/external/inc/win32-msvc/mpir-2.2.1_x64/gmp-mparam.h +++ /dev/null @@ -1,24 +0,0 @@ -/* Generic C gmp-mparam.h -- Compiler/machine parameter header file. - -Copyright 1991, 1993, 1994, 2000 Free Software Foundation, Inc. - -This file is part of the GNU MP Library. - -The GNU MP Library is free software; you can redistribute it and/or modify -it under the terms of the GNU Lesser General Public License as published by -the Free Software Foundation; either version 2.1 of the License, or (at your -option) any later version. - -The GNU MP Library is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public -License for more details. - -You should have received a copy of the GNU Lesser General Public License -along with the GNU MP Library; see the file COPYING.LIB. If not, write to -the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, -MA 02110-1301, USA. */ - - -/* Values for BITS_PER_MP_LIMB etc will be determined by ./configure and put - in config.h. */ diff --git a/src/external/inc/win32-msvc/mpir-2.2.1_x64/gmp.h b/src/external/inc/win32-msvc/mpir-2.2.1_x64/gmp.h deleted file mode 100644 index b4521bede..000000000 --- a/src/external/inc/win32-msvc/mpir-2.2.1_x64/gmp.h +++ /dev/null @@ -1,1842 +0,0 @@ -/* generated from gmp-h.in by gen_mpir_h.bat */ -/* Definitions for GNU multiple precision functions. -*- mode: c -*- -Copyright 1991, 1993, 1994, 1995, 1996, 1997, 1999, 2000, 2001, 2002, 2003, -2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc. -Copyright 2008 William Hart, Gonzalo Tornaria -This file is part of the MPIR Library. -The MPIR Library is free software; you can redistribute it and/or modify -it under the terms of the GNU Lesser General Public License as published by -the Free Software Foundation; either version 3 of the License, or (at your -option) any later version. -The MPIR Library is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public -License for more details. -You should have received a copy of the GNU Lesser General Public License -along with the GNU MP Library. If not, see http://www.gnu.org/licenses/. */ -#ifndef __GMP_H__ -#if defined (__cplusplus) -#include /* for std::istream, std::ostream, std::string */ -#include -#endif -/* Instantiated by configure. */ -#if ! defined (__GMP_WITHIN_CONFIGURE) -#define __GMP_BITS_PER_MP_LIMB 64 -#define GMP_LIMB_BITS 64 -#define GMP_NAIL_BITS 0 -#define SIZEOF_MP_LIMB_T (GMP_LIMB_BITS >> 3) -#if !defined _LONG_LONG_LIMB -# define _LONG_LONG_LIMB 1 -#endif -#endif -#define GMP_NUMB_BITS (GMP_LIMB_BITS - GMP_NAIL_BITS) -#define GMP_NUMB_MASK ((~ __GMP_CAST (mp_limb_t, 0)) >> GMP_NAIL_BITS) -#define GMP_NUMB_MAX GMP_NUMB_MASK -#define GMP_NAIL_MASK (~ GMP_NUMB_MASK) -/* The following (everything under ifndef __GNU_MP__) must be identical in - mpir.h and mp.h to allow both to be included in an application or during - the library build. */ -#ifndef __GNU_MP__ -#define __GNU_MP__ 4 -#define __need_size_t /* tell gcc stddef.h we only want size_t */ -#if defined (__cplusplus) -#include /* for size_t */ -#else -#include /* for size_t */ -#endif -#undef __need_size_t -/* Instantiated by configure. */ -#if ! defined (__GMP_WITHIN_CONFIGURE) -#endif -/* #if defined(__GMP_WITHIN_CONFIGURE) && defined(_WIN64) */ -#ifdef __WIN64 -#define _LONG_LONG_LIMB 1 -#endif -/* __STDC__ - some ANSI compilers define this only to 0, hence the use of - "defined" and not "__STDC__-0". In particular Sun workshop C 5.0 - sets __STDC__ to 0, but requires "##" for token pasting. - _AIX - gnu ansidecl.h asserts that all known AIX compilers are ANSI but - don't always define __STDC__. - __DECC - current versions of DEC C (5.9 for instance) for alpha are ANSI, - but don't define __STDC__ in their default mode. Don't know if old - versions might have been K&R, but let's not worry about that unless - someone is still using one. - _mips - gnu ansidecl.h says the RISC/OS MIPS compiler is ANSI in SVR4 - mode, but doesn't define __STDC__. - _MSC_VER - Microsoft C is ANSI, but __STDC__ is undefined unless the /Za - option is given (in which case it's 1). - _WIN32 - tested for by gnu ansidecl.h, no doubt on the assumption that - all w32 compilers are ansi. - Note: This same set of tests is used by gen-psqr.c and - demos/expr/expr-impl.h, so if anything needs adding, then be sure to - update those too. */ -#if defined (__STDC__) \ - || defined (__cplusplus) \ - || defined (_AIX) \ - || defined (__DECC) \ - || (defined (__mips) && defined (_SYSTYPE_SVR4)) \ - || defined (_MSC_VER) \ - || defined (_WIN32) -#define __GMP_HAVE_CONST 1 -#define __GMP_HAVE_PROTOTYPES 1 -#define __GMP_HAVE_TOKEN_PASTE 1 -#else -#define __GMP_HAVE_CONST 0 -#define __GMP_HAVE_PROTOTYPES 0 -#define __GMP_HAVE_TOKEN_PASTE 0 -#endif -#if __GMP_HAVE_CONST -#define __gmp_const const -#define __gmp_signed signed -#else -#define __gmp_const -#define __gmp_signed -#endif -/* __GMP_DECLSPEC supports Windows DLL versions of libmpir, and is empty in - all other circumstances. - When compiling objects for libmpir, __GMP_DECLSPEC is an export directive, - or when compiling for an application it's an import directive. The two - cases are differentiated by __GMP_WITHIN_GMP defined by the GMP Makefiles - (and not defined from an application). - __GMP_DECLSPEC_XX is similarly used for libmpirxx. __GMP_WITHIN_GMPXX - indicates when building libmpirxx, and in that case libmpirxx functions are - exports, but libmpir functions which might get called are imports. - libmp.la uses __GMP_DECLSPEC, just as if it were libmpir.la. libmpir and - libmp don't call each other, so there's no conflict or confusion. - Libtool DLL_EXPORT define is not used. - There's no attempt to support GMP built both static and DLL. Doing so - would mean applications would have to tell us which of the two is going - to be used when linking, and that seems very tedious and error prone if - using GMP by hand, and equally tedious from a package since autoconf and - automake don't give much help. - __GMP_DECLSPEC is required on all documented global functions and - variables, the various internals in gmp-impl.h etc can be left unadorned. - But internals used by the test programs or speed measuring programs - should have __GMP_DECLSPEC, and certainly constants or variables must - have it or the wrong address will be resolved. - In gcc __declspec can go at either the start or end of a prototype. - In Microsoft C __declspec must go at the start, or after the type like - void __declspec(...) *foo()". There's no __dllexport or anything to - guard against someone foolish #defining dllexport. _export used to be - available, but no longer. - In Borland C _export still exists, but needs to go after the type, like - "void _export foo();". Would have to change the __GMP_DECLSPEC syntax to - make use of that. Probably more trouble than it's worth. */ -#if defined (__GNUC__) -#define __GMP_DECLSPEC_EXPORT __declspec(__dllexport__) -#define __GMP_DECLSPEC_IMPORT __declspec(__dllimport__) -#endif -#if defined (_MSC_VER) || defined (__BORLANDC__) -#define __GMP_DECLSPEC_EXPORT __declspec(dllexport) -#define __GMP_DECLSPEC_IMPORT __declspec(dllimport) -#endif -#ifdef __WATCOMC__ -#define __GMP_DECLSPEC_EXPORT __export -#define __GMP_DECLSPEC_IMPORT __import -#endif -#ifdef __IBMC__ -#define __GMP_DECLSPEC_EXPORT _Export -#define __GMP_DECLSPEC_IMPORT _Import -#endif -#if __GMP_LIBGMP_DLL -#if __GMP_WITHIN_GMP -/* compiling to go into a DLL libmpir */ -#define __GMP_DECLSPEC __GMP_DECLSPEC_EXPORT -#else -/* compiling to go into an application which will link to a DLL libmpir */ -#define __GMP_DECLSPEC __GMP_DECLSPEC_IMPORT -#endif -#else -/* all other cases */ -#define __GMP_DECLSPEC -#endif -#ifdef __GMP_SHORT_LIMB -typedef unsigned int mp_limb_t; -typedef int mp_limb_signed_t; -#else -#ifdef _LONG_LONG_LIMB -typedef unsigned long long int mp_limb_t; -typedef long long int mp_limb_signed_t; -#else -typedef unsigned long int mp_limb_t; -typedef long int mp_limb_signed_t; -#endif -#endif -#ifdef _WIN64 -typedef unsigned long long int mp_bitcnt_t; -#else -typedef unsigned long int mp_bitcnt_t; -#endif -/* For reference, note that the name __mpz_struct gets into C++ mangled - function names, which means although the "__" suggests an internal, we - must leave this name for binary compatibility. */ -typedef struct -{ - int _mp_alloc; /* Number of *limbs* allocated and pointed - to by the _mp_d field. */ - int _mp_size; /* abs(_mp_size) is the number of limbs the - last field points to. If _mp_size is - negative this is a negative number. */ - mp_limb_t *_mp_d; /* Pointer to the limbs. */ -} __mpz_struct; -#endif /* __GNU_MP__ */ -typedef __mpz_struct mpz_t[1]; -typedef mp_limb_t * mp_ptr; -typedef __gmp_const mp_limb_t * mp_srcptr; -#if defined( _WIN64) -#define __GMP_MP_SIZE_T_INT 0 -typedef long long int mp_size_t; -typedef long int mp_exp_t; -#else -#define __GMP_MP_SIZE_T_INT 0 -typedef long int mp_size_t; -typedef long int mp_exp_t; -#endif -typedef struct -{ - __mpz_struct _mp_num; - __mpz_struct _mp_den; -} __mpq_struct; -typedef __mpq_struct mpq_t[1]; -typedef struct -{ - int _mp_prec; /* Max precision, in number of `mp_limb_t's. - Set by mpf_init and modified by - mpf_set_prec. The area pointed to by the - _mp_d field contains `prec' + 1 limbs. */ - int _mp_size; /* abs(_mp_size) is the number of limbs the - last field points to. If _mp_size is - negative this is a negative number. */ - mp_exp_t _mp_exp; /* Exponent, in the base of `mp_limb_t'. */ - mp_limb_t *_mp_d; /* Pointer to the limbs. */ -} __mpf_struct; -typedef __mpf_struct mpf_t[1]; -/* Available random number generation algorithms. */ -typedef enum -{ - GMP_RAND_ALG_DEFAULT = 0, - GMP_RAND_ALG_LC = GMP_RAND_ALG_DEFAULT /* Linear congruential. */ -} gmp_randalg_t; -/* Random state struct. */ -typedef struct -{ - mpz_t _mp_seed; /* _mp_d member points to state of the generator. */ - gmp_randalg_t _mp_alg; /* Currently unused. */ - union { - void *_mp_lc; /* Pointer to function pointers structure. */ - } _mp_algdata; -} __gmp_randstate_struct; -typedef __gmp_randstate_struct gmp_randstate_t[1]; -/* Types for function declarations in gmp files. */ -/* ??? Should not pollute user name space with these ??? */ -typedef __gmp_const __mpz_struct *mpz_srcptr; -typedef __mpz_struct *mpz_ptr; -typedef __gmp_const __mpf_struct *mpf_srcptr; -typedef __mpf_struct *mpf_ptr; -typedef __gmp_const __mpq_struct *mpq_srcptr; -typedef __mpq_struct *mpq_ptr; -/* This is not wanted in mp.h, so put it outside the __GNU_MP__ common - section. */ -#if __GMP_LIBGMP_DLL -#if __GMP_WITHIN_GMPXX -/* compiling to go into a DLL libmpirxx */ -#define __GMP_DECLSPEC_XX __GMP_DECLSPEC_EXPORT -#else -/* compiling to go into a application which will link to a DLL libmpirxx */ -#define __GMP_DECLSPEC_XX __GMP_DECLSPEC_IMPORT -#endif -#else -/* all other cases */ -#define __GMP_DECLSPEC_XX -#endif -#if __GMP_HAVE_PROTOTYPES -#define __GMP_PROTO(x) x -#else -#define __GMP_PROTO(x) () -#endif -#ifndef __MPN -#if __GMP_HAVE_TOKEN_PASTE -#define __MPN(x) __gmpn_##x -#else -#define __MPN(x) __gmpn_/**/x -#endif -#endif -/* For reference, "defined(EOF)" cannot be used here. In g++ 2.95.4, - defines EOF but not FILE. */ -#if defined (FILE) \ - || defined (H_STDIO) \ - || defined (_H_STDIO) /* AIX */ \ - || defined (_STDIO_H) /* glibc, Sun, SCO */ \ - || defined (_STDIO_H_) /* BSD, OSF */ \ - || defined (__STDIO_H) /* Borland */ \ - || defined (__STDIO_H__) /* IRIX */ \ - || defined (_STDIO_INCLUDED) /* HPUX */ \ - || defined (_FILE_DEFINED) /* Microsoft */ \ - || defined (__STDIO__) /* Apple MPW MrC */ \ - || defined (_MSL_STDIO_H) /* Metrowerks */ \ - || defined (_STDIO_H_INCLUDED) /* QNX4 */ \ - || defined (_ISO_STDIO_ISO_H) /* Sun C++ */ -#define _GMP_H_HAVE_FILE 1 -#endif -/* In ISO C, if a prototype involving "struct obstack *" is given without - that structure defined, then the struct is scoped down to just the - prototype, causing a conflict if it's subsequently defined for real. So - only give prototypes if we've got obstack.h. */ -#if defined (_OBSTACK_H) /* glibc */ -#define _GMP_H_HAVE_OBSTACK 1 -#endif -/* The prototypes for gmp_vprintf etc are provided only if va_list is - available, via an application having included or . - Usually va_list is a typedef so can't be tested directly, but C99 - specifies that va_start is a macro (and it was normally a macro on past - systems too), so look for that. - will define some sort of va_list for vprintf and vfprintf, but - let's not bother trying to use that since it's not standard and since - application uses for gmp_vprintf etc will almost certainly require the - whole or anyway. */ -#ifdef va_start -#define _GMP_H_HAVE_VA_LIST 1 -#endif -/* Test for gcc >= maj.min, as per __GNUC_PREREQ in glibc */ -#if defined (__GNUC__) && defined (__GNUC_MINOR__) -#define __GMP_GNUC_PREREQ(maj, min) \ - ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min)) -#else -#define __GMP_GNUC_PREREQ(maj, min) 0 -#endif -/* "pure" is in gcc 2.96 and up, see "(gcc)Function Attributes". Basically - it means a function does nothing but examine its arguments and memory - (global or via arguments) to generate a return value, but changes nothing - and has no side-effects. __GMP_NO_ATTRIBUTE_CONST_PURE lets - tune/common.c etc turn this off when trying to write timing loops. */ -#if __GMP_GNUC_PREREQ (2,96) && ! defined (__GMP_NO_ATTRIBUTE_CONST_PURE) -#define __GMP_ATTRIBUTE_PURE __attribute__ ((__pure__)) -#else -#define __GMP_ATTRIBUTE_PURE -#endif -/* __GMP_CAST allows us to use static_cast in C++, so our macros are clean - to "g++ -Wold-style-cast". - Casts in "extern inline" code within an extern "C" block don't induce - these warnings, so __GMP_CAST only needs to be used on documented - macros. */ -#ifdef __cplusplus -#define __GMP_CAST(type, expr) (static_cast (expr)) -#else -#define __GMP_CAST(type, expr) ((type) (expr)) -#endif -/* An empty "throw ()" means the function doesn't throw any C++ exceptions, - this can save some stack frame info in applications. - Currently it's given only on functions which never divide-by-zero etc, - don't allocate memory, and are expected to never need to allocate memory. - This leaves open the possibility of a C++ throw from a future GMP - exceptions scheme. - mpz_set_ui etc are omitted to leave open the lazy allocation scheme - described in doc/tasks.html. mpz_get_d etc are omitted to leave open - exceptions for float overflows. - Note that __GMP_NOTHROW must be given on any inlines the same as on their - prototypes (for g++ at least, where they're used together). Note also - that g++ 3.0 demands that __GMP_NOTHROW is before other attributes like - __GMP_ATTRIBUTE_PURE. */ -#if defined (__cplusplus) -#define __GMP_NOTHROW throw () -#else -#define __GMP_NOTHROW -#endif -/* PORTME: What other compilers have a useful "extern inline"? "static - inline" would be an acceptable substitute if the compiler (or linker) - discards unused statics. */ -/* gcc has __inline__ in all modes, including strict ansi. Give a prototype - for an inline too, so as to correctly specify "dllimport" on windows, in - case the function is called rather than inlined. */ -#ifdef __GNUC__ -#if defined(__APPLE_CC__) && (__APPLE_CC__ != 1) /* FSF GCC sets this flag to 1 on Apple machines */ -#if ! (__APPLE_CC__ >= 5465 && __STDC_VERSION__ >= 199901L) -#define __GMP_EXTERN_INLINE extern __inline__ -#define __GMP_INLINE_PROTOTYPES 1 -#endif -#else /*GNU CC*/ -#if defined(__GNUC_STDC_INLINE__) || defined (__GNUC_GNU_INLINE__) -#define __GMP_EXTERN_INLINE extern __inline__ __attribute__((__gnu_inline__)) -#else -#define __GMP_EXTERN_INLINE extern __inline__ -#endif -#define __GMP_INLINE_PROTOTYPES 1 -#endif -#endif -/* DEC C (eg. version 5.9) supports "static __inline foo()", even in -std1 - strict ANSI mode. Inlining is done even when not optimizing (ie. -O0 - mode, which is the default), but an unnecessary local copy of foo is - emitted unless -O is used. "extern __inline" is accepted, but the - "extern" appears to be ignored, ie. it becomes a plain global function - but which is inlined within its file. Don't know if all old versions of - DEC C supported __inline, but as a start let's do the right thing for - current versions. */ -#ifdef __DECC -#define __GMP_EXTERN_INLINE static __inline -#endif -/* SCO OpenUNIX 8 cc supports "static inline foo()" but not in -Xc strict - ANSI mode (__STDC__ is 1 in that mode). Inlining only actually takes - place under -O. Without -O "foo" seems to be emitted whether it's used - or not, which is wasteful. "extern inline foo()" isn't useful, the - "extern" is apparently ignored, so foo is inlined if possible but also - emitted as a global, which causes multiple definition errors when - building a shared libmpir. */ -#ifdef __SCO_VERSION__ -#if __SCO_VERSION__ > 400000000 && __STDC__ != 1 \ - && ! defined (__GMP_EXTERN_INLINE) -#define __GMP_EXTERN_INLINE static inline -#endif -#endif -#if defined _MSC_VER -#define __GMP_EXTERN_INLINE static __inline -#endif -/* C++ always has "inline" and since it's a normal feature the linker should - discard duplicate non-inlined copies, or if it doesn't then that's a - problem for everyone, not just GMP. */ -#if defined (__cplusplus) && ! defined (__GMP_EXTERN_INLINE) -#define __GMP_EXTERN_INLINE inline -#endif -/* Don't do any inlining within a configure run, since if the compiler ends - up emitting copies of the code into the object file it can end up - demanding the various support routines (like mpn_popcount) for linking, - making the "alloca" test and perhaps others fail. And on hppa ia64 a - pre-release gcc 3.2 was seen not respecting the "extern" in "extern - __inline__", triggering this problem too. */ -#if defined (__GMP_WITHIN_CONFIGURE) && ! __GMP_WITHIN_CONFIGURE_INLINE -#undef __GMP_EXTERN_INLINE -#endif -/* By default, don't give a prototype when there's going to be an inline - version. Note in particular that Cray C++ objects to the combination of - prototype and inline. */ -#ifdef __GMP_EXTERN_INLINE -#ifndef __GMP_INLINE_PROTOTYPES -#define __GMP_INLINE_PROTOTYPES 0 -#endif -#else -#define __GMP_INLINE_PROTOTYPES 1 -#endif -#define __GMP_ABS(x) ((x) >= 0 ? (x) : -(x)) -#define __GMP_MAX(h,i) ((h) > (i) ? (h) : (i)) -/* __GMP_USHRT_MAX is not "~ (unsigned short) 0" because short is promoted - to int by "~". */ -#define __GMP_UINT_MAX (~ (unsigned) 0) -#define __GMP_ULONG_MAX (~ (unsigned long) 0) -#define __GMP_USHRT_MAX ((unsigned short) ~0) -/* __builtin_expect is in gcc 3.0, and not in 2.95. */ -#if __GMP_GNUC_PREREQ (3,0) -#define __GMP_LIKELY(cond) __builtin_expect ((cond) != 0, 1) -#define __GMP_UNLIKELY(cond) __builtin_expect ((cond) != 0, 0) -#else -#define __GMP_LIKELY(cond) (cond) -#define __GMP_UNLIKELY(cond) (cond) -#endif -/* Allow direct user access to numerator and denominator of a mpq_t object. */ -#define mpq_numref(Q) (&((Q)->_mp_num)) -#define mpq_denref(Q) (&((Q)->_mp_den)) -#if defined (__cplusplus) -extern "C" { -using std::FILE; -#endif -#define mp_set_memory_functions __gmp_set_memory_functions -__GMP_DECLSPEC void mp_set_memory_functions __GMP_PROTO ((void *(*) (size_t), - void *(*) (void *, size_t, size_t), - void (*) (void *, size_t))) __GMP_NOTHROW; -#define mp_get_memory_functions __gmp_get_memory_functions -__GMP_DECLSPEC void mp_get_memory_functions __GMP_PROTO ((void *(**) (size_t), - void *(**) (void *, size_t, size_t), - void (**) (void *, size_t))) __GMP_NOTHROW; -#define mp_bits_per_limb __gmp_bits_per_limb -__GMP_DECLSPEC extern __gmp_const int mp_bits_per_limb; -#define gmp_errno __gmp_errno -__GMP_DECLSPEC extern int gmp_errno; -#define gmp_version __gmp_version -__GMP_DECLSPEC extern __gmp_const char * __gmp_const gmp_version; -#define mpir_version __mpir_version -__GMP_DECLSPEC extern __gmp_const char * __gmp_const mpir_version; -/**************** Random number routines. ****************/ -#define gmp_randinit_default __gmp_randinit_default -__GMP_DECLSPEC void gmp_randinit_default __GMP_PROTO ((gmp_randstate_t)); -#define gmp_randinit_lc_2exp __gmp_randinit_lc_2exp -__GMP_DECLSPEC void gmp_randinit_lc_2exp __GMP_PROTO ((gmp_randstate_t, - mpz_srcptr, unsigned long int, - mp_bitcnt_t)); -#define gmp_randinit_lc_2exp_size __gmp_randinit_lc_2exp_size -__GMP_DECLSPEC int gmp_randinit_lc_2exp_size __GMP_PROTO ((gmp_randstate_t, mp_bitcnt_t)); -#define gmp_randinit_mt __gmp_randinit_mt -__GMP_DECLSPEC void gmp_randinit_mt __GMP_PROTO ((gmp_randstate_t)); -#define gmp_randinit_set __gmp_randinit_set -__GMP_DECLSPEC void gmp_randinit_set __GMP_PROTO ((gmp_randstate_t, __gmp_const __gmp_randstate_struct *)); -#define gmp_randseed __gmp_randseed -__GMP_DECLSPEC void gmp_randseed __GMP_PROTO ((gmp_randstate_t, mpz_srcptr)); -#define gmp_randseed_ui __gmp_randseed_ui -__GMP_DECLSPEC void gmp_randseed_ui __GMP_PROTO ((gmp_randstate_t, unsigned long int)); -#define gmp_randclear __gmp_randclear -__GMP_DECLSPEC void gmp_randclear __GMP_PROTO ((gmp_randstate_t)); -#define gmp_urandomb_ui __gmp_urandomb_ui -__GMP_DECLSPEC unsigned long gmp_urandomb_ui __GMP_PROTO ((gmp_randstate_t, unsigned long)); -#define gmp_urandomm_ui __gmp_urandomm_ui -__GMP_DECLSPEC unsigned long gmp_urandomm_ui __GMP_PROTO ((gmp_randstate_t, unsigned long)); -/**************** Formatted output routines. ****************/ -#define gmp_asprintf __gmp_asprintf -__GMP_DECLSPEC int gmp_asprintf __GMP_PROTO ((char **, __gmp_const char *, ...)); -#define gmp_fprintf __gmp_fprintf -#ifdef _GMP_H_HAVE_FILE -__GMP_DECLSPEC int gmp_fprintf __GMP_PROTO ((FILE *, __gmp_const char *, ...)); -#endif -#define gmp_obstack_printf __gmp_obstack_printf -#if defined (_GMP_H_HAVE_OBSTACK) -__GMP_DECLSPEC int gmp_obstack_printf __GMP_PROTO ((struct obstack *, __gmp_const char *, ...)); -#endif -#define gmp_obstack_vprintf __gmp_obstack_vprintf -#if defined (_GMP_H_HAVE_OBSTACK) && defined (_GMP_H_HAVE_VA_LIST) -__GMP_DECLSPEC int gmp_obstack_vprintf __GMP_PROTO ((struct obstack *, __gmp_const char *, va_list)); -#endif -#define gmp_printf __gmp_printf -__GMP_DECLSPEC int gmp_printf __GMP_PROTO ((__gmp_const char *, ...)); -#define gmp_snprintf __gmp_snprintf -__GMP_DECLSPEC int gmp_snprintf __GMP_PROTO ((char *, size_t, __gmp_const char *, ...)); -#define gmp_sprintf __gmp_sprintf -__GMP_DECLSPEC int gmp_sprintf __GMP_PROTO ((char *, __gmp_const char *, ...)); -#define gmp_vasprintf __gmp_vasprintf -#if defined (_GMP_H_HAVE_VA_LIST) -__GMP_DECLSPEC int gmp_vasprintf __GMP_PROTO ((char **, __gmp_const char *, va_list)); -#endif -#define gmp_vfprintf __gmp_vfprintf -#if defined (_GMP_H_HAVE_FILE) && defined (_GMP_H_HAVE_VA_LIST) -__GMP_DECLSPEC int gmp_vfprintf __GMP_PROTO ((FILE *, __gmp_const char *, va_list)); -#endif -#define gmp_vprintf __gmp_vprintf -#if defined (_GMP_H_HAVE_VA_LIST) -__GMP_DECLSPEC int gmp_vprintf __GMP_PROTO ((__gmp_const char *, va_list)); -#endif -#define gmp_vsnprintf __gmp_vsnprintf -#if defined (_GMP_H_HAVE_VA_LIST) -__GMP_DECLSPEC int gmp_vsnprintf __GMP_PROTO ((char *, size_t, __gmp_const char *, va_list)); -#endif -#define gmp_vsprintf __gmp_vsprintf -#if defined (_GMP_H_HAVE_VA_LIST) -__GMP_DECLSPEC int gmp_vsprintf __GMP_PROTO ((char *, __gmp_const char *, va_list)); -#endif -/**************** Formatted input routines. ****************/ -#define gmp_fscanf __gmp_fscanf -#ifdef _GMP_H_HAVE_FILE -__GMP_DECLSPEC int gmp_fscanf __GMP_PROTO ((FILE *, __gmp_const char *, ...)); -#endif -#define gmp_scanf __gmp_scanf -__GMP_DECLSPEC int gmp_scanf __GMP_PROTO ((__gmp_const char *, ...)); -#define gmp_sscanf __gmp_sscanf -__GMP_DECLSPEC int gmp_sscanf __GMP_PROTO ((__gmp_const char *, __gmp_const char *, ...)); -#define gmp_vfscanf __gmp_vfscanf -#if defined (_GMP_H_HAVE_FILE) && defined (_GMP_H_HAVE_VA_LIST) -__GMP_DECLSPEC int gmp_vfscanf __GMP_PROTO ((FILE *, __gmp_const char *, va_list)); -#endif -#define gmp_vscanf __gmp_vscanf -#if defined (_GMP_H_HAVE_VA_LIST) -__GMP_DECLSPEC int gmp_vscanf __GMP_PROTO ((__gmp_const char *, va_list)); -#endif -#define gmp_vsscanf __gmp_vsscanf -#if defined (_GMP_H_HAVE_VA_LIST) -__GMP_DECLSPEC int gmp_vsscanf __GMP_PROTO ((__gmp_const char *, __gmp_const char *, va_list)); -#endif -/**************** Integer (i.e. Z) routines. ****************/ -#define __GMP_BITS_PER_ULONG (8*sizeof(unsigned long)) -#define _mpz_realloc __gmpz_realloc -#define mpz_realloc __gmpz_realloc -__GMP_DECLSPEC void *_mpz_realloc __GMP_PROTO ((mpz_ptr, mp_size_t)); -#define mpz_abs __gmpz_abs -#define __GMP_MPZ_ABS_MIN_ALLOC(x,y) (__GMP_ABS(y->_mp_size)) -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_abs) -__GMP_DECLSPEC void mpz_abs __GMP_PROTO ((mpz_ptr, mpz_srcptr)); -#endif -#define __GMP_MPZ_ADD_MIN_ALLOC(x,y,z) (__GMP_MAX(__GMP_ABS(y->_mp_size),__GMP_ABS(z->_mp_size))+1) -#define mpz_add __gmpz_add -__GMP_DECLSPEC void mpz_add __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); -#define __GMP_MPZ_ADD_UI_MIN_ALLOC(x,y,z) (__GMP_MAX(__GMP_ABS(y->_mp_size),1+(__GMP_BITS_PER_ULONG-1)/GMP_NUMB_BITS)+1) -#define mpz_add_ui __gmpz_add_ui -__GMP_DECLSPEC void mpz_add_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); -#define mpz_addmul __gmpz_addmul -__GMP_DECLSPEC void mpz_addmul __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); -#define mpz_addmul_ui __gmpz_addmul_ui -__GMP_DECLSPEC void mpz_addmul_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); -#define mpz_and __gmpz_and -__GMP_DECLSPEC void mpz_and __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); -#define mpz_array_init __gmpz_array_init -__GMP_DECLSPEC void mpz_array_init __GMP_PROTO ((mpz_ptr, mp_size_t, mp_size_t)); -#define mpz_bin_ui __gmpz_bin_ui -__GMP_DECLSPEC void mpz_bin_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); -#define mpz_bin_uiui __gmpz_bin_uiui -__GMP_DECLSPEC void mpz_bin_uiui __GMP_PROTO ((mpz_ptr, unsigned long int, unsigned long int)); -#define mpz_cdiv_q __gmpz_cdiv_q -__GMP_DECLSPEC void mpz_cdiv_q __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); -#define mpz_cdiv_q_2exp __gmpz_cdiv_q_2exp -__GMP_DECLSPEC void mpz_cdiv_q_2exp __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long)); -#define mpz_cdiv_q_ui __gmpz_cdiv_q_ui -__GMP_DECLSPEC unsigned long int mpz_cdiv_q_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); -#define mpz_cdiv_qr __gmpz_cdiv_qr -__GMP_DECLSPEC void mpz_cdiv_qr __GMP_PROTO ((mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr)); -#define mpz_cdiv_qr_ui __gmpz_cdiv_qr_ui -__GMP_DECLSPEC unsigned long int mpz_cdiv_qr_ui __GMP_PROTO ((mpz_ptr, mpz_ptr, mpz_srcptr, unsigned long int)); -#define mpz_cdiv_r __gmpz_cdiv_r -__GMP_DECLSPEC void mpz_cdiv_r __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); -#define mpz_cdiv_r_2exp __gmpz_cdiv_r_2exp -__GMP_DECLSPEC void mpz_cdiv_r_2exp __GMP_PROTO ((mpz_ptr, mpz_srcptr, mp_bitcnt_t)); -#define mpz_cdiv_r_ui __gmpz_cdiv_r_ui -__GMP_DECLSPEC unsigned long int mpz_cdiv_r_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); -#define mpz_cdiv_ui __gmpz_cdiv_ui -__GMP_DECLSPEC unsigned long int mpz_cdiv_ui __GMP_PROTO ((mpz_srcptr, unsigned long int)) __GMP_ATTRIBUTE_PURE; -#define mpz_clear __gmpz_clear -__GMP_DECLSPEC void mpz_clear __GMP_PROTO ((mpz_ptr)); -#define mpz_clears __gmpz_clears -__GMP_DECLSPEC void mpz_clears __GMP_PROTO ((mpz_ptr, ...)); -#define mpz_clrbit __gmpz_clrbit -__GMP_DECLSPEC void mpz_clrbit __GMP_PROTO ((mpz_ptr, mp_bitcnt_t)); -#define mpz_cmp __gmpz_cmp -__GMP_DECLSPEC int mpz_cmp __GMP_PROTO ((mpz_srcptr, mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#define mpz_cmp_d __gmpz_cmp_d -__GMP_DECLSPEC int mpz_cmp_d __GMP_PROTO ((mpz_srcptr, double)) __GMP_ATTRIBUTE_PURE; -#define _mpz_cmp_si __gmpz_cmp_si -__GMP_DECLSPEC int _mpz_cmp_si __GMP_PROTO ((mpz_srcptr, signed long int)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#define _mpz_cmp_ui __gmpz_cmp_ui -__GMP_DECLSPEC int _mpz_cmp_ui __GMP_PROTO ((mpz_srcptr, unsigned long int)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#define mpz_cmpabs __gmpz_cmpabs -__GMP_DECLSPEC int mpz_cmpabs __GMP_PROTO ((mpz_srcptr, mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#define mpz_cmpabs_d __gmpz_cmpabs_d -__GMP_DECLSPEC int mpz_cmpabs_d __GMP_PROTO ((mpz_srcptr, double)) __GMP_ATTRIBUTE_PURE; -#define mpz_cmpabs_ui __gmpz_cmpabs_ui -__GMP_DECLSPEC int mpz_cmpabs_ui __GMP_PROTO ((mpz_srcptr, unsigned long int)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#define mpz_com __gmpz_com -__GMP_DECLSPEC void mpz_com __GMP_PROTO ((mpz_ptr, mpz_srcptr)); -#define mpz_combit __gmpz_combit -__GMP_DECLSPEC void mpz_combit __GMP_PROTO ((mpz_ptr, mp_bitcnt_t)); -#define mpz_congruent_p __gmpz_congruent_p -__GMP_DECLSPEC int mpz_congruent_p __GMP_PROTO ((mpz_srcptr, mpz_srcptr, mpz_srcptr)) __GMP_ATTRIBUTE_PURE; -#define mpz_congruent_2exp_p __gmpz_congruent_2exp_p -__GMP_DECLSPEC int mpz_congruent_2exp_p __GMP_PROTO ((mpz_srcptr, mpz_srcptr, mp_bitcnt_t)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#define mpz_congruent_ui_p __gmpz_congruent_ui_p -__GMP_DECLSPEC int mpz_congruent_ui_p __GMP_PROTO ((mpz_srcptr, unsigned long, unsigned long)) __GMP_ATTRIBUTE_PURE; -#define mpz_divexact __gmpz_divexact -__GMP_DECLSPEC void mpz_divexact __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); -#define mpz_divexact_ui __gmpz_divexact_ui -__GMP_DECLSPEC void mpz_divexact_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long)); -#define mpz_divisible_p __gmpz_divisible_p -__GMP_DECLSPEC int mpz_divisible_p __GMP_PROTO ((mpz_srcptr, mpz_srcptr)) __GMP_ATTRIBUTE_PURE; -#define mpz_divisible_ui_p __gmpz_divisible_ui_p -__GMP_DECLSPEC int mpz_divisible_ui_p __GMP_PROTO ((mpz_srcptr, unsigned long)) __GMP_ATTRIBUTE_PURE; -#define mpz_divisible_2exp_p __gmpz_divisible_2exp_p -__GMP_DECLSPEC int mpz_divisible_2exp_p __GMP_PROTO ((mpz_srcptr, mp_bitcnt_t)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#define mpz_dump __gmpz_dump -__GMP_DECLSPEC void mpz_dump __GMP_PROTO ((mpz_srcptr)); -#define mpz_export __gmpz_export -__GMP_DECLSPEC void *mpz_export __GMP_PROTO ((void *, size_t *, int, size_t, int, size_t, mpz_srcptr)); -#define mpz_fac_ui __gmpz_fac_ui -__GMP_DECLSPEC void mpz_fac_ui __GMP_PROTO ((mpz_ptr, unsigned long int)); -#define mpz_fdiv_q __gmpz_fdiv_q -__GMP_DECLSPEC void mpz_fdiv_q __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); -#define mpz_fdiv_q_2exp __gmpz_fdiv_q_2exp -__GMP_DECLSPEC void mpz_fdiv_q_2exp __GMP_PROTO ((mpz_ptr, mpz_srcptr, mp_bitcnt_t)); -#define mpz_fdiv_q_ui __gmpz_fdiv_q_ui -__GMP_DECLSPEC unsigned long int mpz_fdiv_q_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); -#define mpz_fdiv_qr __gmpz_fdiv_qr -__GMP_DECLSPEC void mpz_fdiv_qr __GMP_PROTO ((mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr)); -#define mpz_fdiv_qr_ui __gmpz_fdiv_qr_ui -__GMP_DECLSPEC unsigned long int mpz_fdiv_qr_ui __GMP_PROTO ((mpz_ptr, mpz_ptr, mpz_srcptr, unsigned long int)); -#define mpz_fdiv_r __gmpz_fdiv_r -__GMP_DECLSPEC void mpz_fdiv_r __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); -#define mpz_fdiv_r_2exp __gmpz_fdiv_r_2exp -__GMP_DECLSPEC void mpz_fdiv_r_2exp __GMP_PROTO ((mpz_ptr, mpz_srcptr, mp_bitcnt_t)); -#define mpz_fdiv_r_ui __gmpz_fdiv_r_ui -__GMP_DECLSPEC unsigned long int mpz_fdiv_r_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); -#define mpz_fdiv_ui __gmpz_fdiv_ui -__GMP_DECLSPEC unsigned long int mpz_fdiv_ui __GMP_PROTO ((mpz_srcptr, unsigned long int)) __GMP_ATTRIBUTE_PURE; -#define mpz_fib_ui __gmpz_fib_ui -__GMP_DECLSPEC void mpz_fib_ui __GMP_PROTO ((mpz_ptr, unsigned long int)); -#define mpz_fib2_ui __gmpz_fib2_ui -__GMP_DECLSPEC void mpz_fib2_ui __GMP_PROTO ((mpz_ptr, mpz_ptr, unsigned long int)); -#define mpz_fits_sint_p __gmpz_fits_sint_p -__GMP_DECLSPEC int mpz_fits_sint_p __GMP_PROTO ((mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#define mpz_fits_slong_p __gmpz_fits_slong_p -__GMP_DECLSPEC int mpz_fits_slong_p __GMP_PROTO ((mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#define mpz_fits_sshort_p __gmpz_fits_sshort_p -__GMP_DECLSPEC int mpz_fits_sshort_p __GMP_PROTO ((mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#define mpz_fits_uint_p __gmpz_fits_uint_p -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_fits_uint_p) -__GMP_DECLSPEC int mpz_fits_uint_p __GMP_PROTO ((mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#endif -#define mpz_fits_ulong_p __gmpz_fits_ulong_p -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_fits_ulong_p) -__GMP_DECLSPEC int mpz_fits_ulong_p __GMP_PROTO ((mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#endif -#define mpz_fits_ushort_p __gmpz_fits_ushort_p -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_fits_ushort_p) -__GMP_DECLSPEC int mpz_fits_ushort_p __GMP_PROTO ((mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#endif -#define mpz_gcd __gmpz_gcd -__GMP_DECLSPEC void mpz_gcd __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); -#define mpz_gcd_ui __gmpz_gcd_ui -__GMP_DECLSPEC unsigned long int mpz_gcd_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); -#define mpz_gcdext __gmpz_gcdext -__GMP_DECLSPEC void mpz_gcdext __GMP_PROTO ((mpz_ptr, mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr)); -#define mpz_get_d __gmpz_get_d -__GMP_DECLSPEC double mpz_get_d __GMP_PROTO ((mpz_srcptr)) __GMP_ATTRIBUTE_PURE; -#define mpz_get_d_2exp __gmpz_get_d_2exp -__GMP_DECLSPEC double mpz_get_d_2exp __GMP_PROTO ((signed long int *, mpz_srcptr)); -#define mpz_get_si __gmpz_get_si -__GMP_DECLSPEC /* signed */ long int mpz_get_si __GMP_PROTO ((mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#define mpz_get_str __gmpz_get_str -__GMP_DECLSPEC char *mpz_get_str __GMP_PROTO ((char *, int, mpz_srcptr)); -#define mpz_get_ui __gmpz_get_ui -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_get_ui) -__GMP_DECLSPEC unsigned long int mpz_get_ui __GMP_PROTO ((mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#endif -#define mpz_getlimbn __gmpz_getlimbn -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_getlimbn) -__GMP_DECLSPEC mp_limb_t mpz_getlimbn __GMP_PROTO ((mpz_srcptr, mp_size_t)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#endif -#define mpz_hamdist __gmpz_hamdist -__GMP_DECLSPEC mp_bitcnt_t mpz_hamdist __GMP_PROTO ((mpz_srcptr, mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#define mpz_import __gmpz_import -__GMP_DECLSPEC void mpz_import __GMP_PROTO ((mpz_ptr, size_t, int, size_t, int, size_t, __gmp_const void *)); -#define mpz_init __gmpz_init -__GMP_DECLSPEC void mpz_init __GMP_PROTO ((mpz_ptr)); -#define mpz_init2 __gmpz_init2 -__GMP_DECLSPEC void mpz_init2 __GMP_PROTO ((mpz_ptr, mp_bitcnt_t)); -#define mpz_inits __gmpz_inits -__GMP_DECLSPEC void mpz_inits __GMP_PROTO ((mpz_ptr, ...)); -#define mpz_init_set __gmpz_init_set -__GMP_DECLSPEC void mpz_init_set __GMP_PROTO ((mpz_ptr, mpz_srcptr)); -#define mpz_init_set_d __gmpz_init_set_d -__GMP_DECLSPEC void mpz_init_set_d __GMP_PROTO ((mpz_ptr, double)); -#define mpz_init_set_si __gmpz_init_set_si -__GMP_DECLSPEC void mpz_init_set_si __GMP_PROTO ((mpz_ptr, signed long int)); -#define mpz_init_set_str __gmpz_init_set_str -__GMP_DECLSPEC int mpz_init_set_str __GMP_PROTO ((mpz_ptr, __gmp_const char *, int)); -#define mpz_init_set_ui __gmpz_init_set_ui -__GMP_DECLSPEC void mpz_init_set_ui __GMP_PROTO ((mpz_ptr, unsigned long int)); -#define mpz_inp_raw __gmpz_inp_raw -#ifdef _GMP_H_HAVE_FILE -__GMP_DECLSPEC size_t mpz_inp_raw __GMP_PROTO ((mpz_ptr, FILE *)); -#endif -#define mpz_inp_str __gmpz_inp_str -#ifdef _GMP_H_HAVE_FILE -__GMP_DECLSPEC size_t mpz_inp_str __GMP_PROTO ((mpz_ptr, FILE *, int)); -#endif -#define mpz_invert __gmpz_invert -__GMP_DECLSPEC int mpz_invert __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); -#define mpz_ior __gmpz_ior -__GMP_DECLSPEC void mpz_ior __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); -#define mpz_jacobi __gmpz_jacobi -__GMP_DECLSPEC int mpz_jacobi __GMP_PROTO ((mpz_srcptr, mpz_srcptr)) __GMP_ATTRIBUTE_PURE; -#define mpz_kronecker mpz_jacobi /* alias */ -#define mpz_kronecker_si __gmpz_kronecker_si -__GMP_DECLSPEC int mpz_kronecker_si __GMP_PROTO ((mpz_srcptr, long)) __GMP_ATTRIBUTE_PURE; -#define mpz_kronecker_ui __gmpz_kronecker_ui -__GMP_DECLSPEC int mpz_kronecker_ui __GMP_PROTO ((mpz_srcptr, unsigned long)) __GMP_ATTRIBUTE_PURE; -#define mpz_si_kronecker __gmpz_si_kronecker -__GMP_DECLSPEC int mpz_si_kronecker __GMP_PROTO ((long, mpz_srcptr)) __GMP_ATTRIBUTE_PURE; -#define mpz_ui_kronecker __gmpz_ui_kronecker -__GMP_DECLSPEC int mpz_ui_kronecker __GMP_PROTO ((unsigned long, mpz_srcptr)) __GMP_ATTRIBUTE_PURE; -#define mpz_lcm __gmpz_lcm -__GMP_DECLSPEC void mpz_lcm __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); -#define mpz_lcm_ui __gmpz_lcm_ui -__GMP_DECLSPEC void mpz_lcm_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long)); -#define mpz_legendre mpz_jacobi /* alias */ -#define mpz_lucnum_ui __gmpz_lucnum_ui -__GMP_DECLSPEC void mpz_lucnum_ui __GMP_PROTO ((mpz_ptr, unsigned long int)); -#define mpz_lucnum2_ui __gmpz_lucnum2_ui -__GMP_DECLSPEC void mpz_lucnum2_ui __GMP_PROTO ((mpz_ptr, mpz_ptr, unsigned long int)); -#define mpz_millerrabin __gmpz_millerrabin -__GMP_DECLSPEC int mpz_millerrabin __GMP_PROTO ((mpz_srcptr, int)) __GMP_ATTRIBUTE_PURE; -#define mpz_mod __gmpz_mod -__GMP_DECLSPEC void mpz_mod __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); -#define mpz_mod_ui mpz_fdiv_r_ui /* same as fdiv_r because divisor unsigned */ -#define __GMP_MPZ_MUL_MIN_ALLOC(x,y,z) (__GMP_ABS(y->_mp_size)+__GMP_ABS(z->_mp_size)+1) -#define mpz_mul __gmpz_mul -__GMP_DECLSPEC void mpz_mul __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); -#define mpz_mul_2exp __gmpz_mul_2exp -__GMP_DECLSPEC void mpz_mul_2exp __GMP_PROTO ((mpz_ptr, mpz_srcptr, mp_bitcnt_t)); -#define __GMP_MPZ_MUL_SI_MIN_ALLOC(x,y,z) (__GMP_ABS(y->_mp_size)+(__GMP_BITS_PER_ULONG-1)/GMP_NUMB_BITS+1) -#define mpz_mul_si __gmpz_mul_si -__GMP_DECLSPEC void mpz_mul_si __GMP_PROTO ((mpz_ptr, mpz_srcptr, long int)); -#define __GMP_MPZ_MUL_UI_MIN_ALLOC(x,y,z) (__GMP_ABS(y->_mp_size)+(__GMP_BITS_PER_ULONG-1)/GMP_NUMB_BITS+1) -#define mpz_mul_ui __gmpz_mul_ui -__GMP_DECLSPEC void mpz_mul_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); -#define mpz_neg __gmpz_neg -#define __GMP_MPZ_NEG_MIN_ALLOC(x,y) (__GMP_ABS(y->_mp_size)) -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_neg) -__GMP_DECLSPEC void mpz_neg __GMP_PROTO ((mpz_ptr, mpz_srcptr)); -#endif -#define mpz_nextprime __gmpz_nextprime -__GMP_DECLSPEC void mpz_nextprime __GMP_PROTO ((mpz_ptr, mpz_srcptr)); -#define mpz_next_likely_prime __gmpz_next_likely_prime -__GMP_DECLSPEC void mpz_next_likely_prime __GMP_PROTO ((mpz_ptr, mpz_srcptr,gmp_randstate_t)); -#define mpz_out_raw __gmpz_out_raw -#ifdef _GMP_H_HAVE_FILE -__GMP_DECLSPEC size_t mpz_out_raw __GMP_PROTO ((FILE *, mpz_srcptr)); -#endif -#define mpz_out_str __gmpz_out_str -#ifdef _GMP_H_HAVE_FILE -__GMP_DECLSPEC size_t mpz_out_str __GMP_PROTO ((FILE *, int, mpz_srcptr)); -#endif -#define mpz_perfect_power_p __gmpz_perfect_power_p -__GMP_DECLSPEC int mpz_perfect_power_p __GMP_PROTO ((mpz_srcptr)) __GMP_ATTRIBUTE_PURE; -#define mpz_perfect_square_p __gmpz_perfect_square_p -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_perfect_square_p) -__GMP_DECLSPEC int mpz_perfect_square_p __GMP_PROTO ((mpz_srcptr)) __GMP_ATTRIBUTE_PURE; -#endif -#define mpz_popcount __gmpz_popcount -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_popcount) -__GMP_DECLSPEC mp_bitcnt_t mpz_popcount __GMP_PROTO ((mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#endif -#define mpz_pow_ui __gmpz_pow_ui -__GMP_DECLSPEC void mpz_pow_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); -#define mpz_powm __gmpz_powm -__GMP_DECLSPEC void mpz_powm __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr, mpz_srcptr)); -#define mpz_powm_ui __gmpz_powm_ui -__GMP_DECLSPEC void mpz_powm_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int, mpz_srcptr)); -#define mpz_probab_prime_p __gmpz_probab_prime_p -__GMP_DECLSPEC int mpz_probab_prime_p __GMP_PROTO ((mpz_srcptr, int)) __GMP_ATTRIBUTE_PURE; -#define mpz_probable_prime_p __gmpz_probable_prime_p -__GMP_DECLSPEC int mpz_probable_prime_p __GMP_PROTO ((mpz_srcptr,gmp_randstate_t, int,unsigned long)); -#define mpz_likely_prime_p __gmpz_likely_prime_p -__GMP_DECLSPEC int mpz_likely_prime_p __GMP_PROTO ((mpz_srcptr,gmp_randstate_t, unsigned long)); -#define mpz_realloc2 __gmpz_realloc2 -__GMP_DECLSPEC void mpz_realloc2 __GMP_PROTO ((mpz_ptr, mp_bitcnt_t)); -#define mpz_remove __gmpz_remove -__GMP_DECLSPEC unsigned long int mpz_remove __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); -#define mpz_root __gmpz_root -__GMP_DECLSPEC int mpz_root __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); -#define mpz_nthroot __gmpz_nthroot -__GMP_DECLSPEC void mpz_nthroot __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); -#define mpz_rootrem __gmpz_rootrem -__GMP_DECLSPEC void mpz_rootrem __GMP_PROTO ((mpz_ptr,mpz_ptr, mpz_srcptr, unsigned long int)); -#define mpz_rrandomb __gmpz_rrandomb -__GMP_DECLSPEC void mpz_rrandomb __GMP_PROTO ((mpz_ptr, gmp_randstate_t, mp_bitcnt_t)); -#define mpz_scan0 __gmpz_scan0 -__GMP_DECLSPEC mp_bitcnt_t mpz_scan0 __GMP_PROTO ((mpz_srcptr, mp_bitcnt_t)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#define mpz_scan1 __gmpz_scan1 -__GMP_DECLSPEC mp_bitcnt_t mpz_scan1 __GMP_PROTO ((mpz_srcptr, mp_bitcnt_t)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#define __GMP_MPZ_SET_MIN_ALLOC(x,y) __GMP_ABS(y->_mp_size) -#define mpz_set __gmpz_set -__GMP_DECLSPEC void mpz_set __GMP_PROTO ((mpz_ptr, mpz_srcptr)); -#define mpz_set_d __gmpz_set_d -__GMP_DECLSPEC void mpz_set_d __GMP_PROTO ((mpz_ptr, double)); -#define mpz_set_f __gmpz_set_f -__GMP_DECLSPEC void mpz_set_f __GMP_PROTO ((mpz_ptr, mpf_srcptr)); -#define mpz_set_q __gmpz_set_q -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_set_q) -__GMP_DECLSPEC void mpz_set_q __GMP_PROTO ((mpz_ptr, mpq_srcptr)); -#endif -#define __GMP_MPZ_SET_SI_MIN_ALLOC(x,y) (1+(__GMP_BITS_PER_ULONG-1)/GMP_NUMB_BITS) -#define mpz_set_si __gmpz_set_si -__GMP_DECLSPEC void mpz_set_si __GMP_PROTO ((mpz_ptr, signed long int)); -#define mpz_set_str __gmpz_set_str -__GMP_DECLSPEC int mpz_set_str __GMP_PROTO ((mpz_ptr, __gmp_const char *, int)); -#define __GMP_MPZ_SET_UI_MIN_ALLOC(x,y) (1+(__GMP_BITS_PER_ULONG-1)/GMP_NUMB_BITS) -#define mpz_set_ui __gmpz_set_ui -__GMP_DECLSPEC void mpz_set_ui __GMP_PROTO ((mpz_ptr, unsigned long int)); -#define mpz_setbit __gmpz_setbit -__GMP_DECLSPEC void mpz_setbit __GMP_PROTO ((mpz_ptr, mp_bitcnt_t)); -#define mpz_size __gmpz_size -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_size) -__GMP_DECLSPEC size_t mpz_size __GMP_PROTO ((mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#endif -#define mpz_sizeinbase __gmpz_sizeinbase -__GMP_DECLSPEC size_t mpz_sizeinbase __GMP_PROTO ((mpz_srcptr, int)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#define mpz_sqrt __gmpz_sqrt -__GMP_DECLSPEC void mpz_sqrt __GMP_PROTO ((mpz_ptr, mpz_srcptr)); -#define mpz_sqrtrem __gmpz_sqrtrem -__GMP_DECLSPEC void mpz_sqrtrem __GMP_PROTO ((mpz_ptr, mpz_ptr, mpz_srcptr)); -#define __GMP_MPZ_SUB_MIN_ALLOC(x,y,z) (__GMP_MAX(__GMP_ABS(y->_mp_size),__GMP_ABS(z->_mp_size))+1) -#define mpz_sub __gmpz_sub -__GMP_DECLSPEC void mpz_sub __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); -#define __GMP_MPZ_SUB_UI_MIN_ALLOC(x,y,z) (__GMP_MAX(__GMP_ABS(y->_mp_size),1+(__GMP_BITS_PER_ULONG-1)/GMP_NUMB_BITS)+1) -#define mpz_sub_ui __gmpz_sub_ui -__GMP_DECLSPEC void mpz_sub_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); -#define __GMP_MPZ_UI_SUB_MIN_ALLOC(x,y,z) (__GMP_MAX(__GMP_ABS(z->_mp_size),1+(__GMP_BITS_PER_ULONG-1)/GMP_NUMB_BITS)+1) -#define mpz_ui_sub __gmpz_ui_sub -__GMP_DECLSPEC void mpz_ui_sub __GMP_PROTO ((mpz_ptr, unsigned long int, mpz_srcptr)); -#define mpz_submul __gmpz_submul -__GMP_DECLSPEC void mpz_submul __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); -#define mpz_submul_ui __gmpz_submul_ui -__GMP_DECLSPEC void mpz_submul_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); -#define mpz_swap __gmpz_swap -__GMP_DECLSPEC void mpz_swap __GMP_PROTO ((mpz_ptr, mpz_ptr)) __GMP_NOTHROW; -#define mpz_tdiv_ui __gmpz_tdiv_ui -__GMP_DECLSPEC unsigned long int mpz_tdiv_ui __GMP_PROTO ((mpz_srcptr, unsigned long int)) __GMP_ATTRIBUTE_PURE; -#define mpz_tdiv_q __gmpz_tdiv_q -__GMP_DECLSPEC void mpz_tdiv_q __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); -#define mpz_tdiv_q_2exp __gmpz_tdiv_q_2exp -__GMP_DECLSPEC void mpz_tdiv_q_2exp __GMP_PROTO ((mpz_ptr, mpz_srcptr, mp_bitcnt_t)); -#define mpz_tdiv_q_ui __gmpz_tdiv_q_ui -__GMP_DECLSPEC unsigned long int mpz_tdiv_q_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); -#define mpz_tdiv_qr __gmpz_tdiv_qr -__GMP_DECLSPEC void mpz_tdiv_qr __GMP_PROTO ((mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr)); -#define mpz_tdiv_qr_ui __gmpz_tdiv_qr_ui -__GMP_DECLSPEC unsigned long int mpz_tdiv_qr_ui __GMP_PROTO ((mpz_ptr, mpz_ptr, mpz_srcptr, unsigned long int)); -#define mpz_tdiv_r __gmpz_tdiv_r -__GMP_DECLSPEC void mpz_tdiv_r __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); -#define mpz_tdiv_r_2exp __gmpz_tdiv_r_2exp -__GMP_DECLSPEC void mpz_tdiv_r_2exp __GMP_PROTO ((mpz_ptr, mpz_srcptr, mp_bitcnt_t)); -#define mpz_tdiv_r_ui __gmpz_tdiv_r_ui -__GMP_DECLSPEC unsigned long int mpz_tdiv_r_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); -#define mpz_tstbit __gmpz_tstbit -__GMP_DECLSPEC int mpz_tstbit __GMP_PROTO ((mpz_srcptr, mp_bitcnt_t)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#define mpz_ui_pow_ui __gmpz_ui_pow_ui -__GMP_DECLSPEC void mpz_ui_pow_ui __GMP_PROTO ((mpz_ptr, unsigned long int, unsigned long int)); -#define mpz_urandomb __gmpz_urandomb -__GMP_DECLSPEC void mpz_urandomb __GMP_PROTO ((mpz_ptr, gmp_randstate_t, mp_bitcnt_t)); -#define mpz_urandomm __gmpz_urandomm -__GMP_DECLSPEC void mpz_urandomm __GMP_PROTO ((mpz_ptr, gmp_randstate_t, mpz_srcptr)); -#define mpz_xor __gmpz_xor -#define mpz_eor __gmpz_xor -__GMP_DECLSPEC void mpz_xor __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); -/**************** Rational (i.e. Q) routines. ****************/ -#define mpq_abs __gmpq_abs -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpq_abs) -__GMP_DECLSPEC void mpq_abs __GMP_PROTO ((mpq_ptr, mpq_srcptr)); -#endif -#define mpq_add __gmpq_add -__GMP_DECLSPEC void mpq_add __GMP_PROTO ((mpq_ptr, mpq_srcptr, mpq_srcptr)); -#define mpq_canonicalize __gmpq_canonicalize -__GMP_DECLSPEC void mpq_canonicalize __GMP_PROTO ((mpq_ptr)); -#define mpq_clear __gmpq_clear -__GMP_DECLSPEC void mpq_clear __GMP_PROTO ((mpq_ptr)); -#define mpq_clears __gmpq_clears -__GMP_DECLSPEC void mpq_clears __GMP_PROTO ((mpq_ptr, ...)); -#define mpq_cmp __gmpq_cmp -__GMP_DECLSPEC int mpq_cmp __GMP_PROTO ((mpq_srcptr, mpq_srcptr)) __GMP_ATTRIBUTE_PURE; -#define _mpq_cmp_si __gmpq_cmp_si -__GMP_DECLSPEC int _mpq_cmp_si __GMP_PROTO ((mpq_srcptr, long, unsigned long)) __GMP_ATTRIBUTE_PURE; -#define _mpq_cmp_ui __gmpq_cmp_ui -__GMP_DECLSPEC int _mpq_cmp_ui __GMP_PROTO ((mpq_srcptr, unsigned long int, unsigned long int)) __GMP_ATTRIBUTE_PURE; -#define mpq_div __gmpq_div -__GMP_DECLSPEC void mpq_div __GMP_PROTO ((mpq_ptr, mpq_srcptr, mpq_srcptr)); -#define mpq_div_2exp __gmpq_div_2exp -__GMP_DECLSPEC void mpq_div_2exp __GMP_PROTO ((mpq_ptr, mpq_srcptr, mp_bitcnt_t)); -#define mpq_equal __gmpq_equal -__GMP_DECLSPEC int mpq_equal __GMP_PROTO ((mpq_srcptr, mpq_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#define mpq_get_num __gmpq_get_num -__GMP_DECLSPEC void mpq_get_num __GMP_PROTO ((mpz_ptr, mpq_srcptr)); -#define mpq_get_den __gmpq_get_den -__GMP_DECLSPEC void mpq_get_den __GMP_PROTO ((mpz_ptr, mpq_srcptr)); -#define mpq_get_d __gmpq_get_d -__GMP_DECLSPEC double mpq_get_d __GMP_PROTO ((mpq_srcptr)) __GMP_ATTRIBUTE_PURE; -#define mpq_get_str __gmpq_get_str -__GMP_DECLSPEC char *mpq_get_str __GMP_PROTO ((char *, int, mpq_srcptr)); -#define mpq_init __gmpq_init -__GMP_DECLSPEC void mpq_init __GMP_PROTO ((mpq_ptr)); -#define mpq_inits __gmpq_inits -__GMP_DECLSPEC void mpq_inits __GMP_PROTO ((mpq_ptr, ...)); -#define mpq_inp_str __gmpq_inp_str -#ifdef _GMP_H_HAVE_FILE -__GMP_DECLSPEC size_t mpq_inp_str __GMP_PROTO ((mpq_ptr, FILE *, int)); -#endif -#define mpq_inv __gmpq_inv -__GMP_DECLSPEC void mpq_inv __GMP_PROTO ((mpq_ptr, mpq_srcptr)); -#define mpq_mul __gmpq_mul -__GMP_DECLSPEC void mpq_mul __GMP_PROTO ((mpq_ptr, mpq_srcptr, mpq_srcptr)); -#define mpq_mul_2exp __gmpq_mul_2exp -__GMP_DECLSPEC void mpq_mul_2exp __GMP_PROTO ((mpq_ptr, mpq_srcptr, mp_bitcnt_t)); -#define mpq_neg __gmpq_neg -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpq_neg) -__GMP_DECLSPEC void mpq_neg __GMP_PROTO ((mpq_ptr, mpq_srcptr)); -#endif -#define mpq_out_str __gmpq_out_str -#ifdef _GMP_H_HAVE_FILE -__GMP_DECLSPEC size_t mpq_out_str __GMP_PROTO ((FILE *, int, mpq_srcptr)); -#endif -#define mpq_set __gmpq_set -__GMP_DECLSPEC void mpq_set __GMP_PROTO ((mpq_ptr, mpq_srcptr)); -#define mpq_set_d __gmpq_set_d -__GMP_DECLSPEC void mpq_set_d __GMP_PROTO ((mpq_ptr, double)); -#define mpq_set_den __gmpq_set_den -__GMP_DECLSPEC void mpq_set_den __GMP_PROTO ((mpq_ptr, mpz_srcptr)); -#define mpq_set_f __gmpq_set_f -__GMP_DECLSPEC void mpq_set_f __GMP_PROTO ((mpq_ptr, mpf_srcptr)); -#define mpq_set_num __gmpq_set_num -__GMP_DECLSPEC void mpq_set_num __GMP_PROTO ((mpq_ptr, mpz_srcptr)); -#define mpq_set_si __gmpq_set_si -__GMP_DECLSPEC void mpq_set_si __GMP_PROTO ((mpq_ptr, signed long int, unsigned long int)); -#define mpq_set_str __gmpq_set_str -__GMP_DECLSPEC int mpq_set_str __GMP_PROTO ((mpq_ptr, __gmp_const char *, int)); -#define mpq_set_ui __gmpq_set_ui -__GMP_DECLSPEC void mpq_set_ui __GMP_PROTO ((mpq_ptr, unsigned long int, unsigned long int)); -#define mpq_set_z __gmpq_set_z -__GMP_DECLSPEC void mpq_set_z __GMP_PROTO ((mpq_ptr, mpz_srcptr)); -#define mpq_sub __gmpq_sub -__GMP_DECLSPEC void mpq_sub __GMP_PROTO ((mpq_ptr, mpq_srcptr, mpq_srcptr)); -#define mpq_swap __gmpq_swap -__GMP_DECLSPEC void mpq_swap __GMP_PROTO ((mpq_ptr, mpq_ptr)) __GMP_NOTHROW; -/**************** Float (i.e. F) routines. ****************/ -#define mpf_abs __gmpf_abs -__GMP_DECLSPEC void mpf_abs __GMP_PROTO ((mpf_ptr, mpf_srcptr)); -#define mpf_add __gmpf_add -__GMP_DECLSPEC void mpf_add __GMP_PROTO ((mpf_ptr, mpf_srcptr, mpf_srcptr)); -#define mpf_add_ui __gmpf_add_ui -__GMP_DECLSPEC void mpf_add_ui __GMP_PROTO ((mpf_ptr, mpf_srcptr, unsigned long int)); -#define mpf_ceil __gmpf_ceil -__GMP_DECLSPEC void mpf_ceil __GMP_PROTO ((mpf_ptr, mpf_srcptr)); -#define mpf_clear __gmpf_clear -__GMP_DECLSPEC void mpf_clear __GMP_PROTO ((mpf_ptr)); -#define mpf_clears __gmpf_clears -__GMP_DECLSPEC void mpf_clears __GMP_PROTO ((mpf_ptr, ...)); -#define mpf_cmp __gmpf_cmp -__GMP_DECLSPEC int mpf_cmp __GMP_PROTO ((mpf_srcptr, mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#define mpf_cmp_d __gmpf_cmp_d -__GMP_DECLSPEC int mpf_cmp_d __GMP_PROTO ((mpf_srcptr, double)) __GMP_ATTRIBUTE_PURE; -#define mpf_cmp_si __gmpf_cmp_si -__GMP_DECLSPEC int mpf_cmp_si __GMP_PROTO ((mpf_srcptr, signed long int)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#define mpf_cmp_ui __gmpf_cmp_ui -__GMP_DECLSPEC int mpf_cmp_ui __GMP_PROTO ((mpf_srcptr, unsigned long int)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#define mpf_div __gmpf_div -__GMP_DECLSPEC void mpf_div __GMP_PROTO ((mpf_ptr, mpf_srcptr, mpf_srcptr)); -#define mpf_div_2exp __gmpf_div_2exp -__GMP_DECLSPEC void mpf_div_2exp __GMP_PROTO ((mpf_ptr, mpf_srcptr, mp_bitcnt_t)); -#define mpf_div_ui __gmpf_div_ui -__GMP_DECLSPEC void mpf_div_ui __GMP_PROTO ((mpf_ptr, mpf_srcptr, unsigned long int)); -#define mpf_dump __gmpf_dump -__GMP_DECLSPEC void mpf_dump __GMP_PROTO ((mpf_srcptr)); -#define mpf_eq __gmpf_eq -__GMP_DECLSPEC int mpf_eq __GMP_PROTO ((mpf_srcptr, mpf_srcptr, unsigned long int)) __GMP_ATTRIBUTE_PURE; -#define mpf_fits_sint_p __gmpf_fits_sint_p -__GMP_DECLSPEC int mpf_fits_sint_p __GMP_PROTO ((mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#define mpf_fits_slong_p __gmpf_fits_slong_p -__GMP_DECLSPEC int mpf_fits_slong_p __GMP_PROTO ((mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#define mpf_fits_sshort_p __gmpf_fits_sshort_p -__GMP_DECLSPEC int mpf_fits_sshort_p __GMP_PROTO ((mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#define mpf_fits_uint_p __gmpf_fits_uint_p -__GMP_DECLSPEC int mpf_fits_uint_p __GMP_PROTO ((mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#define mpf_fits_ulong_p __gmpf_fits_ulong_p -__GMP_DECLSPEC int mpf_fits_ulong_p __GMP_PROTO ((mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#define mpf_fits_ushort_p __gmpf_fits_ushort_p -__GMP_DECLSPEC int mpf_fits_ushort_p __GMP_PROTO ((mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#define mpf_floor __gmpf_floor -__GMP_DECLSPEC void mpf_floor __GMP_PROTO ((mpf_ptr, mpf_srcptr)); -#define mpf_get_d __gmpf_get_d -__GMP_DECLSPEC double mpf_get_d __GMP_PROTO ((mpf_srcptr)) __GMP_ATTRIBUTE_PURE; -#define mpf_get_d_2exp __gmpf_get_d_2exp -__GMP_DECLSPEC double mpf_get_d_2exp __GMP_PROTO ((signed long int *, mpf_srcptr)); -#define mpf_get_default_prec __gmpf_get_default_prec -__GMP_DECLSPEC mp_bitcnt_t mpf_get_default_prec __GMP_PROTO ((void)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#define mpf_get_prec __gmpf_get_prec -__GMP_DECLSPEC mp_bitcnt_t mpf_get_prec __GMP_PROTO ((mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#define mpf_get_si __gmpf_get_si -__GMP_DECLSPEC long mpf_get_si __GMP_PROTO ((mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#define mpf_get_str __gmpf_get_str -__GMP_DECLSPEC char *mpf_get_str __GMP_PROTO ((char *, mp_exp_t *, int, size_t, mpf_srcptr)); -#define mpf_get_ui __gmpf_get_ui -__GMP_DECLSPEC unsigned long mpf_get_ui __GMP_PROTO ((mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#define mpf_init __gmpf_init -__GMP_DECLSPEC void mpf_init __GMP_PROTO ((mpf_ptr)); -#define mpf_init2 __gmpf_init2 -__GMP_DECLSPEC void mpf_init2 __GMP_PROTO ((mpf_ptr, mp_bitcnt_t)); -#define mpf_inits __gmpf_inits -__GMP_DECLSPEC void mpf_inits __GMP_PROTO ((mpf_ptr, ...)); -#define mpf_init_set __gmpf_init_set -__GMP_DECLSPEC void mpf_init_set __GMP_PROTO ((mpf_ptr, mpf_srcptr)); -#define mpf_init_set_d __gmpf_init_set_d -__GMP_DECLSPEC void mpf_init_set_d __GMP_PROTO ((mpf_ptr, double)); -#define mpf_init_set_si __gmpf_init_set_si -__GMP_DECLSPEC void mpf_init_set_si __GMP_PROTO ((mpf_ptr, signed long int)); -#define mpf_init_set_str __gmpf_init_set_str -__GMP_DECLSPEC int mpf_init_set_str __GMP_PROTO ((mpf_ptr, __gmp_const char *, int)); -#define mpf_init_set_ui __gmpf_init_set_ui -__GMP_DECLSPEC void mpf_init_set_ui __GMP_PROTO ((mpf_ptr, unsigned long int)); -#define mpf_inp_str __gmpf_inp_str -#ifdef _GMP_H_HAVE_FILE -__GMP_DECLSPEC size_t mpf_inp_str __GMP_PROTO ((mpf_ptr, FILE *, int)); -#endif -#define mpf_integer_p __gmpf_integer_p -__GMP_DECLSPEC int mpf_integer_p __GMP_PROTO ((mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#define mpf_mul __gmpf_mul -__GMP_DECLSPEC void mpf_mul __GMP_PROTO ((mpf_ptr, mpf_srcptr, mpf_srcptr)); -#define mpf_mul_2exp __gmpf_mul_2exp -__GMP_DECLSPEC void mpf_mul_2exp __GMP_PROTO ((mpf_ptr, mpf_srcptr, mp_bitcnt_t)); -#define mpf_mul_ui __gmpf_mul_ui -__GMP_DECLSPEC void mpf_mul_ui __GMP_PROTO ((mpf_ptr, mpf_srcptr, unsigned long int)); -#define mpf_neg __gmpf_neg -__GMP_DECLSPEC void mpf_neg __GMP_PROTO ((mpf_ptr, mpf_srcptr)); -#define mpf_out_str __gmpf_out_str -#ifdef _GMP_H_HAVE_FILE -__GMP_DECLSPEC size_t mpf_out_str __GMP_PROTO ((FILE *, int, size_t, mpf_srcptr)); -#endif -#define mpf_pow_ui __gmpf_pow_ui -__GMP_DECLSPEC void mpf_pow_ui __GMP_PROTO ((mpf_ptr, mpf_srcptr, unsigned long int)); -#define mpf_random2 __gmpf_random2 -__GMP_DECLSPEC void mpf_random2 __GMP_PROTO ((mpf_ptr, mp_size_t, mp_exp_t)); -#define mpf_rrandomb __gmpf_rrandomb -__GMP_DECLSPEC void mpf_rrandomb __GMP_PROTO ((mpf_ptr, gmp_randstate_t, mp_size_t, mp_exp_t)); -#define mpf_reldiff __gmpf_reldiff -__GMP_DECLSPEC void mpf_reldiff __GMP_PROTO ((mpf_ptr, mpf_srcptr, mpf_srcptr)); -#define mpf_set __gmpf_set -__GMP_DECLSPEC void mpf_set __GMP_PROTO ((mpf_ptr, mpf_srcptr)); -#define mpf_set_d __gmpf_set_d -__GMP_DECLSPEC void mpf_set_d __GMP_PROTO ((mpf_ptr, double)); -#define mpf_set_default_prec __gmpf_set_default_prec -__GMP_DECLSPEC void mpf_set_default_prec __GMP_PROTO ((mp_bitcnt_t)) __GMP_NOTHROW; -#define mpf_set_prec __gmpf_set_prec -__GMP_DECLSPEC void mpf_set_prec __GMP_PROTO ((mpf_ptr, mp_bitcnt_t)); -#define mpf_set_prec_raw __gmpf_set_prec_raw -__GMP_DECLSPEC void mpf_set_prec_raw __GMP_PROTO ((mpf_ptr, mp_bitcnt_t)) __GMP_NOTHROW; -#define mpf_set_q __gmpf_set_q -__GMP_DECLSPEC void mpf_set_q __GMP_PROTO ((mpf_ptr, mpq_srcptr)); -#define mpf_set_si __gmpf_set_si -__GMP_DECLSPEC void mpf_set_si __GMP_PROTO ((mpf_ptr, signed long int)); -#define mpf_set_str __gmpf_set_str -__GMP_DECLSPEC int mpf_set_str __GMP_PROTO ((mpf_ptr, __gmp_const char *, int)); -#define mpf_set_ui __gmpf_set_ui -__GMP_DECLSPEC void mpf_set_ui __GMP_PROTO ((mpf_ptr, unsigned long int)); -#define mpf_set_z __gmpf_set_z -__GMP_DECLSPEC void mpf_set_z __GMP_PROTO ((mpf_ptr, mpz_srcptr)); -#define mpf_size __gmpf_size -__GMP_DECLSPEC size_t mpf_size __GMP_PROTO ((mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#define mpf_sqrt __gmpf_sqrt -__GMP_DECLSPEC void mpf_sqrt __GMP_PROTO ((mpf_ptr, mpf_srcptr)); -#define mpf_sqrt_ui __gmpf_sqrt_ui -__GMP_DECLSPEC void mpf_sqrt_ui __GMP_PROTO ((mpf_ptr, unsigned long int)); -#define mpf_sub __gmpf_sub -__GMP_DECLSPEC void mpf_sub __GMP_PROTO ((mpf_ptr, mpf_srcptr, mpf_srcptr)); -#define mpf_sub_ui __gmpf_sub_ui -__GMP_DECLSPEC void mpf_sub_ui __GMP_PROTO ((mpf_ptr, mpf_srcptr, unsigned long int)); -#define mpf_swap __gmpf_swap -__GMP_DECLSPEC void mpf_swap __GMP_PROTO ((mpf_ptr, mpf_ptr)) __GMP_NOTHROW; -#define mpf_trunc __gmpf_trunc -__GMP_DECLSPEC void mpf_trunc __GMP_PROTO ((mpf_ptr, mpf_srcptr)); -#define mpf_ui_div __gmpf_ui_div -__GMP_DECLSPEC void mpf_ui_div __GMP_PROTO ((mpf_ptr, unsigned long int, mpf_srcptr)); -#define mpf_ui_sub __gmpf_ui_sub -__GMP_DECLSPEC void mpf_ui_sub __GMP_PROTO ((mpf_ptr, unsigned long int, mpf_srcptr)); -#define mpf_urandomb __gmpf_urandomb -__GMP_DECLSPEC void mpf_urandomb __GMP_PROTO ((mpf_t, gmp_randstate_t, mp_bitcnt_t)); -/************ Low level positive-integer (i.e. N) routines. ************/ -/* This is ugly, but we need to make user calls reach the prefixed function. */ -#define mpn_add __MPN(add) -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpn_add) -__GMP_DECLSPEC mp_limb_t mpn_add __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_srcptr,mp_size_t)); -#endif -#define mpn_add_1 __MPN(add_1) -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpn_add_1) -__GMP_DECLSPEC mp_limb_t mpn_add_1 __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_limb_t)) __GMP_NOTHROW; -#endif -#define mpn_add_n __MPN(add_n) -__GMP_DECLSPEC mp_limb_t mpn_add_n __GMP_PROTO ((mp_ptr, mp_srcptr, mp_srcptr, mp_size_t)); -#define mpn_addmul_1 __MPN(addmul_1) -__GMP_DECLSPEC mp_limb_t mpn_addmul_1 __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_limb_t)); -#define mpn_bdivmod __MPN(bdivmod) -__GMP_DECLSPEC mp_limb_t mpn_bdivmod __GMP_PROTO ((mp_ptr, mp_ptr, mp_size_t, mp_srcptr, mp_size_t, unsigned long int)); -#define mpn_divrem __MPN(divrem) -__GMP_DECLSPEC mp_limb_t mpn_divrem __GMP_PROTO ((mp_ptr, mp_size_t, mp_ptr, mp_size_t, mp_srcptr, mp_size_t)); -#define mpn_mulmod_2expp1 __MPN(mulmod_2expp1) -__GMP_DECLSPEC int mpn_mulmod_2expp1 __GMP_PROTO ((mp_ptr, mp_srcptr, mp_srcptr,int,unsigned long, mp_ptr)); -#define mpn_mulmod_2expm1 __MPN(mulmod_2expm1) -__GMP_DECLSPEC void mpn_mulmod_2expm1 __GMP_PROTO ((mp_ptr, mp_ptr, mp_ptr,unsigned long, mp_ptr)); -#define mpn_cmp __MPN(cmp) -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpn_cmp) -__GMP_DECLSPEC int mpn_cmp __GMP_PROTO ((mp_srcptr, mp_srcptr, mp_size_t)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#endif -#define mpn_divexact_by3(dst,src,size) \ - mpn_divexact_by3c (dst, src, size, __GMP_CAST (mp_limb_t, 0)) -#define mpn_divexact_by3c __MPN(divexact_by3c) -__GMP_DECLSPEC mp_limb_t mpn_divexact_by3c __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_limb_t)); -#define mpn_divmod_1(qp,np,nsize,dlimb) \ - mpn_divrem_1 (qp, __GMP_CAST (mp_size_t, 0), np, nsize, dlimb) -#define mpn_divrem_1 __MPN(divrem_1) -__GMP_DECLSPEC mp_limb_t mpn_divrem_1 __GMP_PROTO ((mp_ptr, mp_size_t, mp_srcptr, mp_size_t, mp_limb_t)); -#define mpn_divrem_2 __MPN(divrem_2) -__GMP_DECLSPEC mp_limb_t mpn_divrem_2 __GMP_PROTO ((mp_ptr, mp_size_t, mp_ptr, mp_size_t, mp_srcptr)); -#define mpn_invert __MPN(invert) -__GMP_DECLSPEC void mpn_invert __GMP_PROTO ((mp_ptr xp, mp_srcptr ap, mp_size_t n)); -#define mpn_sb_divappr_q __MPN(sb_divappr_q) -__GMP_DECLSPEC mp_limb_t mpn_sb_divappr_q __GMP_PROTO ((mp_ptr qp, mp_ptr np, mp_size_t nn, - mp_srcptr dp, mp_size_t dn, mp_limb_t dip)); -#define mpn_dc_divappr_q_n __MPN(dc_divappr_q_n) -__GMP_DECLSPEC mp_limb_t mpn_dc_divappr_q_n __GMP_PROTO ((mp_ptr qp, mp_ptr np, mp_srcptr dp, mp_size_t n, - mp_limb_t dip, mp_ptr tp)); -#define mpn_dc_bdiv_q_n __MPN(dc_bdiv_q_n) -__GMP_DECLSPEC void mpn_dc_bdiv_q_n __GMP_PROTO ((mp_ptr qp, mp_ptr wp, mp_ptr np, mp_srcptr dp, mp_size_t n, - mp_limb_t dinv, mp_ptr scratch)); -#define mpn_inv_divappr_q_n __MPN(inv_divappr_q_n) -__GMP_DECLSPEC mp_limb_t mpn_inv_divappr_q_n __GMP_PROTO ((mp_ptr qp, mp_ptr np, mp_srcptr dp, mp_size_t n, - mp_srcptr dip)); -#define mpn_dc_divappr_q __MPN(dc_divappr_q) -__GMP_DECLSPEC mp_limb_t mpn_dc_divappr_q __GMP_PROTO ((mp_ptr qp, mp_ptr np, mp_size_t nn, mp_srcptr dp, mp_size_t n, - mp_limb_t dinv)); -#define mpn_dc_div_q __MPN(dc_div_q) -__GMP_DECLSPEC mp_limb_t mpn_dc_div_q __GMP_PROTO ((mp_ptr qp, mp_ptr np, mp_size_t nn, - mp_srcptr dp, mp_size_t dn, mp_limb_t dinv)); -#define mpn_inv_divappr_q __MPN(inv_divappr_q) -__GMP_DECLSPEC mp_limb_t mpn_inv_divappr_q __GMP_PROTO ((mp_ptr qp, mp_ptr np, mp_size_t nn, mp_srcptr dp, mp_size_t n, - mp_srcptr dinv)); -#define mpn_inv_div_q __MPN(inv_div_q) -__GMP_DECLSPEC mp_limb_t mpn_inv_div_q __GMP_PROTO ((mp_ptr qp, mp_ptr np, mp_size_t nn, - mp_srcptr dp, mp_size_t dn, mp_srcptr dinv)); -#define mpn_inv_div_qr __MPN(inv_div_qr) -__GMP_DECLSPEC mp_limb_t mpn_inv_div_qr __GMP_PROTO ((mp_ptr qp, mp_ptr np, mp_size_t nn, - mp_srcptr dp, mp_size_t dn, mp_srcptr dinv)); -#define mpn_inv_div_qr_n __MPN(inv_div_qr_n) -__GMP_DECLSPEC mp_limb_t mpn_inv_div_qr_n __GMP_PROTO ((mp_ptr qp, mp_ptr np, - mp_srcptr dp, mp_size_t dn, mp_srcptr dinv)); -#define mpn_dc_div_qr __MPN(dc_div_qr) -__GMP_DECLSPEC mp_limb_t mpn_dc_div_qr __GMP_PROTO ((mp_ptr qp, mp_ptr np, mp_size_t nn, - mp_srcptr dp, mp_size_t dn, mp_limb_t dinv)); -#define mpn_dc_div_qr_n __MPN(dc_div_qr_n) -__GMP_DECLSPEC mp_limb_t mpn_dc_div_qr_n __GMP_PROTO ((mp_ptr qp, mp_ptr np, mp_srcptr dp, mp_size_t n, - mp_limb_t dinv, mp_ptr tp)); -#define mpn_sb_div_q __MPN(sb_div_q) -__GMP_DECLSPEC mp_limb_t mpn_sb_div_q __GMP_PROTO ((mp_ptr qp, mp_ptr np, mp_size_t nn, - mp_srcptr dp, mp_size_t dn, mp_limb_t dinv)); -#define mpn_sb_bdiv_q __MPN(sb_bdiv_q) -__GMP_DECLSPEC void mpn_sb_bdiv_q __GMP_PROTO ((mp_ptr qp, mp_ptr wp, mp_ptr np, mp_size_t nn, - mp_srcptr dp, mp_size_t dn, mp_limb_t dinv)); -#define mpn_dc_bdiv_q __MPN(dc_bdiv_q) -__GMP_DECLSPEC void mpn_dc_bdiv_q __GMP_PROTO ((mp_ptr qp, mp_ptr np, mp_size_t nn, - mp_srcptr dp, mp_size_t dn, mp_limb_t dinv)); -#define mpn_dc_bdiv_qr __MPN(dc_bdiv_qr) -__GMP_DECLSPEC mp_limb_t mpn_dc_bdiv_qr __GMP_PROTO ((mp_ptr qp, mp_ptr np, mp_size_t nn, - mp_srcptr dp, mp_size_t dn, mp_limb_t dinv)); -#define mpn_dc_bdiv_qr_n __MPN(dc_bdiv_qr_n) -__GMP_DECLSPEC mp_limb_t mpn_dc_bdiv_qr_n __GMP_PROTO ((mp_ptr qp, mp_ptr np, - mp_srcptr dp, mp_size_t n, mp_limb_t dinv, mp_ptr tp)); -#define mpn_sb_div_qr __MPN(sb_div_qr) -__GMP_DECLSPEC mp_limb_t mpn_sb_div_qr __GMP_PROTO ((mp_ptr qp, mp_ptr np, mp_size_t nn, - mp_srcptr dp, mp_size_t dn, mp_limb_t dinv)); -#define mpn_sb_bdiv_qr __MPN(sb_bdiv_qr) -__GMP_DECLSPEC mp_limb_t mpn_sb_bdiv_qr __GMP_PROTO ((mp_ptr qp, mp_ptr np, mp_size_t nn, - mp_srcptr dp, mp_size_t dn, mp_limb_t dinv)); -#define mpn_tdiv_q __MPN(tdiv_q) -__GMP_DECLSPEC void mpn_tdiv_q __GMP_PROTO ((mp_ptr qp, mp_srcptr np, mp_size_t nn, - mp_srcptr dp, mp_size_t dn)); -#define mpn_divexact __MPN(divexact) -__GMP_DECLSPEC void mpn_divexact __GMP_PROTO ((mp_ptr qp, - mp_srcptr np, mp_size_t nn, mp_srcptr dp, mp_size_t dn)); -#define mpn_redc_1 __MPN(redc_1) -__GMP_DECLSPEC void mpn_redc_1 __GMP_PROTO ((mp_ptr, mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);) -#define mpn_gcd __MPN(gcd) -__GMP_DECLSPEC mp_size_t mpn_gcd __GMP_PROTO ((mp_ptr, mp_ptr, mp_size_t, mp_ptr, mp_size_t)); -#define mpn_gcd_1 __MPN(gcd_1) -__GMP_DECLSPEC mp_limb_t mpn_gcd_1 __GMP_PROTO ((mp_srcptr, mp_size_t, mp_limb_t)) __GMP_ATTRIBUTE_PURE; -#define mpn_gcdext __MPN(gcdext) -__GMP_DECLSPEC mp_size_t mpn_gcdext __GMP_PROTO ((mp_ptr, mp_ptr, mp_size_t *, mp_ptr, mp_size_t, mp_ptr, mp_size_t)); -#define mpn_get_str __MPN(get_str) -__GMP_DECLSPEC size_t mpn_get_str __GMP_PROTO ((unsigned char *, int, mp_ptr, mp_size_t)); -#define mpn_hamdist __MPN(hamdist) -__GMP_DECLSPEC mp_bitcnt_t mpn_hamdist __GMP_PROTO ((mp_srcptr, mp_srcptr, mp_size_t)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#define mpn_lshift __MPN(lshift) -__GMP_DECLSPEC mp_limb_t mpn_lshift __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, unsigned int)); -#define mpn_mod_1 __MPN(mod_1) -__GMP_DECLSPEC mp_limb_t mpn_mod_1 __GMP_PROTO ((mp_srcptr, mp_size_t, mp_limb_t)) __GMP_ATTRIBUTE_PURE; -#define mpn_mul __MPN(mul) -__GMP_DECLSPEC mp_limb_t mpn_mul __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t)); -#define mpn_mul_1 __MPN(mul_1) -__GMP_DECLSPEC mp_limb_t mpn_mul_1 __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_limb_t)); -#define mpn_mul_n __MPN(mul_n) -__GMP_DECLSPEC void mpn_mul_n __GMP_PROTO ((mp_ptr, mp_srcptr, mp_srcptr, mp_size_t)); -#define mpn_sqr __MPN(sqr) -__GMP_DECLSPEC void mpn_sqr __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t)); -#define mpn_neg_n __MPN(neg_n) -#define mpn_neg __MPN(neg_n) -__GMP_DECLSPEC mp_limb_t mpn_neg_n __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t)); -#define mpn_com_n __MPN(com_n) -#define mpn_com __MPN(com_n) -__GMP_DECLSPEC void mpn_com_n __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t)); -#define mpn_perfect_square_p __MPN(perfect_square_p) -__GMP_DECLSPEC int mpn_perfect_square_p __GMP_PROTO ((mp_srcptr, mp_size_t)) __GMP_ATTRIBUTE_PURE; -#define mpn_popcount __MPN(popcount) -__GMP_DECLSPEC mp_bitcnt_t mpn_popcount __GMP_PROTO ((mp_srcptr, mp_size_t)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#define mpn_pow_1 __MPN(pow_1) -__GMP_DECLSPEC mp_size_t mpn_pow_1 __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_limb_t, mp_ptr)); -/* undocumented now, but retained here for upward compatibility */ -#define mpn_preinv_mod_1 __MPN(preinv_mod_1) -__GMP_DECLSPEC mp_limb_t mpn_preinv_mod_1 __GMP_PROTO ((mp_srcptr, mp_size_t, mp_limb_t, mp_limb_t)) __GMP_ATTRIBUTE_PURE; -#define mpn_random __MPN(random) -__GMP_DECLSPEC void mpn_random __GMP_PROTO ((mp_ptr, mp_size_t)); -#define mpn_random2 __MPN(random2) -__GMP_DECLSPEC void mpn_random2 __GMP_PROTO ((mp_ptr, mp_size_t)); -#define mpn_urandomb __MPN(urandomb) -__GMP_DECLSPEC void mpn_urandomb __GMP_PROTO ((mp_ptr, gmp_randstate_t, unsigned long)); -#define mpn_urandomm __MPN(urandomm) -__GMP_DECLSPEC void mpn_urandomm __GMP_PROTO ((mp_ptr, gmp_randstate_t, mp_srcptr, mp_size_t)); -#define mpn_randomb __MPN(randomb) -__GMP_DECLSPEC void mpn_randomb __GMP_PROTO ((mp_ptr, gmp_randstate_t, mp_size_t)); -#define mpn_rrandom __MPN(rrandom) -__GMP_DECLSPEC void mpn_rrandom __GMP_PROTO ((mp_ptr, gmp_randstate_t, mp_size_t)); -#define mpn_rshift __MPN(rshift) -__GMP_DECLSPEC mp_limb_t mpn_rshift __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, unsigned int)); -#define mpn_scan0 __MPN(scan0) -__GMP_DECLSPEC mp_bitcnt_t mpn_scan0 __GMP_PROTO ((mp_srcptr, mp_bitcnt_t)) __GMP_ATTRIBUTE_PURE; -#define mpn_scan1 __MPN(scan1) -__GMP_DECLSPEC mp_bitcnt_t mpn_scan1 __GMP_PROTO ((mp_srcptr, mp_bitcnt_t)) __GMP_ATTRIBUTE_PURE; -#define mpn_set_str __MPN(set_str) -__GMP_DECLSPEC mp_size_t mpn_set_str __GMP_PROTO ((mp_ptr, __gmp_const unsigned char *, size_t, int)); -#define mpn_sqrtrem __MPN(sqrtrem) -__GMP_DECLSPEC mp_size_t mpn_sqrtrem __GMP_PROTO ((mp_ptr, mp_ptr, mp_srcptr, mp_size_t)); -#define mpn_sub __MPN(sub) -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpn_sub) -__GMP_DECLSPEC mp_limb_t mpn_sub __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_srcptr,mp_size_t)); -#endif -#define mpn_sub_1 __MPN(sub_1) -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpn_sub_1) -__GMP_DECLSPEC mp_limb_t mpn_sub_1 __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_limb_t)) __GMP_NOTHROW; -#endif -#define mpn_sub_n __MPN(sub_n) -__GMP_DECLSPEC mp_limb_t mpn_sub_n __GMP_PROTO ((mp_ptr, mp_srcptr, mp_srcptr, mp_size_t)); -#define mpn_submul_1 __MPN(submul_1) -__GMP_DECLSPEC mp_limb_t mpn_submul_1 __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_limb_t)); -#define mpn_tdiv_qr __MPN(tdiv_qr) -__GMP_DECLSPEC void mpn_tdiv_qr __GMP_PROTO ((mp_ptr, mp_ptr, mp_size_t, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t)); -#define mpn_and_n __MPN(and_n) -__GMP_DECLSPEC void mpn_and_n __GMP_PROTO ((mp_ptr, mp_srcptr, mp_srcptr, mp_size_t)); -#define mpn_andn_n __MPN(andn_n) -__GMP_DECLSPEC void mpn_andn_n __GMP_PROTO ((mp_ptr, mp_srcptr, mp_srcptr, mp_size_t)); -#define mpn_nand_n __MPN(nand_n) -__GMP_DECLSPEC void mpn_nand_n __GMP_PROTO ((mp_ptr, mp_srcptr, mp_srcptr, mp_size_t)); -#define mpn_ior_n __MPN(ior_n) -__GMP_DECLSPEC void mpn_ior_n __GMP_PROTO ((mp_ptr, mp_srcptr, mp_srcptr, mp_size_t)); -#define mpn_iorn_n __MPN(iorn_n) -__GMP_DECLSPEC void mpn_iorn_n __GMP_PROTO ((mp_ptr, mp_srcptr, mp_srcptr, mp_size_t)); -#define mpn_nior_n __MPN(nior_n) -__GMP_DECLSPEC void mpn_nior_n __GMP_PROTO ((mp_ptr, mp_srcptr, mp_srcptr, mp_size_t)); -#define mpn_xor_n __MPN(xor_n) -__GMP_DECLSPEC void mpn_xor_n __GMP_PROTO ((mp_ptr, mp_srcptr, mp_srcptr, mp_size_t)); -#define mpn_xnor_n __MPN(xnor_n) -__GMP_DECLSPEC void mpn_xnor_n __GMP_PROTO ((mp_ptr, mp_srcptr, mp_srcptr, mp_size_t)); -#define mpn_copyi __MPN(copyi) -__GMP_DECLSPEC void mpn_copyi __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t)); -#define mpn_copyd __MPN(copyd) -__GMP_DECLSPEC void mpn_copyd __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t)); -#define mpn_zero __MPN(zero) -__GMP_DECLSPEC void mpn_zero __GMP_PROTO ((mp_ptr, mp_size_t)); -/**************** mpz inlines ****************/ -/* The following are provided as inlines where possible, but always exist as - library functions too, for binary compatibility. - Within gmp itself this inlining generally isn't relied on, since it - doesn't get done for all compilers, whereas if something is worth - inlining then it's worth arranging always. - There are two styles of inlining here. When the same bit of code is - wanted for the inline as for the library version, then __GMP_FORCE_foo - arranges for that code to be emitted and the __GMP_EXTERN_INLINE - directive suppressed, eg. mpz_fits_uint_p. When a different bit of code - is wanted for the inline than for the library version, then - __GMP_FORCE_foo arranges the inline to be suppressed, eg. mpz_abs. */ -#if defined (__GMP_EXTERN_INLINE) && ! defined (__GMP_FORCE_mpz_abs) -__GMP_EXTERN_INLINE void -mpz_abs (mpz_ptr __gmp_w, mpz_srcptr __gmp_u) -{ - if (__gmp_w != __gmp_u) - mpz_set (__gmp_w, __gmp_u); - __gmp_w->_mp_size = __GMP_ABS (__gmp_w->_mp_size); -} -#endif -#if GMP_NAIL_BITS == 0 -#define __GMPZ_FITS_UTYPE_P(z,maxval) \ - mp_size_t __gmp_n = z->_mp_size; \ - mp_ptr __gmp_p = z->_mp_d; \ - return (__gmp_n == 0 || (__gmp_n == 1 && __gmp_p[0] <= maxval)); -#else -#define __GMPZ_FITS_UTYPE_P(z,maxval) \ - mp_size_t __gmp_n = z->_mp_size; \ - mp_ptr __gmp_p = z->_mp_d; \ - return (__gmp_n == 0 || (__gmp_n == 1 && __gmp_p[0] <= maxval) \ - || (__gmp_n == 2 && __gmp_p[1] <= ((mp_limb_t) maxval >> GMP_NUMB_BITS))); -#endif -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_fits_uint_p) -#if ! defined (__GMP_FORCE_mpz_fits_uint_p) -__GMP_EXTERN_INLINE -#endif -int -mpz_fits_uint_p (mpz_srcptr __gmp_z) __GMP_NOTHROW -{ - __GMPZ_FITS_UTYPE_P (__gmp_z, __GMP_UINT_MAX); -} -#endif -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_fits_ulong_p) -#if ! defined (__GMP_FORCE_mpz_fits_ulong_p) -__GMP_EXTERN_INLINE -#endif -int -mpz_fits_ulong_p (mpz_srcptr __gmp_z) __GMP_NOTHROW -{ - __GMPZ_FITS_UTYPE_P (__gmp_z, __GMP_ULONG_MAX); -} -#endif -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_fits_ushort_p) -#if ! defined (__GMP_FORCE_mpz_fits_ushort_p) -__GMP_EXTERN_INLINE -#endif -int -mpz_fits_ushort_p (mpz_srcptr __gmp_z) __GMP_NOTHROW -{ - __GMPZ_FITS_UTYPE_P (__gmp_z, __GMP_USHRT_MAX); -} -#endif -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_get_ui) -#if ! defined (__GMP_FORCE_mpz_get_ui) -__GMP_EXTERN_INLINE -#endif -unsigned long -mpz_get_ui (mpz_srcptr __gmp_z) __GMP_NOTHROW -{ - mp_ptr __gmp_p = __gmp_z->_mp_d; - mp_size_t __gmp_n = __gmp_z->_mp_size; - mp_limb_t __gmp_l = __gmp_p[0]; - /* This is a "#if" rather than a plain "if" so as to avoid gcc warnings - about "<< GMP_NUMB_BITS" exceeding the type size, and to avoid Borland - C++ 6.0 warnings about condition always true for something like - "__GMP_ULONG_MAX < GMP_NUMB_MASK". */ -#if GMP_NAIL_BITS == 0 || defined (_LONG_LONG_LIMB) - /* limb==long and no nails, or limb==longlong, one limb is enough */ - return (unsigned long)(__gmp_n != 0 ? __gmp_l : 0); -#else - /* limb==long and nails, need two limbs when available */ - __gmp_n = __GMP_ABS (__gmp_n); - if (__gmp_n <= 1) - return (__gmp_n != 0 ? __gmp_l : 0); - else - return __gmp_l + (__gmp_p[1] << GMP_NUMB_BITS); -#endif -} -#endif -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_getlimbn) -#if ! defined (__GMP_FORCE_mpz_getlimbn) -__GMP_EXTERN_INLINE -#endif -mp_limb_t -mpz_getlimbn (mpz_srcptr __gmp_z, mp_size_t __gmp_n) __GMP_NOTHROW -{ - mp_limb_t __gmp_result = 0; - if (__GMP_LIKELY (__gmp_n >= 0 && __gmp_n < __GMP_ABS (__gmp_z->_mp_size))) - __gmp_result = __gmp_z->_mp_d[__gmp_n]; - return __gmp_result; -} -#endif -#if defined (__GMP_EXTERN_INLINE) && ! defined (__GMP_FORCE_mpz_neg) -__GMP_EXTERN_INLINE void -mpz_neg (mpz_ptr __gmp_w, mpz_srcptr __gmp_u) -{ - if (__gmp_w != __gmp_u) - mpz_set (__gmp_w, __gmp_u); - __gmp_w->_mp_size = - __gmp_w->_mp_size; -} -#endif -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_perfect_square_p) -#if ! defined (__GMP_FORCE_mpz_perfect_square_p) -__GMP_EXTERN_INLINE -#endif -int -mpz_perfect_square_p (mpz_srcptr __gmp_a) -{ - mp_size_t __gmp_asize; - int __gmp_result; - __gmp_asize = __gmp_a->_mp_size; - __gmp_result = (__gmp_asize >= 0); /* zero is a square, negatives are not */ - if (__GMP_LIKELY (__gmp_asize > 0)) - __gmp_result = mpn_perfect_square_p (__gmp_a->_mp_d, __gmp_asize); - return __gmp_result; -} -#endif -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_popcount) -#if ! defined (__GMP_FORCE_mpz_popcount) -__GMP_EXTERN_INLINE -#endif -mp_bitcnt_t -mpz_popcount (mpz_srcptr __gmp_u) __GMP_NOTHROW -{ - mp_size_t __gmp_usize; - mp_bitcnt_t __gmp_result; - __gmp_usize = __gmp_u->_mp_size; - __gmp_result = (__gmp_usize < 0 ? __GMP_ULONG_MAX : 0); - if (__GMP_LIKELY (__gmp_usize > 0)) - __gmp_result = mpn_popcount (__gmp_u->_mp_d, __gmp_usize); - return __gmp_result; -} -#endif -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_set_q) -#if ! defined (__GMP_FORCE_mpz_set_q) -__GMP_EXTERN_INLINE -#endif -void -mpz_set_q (mpz_ptr __gmp_w, mpq_srcptr __gmp_u) -{ - mpz_tdiv_q (__gmp_w, mpq_numref (__gmp_u), mpq_denref (__gmp_u)); -} -#endif -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_size) -#if ! defined (__GMP_FORCE_mpz_size) -__GMP_EXTERN_INLINE -#endif -size_t -mpz_size (mpz_srcptr __gmp_z) __GMP_NOTHROW -{ - return __GMP_ABS (__gmp_z->_mp_size); -} -#endif -/**************** mpq inlines ****************/ -#if defined (__GMP_EXTERN_INLINE) && ! defined (__GMP_FORCE_mpq_abs) -__GMP_EXTERN_INLINE void -mpq_abs (mpq_ptr __gmp_w, mpq_srcptr __gmp_u) -{ - if (__gmp_w != __gmp_u) - mpq_set (__gmp_w, __gmp_u); - __gmp_w->_mp_num._mp_size = __GMP_ABS (__gmp_w->_mp_num._mp_size); -} -#endif -#if defined (__GMP_EXTERN_INLINE) && ! defined (__GMP_FORCE_mpq_neg) -__GMP_EXTERN_INLINE void -mpq_neg (mpq_ptr __gmp_w, mpq_srcptr __gmp_u) -{ - if (__gmp_w != __gmp_u) - mpq_set (__gmp_w, __gmp_u); - __gmp_w->_mp_num._mp_size = - __gmp_w->_mp_num._mp_size; -} -#endif -/**************** mpn inlines ****************/ -/* The comments with __GMPN_ADD_1 below apply here too. - The test for FUNCTION returning 0 should predict well. If it's assumed - {yp,ysize} will usually have a random number of bits then the high limb - won't be full and a carry out will occur a good deal less than 50% of the - time. - ysize==0 isn't a documented feature, but is used internally in a few - places. - Producing cout last stops it using up a register during the main part of - the calculation, though gcc (as of 3.0) on an "if (mpn_add (...))" - doesn't seem able to move the true and false legs of the conditional up - to the two places cout is generated. */ -#define __GMPN_AORS(cout, wp, xp, xsize, yp, ysize, FUNCTION, TEST) \ - do { \ - mp_size_t __gmp_i; \ - mp_limb_t __gmp_x; \ - \ - /* ASSERT ((ysize) >= 0); */ \ - /* ASSERT ((xsize) >= (ysize)); */ \ - /* ASSERT (MPN_SAME_OR_SEPARATE2_P (wp, xsize, xp, xsize)); */ \ - /* ASSERT (MPN_SAME_OR_SEPARATE2_P (wp, xsize, yp, ysize)); */ \ - \ - __gmp_i = (ysize); \ - if (__gmp_i != 0) \ - { \ - if (FUNCTION (wp, xp, yp, __gmp_i)) \ - { \ - do \ - { \ - if (__gmp_i >= (xsize)) \ - { \ - (cout) = 1; \ - goto __gmp_done; \ - } \ - __gmp_x = (xp)[__gmp_i]; \ - } \ - while (TEST); \ - } \ - } \ - if ((wp) != (xp)) \ - __GMPN_COPY_REST (wp, xp, xsize, __gmp_i); \ - (cout) = 0; \ - __gmp_done: \ - ; \ - } while (0) -#define __GMPN_ADD(cout, wp, xp, xsize, yp, ysize) \ - __GMPN_AORS (cout, wp, xp, xsize, yp, ysize, mpn_add_n, \ - (((wp)[__gmp_i++] = (__gmp_x + 1) & GMP_NUMB_MASK) == 0)) -#define __GMPN_SUB(cout, wp, xp, xsize, yp, ysize) \ - __GMPN_AORS (cout, wp, xp, xsize, yp, ysize, mpn_sub_n, \ - (((wp)[__gmp_i++] = (__gmp_x - 1) & GMP_NUMB_MASK), __gmp_x == 0)) -/* The use of __gmp_i indexing is designed to ensure a compile time src==dst - remains nice and clear to the compiler, so that __GMPN_COPY_REST can - disappear, and the load/add/store gets a chance to become a - read-modify-write on CISC CPUs. - Alternatives: - Using a pair of pointers instead of indexing would be possible, but gcc - isn't able to recognise compile-time src==dst in that case, even when the - pointers are incremented more or less together. Other compilers would - very likely have similar difficulty. - gcc could use "if (__builtin_constant_p(src==dst) && src==dst)" or - similar to detect a compile-time src==dst. This works nicely on gcc - 2.95.x, it's not good on gcc 3.0 where __builtin_constant_p(p==p) seems - to be always false, for a pointer p. But the current code form seems - good enough for src==dst anyway. - gcc on x86 as usual doesn't give particularly good flags handling for the - carry/borrow detection. It's tempting to want some multi instruction asm - blocks to help it, and this was tried, but in truth there's only a few - instructions to save and any gain is all too easily lost by register - juggling setting up for the asm. */ -#if GMP_NAIL_BITS == 0 -#define __GMPN_AORS_1(cout, dst, src, n, v, OP, CB) \ - do { \ - mp_size_t __gmp_i; \ - mp_limb_t __gmp_x, __gmp_r; \ - \ - /* ASSERT ((n) >= 1); */ \ - /* ASSERT (MPN_SAME_OR_SEPARATE_P (dst, src, n)); */ \ - \ - __gmp_x = (src)[0]; \ - __gmp_r = __gmp_x OP (v); \ - (dst)[0] = __gmp_r; \ - if (CB (__gmp_r, __gmp_x, (v))) \ - { \ - (cout) = 1; \ - for (__gmp_i = 1; __gmp_i < (n);) \ - { \ - __gmp_x = (src)[__gmp_i]; \ - __gmp_r = __gmp_x OP 1; \ - (dst)[__gmp_i] = __gmp_r; \ - ++__gmp_i; \ - if (!CB (__gmp_r, __gmp_x, 1)) \ - { \ - if ((src) != (dst)) \ - __GMPN_COPY_REST (dst, src, n, __gmp_i); \ - (cout) = 0; \ - break; \ - } \ - } \ - } \ - else \ - { \ - if ((src) != (dst)) \ - __GMPN_COPY_REST (dst, src, n, 1); \ - (cout) = 0; \ - } \ - } while (0) -#endif -#if GMP_NAIL_BITS >= 1 -#define __GMPN_AORS_1(cout, dst, src, n, v, OP, CB) \ - do { \ - mp_size_t __gmp_i; \ - mp_limb_t __gmp_x, __gmp_r; \ - \ - /* ASSERT ((n) >= 1); */ \ - /* ASSERT (MPN_SAME_OR_SEPARATE_P (dst, src, n)); */ \ - \ - __gmp_x = (src)[0]; \ - __gmp_r = __gmp_x OP (v); \ - (dst)[0] = __gmp_r & GMP_NUMB_MASK; \ - if (__gmp_r >> GMP_NUMB_BITS != 0) \ - { \ - (cout) = 1; \ - for (__gmp_i = 1; __gmp_i < (n);) \ - { \ - __gmp_x = (src)[__gmp_i]; \ - __gmp_r = __gmp_x OP 1; \ - (dst)[__gmp_i] = __gmp_r & GMP_NUMB_MASK; \ - ++__gmp_i; \ - if (__gmp_r >> GMP_NUMB_BITS == 0) \ - { \ - if ((src) != (dst)) \ - __GMPN_COPY_REST (dst, src, n, __gmp_i); \ - (cout) = 0; \ - break; \ - } \ - } \ - } \ - else \ - { \ - if ((src) != (dst)) \ - __GMPN_COPY_REST (dst, src, n, 1); \ - (cout) = 0; \ - } \ - } while (0) -#endif -#define __GMPN_ADDCB(r,x,y) ((r) < (y)) -#define __GMPN_SUBCB(r,x,y) ((x) < (y)) -#define __GMPN_ADD_1(cout, dst, src, n, v) \ - __GMPN_AORS_1(cout, dst, src, n, v, +, __GMPN_ADDCB) -#define __GMPN_SUB_1(cout, dst, src, n, v) \ - __GMPN_AORS_1(cout, dst, src, n, v, -, __GMPN_SUBCB) -/* Compare {xp,size} and {yp,size}, setting "result" to positive, zero or - negative. size==0 is allowed. On random data usually only one limb will - need to be examined to get a result, so it's worth having it inline. */ -#define __GMPN_CMP(result, xp, yp, size) \ - do { \ - mp_size_t __gmp_i; \ - mp_limb_t __gmp_x, __gmp_y; \ - \ - /* ASSERT ((size) >= 0); */ \ - \ - (result) = 0; \ - __gmp_i = (size); \ - while (--__gmp_i >= 0) \ - { \ - __gmp_x = (xp)[__gmp_i]; \ - __gmp_y = (yp)[__gmp_i]; \ - if (__gmp_x != __gmp_y) \ - { \ - /* Cannot use __gmp_x - __gmp_y, may overflow an "int" */ \ - (result) = (__gmp_x > __gmp_y ? 1 : -1); \ - break; \ - } \ - } \ - } while (0) -#if defined (__GMPN_COPY) && ! defined (__GMPN_COPY_REST) -#define __GMPN_COPY_REST(dst, src, size, start) \ - do { \ - /* ASSERT ((start) >= 0); */ \ - /* ASSERT ((start) <= (size)); */ \ - __GMPN_COPY ((dst)+(start), (src)+(start), (size)-(start)); \ - } while (0) -#endif -/* Copy {src,size} to {dst,size}, starting at "start". This is designed to - keep the indexing dst[j] and src[j] nice and simple for __GMPN_ADD_1, - __GMPN_ADD, etc. */ -#if ! defined (__GMPN_COPY_REST) -#define __GMPN_COPY_REST(dst, src, size, start) \ - do { \ - mp_size_t __gmp_j; \ - /* ASSERT ((size) >= 0); */ \ - /* ASSERT ((start) >= 0); */ \ - /* ASSERT ((start) <= (size)); */ \ - /* ASSERT (MPN_SAME_OR_SEPARATE_P (dst, src, size)); */ \ - for (__gmp_j = (start); __gmp_j < (size); __gmp_j++) \ - (dst)[__gmp_j] = (src)[__gmp_j]; \ - } while (0) -#endif -/* Enhancement: Use some of the smarter code from gmp-impl.h. Maybe use - mpn_copyi if there's a native version, and if we don't mind demanding - binary compatibility for it (on targets which use it). */ -#if ! defined (__GMPN_COPY) -#define __GMPN_COPY(dst, src, size) __GMPN_COPY_REST (dst, src, size, 0) -#endif -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpn_add) -#if ! defined (__GMP_FORCE_mpn_add) -__GMP_EXTERN_INLINE -#endif -mp_limb_t -mpn_add (mp_ptr __gmp_wp, mp_srcptr __gmp_xp, mp_size_t __gmp_xsize, mp_srcptr __gmp_yp, mp_size_t __gmp_ysize) -{ - mp_limb_t __gmp_c; - __GMPN_ADD (__gmp_c, __gmp_wp, __gmp_xp, __gmp_xsize, __gmp_yp, __gmp_ysize); - return __gmp_c; -} -#endif -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpn_add_1) -#if ! defined (__GMP_FORCE_mpn_add_1) -__GMP_EXTERN_INLINE -#endif -mp_limb_t -mpn_add_1 (mp_ptr __gmp_dst, mp_srcptr __gmp_src, mp_size_t __gmp_size, mp_limb_t __gmp_n) __GMP_NOTHROW -{ - mp_limb_t __gmp_c; - __GMPN_ADD_1 (__gmp_c, __gmp_dst, __gmp_src, __gmp_size, __gmp_n); - return __gmp_c; -} -#endif -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpn_cmp) -#if ! defined (__GMP_FORCE_mpn_cmp) -__GMP_EXTERN_INLINE -#endif -int -mpn_cmp (mp_srcptr __gmp_xp, mp_srcptr __gmp_yp, mp_size_t __gmp_size) __GMP_NOTHROW -{ - int __gmp_result; - __GMPN_CMP (__gmp_result, __gmp_xp, __gmp_yp, __gmp_size); - return __gmp_result; -} -#endif -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpn_sub) -#if ! defined (__GMP_FORCE_mpn_sub) -__GMP_EXTERN_INLINE -#endif -mp_limb_t -mpn_sub (mp_ptr __gmp_wp, mp_srcptr __gmp_xp, mp_size_t __gmp_xsize, mp_srcptr __gmp_yp, mp_size_t __gmp_ysize) -{ - mp_limb_t __gmp_c; - __GMPN_SUB (__gmp_c, __gmp_wp, __gmp_xp, __gmp_xsize, __gmp_yp, __gmp_ysize); - return __gmp_c; -} -#endif -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpn_sub_1) -#if ! defined (__GMP_FORCE_mpn_sub_1) -__GMP_EXTERN_INLINE -#endif -mp_limb_t -mpn_sub_1 (mp_ptr __gmp_dst, mp_srcptr __gmp_src, mp_size_t __gmp_size, mp_limb_t __gmp_n) __GMP_NOTHROW -{ - mp_limb_t __gmp_c; - __GMPN_SUB_1 (__gmp_c, __gmp_dst, __gmp_src, __gmp_size, __gmp_n); - return __gmp_c; -} -#endif -#if defined (__cplusplus) -} -#endif -/* Allow faster testing for negative, zero, and positive. */ -#define mpz_sgn(Z) ((Z)->_mp_size < 0 ? -1 : (Z)->_mp_size > 0) -#define mpf_sgn(F) ((F)->_mp_size < 0 ? -1 : (F)->_mp_size > 0) -#define mpq_sgn(Q) ((Q)->_mp_num._mp_size < 0 ? -1 : (Q)->_mp_num._mp_size > 0) -/* When using GCC, optimize certain common comparisons. */ -#if defined (__GNUC__) -#define mpz_cmp_ui(Z,UI) \ - (__builtin_constant_p (UI) && (UI) == 0 \ - ? mpz_sgn (Z) : _mpz_cmp_ui (Z,UI)) -#define mpz_cmp_si(Z,SI) \ - (__builtin_constant_p (SI) && (SI) == 0 ? mpz_sgn (Z) \ - : __builtin_constant_p (SI) && (SI) > 0 \ - ? _mpz_cmp_ui (Z, __GMP_CAST (unsigned long int, SI)) \ - : _mpz_cmp_si (Z,SI)) -#define mpq_cmp_ui(Q,NUI,DUI) \ - (__builtin_constant_p (NUI) && (NUI) == 0 \ - ? mpq_sgn (Q) : _mpq_cmp_ui (Q,NUI,DUI)) -#define mpq_cmp_si(q,n,d) \ - (__builtin_constant_p ((n) >= 0) && (n) >= 0 \ - ? mpq_cmp_ui (q, __GMP_CAST (unsigned long, n), d) \ - : _mpq_cmp_si (q, n, d)) -#else -#define mpz_cmp_ui(Z,UI) _mpz_cmp_ui (Z,UI) -#define mpz_cmp_si(Z,UI) _mpz_cmp_si (Z,UI) -#define mpq_cmp_ui(Q,NUI,DUI) _mpq_cmp_ui (Q,NUI,DUI) -#define mpq_cmp_si(q,n,d) _mpq_cmp_si(q,n,d) -#endif -/* Using "&" rather than "&&" means these can come out branch-free. Every - mpz_t has at least one limb allocated, so fetching the low limb is always - allowed. */ -#define mpz_odd_p(z) (((z)->_mp_size != 0) & __GMP_CAST (int, (z)->_mp_d[0])) -#define mpz_even_p(z) (! mpz_odd_p (z)) -/**************** C++ routines ****************/ -#ifdef __cplusplus -__GMP_DECLSPEC_XX std::ostream& operator<< (std::ostream &, mpz_srcptr); -__GMP_DECLSPEC_XX std::ostream& operator<< (std::ostream &, mpq_srcptr); -__GMP_DECLSPEC_XX std::ostream& operator<< (std::ostream &, mpf_srcptr); -__GMP_DECLSPEC_XX std::istream& operator>> (std::istream &, mpz_ptr); -__GMP_DECLSPEC_XX std::istream& operator>> (std::istream &, mpq_ptr); -__GMP_DECLSPEC_XX std::istream& operator>> (std::istream &, mpf_ptr); -#endif -/* Source-level compatibility with GMP 1. */ -#define mpz_mdiv mpz_fdiv_q -#define mpz_mdivmod mpz_fdiv_qr -#define mpz_mmod mpz_fdiv_r -#define mpz_mdiv_ui mpz_fdiv_q_ui -#define mpz_mdivmod_ui(q,r,n,d) \ - (((r) == 0) ? mpz_fdiv_q_ui (q,n,d) : mpz_fdiv_qr_ui (q,r,n,d)) -#define mpz_mmod_ui(r,n,d) \ - (((r) == 0) ? mpz_fdiv_ui (n,d) : mpz_fdiv_r_ui (r,n,d)) -#define gmp_randinit(x,y,z) gmp_randinit_lc_2exp_size(x,z) -typedef __mpz_struct MP_INT; /* gmp 1 source compatibility */ -typedef __mpq_struct MP_RAT; /* gmp 1 source compatibility */ -#define mpz_div mpz_fdiv_q -#define mpz_divmod mpz_fdiv_qr -#define mpz_div_ui mpz_fdiv_q_ui -#define mpz_divmod_ui mpz_fdiv_qr_ui -#define mpz_div_2exp mpz_fdiv_q_2exp -#define mpz_mod_2exp mpz_fdiv_r_2exp -enum -{ - GMP_ERROR_NONE = 0, - GMP_ERROR_UNSUPPORTED_ARGUMENT = 1, - GMP_ERROR_DIVISION_BY_ZERO = 2, - GMP_ERROR_SQRT_OF_NEGATIVE = 4, - GMP_ERROR_INVALID_ARGUMENT = 8 -}; -/* Major version number is the value of __GNU_MP__ too, above and in mp.h. */ -#define __GNU_MP_VERSION 5 -#define __GNU_MP_VERSION_MINOR 0 -#define __GNU_MP_VERSION_PATCHLEVEL 1 -#define GMP_VERSION "5.0.1" -#define __MPIR_VERSION 2 -#define __MPIR_VERSION_MINOR 2 -#define __MPIR_VERSION_PATCHLEVEL 1 -#if defined( _MSC_VER ) -#define _MSC_MPIR_VERSION "2.2.1" -#endif -/* These are for programs like MPFR to use the same CC and CFLAGS as MPIR */ -#if ! defined (__GMP_WITHIN_CONFIGURE) -#endif -#define __GMP_H__ -#endif /* __GMP_H__ */ diff --git a/src/external/inc/win32-msvc/mpir-2.2.1_x64/gmpxx.h b/src/external/inc/win32-msvc/mpir-2.2.1_x64/gmpxx.h deleted file mode 100644 index 3ad1dcf6f..000000000 --- a/src/external/inc/win32-msvc/mpir-2.2.1_x64/gmpxx.h +++ /dev/null @@ -1,3403 +0,0 @@ -/* mpirxx.h -- C++ class wrapper for GMP types. -*- C++ -*- - -Copyright 2001, 2002, 2003, 2006, 2008 Free Software Foundation, Inc. - -Copyright 2009 William Hart - -This file is part of the GNU MP Library. - -The GNU MP Library is free software; you can redistribute it and/or modify -it under the terms of the GNU Lesser General Public License as published by -the Free Software Foundation; either version 3 of the License, or (at your -option) any later version. - -The GNU MP Library is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public -License for more details. - -You should have received a copy of the GNU Lesser General Public License -along with the GNU MP Library. If not, see http://www.gnu.org/licenses/. */ - -/* the C++ compiler must implement the following features: - - member templates - - partial specialization of templates - - namespace support - for g++, this means version 2.91 or higher - for other compilers, I don't know */ -#ifdef __GNUC__ -#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 91) -#error mpirxx.h requires g++ version 2.91 (egcs 1.1.2) or higher -#endif -#endif - -#ifndef __GMP_PLUSPLUS__ -#define __GMP_PLUSPLUS__ - -#include - -#include /* for strlen */ -#include -#include -#include -#include - - -/**************** Function objects ****************/ -/* Any evaluation of a __gmp_expr ends up calling one of these functions - all intermediate functions being inline, the evaluation should optimize - to a direct call to the relevant function, thus yielding no overhead - over the C interface. */ - -struct __gmp_unary_plus -{ - static void eval(mpz_ptr z, mpz_srcptr w) { mpz_set(z, w); } - static void eval(mpq_ptr q, mpq_srcptr r) { mpq_set(q, r); } - static void eval(mpf_ptr f, mpf_srcptr g) { mpf_set(f, g); } -}; - -struct __gmp_unary_minus -{ - static void eval(mpz_ptr z, mpz_srcptr w) { mpz_neg(z, w); } - static void eval(mpq_ptr q, mpq_srcptr r) { mpq_neg(q, r); } - static void eval(mpf_ptr f, mpf_srcptr g) { mpf_neg(f, g); } -}; - -struct __gmp_unary_com -{ - static void eval(mpz_ptr z, mpz_srcptr w) { mpz_com(z, w); } -}; - -struct __gmp_binary_plus -{ - static void eval(mpz_ptr z, mpz_srcptr w, mpz_srcptr v) - { mpz_add(z, w, v); } - - static void eval(mpz_ptr z, mpz_srcptr w, unsigned long int l) - { mpz_add_ui(z, w, l); } - static void eval(mpz_ptr z, unsigned long int l, mpz_srcptr w) - { mpz_add_ui(z, w, l); } - static void eval(mpz_ptr z, mpz_srcptr w, signed long int l) - { - if (l >= 0) - mpz_add_ui(z, w, l); - else - mpz_sub_ui(z, w, -l); - } - static void eval(mpz_ptr z, signed long int l, mpz_srcptr w) - { - if (l >= 0) - mpz_add_ui(z, w, l); - else - mpz_sub_ui(z, w, -l); - } - static void eval(mpz_ptr z, mpz_srcptr w, double d) - { - mpz_t temp; - mpz_init_set_d(temp, d); - mpz_add(z, w, temp); - mpz_clear(temp); - } - static void eval(mpz_ptr z, double d, mpz_srcptr w) - { - mpz_t temp; - mpz_init_set_d(temp, d); - mpz_add(z, temp, w); - mpz_clear(temp); - } - - static void eval(mpq_ptr q, mpq_srcptr r, mpq_srcptr s) - { mpq_add(q, r, s); } - - static void eval(mpq_ptr q, mpq_srcptr r, unsigned long int l) - { mpq_set(q, r); mpz_addmul_ui(mpq_numref(q), mpq_denref(q), l); } - static void eval(mpq_ptr q, unsigned long int l, mpq_srcptr r) - { mpq_set(q, r); mpz_addmul_ui(mpq_numref(q), mpq_denref(q), l); } - static void eval(mpq_ptr q, mpq_srcptr r, signed long int l) - { - mpq_set(q, r); - if (l >= 0) - mpz_addmul_ui(mpq_numref(q), mpq_denref(q), l); - else - mpz_submul_ui(mpq_numref(q), mpq_denref(q), -l); - } - static void eval(mpq_ptr q, signed long int l, mpq_srcptr r) - { - mpq_set(q, r); - if (l >= 0) - mpz_addmul_ui(mpq_numref(q), mpq_denref(q), l); - else - mpz_submul_ui(mpq_numref(q), mpq_denref(q), -l); - } - static void eval(mpq_ptr q, mpq_srcptr r, double d) - { - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - mpq_add(q, r, temp); - mpq_clear(temp); - } - static void eval(mpq_ptr q, double d, mpq_srcptr r) - { - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - mpq_add(q, temp, r); - mpq_clear(temp); - } - - static void eval(mpq_ptr q, mpq_srcptr r, mpz_srcptr z) - { mpq_set(q, r); mpz_addmul(mpq_numref(q), mpq_denref(q), z); } - static void eval(mpq_ptr q, mpz_srcptr z, mpq_srcptr r) - { mpq_set(q, r); mpz_addmul(mpq_numref(q), mpq_denref(q), z); } - - static void eval(mpf_ptr f, mpf_srcptr g, mpf_srcptr h) - { mpf_add(f, g, h); } - - static void eval(mpf_ptr f, mpf_srcptr g, unsigned long int l) - { mpf_add_ui(f, g, l); } - static void eval(mpf_ptr f, unsigned long int l, mpf_srcptr g) - { mpf_add_ui(f, g, l); } - static void eval(mpf_ptr f, mpf_srcptr g, signed long int l) - { - if (l >= 0) - mpf_add_ui(f, g, l); - else - mpf_sub_ui(f, g, -l); - } - static void eval(mpf_ptr f, signed long int l, mpf_srcptr g) - { - if (l >= 0) - mpf_add_ui(f, g, l); - else - mpf_sub_ui(f, g, -l); - } - static void eval(mpf_ptr f, mpf_srcptr g, double d) - { - mpf_t temp; - mpf_init2(temp, 8*sizeof(double)); - mpf_set_d(temp, d); - mpf_add(f, g, temp); - mpf_clear(temp); - } - static void eval(mpf_ptr f, double d, mpf_srcptr g) - { - mpf_t temp; - mpf_init2(temp, 8*sizeof(double)); - mpf_set_d(temp, d); - mpf_add(f, temp, g); - mpf_clear(temp); - } -}; - -struct __gmp_binary_minus -{ - static void eval(mpz_ptr z, mpz_srcptr w, mpz_srcptr v) - { mpz_sub(z, w, v); } - - static void eval(mpz_ptr z, mpz_srcptr w, unsigned long int l) - { mpz_sub_ui(z, w, l); } - static void eval(mpz_ptr z, unsigned long int l, mpz_srcptr w) - { mpz_ui_sub(z, l, w); } - static void eval(mpz_ptr z, mpz_srcptr w, signed long int l) - { - if (l >= 0) - mpz_sub_ui(z, w, l); - else - mpz_add_ui(z, w, -l); - } - static void eval(mpz_ptr z, signed long int l, mpz_srcptr w) - { - if (l >= 0) - mpz_ui_sub(z, l, w); - else - { - mpz_add_ui(z, w, -l); - mpz_neg(z, z); - } - } - static void eval(mpz_ptr z, mpz_srcptr w, double d) - { - mpz_t temp; - mpz_init_set_d(temp, d); - mpz_sub(z, w, temp); - mpz_clear(temp); - } - static void eval(mpz_ptr z, double d, mpz_srcptr w) - { - mpz_t temp; - mpz_init_set_d(temp, d); - mpz_sub(z, temp, w); - mpz_clear(temp); - } - - static void eval(mpq_ptr q, mpq_srcptr r, mpq_srcptr s) - { mpq_sub(q, r, s); } - - static void eval(mpq_ptr q, mpq_srcptr r, unsigned long int l) - { mpq_set(q, r); mpz_submul_ui(mpq_numref(q), mpq_denref(q), l); } - static void eval(mpq_ptr q, unsigned long int l, mpq_srcptr r) - { mpq_neg(q, r); mpz_addmul_ui(mpq_numref(q), mpq_denref(q), l); } - static void eval(mpq_ptr q, mpq_srcptr r, signed long int l) - { - mpq_set(q, r); - if (l >= 0) - mpz_submul_ui(mpq_numref(q), mpq_denref(q), l); - else - mpz_addmul_ui(mpq_numref(q), mpq_denref(q), -l); - } - static void eval(mpq_ptr q, signed long int l, mpq_srcptr r) - { - mpq_neg(q, r); - if (l >= 0) - mpz_addmul_ui(mpq_numref(q), mpq_denref(q), l); - else - mpz_submul_ui(mpq_numref(q), mpq_denref(q), -l); - } - static void eval(mpq_ptr q, mpq_srcptr r, double d) - { - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - mpq_sub(q, r, temp); - mpq_clear(temp); - } - static void eval(mpq_ptr q, double d, mpq_srcptr r) - { - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - mpq_sub(q, temp, r); - mpq_clear(temp); - } - - static void eval(mpq_ptr q, mpq_srcptr r, mpz_srcptr z) - { mpq_set(q, r); mpz_submul(mpq_numref(q), mpq_denref(q), z); } - static void eval(mpq_ptr q, mpz_srcptr z, mpq_srcptr r) - { mpq_neg(q, r); mpz_addmul(mpq_numref(q), mpq_denref(q), z); } - - static void eval(mpf_ptr f, mpf_srcptr g, mpf_srcptr h) - { mpf_sub(f, g, h); } - - static void eval(mpf_ptr f, mpf_srcptr g, unsigned long int l) - { mpf_sub_ui(f, g, l); } - static void eval(mpf_ptr f, unsigned long int l, mpf_srcptr g) - { mpf_ui_sub(f, l, g); } - static void eval(mpf_ptr f, mpf_srcptr g, signed long int l) - { - if (l >= 0) - mpf_sub_ui(f, g, l); - else - mpf_add_ui(f, g, -l); - } - static void eval(mpf_ptr f, signed long int l, mpf_srcptr g) - { - if (l >= 0) - mpf_sub_ui(f, g, l); - else - mpf_add_ui(f, g, -l); - mpf_neg(f, f); - } - static void eval(mpf_ptr f, mpf_srcptr g, double d) - { - mpf_t temp; - mpf_init2(temp, 8*sizeof(double)); - mpf_set_d(temp, d); - mpf_sub(f, g, temp); - mpf_clear(temp); - } - static void eval(mpf_ptr f, double d, mpf_srcptr g) - { - mpf_t temp; - mpf_init2(temp, 8*sizeof(double)); - mpf_set_d(temp, d); - mpf_sub(f, temp, g); - mpf_clear(temp); - } -}; - -struct __gmp_binary_multiplies -{ - static void eval(mpz_ptr z, mpz_srcptr w, mpz_srcptr v) - { mpz_mul(z, w, v); } - - static void eval(mpz_ptr z, mpz_srcptr w, unsigned long int l) - { mpz_mul_ui(z, w, l); } - static void eval(mpz_ptr z, unsigned long int l, mpz_srcptr w) - { mpz_mul_ui(z, w, l); } - static void eval(mpz_ptr z, mpz_srcptr w, signed long int l) - { mpz_mul_si (z, w, l); } - static void eval(mpz_ptr z, signed long int l, mpz_srcptr w) - { mpz_mul_si (z, w, l); } - static void eval(mpz_ptr z, mpz_srcptr w, double d) - { - mpz_t temp; - mpz_init_set_d(temp, d); - mpz_mul(z, w, temp); - mpz_clear(temp); - } - static void eval(mpz_ptr z, double d, mpz_srcptr w) - { - mpz_t temp; - mpz_init_set_d(temp, d); - mpz_mul(z, temp, w); - mpz_clear(temp); - } - - static void eval(mpq_ptr q, mpq_srcptr r, mpq_srcptr s) - { mpq_mul(q, r, s); } - - static void eval(mpq_ptr q, mpq_srcptr r, unsigned long int l) - { - mpq_t temp; - mpq_init(temp); - mpq_set_ui(temp, l, 1); - mpq_mul(q, r, temp); - mpq_clear(temp); - } - static void eval(mpq_ptr q, unsigned long int l, mpq_srcptr r) - { - mpq_t temp; - mpq_init(temp); - mpq_set_ui(temp, l, 1); - mpq_mul(q, temp, r); - mpq_clear(temp); - } - static void eval(mpq_ptr q, mpq_srcptr r, signed long int l) - { - mpq_t temp; - mpq_init(temp); - mpq_set_si(temp, l, 1); - mpq_mul(q, r, temp); - mpq_clear(temp); - } - static void eval(mpq_ptr q, signed long int l, mpq_srcptr r) - { - mpq_t temp; - mpq_init(temp); - mpq_set_si(temp, l, 1); - mpq_mul(q, temp, r); - mpq_clear(temp); - } - static void eval(mpq_ptr q, mpq_srcptr r, double d) - { - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - mpq_mul(q, r, temp); - mpq_clear(temp); - } - static void eval(mpq_ptr q, double d, mpq_srcptr r) - { - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - mpq_mul(q, temp, r); - mpq_clear(temp); - } - - static void eval(mpf_ptr f, mpf_srcptr g, mpf_srcptr h) - { mpf_mul(f, g, h); } - - static void eval(mpf_ptr f, mpf_srcptr g, unsigned long int l) - { mpf_mul_ui(f, g, l); } - static void eval(mpf_ptr f, unsigned long int l, mpf_srcptr g) - { mpf_mul_ui(f, g, l); } - static void eval(mpf_ptr f, mpf_srcptr g, signed long int l) - { - if (l >= 0) - mpf_mul_ui(f, g, l); - else - { - mpf_mul_ui(f, g, -l); - mpf_neg(f, f); - } - } - static void eval(mpf_ptr f, signed long int l, mpf_srcptr g) - { - if (l >= 0) - mpf_mul_ui(f, g, l); - else - { - mpf_mul_ui(f, g, -l); - mpf_neg(f, f); - } - } - static void eval(mpf_ptr f, mpf_srcptr g, double d) - { - mpf_t temp; - mpf_init2(temp, 8*sizeof(double)); - mpf_set_d(temp, d); - mpf_mul(f, g, temp); - mpf_clear(temp); - } - static void eval(mpf_ptr f, double d, mpf_srcptr g) - { - mpf_t temp; - mpf_init2(temp, 8*sizeof(double)); - mpf_set_d(temp, d); - mpf_mul(f, temp, g); - mpf_clear(temp); - } -}; - -struct __gmp_binary_divides -{ - static void eval(mpz_ptr z, mpz_srcptr w, mpz_srcptr v) - { mpz_tdiv_q(z, w, v); } - - static void eval(mpz_ptr z, mpz_srcptr w, unsigned long int l) - { mpz_tdiv_q_ui(z, w, l); } - static void eval(mpz_ptr z, unsigned long int l, mpz_srcptr w) - { - if (mpz_sgn(w) >= 0) - { - if (mpz_fits_ulong_p(w)) - mpz_set_ui(z, l / mpz_get_ui(w)); - else - mpz_set_ui(z, 0); - } - else - { - mpz_neg(z, w); - if (mpz_fits_ulong_p(z)) - { - mpz_set_ui(z, l / mpz_get_ui(z)); - mpz_neg(z, z); - } - else - mpz_set_ui(z, 0); - } - } - static void eval(mpz_ptr z, mpz_srcptr w, signed long int l) - { - if (l >= 0) - mpz_tdiv_q_ui(z, w, l); - else - { - mpz_tdiv_q_ui(z, w, -l); - mpz_neg(z, z); - } - } - static void eval(mpz_ptr z, signed long int l, mpz_srcptr w) - { - if (mpz_fits_slong_p(w)) - mpz_set_si(z, l / mpz_get_si(w)); - else - { - /* if w is bigger than a long then the quotient must be zero, unless - l==LONG_MIN and w==-LONG_MIN in which case the quotient is -1 */ - mpz_set_si (z, (mpz_cmpabs_ui (w, (l >= 0 ? l : -l)) == 0 ? -1 : 0)); - } - } - static void eval(mpz_ptr z, mpz_srcptr w, double d) - { - mpz_t temp; - mpz_init_set_d(temp, d); - mpz_tdiv_q(z, w, temp); - mpz_clear(temp); - } - static void eval(mpz_ptr z, double d, mpz_srcptr w) - { - mpz_t temp; - mpz_init_set_d(temp, d); - mpz_tdiv_q(z, temp, w); - mpz_clear(temp); - } - - static void eval(mpq_ptr q, mpq_srcptr r, mpq_srcptr s) - { mpq_div(q, r, s); } - - static void eval(mpq_ptr q, mpq_srcptr r, unsigned long int l) - { - mpq_t temp; - mpq_init(temp); - mpq_set_ui(temp, l, 1); - mpq_div(q, r, temp); - mpq_clear(temp); - } - static void eval(mpq_ptr q, unsigned long int l, mpq_srcptr r) - { - mpq_t temp; - mpq_init(temp); - mpq_set_ui(temp, l, 1); - mpq_div(q, temp, r); - mpq_clear(temp); - } - static void eval(mpq_ptr q, mpq_srcptr r, signed long int l) - { - mpq_t temp; - mpq_init(temp); - mpq_set_si(temp, l, 1); - mpq_div(q, r, temp); - mpq_clear(temp); - } - static void eval(mpq_ptr q, signed long int l, mpq_srcptr r) - { - mpq_t temp; - mpq_init(temp); - mpq_set_si(temp, l, 1); - mpq_div(q, temp, r); - mpq_clear(temp); - } - static void eval(mpq_ptr q, mpq_srcptr r, double d) - { - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - mpq_div(q, r, temp); - mpq_clear(temp); - } - static void eval(mpq_ptr q, double d, mpq_srcptr r) - { - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - mpq_div(q, temp, r); - mpq_clear(temp); - } - - static void eval(mpf_ptr f, mpf_srcptr g, mpf_srcptr h) - { mpf_div(f, g, h); } - - static void eval(mpf_ptr f, mpf_srcptr g, unsigned long int l) - { mpf_div_ui(f, g, l); } - static void eval(mpf_ptr f, unsigned long int l, mpf_srcptr g) - { mpf_ui_div(f, l, g); } - static void eval(mpf_ptr f, mpf_srcptr g, signed long int l) - { - if (l >= 0) - mpf_div_ui(f, g, l); - else - { - mpf_div_ui(f, g, -l); - mpf_neg(f, f); - } - } - static void eval(mpf_ptr f, signed long int l, mpf_srcptr g) - { - if (l >= 0) - mpf_ui_div(f, l, g); - else - { - mpf_ui_div(f, -l, g); - mpf_neg(f, f); - } - } - static void eval(mpf_ptr f, mpf_srcptr g, double d) - { - mpf_t temp; - mpf_init2(temp, 8*sizeof(double)); - mpf_set_d(temp, d); - mpf_div(f, g, temp); - mpf_clear(temp); - } - static void eval(mpf_ptr f, double d, mpf_srcptr g) - { - mpf_t temp; - mpf_init2(temp, 8*sizeof(double)); - mpf_set_d(temp, d); - mpf_div(f, temp, g); - mpf_clear(temp); - } -}; - -struct __gmp_binary_modulus -{ - static void eval(mpz_ptr z, mpz_srcptr w, mpz_srcptr v) - { mpz_tdiv_r(z, w, v); } - - static void eval(mpz_ptr z, mpz_srcptr w, unsigned long int l) - { mpz_tdiv_r_ui(z, w, l); } - static void eval(mpz_ptr z, unsigned long int l, mpz_srcptr w) - { - if (mpz_sgn(w) >= 0) - { - if (mpz_fits_ulong_p(w)) - mpz_set_ui(z, l % mpz_get_ui(w)); - else - mpz_set_ui(z, l); - } - else - { - mpz_neg(z, w); - if (mpz_fits_ulong_p(z)) - mpz_set_ui(z, l % mpz_get_ui(z)); - else - mpz_set_ui(z, l); - } - } - static void eval(mpz_ptr z, mpz_srcptr w, signed long int l) - { - mpz_tdiv_r_ui (z, w, (l >= 0 ? l : -l)); - } - static void eval(mpz_ptr z, signed long int l, mpz_srcptr w) - { - if (mpz_fits_slong_p(w)) - mpz_set_si(z, l % mpz_get_si(w)); - else - { - /* if w is bigger than a long then the remainder is l unchanged, - unless l==LONG_MIN and w==-LONG_MIN in which case it's 0 */ - mpz_set_si (z, mpz_cmpabs_ui (w, (l >= 0 ? l : -l)) == 0 ? 0 : l); - } - } - static void eval(mpz_ptr z, mpz_srcptr w, double d) - { - mpz_t temp; - mpz_init_set_d(temp, d); - mpz_tdiv_r(z, w, temp); - mpz_clear(temp); - } - static void eval(mpz_ptr z, double d, mpz_srcptr w) - { - mpz_t temp; - mpz_init_set_d(temp, d); - mpz_tdiv_r(z, temp, w); - mpz_clear(temp); - } -}; - -// Max allocations for plain types when converted to mpz_t -#define __GMP_DBL_LIMBS (2 + DBL_MAX_EXP / GMP_NUMB_BITS) -#define __GMP_ULI_LIMBS (1 + (8 * sizeof (long) - 1) / GMP_NUMB_BITS) - -#define __GMPXX_TMP_UI \ - mpz_t temp; \ - mp_limb_t limbs[__GMP_ULI_LIMBS]; \ - temp->_mp_d = limbs; \ - temp->_mp_alloc = __GMP_ULI_LIMBS; \ - mpz_set_ui (temp, l) -#define __GMPXX_TMP_SI \ - mpz_t temp; \ - mp_limb_t limbs[__GMP_ULI_LIMBS]; \ - temp->_mp_d = limbs; \ - temp->_mp_alloc = __GMP_ULI_LIMBS; \ - mpz_set_si (temp, l) -#define __GMPXX_TMP_D \ - mpz_t temp; \ - mp_limb_t limbs[__GMP_DBL_LIMBS]; \ - temp->_mp_d = limbs; \ - temp->_mp_alloc = __GMP_DBL_LIMBS; \ - mpz_set_d (temp, d) - -struct __gmp_binary_and -{ - static void eval(mpz_ptr z, mpz_srcptr w, mpz_srcptr v) - { mpz_and(z, w, v); } - - static void eval(mpz_ptr z, mpz_srcptr w, unsigned long int l) - { __GMPXX_TMP_UI; mpz_and (z, w, temp); } - static void eval(mpz_ptr z, unsigned long int l, mpz_srcptr w) - { __GMPXX_TMP_UI; mpz_and (z, w, temp); } - static void eval(mpz_ptr z, mpz_srcptr w, signed long int l) - { __GMPXX_TMP_SI; mpz_and (z, w, temp); } - static void eval(mpz_ptr z, signed long int l, mpz_srcptr w) - { __GMPXX_TMP_SI; mpz_and (z, w, temp); } - static void eval(mpz_ptr z, mpz_srcptr w, double d) - { __GMPXX_TMP_D; mpz_and (z, w, temp); } - static void eval(mpz_ptr z, double d, mpz_srcptr w) - { __GMPXX_TMP_D; mpz_and (z, w, temp); } -}; - -struct __gmp_binary_ior -{ - static void eval(mpz_ptr z, mpz_srcptr w, mpz_srcptr v) - { mpz_ior(z, w, v); } - static void eval(mpz_ptr z, mpz_srcptr w, unsigned long int l) - { __GMPXX_TMP_UI; mpz_ior (z, w, temp); } - static void eval(mpz_ptr z, unsigned long int l, mpz_srcptr w) - { __GMPXX_TMP_UI; mpz_ior (z, w, temp); } - static void eval(mpz_ptr z, mpz_srcptr w, signed long int l) - { __GMPXX_TMP_SI; mpz_ior (z, w, temp); } - static void eval(mpz_ptr z, signed long int l, mpz_srcptr w) - { __GMPXX_TMP_SI; mpz_ior (z, w, temp); } - static void eval(mpz_ptr z, mpz_srcptr w, double d) - { __GMPXX_TMP_D; mpz_ior (z, w, temp); } - static void eval(mpz_ptr z, double d, mpz_srcptr w) - { __GMPXX_TMP_D; mpz_ior (z, w, temp); } -}; - -struct __gmp_binary_xor -{ - static void eval(mpz_ptr z, mpz_srcptr w, mpz_srcptr v) - { mpz_xor(z, w, v); } - static void eval(mpz_ptr z, mpz_srcptr w, unsigned long int l) - { __GMPXX_TMP_UI; mpz_xor (z, w, temp); } - static void eval(mpz_ptr z, unsigned long int l, mpz_srcptr w) - { __GMPXX_TMP_UI; mpz_xor (z, w, temp); } - static void eval(mpz_ptr z, mpz_srcptr w, signed long int l) - { __GMPXX_TMP_SI; mpz_xor (z, w, temp); } - static void eval(mpz_ptr z, signed long int l, mpz_srcptr w) - { __GMPXX_TMP_SI; mpz_xor (z, w, temp); } - static void eval(mpz_ptr z, mpz_srcptr w, double d) - { __GMPXX_TMP_D; mpz_xor (z, w, temp); } - static void eval(mpz_ptr z, double d, mpz_srcptr w) - { __GMPXX_TMP_D; mpz_xor (z, w, temp); } -}; - -struct __gmp_binary_lshift -{ - static void eval(mpz_ptr z, mpz_srcptr w, unsigned long int l) - { mpz_mul_2exp(z, w, l); } - static void eval(mpq_ptr q, mpq_srcptr r, unsigned long int l) - { mpq_mul_2exp(q, r, l); } - static void eval(mpf_ptr f, mpf_srcptr g, unsigned long int l) - { mpf_mul_2exp(f, g, l); } -}; - -struct __gmp_binary_rshift -{ - static void eval(mpz_ptr z, mpz_srcptr w, unsigned long int l) - { mpz_fdiv_q_2exp(z, w, l); } - static void eval(mpq_ptr q, mpq_srcptr r, unsigned long int l) - { mpq_div_2exp(q, r, l); } - static void eval(mpf_ptr f, mpf_srcptr g, unsigned long int l) - { mpf_div_2exp(f, g, l); } -}; - -struct __gmp_binary_equal -{ - static bool eval(mpz_srcptr z, mpz_srcptr w) { return mpz_cmp(z, w) == 0; } - - static bool eval(mpz_srcptr z, unsigned long int l) - { return mpz_cmp_ui(z, l) == 0; } - static bool eval(unsigned long int l, mpz_srcptr z) - { return mpz_cmp_ui(z, l) == 0; } - static bool eval(mpz_srcptr z, signed long int l) - { return mpz_cmp_si(z, l) == 0; } - static bool eval(signed long int l, mpz_srcptr z) - { return mpz_cmp_si(z, l) == 0; } - static bool eval(mpz_srcptr z, double d) - { return mpz_cmp_d(z, d) == 0; } - static bool eval(double d, mpz_srcptr z) - { return mpz_cmp_d(z, d) == 0; } - - static bool eval(mpq_srcptr q, mpq_srcptr r) - { return mpq_equal(q, r) != 0; } - - static bool eval(mpq_srcptr q, unsigned long int l) - { return mpq_cmp_ui(q, l, 1) == 0; } - static bool eval(unsigned long int l, mpq_srcptr q) - { return mpq_cmp_ui(q, l, 1) == 0; } - static bool eval(mpq_srcptr q, signed long int l) - { return mpq_cmp_si(q, l, 1) == 0; } - static bool eval(signed long int l, mpq_srcptr q) - { return mpq_cmp_si(q, l, 1) == 0; } - static bool eval(mpq_srcptr q, double d) - { - bool b; - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - b = (mpq_equal(q, temp) != 0); - mpq_clear(temp); - return b; - } - static bool eval(double d, mpq_srcptr q) - { - bool b; - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - b = (mpq_equal(temp, q) != 0); - mpq_clear(temp); - return b; - } - - static bool eval(mpf_srcptr f, mpf_srcptr g) { return mpf_cmp(f, g) == 0; } - - static bool eval(mpf_srcptr f, unsigned long int l) - { return mpf_cmp_ui(f, l) == 0; } - static bool eval(unsigned long int l, mpf_srcptr f) - { return mpf_cmp_ui(f, l) == 0; } - static bool eval(mpf_srcptr f, signed long int l) - { return mpf_cmp_si(f, l) == 0; } - static bool eval(signed long int l, mpf_srcptr f) - { return mpf_cmp_si(f, l) == 0; } - static bool eval(mpf_srcptr f, double d) - { return mpf_cmp_d(f, d) == 0; } - static bool eval(double d, mpf_srcptr f) - { return mpf_cmp_d(f, d) == 0; } -}; - -struct __gmp_binary_not_equal -{ - static bool eval(mpz_srcptr z, mpz_srcptr w) { return mpz_cmp(z, w) != 0; } - - static bool eval(mpz_srcptr z, unsigned long int l) - { return mpz_cmp_ui(z, l) != 0; } - static bool eval(unsigned long int l, mpz_srcptr z) - { return mpz_cmp_ui(z, l) != 0; } - static bool eval(mpz_srcptr z, signed long int l) - { return mpz_cmp_si(z, l) != 0; } - static bool eval(signed long int l, mpz_srcptr z) - { return mpz_cmp_si(z, l) != 0; } - static bool eval(mpz_srcptr z, double d) - { return mpz_cmp_d(z, d) != 0; } - static bool eval(double d, mpz_srcptr z) - { return mpz_cmp_d(z, d) != 0; } - - static bool eval(mpq_srcptr q, mpq_srcptr r) - { return mpq_equal(q, r) == 0; } - - static bool eval(mpq_srcptr q, unsigned long int l) - { return mpq_cmp_ui(q, l, 1) != 0; } - static bool eval(unsigned long int l, mpq_srcptr q) - { return mpq_cmp_ui(q, l, 1) != 0; } - static bool eval(mpq_srcptr q, signed long int l) - { return mpq_cmp_si(q, l, 1) != 0; } - static bool eval(signed long int l, mpq_srcptr q) - { return mpq_cmp_si(q, l, 1) != 0; } - static bool eval(mpq_srcptr q, double d) - { - bool b; - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - b = (mpq_equal(q, temp) == 0); - mpq_clear(temp); - return b; - } - static bool eval(double d, mpq_srcptr q) - { - bool b; - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - b = (mpq_equal(temp, q) == 0); - mpq_clear(temp); - return b; - } - - static bool eval(mpf_srcptr f, mpf_srcptr g) { return mpf_cmp(f, g) != 0; } - - static bool eval(mpf_srcptr f, unsigned long int l) - { return mpf_cmp_ui(f, l) != 0; } - static bool eval(unsigned long int l, mpf_srcptr f) - { return mpf_cmp_ui(f, l) != 0; } - static bool eval(mpf_srcptr f, signed long int l) - { return mpf_cmp_si(f, l) != 0; } - static bool eval(signed long int l, mpf_srcptr f) - { return mpf_cmp_si(f, l) != 0; } - static bool eval(mpf_srcptr f, double d) - { return mpf_cmp_d(f, d) != 0; } - static bool eval(double d, mpf_srcptr f) - { return mpf_cmp_d(f, d) != 0; } -}; - -struct __gmp_binary_less -{ - static bool eval(mpz_srcptr z, mpz_srcptr w) { return mpz_cmp(z, w) < 0; } - - static bool eval(mpz_srcptr z, unsigned long int l) - { return mpz_cmp_ui(z, l) < 0; } - static bool eval(unsigned long int l, mpz_srcptr z) - { return mpz_cmp_ui(z, l) > 0; } - static bool eval(mpz_srcptr z, signed long int l) - { return mpz_cmp_si(z, l) < 0; } - static bool eval(signed long int l, mpz_srcptr z) - { return mpz_cmp_si(z, l) > 0; } - static bool eval(mpz_srcptr z, double d) - { return mpz_cmp_d(z, d) < 0; } - static bool eval(double d, mpz_srcptr z) - { return mpz_cmp_d(z, d) > 0; } - - static bool eval(mpq_srcptr q, mpq_srcptr r) { return mpq_cmp(q, r) < 0; } - - static bool eval(mpq_srcptr q, unsigned long int l) - { return mpq_cmp_ui(q, l, 1) < 0; } - static bool eval(unsigned long int l, mpq_srcptr q) - { return mpq_cmp_ui(q, l, 1) > 0; } - static bool eval(mpq_srcptr q, signed long int l) - { return mpq_cmp_si(q, l, 1) < 0; } - static bool eval(signed long int l, mpq_srcptr q) - { return mpq_cmp_si(q, l, 1) > 0; } - static bool eval(mpq_srcptr q, double d) - { - bool b; - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - b = (mpq_cmp(q, temp) < 0); - mpq_clear(temp); - return b; - } - static bool eval(double d, mpq_srcptr q) - { - bool b; - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - b = (mpq_cmp(temp, q) < 0); - mpq_clear(temp); - return b; - } - - static bool eval(mpf_srcptr f, mpf_srcptr g) { return mpf_cmp(f, g) < 0; } - - static bool eval(mpf_srcptr f, unsigned long int l) - { return mpf_cmp_ui(f, l) < 0; } - static bool eval(unsigned long int l, mpf_srcptr f) - { return mpf_cmp_ui(f, l) > 0; } - static bool eval(mpf_srcptr f, signed long int l) - { return mpf_cmp_si(f, l) < 0; } - static bool eval(signed long int l, mpf_srcptr f) - { return mpf_cmp_si(f, l) > 0; } - static bool eval(mpf_srcptr f, double d) - { return mpf_cmp_d(f, d) < 0; } - static bool eval(double d, mpf_srcptr f) - { return mpf_cmp_d(f, d) > 0; } -}; - -struct __gmp_binary_less_equal -{ - static bool eval(mpz_srcptr z, mpz_srcptr w) { return mpz_cmp(z, w) <= 0; } - - static bool eval(mpz_srcptr z, unsigned long int l) - { return mpz_cmp_ui(z, l) <= 0; } - static bool eval(unsigned long int l, mpz_srcptr z) - { return mpz_cmp_ui(z, l) >= 0; } - static bool eval(mpz_srcptr z, signed long int l) - { return mpz_cmp_si(z, l) <= 0; } - static bool eval(signed long int l, mpz_srcptr z) - { return mpz_cmp_si(z, l) >= 0; } - static bool eval(mpz_srcptr z, double d) - { return mpz_cmp_d(z, d) <= 0; } - static bool eval(double d, mpz_srcptr z) - { return mpz_cmp_d(z, d) >= 0; } - - static bool eval(mpq_srcptr q, mpq_srcptr r) { return mpq_cmp(q, r) <= 0; } - - static bool eval(mpq_srcptr q, unsigned long int l) - { return mpq_cmp_ui(q, l, 1) <= 0; } - static bool eval(unsigned long int l, mpq_srcptr q) - { return mpq_cmp_ui(q, l, 1) >= 0; } - static bool eval(mpq_srcptr q, signed long int l) - { return mpq_cmp_si(q, l, 1) <= 0; } - static bool eval(signed long int l, mpq_srcptr q) - { return mpq_cmp_si(q, l, 1) >= 0; } - static bool eval(mpq_srcptr q, double d) - { - bool b; - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - b = (mpq_cmp(q, temp) <= 0); - mpq_clear(temp); - return b; - } - static bool eval(double d, mpq_srcptr q) - { - bool b; - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - b = (mpq_cmp(temp, q) <= 0); - mpq_clear(temp); - return b; - } - - static bool eval(mpf_srcptr f, mpf_srcptr g) { return mpf_cmp(f, g) <= 0; } - - static bool eval(mpf_srcptr f, unsigned long int l) - { return mpf_cmp_ui(f, l) <= 0; } - static bool eval(unsigned long int l, mpf_srcptr f) - { return mpf_cmp_ui(f, l) >= 0; } - static bool eval(mpf_srcptr f, signed long int l) - { return mpf_cmp_si(f, l) <= 0; } - static bool eval(signed long int l, mpf_srcptr f) - { return mpf_cmp_si(f, l) >= 0; } - static bool eval(mpf_srcptr f, double d) - { return mpf_cmp_d(f, d) <= 0; } - static bool eval(double d, mpf_srcptr f) - { return mpf_cmp_d(f, d) >= 0; } -}; - -struct __gmp_binary_greater -{ - static bool eval(mpz_srcptr z, mpz_srcptr w) { return mpz_cmp(z, w) > 0; } - - static bool eval(mpz_srcptr z, unsigned long int l) - { return mpz_cmp_ui(z, l) > 0; } - static bool eval(unsigned long int l, mpz_srcptr z) - { return mpz_cmp_ui(z, l) < 0; } - static bool eval(mpz_srcptr z, signed long int l) - { return mpz_cmp_si(z, l) > 0; } - static bool eval(signed long int l, mpz_srcptr z) - { return mpz_cmp_si(z, l) < 0; } - static bool eval(mpz_srcptr z, double d) - { return mpz_cmp_d(z, d) > 0; } - static bool eval(double d, mpz_srcptr z) - { return mpz_cmp_d(z, d) < 0; } - - static bool eval(mpq_srcptr q, mpq_srcptr r) { return mpq_cmp(q, r) > 0; } - - static bool eval(mpq_srcptr q, unsigned long int l) - { return mpq_cmp_ui(q, l, 1) > 0; } - static bool eval(unsigned long int l, mpq_srcptr q) - { return mpq_cmp_ui(q, l, 1) < 0; } - static bool eval(mpq_srcptr q, signed long int l) - { return mpq_cmp_si(q, l, 1) > 0; } - static bool eval(signed long int l, mpq_srcptr q) - { return mpq_cmp_si(q, l, 1) < 0; } - static bool eval(mpq_srcptr q, double d) - { - bool b; - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - b = (mpq_cmp(q, temp) > 0); - mpq_clear(temp); - return b; - } - static bool eval(double d, mpq_srcptr q) - { - bool b; - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - b = (mpq_cmp(temp, q) > 0); - mpq_clear(temp); - return b; - } - - static bool eval(mpf_srcptr f, mpf_srcptr g) { return mpf_cmp(f, g) > 0; } - - static bool eval(mpf_srcptr f, unsigned long int l) - { return mpf_cmp_ui(f, l) > 0; } - static bool eval(unsigned long int l, mpf_srcptr f) - { return mpf_cmp_ui(f, l) < 0; } - static bool eval(mpf_srcptr f, signed long int l) - { return mpf_cmp_si(f, l) > 0; } - static bool eval(signed long int l, mpf_srcptr f) - { return mpf_cmp_si(f, l) < 0; } - static bool eval(mpf_srcptr f, double d) - { return mpf_cmp_d(f, d) > 0; } - static bool eval(double d, mpf_srcptr f) - { return mpf_cmp_d(f, d) < 0; } -}; - -struct __gmp_binary_greater_equal -{ - static bool eval(mpz_srcptr z, mpz_srcptr w) { return mpz_cmp(z, w) >= 0; } - - static bool eval(mpz_srcptr z, unsigned long int l) - { return mpz_cmp_ui(z, l) >= 0; } - static bool eval(unsigned long int l, mpz_srcptr z) - { return mpz_cmp_ui(z, l) <= 0; } - static bool eval(mpz_srcptr z, signed long int l) - { return mpz_cmp_si(z, l) >= 0; } - static bool eval(signed long int l, mpz_srcptr z) - { return mpz_cmp_si(z, l) <= 0; } - static bool eval(mpz_srcptr z, double d) - { return mpz_cmp_d(z, d) >= 0; } - static bool eval(double d, mpz_srcptr z) - { return mpz_cmp_d(z, d) <= 0; } - - static bool eval(mpq_srcptr q, mpq_srcptr r) { return mpq_cmp(q, r) >= 0; } - - static bool eval(mpq_srcptr q, unsigned long int l) - { return mpq_cmp_ui(q, l, 1) >= 0; } - static bool eval(unsigned long int l, mpq_srcptr q) - { return mpq_cmp_ui(q, l, 1) <= 0; } - static bool eval(mpq_srcptr q, signed long int l) - { return mpq_cmp_si(q, l, 1) >= 0; } - static bool eval(signed long int l, mpq_srcptr q) - { return mpq_cmp_si(q, l, 1) <= 0; } - static bool eval(mpq_srcptr q, double d) - { - bool b; - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - b = (mpq_cmp(q, temp) >= 0); - mpq_clear(temp); - return b; - } - static bool eval(double d, mpq_srcptr q) - { - bool b; - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - b = (mpq_cmp(temp, q) >= 0); - mpq_clear(temp); - return b; - } - - static bool eval(mpf_srcptr f, mpf_srcptr g) { return mpf_cmp(f, g) >= 0; } - - static bool eval(mpf_srcptr f, unsigned long int l) - { return mpf_cmp_ui(f, l) >= 0; } - static bool eval(unsigned long int l, mpf_srcptr f) - { return mpf_cmp_ui(f, l) <= 0; } - static bool eval(mpf_srcptr f, signed long int l) - { return mpf_cmp_si(f, l) >= 0; } - static bool eval(signed long int l, mpf_srcptr f) - { return mpf_cmp_si(f, l) <= 0; } - static bool eval(mpf_srcptr f, double d) - { return mpf_cmp_d(f, d) >= 0; } - static bool eval(double d, mpf_srcptr f) - { return mpf_cmp_d(f, d) <= 0; } -}; - -struct __gmp_unary_increment -{ - static void eval(mpz_ptr z) { mpz_add_ui(z, z, 1); } - static void eval(mpq_ptr q) - { mpz_add(mpq_numref(q), mpq_numref(q), mpq_denref(q)); } - static void eval(mpf_ptr f) { mpf_add_ui(f, f, 1); } -}; - -struct __gmp_unary_decrement -{ - static void eval(mpz_ptr z) { mpz_sub_ui(z, z, 1); } - static void eval(mpq_ptr q) - { mpz_sub(mpq_numref(q), mpq_numref(q), mpq_denref(q)); } - static void eval(mpf_ptr f) { mpf_sub_ui(f, f, 1); } -}; - -struct __gmp_abs_function -{ - static void eval(mpz_ptr z, mpz_srcptr w) { mpz_abs(z, w); } - static void eval(mpq_ptr q, mpq_srcptr r) { mpq_abs(q, r); } - static void eval(mpf_ptr f, mpf_srcptr g) { mpf_abs(f, g); } -}; - -struct __gmp_trunc_function -{ - static void eval(mpf_ptr f, mpf_srcptr g) { mpf_trunc(f, g); } -}; - -struct __gmp_floor_function -{ - static void eval(mpf_ptr f, mpf_srcptr g) { mpf_floor(f, g); } -}; - -struct __gmp_ceil_function -{ - static void eval(mpf_ptr f, mpf_srcptr g) { mpf_ceil(f, g); } -}; - -struct __gmp_sqrt_function -{ - static void eval(mpz_ptr z, mpz_srcptr w) { mpz_sqrt(z, w); } - static void eval(mpf_ptr f, mpf_srcptr g) { mpf_sqrt(f, g); } -}; - -struct __gmp_hypot_function -{ - static void eval(mpf_ptr f, mpf_srcptr g, mpf_srcptr h) - { - mpf_t temp; - mpf_init2(temp, mpf_get_prec(f)); - mpf_mul(temp, g, g); - mpf_mul(f, h, h); - mpf_add(f, f, temp); - mpf_sqrt(f, f); - mpf_clear(temp); - } - - static void eval(mpf_ptr f, mpf_srcptr g, unsigned long int l) - { - mpf_t temp; - mpf_init2(temp, mpf_get_prec(f)); - mpf_mul(temp, g, g); - mpf_set_ui(f, l); - mpf_mul(f, f, f); - mpf_add(f, f, temp); - mpf_sqrt(f, f); - mpf_clear(temp); - } - static void eval(mpf_ptr f, unsigned long int l, mpf_srcptr g) - { - mpf_t temp; - mpf_init2(temp, mpf_get_prec(f)); - mpf_mul(temp, g, g); - mpf_set_ui(f, l); - mpf_mul(f, f, f); - mpf_add(f, f, temp); - mpf_sqrt(f, f); - mpf_clear(temp); - } - static void eval(mpf_ptr f, mpf_srcptr g, signed long int l) - { - mpf_t temp; - mpf_init2(temp, mpf_get_prec(f)); - mpf_mul(temp, g, g); - mpf_set_si(f, l); - mpf_mul(f, f, f); - mpf_add(f, f, temp); - mpf_sqrt(f, f); - mpf_clear(temp); - } - static void eval(mpf_ptr f, signed long int l, mpf_srcptr g) - { - mpf_t temp; - mpf_init2(temp, mpf_get_prec(f)); - mpf_mul(temp, g, g); - mpf_set_si(f, l); - mpf_mul(f, f, f); - mpf_add(f, f, temp); - mpf_sqrt(f, f); - mpf_clear(temp); - } - static void eval(mpf_ptr f, mpf_srcptr g, double d) - { - mpf_t temp; - mpf_init2(temp, mpf_get_prec(f)); - mpf_mul(temp, g, g); - mpf_set_d(f, d); - mpf_mul(f, f, f); - mpf_add(f, f, temp); - mpf_sqrt(f, f); - mpf_clear(temp); - } - static void eval(mpf_ptr f, double d, mpf_srcptr g) - { - mpf_t temp; - mpf_init2(temp, mpf_get_prec(f)); - mpf_mul(temp, g, g); - mpf_set_d(f, d); - mpf_mul(f, f, f); - mpf_add(f, f, temp); - mpf_sqrt(f, f); - mpf_clear(temp); - } -}; - -struct __gmp_sgn_function -{ - static int eval(mpz_srcptr z) { return mpz_sgn(z); } - static int eval(mpq_srcptr q) { return mpq_sgn(q); } - static int eval(mpf_srcptr f) { return mpf_sgn(f); } -}; - -struct __gmp_cmp_function -{ - static int eval(mpz_srcptr z, mpz_srcptr w) { return mpz_cmp(z, w); } - - static int eval(mpz_srcptr z, unsigned long int l) - { return mpz_cmp_ui(z, l); } - static int eval(unsigned long int l, mpz_srcptr z) - { return -mpz_cmp_ui(z, l); } - static int eval(mpz_srcptr z, signed long int l) - { return mpz_cmp_si(z, l); } - static int eval(signed long int l, mpz_srcptr z) - { return -mpz_cmp_si(z, l); } - static int eval(mpz_srcptr z, double d) - { return mpz_cmp_d(z, d); } - static int eval(double d, mpz_srcptr z) - { return -mpz_cmp_d(z, d); } - - static int eval(mpq_srcptr q, mpq_srcptr r) { return mpq_cmp(q, r); } - - static int eval(mpq_srcptr q, unsigned long int l) - { return mpq_cmp_ui(q, l, 1); } - static int eval(unsigned long int l, mpq_srcptr q) - { return -mpq_cmp_ui(q, l, 1); } - static int eval(mpq_srcptr q, signed long int l) - { return mpq_cmp_si(q, l, 1); } - static int eval(signed long int l, mpq_srcptr q) - { return -mpq_cmp_si(q, l, 1); } - static int eval(mpq_srcptr q, double d) - { - int i; - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - i = mpq_cmp(q, temp); - mpq_clear(temp); - return i; - } - static int eval(double d, mpq_srcptr q) - { - int i; - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - i = mpq_cmp(temp, q); - mpq_clear(temp); - return i; - } - - static int eval(mpf_srcptr f, mpf_srcptr g) { return mpf_cmp(f, g); } - - static int eval(mpf_srcptr f, unsigned long int l) - { return mpf_cmp_ui(f, l); } - static int eval(unsigned long int l, mpf_srcptr f) - { return -mpf_cmp_ui(f, l); } - static int eval(mpf_srcptr f, signed long int l) - { return mpf_cmp_si(f, l); } - static int eval(signed long int l, mpf_srcptr f) - { return -mpf_cmp_si(f, l); } - static int eval(mpf_srcptr f, double d) - { return mpf_cmp_d(f, d); } - static int eval(double d, mpf_srcptr f) - { return -mpf_cmp_d(f, d); } -}; - -struct __gmp_rand_function -{ - static void eval(mpz_ptr z, gmp_randstate_t s, unsigned long int l) - { mpz_urandomb(z, s, l); } - static void eval(mpz_ptr z, gmp_randstate_t s, mpz_srcptr w) - { mpz_urandomm(z, s, w); } - static void eval(mpf_ptr f, gmp_randstate_t s, mp_bitcnt_t prec) - { mpf_urandomb(f, s, prec); } -}; - - -/**************** Auxiliary classes ****************/ - -/* this is much the same as gmp_allocated_string in gmp-impl.h - since gmp-impl.h is not publicly available, I redefine it here - I use a different name to avoid possible clashes */ -extern "C" { -struct __gmp_alloc_cstring_c -{ - void (*free_func) (void *, size_t); -}; -} - -struct __gmp_alloc_cstring : __gmp_alloc_cstring_c -{ - char *str; - __gmp_alloc_cstring(char *s) { str = s; } - ~__gmp_alloc_cstring() - { - mp_get_memory_functions (NULL, NULL, &free_func); - (*free_func) (str, std::strlen(str)+1); - } -}; - -// general expression template class -template -class __gmp_expr; - - -// templates for resolving expression types -template -struct __gmp_resolve_ref -{ - typedef T ref_type; -}; - -template -struct __gmp_resolve_ref<__gmp_expr > -{ - typedef const __gmp_expr & ref_type; -}; - - -template -struct __gmp_resolve_expr; - -template <> -struct __gmp_resolve_expr -{ - typedef mpz_t value_type; - typedef mpz_ptr ptr_type; -}; - -template <> -struct __gmp_resolve_expr -{ - typedef mpq_t value_type; - typedef mpq_ptr ptr_type; -}; - -template <> -struct __gmp_resolve_expr -{ - typedef mpf_t value_type; - typedef mpf_ptr ptr_type; -}; - -template <> -struct __gmp_resolve_expr -{ - typedef mpq_t value_type; -}; - -template <> -struct __gmp_resolve_expr -{ - typedef mpq_t value_type; -}; - -template <> -struct __gmp_resolve_expr -{ - typedef mpf_t value_type; -}; - -template <> -struct __gmp_resolve_expr -{ - typedef mpf_t value_type; -}; - -template <> -struct __gmp_resolve_expr -{ - typedef mpf_t value_type; -}; - -template <> -struct __gmp_resolve_expr -{ - typedef mpf_t value_type; -}; - - - -template -struct __gmp_resolve_temp -{ - typedef __gmp_expr temp_type; -}; - -template -struct __gmp_resolve_temp -{ - typedef const __gmp_expr & temp_type; -}; - - -// classes for evaluating unary and binary expressions -template -struct __gmp_unary_expr -{ - const T &val; - - __gmp_unary_expr(const T &v) : val(v) { } -private: - __gmp_unary_expr(); -}; - -template -struct __gmp_binary_expr -{ - typename __gmp_resolve_ref::ref_type val1; - typename __gmp_resolve_ref::ref_type val2; - - __gmp_binary_expr(const T &v1, const U &v2) : val1(v1), val2(v2) { } -private: - __gmp_binary_expr(); -}; - - -// functions for evaluating expressions -template -void __gmp_set_expr(mpz_ptr, const __gmp_expr &); -template -void __gmp_set_expr(mpq_ptr, const __gmp_expr &); -template -void __gmp_set_expr(mpf_ptr, const __gmp_expr &); - - -/**************** Macros for in-class declarations ****************/ -/* This is just repetitive code that is easier to maintain if it's written - only once */ - -#define __GMPP_DECLARE_COMPOUND_OPERATOR(fun) \ - template \ - __gmp_expr & fun(const __gmp_expr &); - -#define __GMPN_DECLARE_COMPOUND_OPERATOR(fun) \ - __gmp_expr & fun(signed char); \ - __gmp_expr & fun(unsigned char); \ - __gmp_expr & fun(signed int); \ - __gmp_expr & fun(unsigned int); \ - __gmp_expr & fun(signed short int); \ - __gmp_expr & fun(unsigned short int); \ - __gmp_expr & fun(signed long int); \ - __gmp_expr & fun(unsigned long int); \ - __gmp_expr & fun(float); \ - __gmp_expr & fun(double); \ - __gmp_expr & fun(long double); - -#define __GMP_DECLARE_COMPOUND_OPERATOR(fun) \ -__GMPP_DECLARE_COMPOUND_OPERATOR(fun) \ -__GMPN_DECLARE_COMPOUND_OPERATOR(fun) - -#define __GMP_DECLARE_COMPOUND_OPERATOR_UI(fun) \ - __gmp_expr & fun(unsigned long int); - -#define __GMP_DECLARE_INCREMENT_OPERATOR(fun) \ - inline __gmp_expr & fun(); \ - inline __gmp_expr fun(int); - - -/**************** mpz_class -- wrapper for mpz_t ****************/ - -template <> -class __gmp_expr -{ -private: - typedef mpz_t value_type; - value_type mp; -public: - mp_bitcnt_t get_prec() const { return mpf_get_default_prec(); } - - // constructors and destructor - __gmp_expr() { mpz_init(mp); } - - __gmp_expr(const __gmp_expr &z) { mpz_init_set(mp, z.mp); } - template - __gmp_expr(const __gmp_expr &expr) - { mpz_init(mp); __gmp_set_expr(mp, expr); } - - __gmp_expr(signed char c) { mpz_init_set_si(mp, c); } - __gmp_expr(unsigned char c) { mpz_init_set_ui(mp, c); } - - __gmp_expr(signed int i) { mpz_init_set_si(mp, i); } - __gmp_expr(unsigned int i) { mpz_init_set_ui(mp, i); } - - __gmp_expr(signed short int s) { mpz_init_set_si(mp, s); } - __gmp_expr(unsigned short int s) { mpz_init_set_ui(mp, s); } - - __gmp_expr(signed long int l) { mpz_init_set_si(mp, l); } - __gmp_expr(unsigned long int l) { mpz_init_set_ui(mp, l); } - - __gmp_expr(float f) { mpz_init_set_d(mp, f); } - __gmp_expr(double d) { mpz_init_set_d(mp, d); } - // __gmp_expr(long double ld) { mpz_init_set_d(mp, ld); } - - explicit __gmp_expr(const char *s) - { - if (mpz_init_set_str (mp, s, 0) != 0) - { - mpz_clear (mp); - throw std::invalid_argument ("mpz_set_str"); - } - } - __gmp_expr(const char *s, int base) - { - if (mpz_init_set_str (mp, s, base) != 0) - { - mpz_clear (mp); - throw std::invalid_argument ("mpz_set_str"); - } - } - explicit __gmp_expr(const std::string &s) - { - if (mpz_init_set_str (mp, s.c_str(), 0) != 0) - { - mpz_clear (mp); - throw std::invalid_argument ("mpz_set_str"); - } - } - __gmp_expr(const std::string &s, int base) - { - if (mpz_init_set_str(mp, s.c_str(), base) != 0) - { - mpz_clear (mp); - throw std::invalid_argument ("mpz_set_str"); - } - } - - explicit __gmp_expr(mpz_srcptr z) { mpz_init_set(mp, z); } - - ~__gmp_expr() { mpz_clear(mp); } - - // assignment operators - __gmp_expr & operator=(const __gmp_expr &z) - { mpz_set(mp, z.mp); return *this; } - template - __gmp_expr & operator=(const __gmp_expr &expr) - { __gmp_set_expr(mp, expr); return *this; } - - __gmp_expr & operator=(signed char c) { mpz_set_si(mp, c); return *this; } - __gmp_expr & operator=(unsigned char c) { mpz_set_ui(mp, c); return *this; } - - __gmp_expr & operator=(signed int i) { mpz_set_si(mp, i); return *this; } - __gmp_expr & operator=(unsigned int i) { mpz_set_ui(mp, i); return *this; } - - __gmp_expr & operator=(signed short int s) - { mpz_set_si(mp, s); return *this; } - __gmp_expr & operator=(unsigned short int s) - { mpz_set_ui(mp, s); return *this; } - - __gmp_expr & operator=(signed long int l) - { mpz_set_si(mp, l); return *this; } - __gmp_expr & operator=(unsigned long int l) - { mpz_set_ui(mp, l); return *this; } - - __gmp_expr & operator=(float f) { mpz_set_d(mp, f); return *this; } - __gmp_expr & operator=(double d) { mpz_set_d(mp, d); return *this; } - // __gmp_expr & operator=(long double ld) - // { mpz_set_ld(mp, ld); return *this; } - - __gmp_expr & operator=(const char *s) - { - if (mpz_set_str (mp, s, 0) != 0) - throw std::invalid_argument ("mpz_set_str"); - return *this; - } - __gmp_expr & operator=(const std::string &s) - { - if (mpz_set_str(mp, s.c_str(), 0) != 0) - throw std::invalid_argument ("mpz_set_str"); - return *this; - } - - // string input/output functions - int set_str(const char *s, int base) - { return mpz_set_str(mp, s, base); } - int set_str(const std::string &s, int base) - { return mpz_set_str(mp, s.c_str(), base); } - std::string get_str(int base = 10) const - { - __gmp_alloc_cstring temp(mpz_get_str(0, base, mp)); - return std::string(temp.str); - } - - // conversion functions - mpz_srcptr __get_mp() const { return mp; } - mpz_ptr __get_mp() { return mp; } - mpz_srcptr get_mpz_t() const { return mp; } - mpz_ptr get_mpz_t() { return mp; } - - signed long int get_si() const { return mpz_get_si(mp); } - unsigned long int get_ui() const { return mpz_get_ui(mp); } - double get_d() const { return mpz_get_d(mp); } - - // bool fits_schar_p() const { return mpz_fits_schar_p(mp); } - // bool fits_uchar_p() const { return mpz_fits_uchar_p(mp); } - bool fits_sint_p() const { return mpz_fits_sint_p(mp); } - bool fits_uint_p() const { return mpz_fits_uint_p(mp); } - bool fits_sshort_p() const { return mpz_fits_sshort_p(mp); } - bool fits_ushort_p() const { return mpz_fits_ushort_p(mp); } - bool fits_slong_p() const { return mpz_fits_slong_p(mp); } - bool fits_ulong_p() const { return mpz_fits_ulong_p(mp); } - // bool fits_float_p() const { return mpz_fits_float_p(mp); } - // bool fits_double_p() const { return mpz_fits_double_p(mp); } - // bool fits_ldouble_p() const { return mpz_fits_ldouble_p(mp); } - - // member operators - __GMP_DECLARE_COMPOUND_OPERATOR(operator+=) - __GMP_DECLARE_COMPOUND_OPERATOR(operator-=) - __GMP_DECLARE_COMPOUND_OPERATOR(operator*=) - __GMP_DECLARE_COMPOUND_OPERATOR(operator/=) - __GMP_DECLARE_COMPOUND_OPERATOR(operator%=) - - __GMPP_DECLARE_COMPOUND_OPERATOR(operator&=) - __GMPP_DECLARE_COMPOUND_OPERATOR(operator|=) - __GMPP_DECLARE_COMPOUND_OPERATOR(operator^=) - - __GMP_DECLARE_COMPOUND_OPERATOR_UI(operator<<=) - __GMP_DECLARE_COMPOUND_OPERATOR_UI(operator>>=) - - __GMP_DECLARE_INCREMENT_OPERATOR(operator++) - __GMP_DECLARE_INCREMENT_OPERATOR(operator--) -}; - -typedef __gmp_expr mpz_class; - - -/**************** mpq_class -- wrapper for mpq_t ****************/ - -template <> -class __gmp_expr -{ -private: - typedef mpq_t value_type; - value_type mp; -public: - mp_bitcnt_t get_prec() const { return mpf_get_default_prec(); } - void canonicalize() { mpq_canonicalize(mp); } - - // constructors and destructor - __gmp_expr() { mpq_init(mp); } - - __gmp_expr(const __gmp_expr &q) { mpq_init(mp); mpq_set(mp, q.mp); } - template - __gmp_expr(const __gmp_expr &expr) - { mpq_init(mp); __gmp_set_expr(mp, expr); } - - __gmp_expr(signed char c) { mpq_init(mp); mpq_set_si(mp, c, 1); } - __gmp_expr(unsigned char c) { mpq_init(mp); mpq_set_ui(mp, c, 1); } - - __gmp_expr(signed int i) { mpq_init(mp); mpq_set_si(mp, i, 1); } - __gmp_expr(unsigned int i) { mpq_init(mp); mpq_set_ui(mp, i, 1); } - - __gmp_expr(signed short int s) { mpq_init(mp); mpq_set_si(mp, s, 1); } - __gmp_expr(unsigned short int s) { mpq_init(mp); mpq_set_ui(mp, s, 1); } - - __gmp_expr(signed long int l) { mpq_init(mp); mpq_set_si(mp, l, 1); } - __gmp_expr(unsigned long int l) { mpq_init(mp); mpq_set_ui(mp, l, 1); } - - __gmp_expr(float f) { mpq_init(mp); mpq_set_d(mp, f); } - __gmp_expr(double d) { mpq_init(mp); mpq_set_d(mp, d); } - // __gmp_expr(long double ld) { mpq_init(mp); mpq_set_ld(mp, ld); } - - explicit __gmp_expr(const char *s) - { - mpq_init (mp); - if (mpq_set_str (mp, s, 0) != 0) - { - mpq_clear (mp); - throw std::invalid_argument ("mpq_set_str"); - } - } - __gmp_expr(const char *s, int base) - { - mpq_init (mp); - if (mpq_set_str(mp, s, base) != 0) - { - mpq_clear (mp); - throw std::invalid_argument ("mpq_set_str"); - } - } - explicit __gmp_expr(const std::string &s) - { - mpq_init (mp); - if (mpq_set_str (mp, s.c_str(), 0) != 0) - { - mpq_clear (mp); - throw std::invalid_argument ("mpq_set_str"); - } - } - __gmp_expr(const std::string &s, int base) - { - mpq_init(mp); - if (mpq_set_str (mp, s.c_str(), base) != 0) - { - mpq_clear (mp); - throw std::invalid_argument ("mpq_set_str"); - } - } - explicit __gmp_expr(mpq_srcptr q) { mpq_init(mp); mpq_set(mp, q); } - - __gmp_expr(const mpz_class &num, const mpz_class &den) - { - mpq_init(mp); - mpz_set(mpq_numref(mp), num.get_mpz_t()); - mpz_set(mpq_denref(mp), den.get_mpz_t()); - } - - ~__gmp_expr() { mpq_clear(mp); } - - // assignment operators - __gmp_expr & operator=(const __gmp_expr &q) - { mpq_set(mp, q.mp); return *this; } - template - __gmp_expr & operator=(const __gmp_expr &expr) - { __gmp_set_expr(mp, expr); return *this; } - - __gmp_expr & operator=(signed char c) - { mpq_set_si(mp, c, 1); return *this; } - __gmp_expr & operator=(unsigned char c) - { mpq_set_ui(mp, c, 1); return *this; } - - __gmp_expr & operator=(signed int i) { mpq_set_si(mp, i, 1); return *this; } - __gmp_expr & operator=(unsigned int i) - { mpq_set_ui(mp, i, 1); return *this; } - - __gmp_expr & operator=(signed short int s) - { mpq_set_si(mp, s, 1); return *this; } - __gmp_expr & operator=(unsigned short int s) - { mpq_set_ui(mp, s, 1); return *this; } - - __gmp_expr & operator=(signed long int l) - { mpq_set_si(mp, l, 1); return *this; } - __gmp_expr & operator=(unsigned long int l) - { mpq_set_ui(mp, l, 1); return *this; } - - __gmp_expr & operator=(float f) { mpq_set_d(mp, f); return *this; } - __gmp_expr & operator=(double d) { mpq_set_d(mp, d); return *this; } - // __gmp_expr & operator=(long double ld) - // { mpq_set_ld(mp, ld); return *this; } - - __gmp_expr & operator=(const char *s) - { - if (mpq_set_str (mp, s, 0) != 0) - throw std::invalid_argument ("mpq_set_str"); - return *this; - } - __gmp_expr & operator=(const std::string &s) - { - if (mpq_set_str(mp, s.c_str(), 0) != 0) - throw std::invalid_argument ("mpq_set_str"); - return *this; - } - - // string input/output functions - int set_str(const char *s, int base) - { return mpq_set_str(mp, s, base); } - int set_str(const std::string &s, int base) - { return mpq_set_str(mp, s.c_str(), base); } - std::string get_str(int base = 10) const - { - __gmp_alloc_cstring temp(mpq_get_str(0, base, mp)); - return std::string(temp.str); - } - - // conversion functions - - // casting a reference to an mpz_t to mpz_class & is a dirty hack, - // but works because the internal representation of mpz_class is - // exactly an mpz_t - const mpz_class & get_num() const - { return reinterpret_cast(*mpq_numref(mp)); } - mpz_class & get_num() - { return reinterpret_cast(*mpq_numref(mp)); } - const mpz_class & get_den() const - { return reinterpret_cast(*mpq_denref(mp)); } - mpz_class & get_den() - { return reinterpret_cast(*mpq_denref(mp)); } - - mpq_srcptr __get_mp() const { return mp; } - mpq_ptr __get_mp() { return mp; } - mpq_srcptr get_mpq_t() const { return mp; } - mpq_ptr get_mpq_t() { return mp; } - - mpz_srcptr get_num_mpz_t() const { return mpq_numref(mp); } - mpz_ptr get_num_mpz_t() { return mpq_numref(mp); } - mpz_srcptr get_den_mpz_t() const { return mpq_denref(mp); } - mpz_ptr get_den_mpz_t() { return mpq_denref(mp); } - - double get_d() const { return mpq_get_d(mp); } - - // compound assignments - __GMP_DECLARE_COMPOUND_OPERATOR(operator+=) - __GMP_DECLARE_COMPOUND_OPERATOR(operator-=) - __GMP_DECLARE_COMPOUND_OPERATOR(operator*=) - __GMP_DECLARE_COMPOUND_OPERATOR(operator/=) - - __GMP_DECLARE_COMPOUND_OPERATOR_UI(operator<<=) - __GMP_DECLARE_COMPOUND_OPERATOR_UI(operator>>=) - - __GMP_DECLARE_INCREMENT_OPERATOR(operator++) - __GMP_DECLARE_INCREMENT_OPERATOR(operator--) -}; - -typedef __gmp_expr mpq_class; - - -/**************** mpf_class -- wrapper for mpf_t ****************/ - -template <> -class __gmp_expr -{ -private: - typedef mpf_t value_type; - value_type mp; -public: - mp_bitcnt_t get_prec() const { return mpf_get_prec(mp); } - - void set_prec(mp_bitcnt_t prec) { mpf_set_prec(mp, prec); } - void set_prec_raw(mp_bitcnt_t prec) { mpf_set_prec_raw(mp, prec); } - - // constructors and destructor - __gmp_expr() { mpf_init(mp); } - - __gmp_expr(const __gmp_expr &f) - { mpf_init2(mp, f.get_prec()); mpf_set(mp, f.mp); } - __gmp_expr(const __gmp_expr &f, mp_bitcnt_t prec) - { mpf_init2(mp, prec); mpf_set(mp, f.mp); } - template - __gmp_expr(const __gmp_expr &expr) - { mpf_init2(mp, expr.get_prec()); __gmp_set_expr(mp, expr); } - template - __gmp_expr(const __gmp_expr &expr, mp_bitcnt_t prec) - { mpf_init2(mp, prec); __gmp_set_expr(mp, expr); } - - __gmp_expr(signed char c) { mpf_init_set_si(mp, c); } - __gmp_expr(signed char c, mp_bitcnt_t prec) - { mpf_init2(mp, prec); mpf_set_si(mp, c); } - __gmp_expr(unsigned char c) { mpf_init_set_ui(mp, c); } - __gmp_expr(unsigned char c, mp_bitcnt_t prec) - { mpf_init2(mp, prec); mpf_set_ui(mp, c); } - - __gmp_expr(signed int i) { mpf_init_set_si(mp, i); } - __gmp_expr(signed int i, mp_bitcnt_t prec) - { mpf_init2(mp, prec); mpf_set_si(mp, i); } - __gmp_expr(unsigned int i) { mpf_init_set_ui(mp, i); } - __gmp_expr(unsigned int i, mp_bitcnt_t prec) - { mpf_init2(mp, prec); mpf_set_ui(mp, i); } - - __gmp_expr(signed short int s) { mpf_init_set_si(mp, s); } - __gmp_expr(signed short int s, mp_bitcnt_t prec) - { mpf_init2(mp, prec); mpf_set_si(mp, s); } - __gmp_expr(unsigned short int s) { mpf_init_set_ui(mp, s); } - __gmp_expr(unsigned short int s, mp_bitcnt_t prec) - { mpf_init2(mp, prec); mpf_set_ui(mp, s); } - - __gmp_expr(signed long int l) { mpf_init_set_si(mp, l); } - __gmp_expr(signed long int l, mp_bitcnt_t prec) - { mpf_init2(mp, prec); mpf_set_si(mp, l); } - __gmp_expr(unsigned long int l) { mpf_init_set_ui(mp, l); } - __gmp_expr(unsigned long int l, mp_bitcnt_t prec) - { mpf_init2(mp, prec); mpf_set_ui(mp, l); } - - __gmp_expr(float f) { mpf_init_set_d(mp, f); } - __gmp_expr(float f, mp_bitcnt_t prec) - { mpf_init2(mp, prec); mpf_set_d(mp, f); } - __gmp_expr(double d) { mpf_init_set_d(mp, d); } - __gmp_expr(double d, mp_bitcnt_t prec) - { mpf_init2(mp, prec); mpf_set_d(mp, d); } - // __gmp_expr(long double ld) { mpf_init_set_d(mp, ld); } - // __gmp_expr(long double ld, mp_bitcnt_t prec) - // { mpf_init2(mp, prec); mpf_set_d(mp, ld); } - - explicit __gmp_expr(const char *s) - { - if (mpf_init_set_str (mp, s, 0) != 0) - { - mpf_clear (mp); - throw std::invalid_argument ("mpf_set_str"); - } - } - __gmp_expr(const char *s, mp_bitcnt_t prec, int base = 0) - { - mpf_init2(mp, prec); - if (mpf_set_str(mp, s, base) != 0) - { - mpf_clear (mp); - throw std::invalid_argument ("mpf_set_str"); - } - } - explicit __gmp_expr(const std::string &s) - { - if (mpf_init_set_str(mp, s.c_str(), 0) != 0) - { - mpf_clear (mp); - throw std::invalid_argument ("mpf_set_str"); - } - } - __gmp_expr(const std::string &s, mp_bitcnt_t prec, int base = 0) - { - mpf_init2(mp, prec); - if (mpf_set_str(mp, s.c_str(), base) != 0) - { - mpf_clear (mp); - throw std::invalid_argument ("mpf_set_str"); - } - } - - explicit __gmp_expr(mpf_srcptr f) - { mpf_init2(mp, mpf_get_prec(f)); mpf_set(mp, f); } - __gmp_expr(mpf_srcptr f, mp_bitcnt_t prec) - { mpf_init2(mp, prec); mpf_set(mp, f); } - - ~__gmp_expr() { mpf_clear(mp); } - - // assignment operators - __gmp_expr & operator=(const __gmp_expr &f) - { mpf_set(mp, f.mp); return *this; } - template - __gmp_expr & operator=(const __gmp_expr &expr) - { __gmp_set_expr(mp, expr); return *this; } - - __gmp_expr & operator=(signed char c) { mpf_set_si(mp, c); return *this; } - __gmp_expr & operator=(unsigned char c) { mpf_set_ui(mp, c); return *this; } - - __gmp_expr & operator=(signed int i) { mpf_set_si(mp, i); return *this; } - __gmp_expr & operator=(unsigned int i) { mpf_set_ui(mp, i); return *this; } - - __gmp_expr & operator=(signed short int s) - { mpf_set_si(mp, s); return *this; } - __gmp_expr & operator=(unsigned short int s) - { mpf_set_ui(mp, s); return *this; } - - __gmp_expr & operator=(signed long int l) - { mpf_set_si(mp, l); return *this; } - __gmp_expr & operator=(unsigned long int l) - { mpf_set_ui(mp, l); return *this; } - - __gmp_expr & operator=(float f) { mpf_set_d(mp, f); return *this; } - __gmp_expr & operator=(double d) { mpf_set_d(mp, d); return *this; } - // __gmp_expr & operator=(long double ld) - // { mpf_set_ld(mp, ld); return *this; } - - __gmp_expr & operator=(const char *s) - { - if (mpf_set_str (mp, s, 0) != 0) - throw std::invalid_argument ("mpf_set_str"); - return *this; - } - __gmp_expr & operator=(const std::string &s) - { - if (mpf_set_str(mp, s.c_str(), 0) != 0) - throw std::invalid_argument ("mpf_set_str"); - return *this; - } - - // string input/output functions - int set_str(const char *s, int base) - { return mpf_set_str(mp, s, base); } - int set_str(const std::string &s, int base) - { return mpf_set_str(mp, s.c_str(), base); } - std::string get_str(mp_exp_t &expo, int base = 10, size_t size = 0) const - { - __gmp_alloc_cstring temp(mpf_get_str(0, &expo, base, size, mp)); - return std::string(temp.str); - } - - // conversion functions - mpf_srcptr __get_mp() const { return mp; } - mpf_ptr __get_mp() { return mp; } - mpf_srcptr get_mpf_t() const { return mp; } - mpf_ptr get_mpf_t() { return mp; } - - signed long int get_si() const { return mpf_get_si(mp); } - unsigned long int get_ui() const { return mpf_get_ui(mp); } - double get_d() const { return mpf_get_d(mp); } - - // bool fits_schar_p() const { return mpf_fits_schar_p(mp); } - // bool fits_uchar_p() const { return mpf_fits_uchar_p(mp); } - bool fits_sint_p() const { return mpf_fits_sint_p(mp); } - bool fits_uint_p() const { return mpf_fits_uint_p(mp); } - bool fits_sshort_p() const { return mpf_fits_sshort_p(mp); } - bool fits_ushort_p() const { return mpf_fits_ushort_p(mp); } - bool fits_slong_p() const { return mpf_fits_slong_p(mp); } - bool fits_ulong_p() const { return mpf_fits_ulong_p(mp); } - // bool fits_float_p() const { return mpf_fits_float_p(mp); } - // bool fits_double_p() const { return mpf_fits_double_p(mp); } - // bool fits_ldouble_p() const { return mpf_fits_ldouble_p(mp); } - - // compound assignments - __GMP_DECLARE_COMPOUND_OPERATOR(operator+=) - __GMP_DECLARE_COMPOUND_OPERATOR(operator-=) - __GMP_DECLARE_COMPOUND_OPERATOR(operator*=) - __GMP_DECLARE_COMPOUND_OPERATOR(operator/=) - - __GMP_DECLARE_COMPOUND_OPERATOR_UI(operator<<=) - __GMP_DECLARE_COMPOUND_OPERATOR_UI(operator>>=) - - __GMP_DECLARE_INCREMENT_OPERATOR(operator++) - __GMP_DECLARE_INCREMENT_OPERATOR(operator--) -}; - -typedef __gmp_expr mpf_class; - - - -/**************** I/O operators ****************/ - -// these should (and will) be provided separately - -template -inline std::ostream & operator<< -(std::ostream &o, const __gmp_expr &expr) -{ - return o << expr.__get_mp(); -} - -template -inline std::ostream & operator<< -(std::ostream &o, const __gmp_expr &expr) -{ - __gmp_expr temp(expr); - return o << temp.__get_mp(); -} - - -template -inline std::istream & operator>>(std::istream &i, __gmp_expr &expr) -{ - return i >> expr.__get_mp(); -} - -inline std::istream & operator>>(std::istream &i, mpq_class &q) -{ - i >> q.get_mpq_t(); - // q.canonicalize(); // you might want to uncomment this - return i; -} - - -/**************** Functions for type conversion ****************/ - -template <> -inline void __gmp_set_expr(mpz_ptr z, const mpz_class &w) -{ - mpz_set(z, w.get_mpz_t()); -} - -template -inline void __gmp_set_expr(mpz_ptr z, const __gmp_expr &expr) -{ - expr.eval(z); -} - -template <> -inline void __gmp_set_expr(mpz_ptr z, const mpq_class &q) -{ - mpz_set_q(z, q.get_mpq_t()); -} - -template -inline void __gmp_set_expr(mpz_ptr z, const __gmp_expr &expr) -{ - mpq_class temp(expr); - mpz_set_q(z, temp.get_mpq_t()); -} - -template -inline void __gmp_set_expr(mpz_ptr z, const mpf_class &f) -{ - mpz_set_f(z, f.get_mpf_t()); -} - -template -inline void __gmp_set_expr(mpz_ptr z, const __gmp_expr &expr) -{ - mpf_class temp(expr); - mpz_set_f(z, temp.get_mpf_t()); -} - -template <> -inline void __gmp_set_expr(mpq_ptr q, const mpz_class &z) -{ - mpq_set_z(q, z.get_mpz_t()); -} - -template -inline void __gmp_set_expr(mpq_ptr q, const __gmp_expr &expr) -{ - mpz_class temp(expr); - mpq_set_z(q, temp.get_mpz_t()); -} - -template <> -inline void __gmp_set_expr(mpq_ptr q, const mpq_class &r) -{ - mpq_set(q, r.get_mpq_t()); -} - -template -inline void __gmp_set_expr(mpq_ptr q, const __gmp_expr &expr) -{ - expr.eval(q); -} - -template -inline void __gmp_set_expr(mpq_ptr q, const mpf_class &f) -{ - mpq_set_f(q, f.get_mpf_t()); -} - -template -inline void __gmp_set_expr(mpq_ptr q, const __gmp_expr &expr) -{ - mpf_class temp(expr); - mpq_set_f(q, temp.get_mpf_t()); -} - -template -inline void __gmp_set_expr(mpf_ptr f, const mpz_class &z) -{ - mpf_set_z(f, z.get_mpz_t()); -} - -template -inline void __gmp_set_expr(mpf_ptr f, const __gmp_expr &expr) -{ - mpz_class temp(expr); - mpf_set_z(f, temp.get_mpz_t()); -} - -template -inline void __gmp_set_expr(mpf_ptr f, const mpq_class &q) -{ - mpf_set_q(f, q.get_mpq_t()); -} - -template -inline void __gmp_set_expr(mpf_ptr f, const __gmp_expr &expr) -{ - mpq_class temp(expr); - mpf_set_q(f, temp.get_mpq_t()); -} - -template <> -inline void __gmp_set_expr(mpf_ptr f, const mpf_class &g) -{ - mpf_set(f, g.get_mpf_t()); -} - -template -inline void __gmp_set_expr(mpf_ptr f, const __gmp_expr &expr) -{ - expr.eval(f, mpf_get_prec(f)); -} - - -/**************** Specializations of __gmp_expr ****************/ -/* The eval() method of __gmp_expr evaluates the corresponding - expression and assigns the result to its argument, which is either an - mpz_t, mpq_t, or mpf_t as specified by the T argument. - Compound expressions are evaluated recursively (temporaries are created - to hold intermediate values), while for simple expressions the eval() - method of the appropriate function object (available as the Op argument - of either __gmp_unary_expr or __gmp_binary_expr) is - called. */ - - -/**************** Unary expressions ****************/ -/* cases: - - simple: argument is mp*_class, that is, __gmp_expr - - compound: argument is __gmp_expr (with U not equal to T) */ - - -// simple expressions - -template -class __gmp_expr, Op> > -{ -private: - typedef __gmp_expr val_type; - - __gmp_unary_expr expr; -public: - __gmp_expr(const val_type &val) : expr(val) { } - void eval(typename __gmp_resolve_expr::ptr_type p, - unsigned long int = 0) const - { Op::eval(p, expr.val.__get_mp()); } - const val_type & get_val() const { return expr.val; } - unsigned long int get_prec() const { return expr.val.get_prec(); } -}; - - -// compound expressions - -template -class __gmp_expr, Op> > -{ -private: - typedef __gmp_expr val_type; - - __gmp_unary_expr expr; -public: - __gmp_expr(const val_type &val) : expr(val) { } - void eval(typename __gmp_resolve_expr::ptr_type p) const - { __gmp_expr temp(expr.val); Op::eval(p, temp.__get_mp()); } - void eval(typename __gmp_resolve_expr::ptr_type p, - mp_bitcnt_t prec) const - { __gmp_expr temp(expr.val, prec); Op::eval(p, temp.__get_mp()); } - const val_type & get_val() const { return expr.val; } - unsigned long int get_prec() const { return expr.val.get_prec(); } -}; - - -/**************** Binary expressions ****************/ -/* simple: - - arguments are both mp*_class - - one argument is mp*_class, one is a built-in type - compound: - - one is mp*_class, one is __gmp_expr - - one is __gmp_expr, one is built-in - - both arguments are __gmp_expr<...> */ - - -// simple expressions - -template -class __gmp_expr -, __gmp_expr, Op> > -{ -private: - typedef __gmp_expr val1_type; - typedef __gmp_expr val2_type; - - __gmp_binary_expr expr; -public: - __gmp_expr(const val1_type &val1, const val2_type &val2) - : expr(val1, val2) { } - void eval(typename __gmp_resolve_expr::ptr_type p, - unsigned long int = 0) const - { Op::eval(p, expr.val1.__get_mp(), expr.val2.__get_mp()); } - const val1_type & get_val1() const { return expr.val1; } - const val2_type & get_val2() const { return expr.val2; } - unsigned long int get_prec() const - { - mp_bitcnt_t prec1 = expr.val1.get_prec(), - prec2 = expr.val2.get_prec(); - return (prec1 > prec2) ? prec1 : prec2; - } -}; - - -// simple expressions, T is a built-in numerical type - -template -class __gmp_expr, U, Op> > -{ -private: - typedef __gmp_expr val1_type; - typedef U val2_type; - - __gmp_binary_expr expr; -public: - __gmp_expr(const val1_type &val1, const val2_type &val2) - : expr(val1, val2) { } - void eval(typename __gmp_resolve_expr::ptr_type p, - unsigned long int = 0) const - { Op::eval(p, expr.val1.__get_mp(), expr.val2); } - const val1_type & get_val1() const { return expr.val1; } - const val2_type & get_val2() const { return expr.val2; } - unsigned long int get_prec() const { return expr.val1.get_prec(); } -}; - -template -class __gmp_expr, Op> > -{ -private: - typedef U val1_type; - typedef __gmp_expr val2_type; - - __gmp_binary_expr expr; -public: - __gmp_expr(const val1_type &val1, const val2_type &val2) - : expr(val1, val2) { } - void eval(typename __gmp_resolve_expr::ptr_type p, - unsigned long int = 0) const - { Op::eval(p, expr.val1, expr.val2.__get_mp()); } - const val1_type & get_val1() const { return expr.val1; } - const val2_type & get_val2() const { return expr.val2; } - unsigned long int get_prec() const { return expr.val2.get_prec(); } -}; - - -// compound expressions, one argument is a subexpression - -template -class __gmp_expr -, __gmp_expr, Op> > -{ -private: - typedef __gmp_expr val1_type; - typedef __gmp_expr val2_type; - - __gmp_binary_expr expr; -public: - __gmp_expr(const val1_type &val1, const val2_type &val2) - : expr(val1, val2) { } - void eval(typename __gmp_resolve_expr::ptr_type p) const - { - __gmp_expr temp(expr.val2); - Op::eval(p, expr.val1.__get_mp(), temp.__get_mp()); - } - void eval(typename __gmp_resolve_expr::ptr_type p, - mp_bitcnt_t prec) const - { - __gmp_expr temp(expr.val2, prec); - Op::eval(p, expr.val1.__get_mp(), temp.__get_mp()); - } - const val1_type & get_val1() const { return expr.val1; } - const val2_type & get_val2() const { return expr.val2; } - unsigned long int get_prec() const - { - mp_bitcnt_t prec1 = expr.val1.get_prec(), - prec2 = expr.val2.get_prec(); - return (prec1 > prec2) ? prec1 : prec2; - } -}; - -template -class __gmp_expr -, __gmp_expr, Op> > -{ -private: - typedef __gmp_expr val1_type; - typedef __gmp_expr val2_type; - - __gmp_binary_expr expr; -public: - __gmp_expr(const val1_type &val1, const val2_type &val2) - : expr(val1, val2) { } - void eval(typename __gmp_resolve_expr::ptr_type p) const - { - __gmp_expr temp(expr.val1); - Op::eval(p, temp.__get_mp(), expr.val2.__get_mp()); - } - void eval(typename __gmp_resolve_expr::ptr_type p, - mp_bitcnt_t prec) const - { - __gmp_expr temp(expr.val1, prec); - Op::eval(p, temp.__get_mp(), expr.val2.__get_mp()); - } - const val1_type & get_val1() const { return expr.val1; } - const val2_type & get_val2() const { return expr.val2; } - unsigned long int get_prec() const - { - mp_bitcnt_t prec1 = expr.val1.get_prec(), - prec2 = expr.val2.get_prec(); - return (prec1 > prec2) ? prec1 : prec2; - } -}; - -template -class __gmp_expr -, __gmp_expr, Op> > -{ -private: - typedef __gmp_expr val1_type; - typedef __gmp_expr val2_type; - - __gmp_binary_expr expr; -public: - __gmp_expr(const val1_type &val1, const val2_type &val2) - : expr(val1, val2) { } - void eval(typename __gmp_resolve_expr::ptr_type p) const - { - __gmp_expr temp(expr.val2); - Op::eval(p, expr.val1.__get_mp(), temp.__get_mp()); - } - void eval(typename __gmp_resolve_expr::ptr_type p, - mp_bitcnt_t prec) const - { - __gmp_expr temp(expr.val2, prec); - Op::eval(p, expr.val1.__get_mp(), temp.__get_mp()); - } - const val1_type & get_val1() const { return expr.val1; } - const val2_type & get_val2() const { return expr.val2; } - unsigned long int get_prec() const - { - mp_bitcnt_t prec1 = expr.val1.get_prec(), - prec2 = expr.val2.get_prec(); - return (prec1 > prec2) ? prec1 : prec2; - } -}; - -template -class __gmp_expr -, __gmp_expr, Op> > -{ -private: - typedef __gmp_expr val1_type; - typedef __gmp_expr val2_type; - - __gmp_binary_expr expr; -public: - __gmp_expr(const val1_type &val1, const val2_type &val2) - : expr(val1, val2) { } - void eval(typename __gmp_resolve_expr::ptr_type p) const - { - __gmp_expr temp(expr.val1); - Op::eval(p, temp.__get_mp(), expr.val2.__get_mp()); - } - void eval(typename __gmp_resolve_expr::ptr_type p, - mp_bitcnt_t prec) const - { - __gmp_expr temp(expr.val1, prec); - Op::eval(p, temp.__get_mp(), expr.val2.__get_mp()); - } - const val1_type & get_val1() const { return expr.val1; } - const val2_type & get_val2() const { return expr.val2; } - unsigned long int get_prec() const - { - mp_bitcnt_t prec1 = expr.val1.get_prec(), - prec2 = expr.val2.get_prec(); - return (prec1 > prec2) ? prec1 : prec2; - } -}; - - -// one argument is a subexpression, one is a built-in - -template -class __gmp_expr, V, Op> > -{ -private: - typedef __gmp_expr val1_type; - typedef V val2_type; - - __gmp_binary_expr expr; -public: - __gmp_expr(const val1_type &val1, const val2_type &val2) - : expr(val1, val2) { } - void eval(typename __gmp_resolve_expr::ptr_type p) const - { - __gmp_expr temp(expr.val1); - Op::eval(p, temp.__get_mp(), expr.val2); - } - void eval(typename __gmp_resolve_expr::ptr_type p, - mp_bitcnt_t prec) const - { - __gmp_expr temp(expr.val1, prec); - Op::eval(p, temp.__get_mp(), expr.val2); - } - const val1_type & get_val1() const { return expr.val1; } - const val2_type & get_val2() const { return expr.val2; } - unsigned long int get_prec() const { return expr.val1.get_prec(); } -}; - -template -class __gmp_expr, Op> > -{ -private: - typedef U val1_type; - typedef __gmp_expr val2_type; - - __gmp_binary_expr expr; -public: - __gmp_expr(const val1_type &val1, const val2_type &val2) - : expr(val1, val2) { } - void eval(typename __gmp_resolve_expr::ptr_type p) const - { - __gmp_expr temp(expr.val2); - Op::eval(p, expr.val1, temp.__get_mp()); - } - void eval(typename __gmp_resolve_expr::ptr_type p, - mp_bitcnt_t prec) const - { - __gmp_expr temp(expr.val2, prec); - Op::eval(p, expr.val1, temp.__get_mp()); - } - const val1_type & get_val1() const { return expr.val1; } - const val2_type & get_val2() const { return expr.val2; } - unsigned long int get_prec() const { return expr.val2.get_prec(); } -}; - - -// both arguments are subexpressions - -template -class __gmp_expr -, __gmp_expr, Op> > -{ -private: - typedef __gmp_expr val1_type; - typedef __gmp_expr val2_type; - - __gmp_binary_expr expr; -public: - __gmp_expr(const val1_type &val1, const val2_type &val2) - : expr(val1, val2) { } - void eval(typename __gmp_resolve_expr::ptr_type p) const - { - __gmp_expr temp1(expr.val1), temp2(expr.val2); - Op::eval(p, temp1.__get_mp(), temp2.__get_mp()); - } - void eval(typename __gmp_resolve_expr::ptr_type p, - mp_bitcnt_t prec) const - { - __gmp_expr temp1(expr.val1, prec), temp2(expr.val2, prec); - Op::eval(p, temp1.__get_mp(), temp2.__get_mp()); - } - const val1_type & get_val1() const { return expr.val1; } - const val2_type & get_val2() const { return expr.val2; } - unsigned long int get_prec() const - { - mp_bitcnt_t prec1 = expr.val1.get_prec(), - prec2 = expr.val2.get_prec(); - return (prec1 > prec2) ? prec1 : prec2; - } -}; - -template -class __gmp_expr -, __gmp_expr, Op> > -{ -private: - typedef __gmp_expr val1_type; - typedef __gmp_expr val2_type; - - __gmp_binary_expr expr; -public: - __gmp_expr(const val1_type &val1, const val2_type &val2) - : expr(val1, val2) { } - void eval(typename __gmp_resolve_expr::ptr_type p) const - { - __gmp_expr temp1(expr.val1), temp2(expr.val2); - Op::eval(p, temp1.__get_mp(), temp2.__get_mp()); - } - void eval(typename __gmp_resolve_expr::ptr_type p, - mp_bitcnt_t prec) const - { - __gmp_expr temp1(expr.val1, prec), temp2(expr.val2, prec); - Op::eval(p, temp1.__get_mp(), temp2.__get_mp()); - } - const val1_type & get_val1() const { return expr.val1; } - const val2_type & get_val2() const { return expr.val2; } - unsigned long int get_prec() const - { - mp_bitcnt_t prec1 = expr.val1.get_prec(), - prec2 = expr.val2.get_prec(); - return (prec1 > prec2) ? prec1 : prec2; - } -}; - -template -class __gmp_expr -, __gmp_expr, Op> > -{ -private: - typedef __gmp_expr val1_type; - typedef __gmp_expr val2_type; - - __gmp_binary_expr expr; -public: - __gmp_expr(const val1_type &val1, const val2_type &val2) - : expr(val1, val2) { } - void eval(typename __gmp_resolve_expr::ptr_type p) const - { - __gmp_expr temp1(expr.val1), temp2(expr.val2); - Op::eval(p, temp1.__get_mp(), temp2.__get_mp()); - } - void eval(typename __gmp_resolve_expr::ptr_type p, - mp_bitcnt_t prec) const - { - __gmp_expr temp1(expr.val1, prec), temp2(expr.val2, prec); - Op::eval(p, temp1.__get_mp(), temp2.__get_mp()); - } - const val1_type & get_val1() const { return expr.val1; } - const val2_type & get_val2() const { return expr.val2; } - unsigned long int get_prec() const - { - mp_bitcnt_t prec1 = expr.val1.get_prec(), - prec2 = expr.val2.get_prec(); - return (prec1 > prec2) ? prec1 : prec2; - } -}; - - -/**************** Special cases ****************/ - -/* Some operations (i.e., add and subtract) with mixed mpz/mpq arguments - can be done directly without first converting the mpz to mpq. - Appropriate specializations of __gmp_expr are required. */ - - -#define __GMPZQ_DEFINE_EXPR(eval_fun) \ - \ -template <> \ -class __gmp_expr > \ -{ \ -private: \ - typedef mpz_class val1_type; \ - typedef mpq_class val2_type; \ - \ - __gmp_binary_expr expr; \ -public: \ - __gmp_expr(const val1_type &val1, const val2_type &val2) \ - : expr(val1, val2) { } \ - void eval(mpq_ptr q) const \ - { eval_fun::eval(q, expr.val1.get_mpz_t(), expr.val2.get_mpq_t()); } \ - const val1_type & get_val1() const { return expr.val1; } \ - const val2_type & get_val2() const { return expr.val2; } \ - unsigned long int get_prec() const { return mpf_get_default_prec(); } \ -}; \ - \ -template <> \ -class __gmp_expr > \ -{ \ -private: \ - typedef mpq_class val1_type; \ - typedef mpz_class val2_type; \ - \ - __gmp_binary_expr expr; \ -public: \ - __gmp_expr(const val1_type &val1, const val2_type &val2) \ - : expr(val1, val2) { } \ - void eval(mpq_ptr q) const \ - { eval_fun::eval(q, expr.val1.get_mpq_t(), expr.val2.get_mpz_t()); } \ - const val1_type & get_val1() const { return expr.val1; } \ - const val2_type & get_val2() const { return expr.val2; } \ - unsigned long int get_prec() const { return mpf_get_default_prec(); } \ -}; \ - \ -template \ -class __gmp_expr \ -, eval_fun> > \ -{ \ -private: \ - typedef mpz_class val1_type; \ - typedef __gmp_expr val2_type; \ - \ - __gmp_binary_expr expr; \ -public: \ - __gmp_expr(const val1_type &val1, const val2_type &val2) \ - : expr(val1, val2) { } \ - void eval(mpq_ptr q) const \ - { \ - mpq_class temp(expr.val2); \ - eval_fun::eval(q, expr.val1.get_mpz_t(), temp.get_mpq_t()); \ - } \ - const val1_type & get_val1() const { return expr.val1; } \ - const val2_type & get_val2() const { return expr.val2; } \ - unsigned long int get_prec() const { return mpf_get_default_prec(); } \ -}; \ - \ -template \ -class __gmp_expr \ -, eval_fun> > \ -{ \ -private: \ - typedef mpq_class val1_type; \ - typedef __gmp_expr val2_type; \ - \ - __gmp_binary_expr expr; \ -public: \ - __gmp_expr(const val1_type &val1, const val2_type &val2) \ - : expr(val1, val2) { } \ - void eval(mpq_ptr q) const \ - { \ - mpz_class temp(expr.val2); \ - eval_fun::eval(q, expr.val1.get_mpq_t(), temp.get_mpz_t()); \ - } \ - const val1_type & get_val1() const { return expr.val1; } \ - const val2_type & get_val2() const { return expr.val2; } \ - unsigned long int get_prec() const { return mpf_get_default_prec(); } \ -}; \ - \ -template \ -class __gmp_expr \ -, mpq_class, eval_fun> > \ -{ \ -private: \ - typedef __gmp_expr val1_type; \ - typedef mpq_class val2_type; \ - \ - __gmp_binary_expr expr; \ -public: \ - __gmp_expr(const val1_type &val1, const val2_type &val2) \ - : expr(val1, val2) { } \ - void eval(mpq_ptr q) const \ - { \ - mpz_class temp(expr.val1); \ - eval_fun::eval(q, temp.get_mpz_t(), expr.val2.get_mpq_t()); \ - } \ - const val1_type & get_val1() const { return expr.val1; } \ - const val2_type & get_val2() const { return expr.val2; } \ - unsigned long int get_prec() const { return mpf_get_default_prec(); } \ -}; \ - \ -template \ -class __gmp_expr \ -, mpz_class, eval_fun> > \ -{ \ -private: \ - typedef __gmp_expr val1_type; \ - typedef mpz_class val2_type; \ - \ - __gmp_binary_expr expr; \ -public: \ - __gmp_expr(const val1_type &val1, const val2_type &val2) \ - : expr(val1, val2) { } \ - void eval(mpq_ptr q) const \ - { \ - mpq_class temp(expr.val1); \ - eval_fun::eval(q, temp.get_mpq_t(), expr.val2.get_mpz_t()); \ - } \ - const val1_type & get_val1() const { return expr.val1; } \ - const val2_type & get_val2() const { return expr.val2; } \ - unsigned long int get_prec() const { return mpf_get_default_prec(); } \ -}; \ - \ -template \ -class __gmp_expr, __gmp_expr, eval_fun> > \ -{ \ -private: \ - typedef __gmp_expr val1_type; \ - typedef __gmp_expr val2_type; \ - \ - __gmp_binary_expr expr; \ -public: \ - __gmp_expr(const val1_type &val1, const val2_type &val2) \ - : expr(val1, val2) { } \ - void eval(mpq_ptr q) const \ - { \ - mpz_class temp1(expr.val1); \ - mpq_class temp2(expr.val2); \ - eval_fun::eval(q, temp1.get_mpz_t(), temp2.get_mpq_t()); \ - } \ - const val1_type & get_val1() const { return expr.val1; } \ - const val2_type & get_val2() const { return expr.val2; } \ - unsigned long int get_prec() const { return mpf_get_default_prec(); } \ -}; \ - \ -template \ -class __gmp_expr, __gmp_expr, eval_fun> > \ -{ \ -private: \ - typedef __gmp_expr val1_type; \ - typedef __gmp_expr val2_type; \ - \ - __gmp_binary_expr expr; \ -public: \ - __gmp_expr(const val1_type &val1, const val2_type &val2) \ - : expr(val1, val2) { } \ - void eval(mpq_ptr q) const \ - { \ - mpq_class temp1(expr.val1); \ - mpz_class temp2(expr.val2); \ - eval_fun::eval(q, temp1.get_mpq_t(), temp2.get_mpz_t()); \ - } \ - const val1_type & get_val1() const { return expr.val1; } \ - const val2_type & get_val2() const { return expr.val2; } \ - unsigned long int get_prec() const { return mpf_get_default_prec(); } \ -}; - - -__GMPZQ_DEFINE_EXPR(__gmp_binary_plus) -__GMPZQ_DEFINE_EXPR(__gmp_binary_minus) - -/**************** Macros for defining functions ****************/ -/* Results of operators and functions are instances of __gmp_expr. - T determines the numerical type of the expression: it can be either - mpz_t, mpq_t, or mpf_t. When the arguments of a binary - expression have different numerical types, __gmp_resolve_expr is used - to determine the "larger" type. - U is either __gmp_unary_expr or __gmp_binary_expr, - where V and W are the arguments' types -- they can in turn be - expressions, thus allowing to build compound expressions to any - degree of complexity. - Op is a function object that must have an eval() method accepting - appropriate arguments. - Actual evaluation of a __gmp_expr object is done when it gets - assigned to an mp*_class ("lazy" evaluation): this is done by calling - its eval() method. */ - - -// non-member unary operators and functions - -#define __GMP_DEFINE_UNARY_FUNCTION(fun, eval_fun) \ - \ -template \ -inline __gmp_expr, eval_fun> > \ -fun(const __gmp_expr &expr) \ -{ \ - return __gmp_expr, eval_fun> >(expr); \ -} - -#define __GMP_DEFINE_UNARY_TYPE_FUNCTION(type, fun, eval_fun) \ - \ -template \ -inline type fun(const __gmp_expr &expr) \ -{ \ - typename __gmp_resolve_temp::temp_type temp(expr); \ - return eval_fun::eval(temp.__get_mp()); \ -} - - -// non-member binary operators and functions - -#define __GMPP_DEFINE_BINARY_FUNCTION(fun, eval_fun) \ - \ -template \ -inline __gmp_expr::value_type, \ -__gmp_binary_expr<__gmp_expr, __gmp_expr, eval_fun> > \ -fun(const __gmp_expr &expr1, const __gmp_expr &expr2) \ -{ \ - return __gmp_expr::value_type, \ - __gmp_binary_expr<__gmp_expr, __gmp_expr, eval_fun> > \ - (expr1, expr2); \ -} - -#define __GMPNN_DEFINE_BINARY_FUNCTION(fun, eval_fun, type, bigtype) \ - \ -template \ -inline __gmp_expr \ -, bigtype, eval_fun> > \ -fun(const __gmp_expr &expr, type t) \ -{ \ - return __gmp_expr \ - , bigtype, eval_fun> >(expr, t); \ -} \ - \ -template \ -inline __gmp_expr \ -, eval_fun> > \ -fun(type t, const __gmp_expr &expr) \ -{ \ - return __gmp_expr \ - , eval_fun> >(t, expr); \ -} - -#define __GMPNS_DEFINE_BINARY_FUNCTION(fun, eval_fun, type) \ -__GMPNN_DEFINE_BINARY_FUNCTION(fun, eval_fun, type, signed long int) - -#define __GMPNU_DEFINE_BINARY_FUNCTION(fun, eval_fun, type) \ -__GMPNN_DEFINE_BINARY_FUNCTION(fun, eval_fun, type, unsigned long int) - -#define __GMPND_DEFINE_BINARY_FUNCTION(fun, eval_fun, type) \ -__GMPNN_DEFINE_BINARY_FUNCTION(fun, eval_fun, type, double) - -#define __GMPNLD_DEFINE_BINARY_FUNCTION(fun, eval_fun, type) \ -__GMPNN_DEFINE_BINARY_FUNCTION(fun, eval_fun, type, long double) - -#define __GMPN_DEFINE_BINARY_FUNCTION(fun, eval_fun) \ -__GMPNS_DEFINE_BINARY_FUNCTION(fun, eval_fun, signed char) \ -__GMPNU_DEFINE_BINARY_FUNCTION(fun, eval_fun, unsigned char) \ -__GMPNS_DEFINE_BINARY_FUNCTION(fun, eval_fun, signed int) \ -__GMPNU_DEFINE_BINARY_FUNCTION(fun, eval_fun, unsigned int) \ -__GMPNS_DEFINE_BINARY_FUNCTION(fun, eval_fun, signed short int) \ -__GMPNU_DEFINE_BINARY_FUNCTION(fun, eval_fun, unsigned short int) \ -__GMPNS_DEFINE_BINARY_FUNCTION(fun, eval_fun, signed long int) \ -__GMPNU_DEFINE_BINARY_FUNCTION(fun, eval_fun, unsigned long int) \ -__GMPND_DEFINE_BINARY_FUNCTION(fun, eval_fun, float) \ -__GMPND_DEFINE_BINARY_FUNCTION(fun, eval_fun, double) \ -__GMPNLD_DEFINE_BINARY_FUNCTION(fun, eval_fun, long double) - -#define __GMP_DEFINE_BINARY_FUNCTION(fun, eval_fun) \ -__GMPP_DEFINE_BINARY_FUNCTION(fun, eval_fun) \ -__GMPN_DEFINE_BINARY_FUNCTION(fun, eval_fun) - - -#define __GMP_DEFINE_BINARY_FUNCTION_UI(fun, eval_fun) \ - \ -template \ -inline __gmp_expr \ -, unsigned long int, eval_fun> > \ -fun(const __gmp_expr &expr, unsigned long int l) \ -{ \ - return __gmp_expr, unsigned long int, eval_fun> >(expr, l); \ -} - - -#define __GMPP_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun) \ - \ -template \ -inline type fun(const __gmp_expr &expr1, \ - const __gmp_expr &expr2) \ -{ \ - typedef typename __gmp_resolve_expr::value_type eval_type; \ - typename __gmp_resolve_temp::temp_type temp1(expr1); \ - typename __gmp_resolve_temp::temp_type temp2(expr2); \ - return eval_fun::eval(temp1.__get_mp(), temp2.__get_mp()); \ -} - -#define __GMPNN_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, \ - type2, bigtype) \ - \ -template \ -inline type fun(const __gmp_expr &expr, type2 t) \ -{ \ - typename __gmp_resolve_temp::temp_type temp(expr); \ - return eval_fun::eval(temp.__get_mp(), static_cast(t)); \ -} \ - \ -template \ -inline type fun(type2 t, const __gmp_expr &expr) \ -{ \ - typename __gmp_resolve_temp::temp_type temp(expr); \ - return eval_fun::eval(static_cast(t), temp.__get_mp()); \ -} - -#define __GMPNS_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, type2) \ -__GMPNN_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, \ - type2, signed long int) - -#define __GMPNU_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, type2) \ -__GMPNN_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, \ - type2, unsigned long int) - -#define __GMPND_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, type2) \ -__GMPNN_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, type2, double) - -#define __GMPNLD_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, type2) \ -__GMPNN_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, type2, long double) - -#define __GMPN_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun) \ -__GMPNS_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, signed char) \ -__GMPNU_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, unsigned char) \ -__GMPNS_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, signed int) \ -__GMPNU_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, unsigned int) \ -__GMPNS_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, signed short int) \ -__GMPNU_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, unsigned short int) \ -__GMPNS_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, signed long int) \ -__GMPNU_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, unsigned long int) \ -__GMPND_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, float) \ -__GMPND_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, double) \ -__GMPNLD_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, long double) - -#define __GMP_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun) \ -__GMPP_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun) \ -__GMPN_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun) - - -// member operators - -#define __GMPP_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun) \ - \ -template \ -inline type##_class & type##_class::fun(const __gmp_expr &expr) \ -{ \ - __gmp_set_expr(mp, __gmp_expr, eval_fun> >(*this, expr)); \ - return *this; \ -} - -#define __GMPNN_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, \ - type2, bigtype) \ - \ -inline type##_class & type##_class::fun(type2 t) \ -{ \ - __gmp_set_expr(mp, __gmp_expr >(*this, t)); \ - return *this; \ -} - -#define __GMPNS_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, type2) \ -__GMPNN_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, \ - type2, signed long int) - -#define __GMPNU_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, type2) \ -__GMPNN_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, \ - type2, unsigned long int) - -#define __GMPND_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, type2) \ -__GMPNN_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, type2, double) - -#define __GMPNLD_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, type2) \ -__GMPNN_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, type2, long double) - -#define __GMPN_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun) \ -__GMPNS_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, signed char) \ -__GMPNU_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, unsigned char) \ -__GMPNS_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, signed int) \ -__GMPNU_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, unsigned int) \ -__GMPNS_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, signed short int) \ -__GMPNU_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, unsigned short int) \ -__GMPNS_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, signed long int) \ -__GMPNU_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, unsigned long int) \ -__GMPND_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, float) \ -__GMPND_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, double) \ -/* __GMPNLD_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, long double) */ - -#define __GMP_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun) \ -__GMPP_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun) \ -__GMPN_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun) - -#define __GMPZ_DEFINE_COMPOUND_OPERATOR(fun, eval_fun) \ -__GMP_DEFINE_COMPOUND_OPERATOR(mpz, fun, eval_fun) - -#define __GMPZZ_DEFINE_COMPOUND_OPERATOR(fun, eval_fun) \ -__GMPP_DEFINE_COMPOUND_OPERATOR(mpz, fun, eval_fun) - -#define __GMPQ_DEFINE_COMPOUND_OPERATOR(fun, eval_fun) \ -__GMP_DEFINE_COMPOUND_OPERATOR(mpq, fun, eval_fun) - -#define __GMPF_DEFINE_COMPOUND_OPERATOR(fun, eval_fun) \ -__GMP_DEFINE_COMPOUND_OPERATOR(mpf, fun, eval_fun) - - - -#define __GMP_DEFINE_COMPOUND_OPERATOR_UI(type, fun, eval_fun) \ - \ -inline type##_class & type##_class::fun(unsigned long int l) \ -{ \ - __gmp_set_expr(mp, __gmp_expr >(*this, l)); \ - return *this; \ -} - -#define __GMPZ_DEFINE_COMPOUND_OPERATOR_UI(fun, eval_fun) \ -__GMP_DEFINE_COMPOUND_OPERATOR_UI(mpz, fun, eval_fun) - -#define __GMPQ_DEFINE_COMPOUND_OPERATOR_UI(fun, eval_fun) \ -__GMP_DEFINE_COMPOUND_OPERATOR_UI(mpq, fun, eval_fun) - -#define __GMPF_DEFINE_COMPOUND_OPERATOR_UI(fun, eval_fun) \ -__GMP_DEFINE_COMPOUND_OPERATOR_UI(mpf, fun, eval_fun) - - - -#define __GMP_DEFINE_INCREMENT_OPERATOR(type, fun, eval_fun) \ - \ -inline type##_class & type##_class::fun() \ -{ \ - eval_fun::eval(mp); \ - return *this; \ -} \ - \ -inline type##_class type##_class::fun(int) \ -{ \ - type##_class temp(*this); \ - eval_fun::eval(mp); \ - return temp; \ -} - -#define __GMPZ_DEFINE_INCREMENT_OPERATOR(fun, eval_fun) \ -__GMP_DEFINE_INCREMENT_OPERATOR(mpz, fun, eval_fun) - -#define __GMPQ_DEFINE_INCREMENT_OPERATOR(fun, eval_fun) \ -__GMP_DEFINE_INCREMENT_OPERATOR(mpq, fun, eval_fun) - -#define __GMPF_DEFINE_INCREMENT_OPERATOR(fun, eval_fun) \ -__GMP_DEFINE_INCREMENT_OPERATOR(mpf, fun, eval_fun) - - - -/**************** Arithmetic operators and functions ****************/ - -// non-member operators and functions - -__GMP_DEFINE_UNARY_FUNCTION(operator+, __gmp_unary_plus) -__GMP_DEFINE_UNARY_FUNCTION(operator-, __gmp_unary_minus) -__GMP_DEFINE_UNARY_FUNCTION(operator~, __gmp_unary_com) - -__GMP_DEFINE_BINARY_FUNCTION(operator+, __gmp_binary_plus) -__GMP_DEFINE_BINARY_FUNCTION(operator-, __gmp_binary_minus) -__GMP_DEFINE_BINARY_FUNCTION(operator*, __gmp_binary_multiplies) -__GMP_DEFINE_BINARY_FUNCTION(operator/, __gmp_binary_divides) -__GMP_DEFINE_BINARY_FUNCTION(operator%, __gmp_binary_modulus) -__GMP_DEFINE_BINARY_FUNCTION(operator&, __gmp_binary_and) -__GMP_DEFINE_BINARY_FUNCTION(operator|, __gmp_binary_ior) -__GMP_DEFINE_BINARY_FUNCTION(operator^, __gmp_binary_xor) - -__GMP_DEFINE_BINARY_FUNCTION_UI(operator<<, __gmp_binary_lshift) -__GMP_DEFINE_BINARY_FUNCTION_UI(operator>>, __gmp_binary_rshift) - -__GMP_DEFINE_BINARY_TYPE_FUNCTION(bool, operator==, __gmp_binary_equal) -__GMP_DEFINE_BINARY_TYPE_FUNCTION(bool, operator!=, __gmp_binary_not_equal) -__GMP_DEFINE_BINARY_TYPE_FUNCTION(bool, operator<, __gmp_binary_less) -__GMP_DEFINE_BINARY_TYPE_FUNCTION(bool, operator<=, __gmp_binary_less_equal) -__GMP_DEFINE_BINARY_TYPE_FUNCTION(bool, operator>, __gmp_binary_greater) -__GMP_DEFINE_BINARY_TYPE_FUNCTION(bool, operator>=, \ - __gmp_binary_greater_equal) - -__GMP_DEFINE_UNARY_FUNCTION(abs, __gmp_abs_function) -__GMP_DEFINE_UNARY_FUNCTION(trunc, __gmp_trunc_function) -__GMP_DEFINE_UNARY_FUNCTION(floor, __gmp_floor_function) -__GMP_DEFINE_UNARY_FUNCTION(ceil, __gmp_ceil_function) -__GMP_DEFINE_UNARY_FUNCTION(sqrt, __gmp_sqrt_function) -__GMP_DEFINE_BINARY_FUNCTION(hypot, __gmp_hypot_function) - -__GMP_DEFINE_UNARY_TYPE_FUNCTION(int, sgn, __gmp_sgn_function) -__GMP_DEFINE_BINARY_TYPE_FUNCTION(int, cmp, __gmp_cmp_function) - -// member operators for mpz_class - -__GMPZ_DEFINE_COMPOUND_OPERATOR(operator+=, __gmp_binary_plus) -__GMPZ_DEFINE_COMPOUND_OPERATOR(operator-=, __gmp_binary_minus) -__GMPZ_DEFINE_COMPOUND_OPERATOR(operator*=, __gmp_binary_multiplies) -__GMPZ_DEFINE_COMPOUND_OPERATOR(operator/=, __gmp_binary_divides) -__GMPZ_DEFINE_COMPOUND_OPERATOR(operator%=, __gmp_binary_modulus) - -__GMPZZ_DEFINE_COMPOUND_OPERATOR(operator&=, __gmp_binary_and) -__GMPZZ_DEFINE_COMPOUND_OPERATOR(operator|=, __gmp_binary_ior) -__GMPZZ_DEFINE_COMPOUND_OPERATOR(operator^=, __gmp_binary_xor) - -__GMPZ_DEFINE_COMPOUND_OPERATOR_UI(operator<<=, __gmp_binary_lshift) -__GMPZ_DEFINE_COMPOUND_OPERATOR_UI(operator>>=, __gmp_binary_rshift) - -__GMPZ_DEFINE_INCREMENT_OPERATOR(operator++, __gmp_unary_increment) -__GMPZ_DEFINE_INCREMENT_OPERATOR(operator--, __gmp_unary_decrement) - -// member operators for mpq_class - -__GMPQ_DEFINE_COMPOUND_OPERATOR(operator+=, __gmp_binary_plus) -__GMPQ_DEFINE_COMPOUND_OPERATOR(operator-=, __gmp_binary_minus) -__GMPQ_DEFINE_COMPOUND_OPERATOR(operator*=, __gmp_binary_multiplies) -__GMPQ_DEFINE_COMPOUND_OPERATOR(operator/=, __gmp_binary_divides) - -__GMPQ_DEFINE_COMPOUND_OPERATOR_UI(operator<<=, __gmp_binary_lshift) -__GMPQ_DEFINE_COMPOUND_OPERATOR_UI(operator>>=, __gmp_binary_rshift) - -__GMPQ_DEFINE_INCREMENT_OPERATOR(operator++, __gmp_unary_increment) -__GMPQ_DEFINE_INCREMENT_OPERATOR(operator--, __gmp_unary_decrement) - -// member operators for mpf_class - -__GMPF_DEFINE_COMPOUND_OPERATOR(operator+=, __gmp_binary_plus) -__GMPF_DEFINE_COMPOUND_OPERATOR(operator-=, __gmp_binary_minus) -__GMPF_DEFINE_COMPOUND_OPERATOR(operator*=, __gmp_binary_multiplies) -__GMPF_DEFINE_COMPOUND_OPERATOR(operator/=, __gmp_binary_divides) - -__GMPF_DEFINE_COMPOUND_OPERATOR_UI(operator<<=, __gmp_binary_lshift) -__GMPF_DEFINE_COMPOUND_OPERATOR_UI(operator>>=, __gmp_binary_rshift) - -__GMPF_DEFINE_INCREMENT_OPERATOR(operator++, __gmp_unary_increment) -__GMPF_DEFINE_INCREMENT_OPERATOR(operator--, __gmp_unary_decrement) - - - -/**************** Class wrapper for gmp_randstate_t ****************/ - -class __gmp_urandomb_value { }; -class __gmp_urandomm_value { }; - -template <> -class __gmp_expr -{ -private: - __gmp_randstate_struct *state; - unsigned long int bits; -public: - __gmp_expr(gmp_randstate_t s, unsigned long int l) : state(s), bits(l) { } - void eval(mpz_ptr z) const { __gmp_rand_function::eval(z, state, bits); } - unsigned long int get_prec() const { return mpf_get_default_prec(); } -}; - -template <> -class __gmp_expr -{ -private: - __gmp_randstate_struct *state; - mpz_class range; -public: - __gmp_expr(gmp_randstate_t s, const mpz_class &z) : state(s), range(z) { } - void eval(mpz_ptr z) const - { __gmp_rand_function::eval(z, state, range.get_mpz_t()); } - unsigned long int get_prec() const { return mpf_get_default_prec(); } -}; - -template <> -class __gmp_expr -{ -private: - __gmp_randstate_struct *state; - unsigned long int bits; -public: - __gmp_expr(gmp_randstate_t s, unsigned long int l) : state(s), bits(l) { } - void eval(mpf_ptr f, mp_bitcnt_t prec) const - { __gmp_rand_function::eval(f, state, (bits>0) ? get_prec() : prec); } - unsigned long int get_prec() const - { - if (bits == 0) - return mpf_get_default_prec(); - else - return bits; - } -}; - -extern "C" { - typedef void __gmp_randinit_default_t (gmp_randstate_t); - typedef void __gmp_randinit_lc_2exp_t (gmp_randstate_t, mpz_srcptr, unsigned long int, mp_bitcnt_t); - typedef int __gmp_randinit_lc_2exp_size_t (gmp_randstate_t, mp_bitcnt_t); -} - -class gmp_randclass -{ -private: - gmp_randstate_t state; - - // copy construction and assignment not allowed - gmp_randclass(const gmp_randclass &); - void operator=(const gmp_randclass &); -public: - // constructors and destructor - gmp_randclass(gmp_randalg_t alg, unsigned long int size) - { - switch (alg) - { - case GMP_RAND_ALG_LC: // no other cases for now - default: - gmp_randinit_lc_2exp_size(state, size); - break; - } - } - - // gmp_randinit_default - gmp_randclass(__gmp_randinit_default_t* f) { f(state); } - - // gmp_randinit_lc_2exp - gmp_randclass(__gmp_randinit_lc_2exp_t* f, - mpz_class z, unsigned long int l1, unsigned long int l2) - { f(state, z.get_mpz_t(), l1, l2); } - - // gmp_randinit_lc_2exp_size - gmp_randclass(__gmp_randinit_lc_2exp_size_t* f, - unsigned long int size) - { - if (f (state, size) == 0) - throw std::length_error ("gmp_randinit_lc_2exp_size"); - } - - ~gmp_randclass() { gmp_randclear(state); } - - // initialize - void seed(); // choose a random seed some way (?) - void seed(unsigned long int s) { gmp_randseed_ui(state, s); } - void seed(const mpz_class &z) { gmp_randseed(state, z.get_mpz_t()); } - - // get random number - __gmp_expr get_z_bits(unsigned long int l) - { return __gmp_expr(state, l); } - __gmp_expr get_z_bits(const mpz_class &z) - { return get_z_bits(z.get_ui()); } - - __gmp_expr get_z_range(const mpz_class &z) - { return __gmp_expr(state, z); } - - __gmp_expr get_f(unsigned long int prec = 0) - { return __gmp_expr(state, prec); } -}; - - -/**************** #undef all private macros ****************/ - -#undef __GMPP_DECLARE_COMPOUND_OPERATOR -#undef __GMPN_DECLARE_COMPOUND_OPERATOR -#undef __GMP_DECLARE_COMPOUND_OPERATOR -#undef __GMP_DECLARE_COMPOUND_OPERATOR_UI -#undef __GMP_DECLARE_INCREMENT_OPERATOR - -#undef __GMPZQ_DEFINE_EXPR -#undef __GMP_DEFINE_TERNARY_EXPR - -#undef __GMP_DEFINE_UNARY_FUNCTION -#undef __GMP_DEFINE_UNARY_TYPE_FUNCTION - -#undef __GMPP_DEFINE_BINARY_FUNCTION -#undef __GMPNN_DEFINE_BINARY_FUNCTION -#undef __GMPNS_DEFINE_BINARY_FUNCTION -#undef __GMPNU_DEFINE_BINARY_FUNCTION -#undef __GMPND_DEFINE_BINARY_FUNCTION -#undef __GMPNLD_DEFINE_BINARY_FUNCTION -#undef __GMPN_DEFINE_BINARY_FUNCTION -#undef __GMP_DEFINE_BINARY_FUNCTION - -#undef __GMP_DEFINE_BINARY_FUNCTION_UI - -#undef __GMPP_DEFINE_BINARY_TYPE_FUNCTION -#undef __GMPNN_DEFINE_BINARY_TYPE_FUNCTION -#undef __GMPNS_DEFINE_BINARY_TYPE_FUNCTION -#undef __GMPNU_DEFINE_BINARY_TYPE_FUNCTION -#undef __GMPND_DEFINE_BINARY_TYPE_FUNCTION -#undef __GMPNLD_DEFINE_BINARY_TYPE_FUNCTION -#undef __GMPN_DEFINE_BINARY_TYPE_FUNCTION -#undef __GMP_DEFINE_BINARY_TYPE_FUNCTION - -#undef __GMPP_DECLARE_COMPOUND_OPERATOR -#undef __GMPN_DECLARE_COMPOUND_OPERATOR -#undef __GMP_DECLARE_COMPOUND_OPERATOR - -#undef __GMP_DECLARE_COMPOUND_OPERATOR_UI -#undef __GMP_DECLARE_INCREMENT_OPERATOR - -#undef __GMPZ_DEFINE_COMPOUND_OPERATOR -#undef __GMPZZ_DEFINE_COMPOUND_OPERATOR -#undef __GMPZN_DEFINE_COMPOUND_OPERATOR -#undef __GMPZNN_DEFINE_COMPOUND_OPERATOR -#undef __GMPZNS_DEFINE_COMPOUND_OPERATOR -#undef __GMPZNU_DEFINE_COMPOUND_OPERATOR -#undef __GMPZND_DEFINE_COMPOUND_OPERATOR -#undef __GMPZNLD_DEFINE_COMPOUND_OPERATOR - -#undef __GMPP_DEFINE_COMPOUND_OPERATOR -#undef __GMPNN_DEFINE_COMPOUND_OPERATOR -#undef __GMPNS_DEFINE_COMPOUND_OPERATOR -#undef __GMPNU_DEFINE_COMPOUND_OPERATOR -#undef __GMPND_DEFINE_COMPOUND_OPERATOR -#undef __GMPNLD_DEFINE_COMPOUND_OPERATOR -#undef __GMPN_DEFINE_COMPOUND_OPERATOR -#undef __GMP_DEFINE_COMPOUND_OPERATOR - -#undef __GMPZ_DEFINE_COMPOUND_OPERATOR -#undef __GMPZZ_DEFINE_COMPOUND_OPERATOR -#undef __GMPQ_DEFINE_COMPOUND_OPERATOR -#undef __GMPF_DEFINE_COMPOUND_OPERATOR - -#undef __GMP_DEFINE_COMPOUND_OPERATOR_UI -#undef __GMPZ_DEFINE_COMPOUND_OPERATOR_UI -#undef __GMPQ_DEFINE_COMPOUND_OPERATOR_UI -#undef __GMPF_DEFINE_COMPOUND_OPERATOR_UI - -#undef __GMP_DEFINE_INCREMENT_OPERATOR -#undef __GMPZ_DEFINE_INCREMENT_OPERATOR -#undef __GMPQ_DEFINE_INCREMENT_OPERATOR -#undef __GMPF_DEFINE_INCREMENT_OPERATOR - -#endif /* __GMP_PLUSPLUS__ */ diff --git a/src/external/inc/win32-msvc/mpir-2.2.1_x64/mpir.h b/src/external/inc/win32-msvc/mpir-2.2.1_x64/mpir.h deleted file mode 100644 index b4521bede..000000000 --- a/src/external/inc/win32-msvc/mpir-2.2.1_x64/mpir.h +++ /dev/null @@ -1,1842 +0,0 @@ -/* generated from gmp-h.in by gen_mpir_h.bat */ -/* Definitions for GNU multiple precision functions. -*- mode: c -*- -Copyright 1991, 1993, 1994, 1995, 1996, 1997, 1999, 2000, 2001, 2002, 2003, -2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc. -Copyright 2008 William Hart, Gonzalo Tornaria -This file is part of the MPIR Library. -The MPIR Library is free software; you can redistribute it and/or modify -it under the terms of the GNU Lesser General Public License as published by -the Free Software Foundation; either version 3 of the License, or (at your -option) any later version. -The MPIR Library is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public -License for more details. -You should have received a copy of the GNU Lesser General Public License -along with the GNU MP Library. If not, see http://www.gnu.org/licenses/. */ -#ifndef __GMP_H__ -#if defined (__cplusplus) -#include /* for std::istream, std::ostream, std::string */ -#include -#endif -/* Instantiated by configure. */ -#if ! defined (__GMP_WITHIN_CONFIGURE) -#define __GMP_BITS_PER_MP_LIMB 64 -#define GMP_LIMB_BITS 64 -#define GMP_NAIL_BITS 0 -#define SIZEOF_MP_LIMB_T (GMP_LIMB_BITS >> 3) -#if !defined _LONG_LONG_LIMB -# define _LONG_LONG_LIMB 1 -#endif -#endif -#define GMP_NUMB_BITS (GMP_LIMB_BITS - GMP_NAIL_BITS) -#define GMP_NUMB_MASK ((~ __GMP_CAST (mp_limb_t, 0)) >> GMP_NAIL_BITS) -#define GMP_NUMB_MAX GMP_NUMB_MASK -#define GMP_NAIL_MASK (~ GMP_NUMB_MASK) -/* The following (everything under ifndef __GNU_MP__) must be identical in - mpir.h and mp.h to allow both to be included in an application or during - the library build. */ -#ifndef __GNU_MP__ -#define __GNU_MP__ 4 -#define __need_size_t /* tell gcc stddef.h we only want size_t */ -#if defined (__cplusplus) -#include /* for size_t */ -#else -#include /* for size_t */ -#endif -#undef __need_size_t -/* Instantiated by configure. */ -#if ! defined (__GMP_WITHIN_CONFIGURE) -#endif -/* #if defined(__GMP_WITHIN_CONFIGURE) && defined(_WIN64) */ -#ifdef __WIN64 -#define _LONG_LONG_LIMB 1 -#endif -/* __STDC__ - some ANSI compilers define this only to 0, hence the use of - "defined" and not "__STDC__-0". In particular Sun workshop C 5.0 - sets __STDC__ to 0, but requires "##" for token pasting. - _AIX - gnu ansidecl.h asserts that all known AIX compilers are ANSI but - don't always define __STDC__. - __DECC - current versions of DEC C (5.9 for instance) for alpha are ANSI, - but don't define __STDC__ in their default mode. Don't know if old - versions might have been K&R, but let's not worry about that unless - someone is still using one. - _mips - gnu ansidecl.h says the RISC/OS MIPS compiler is ANSI in SVR4 - mode, but doesn't define __STDC__. - _MSC_VER - Microsoft C is ANSI, but __STDC__ is undefined unless the /Za - option is given (in which case it's 1). - _WIN32 - tested for by gnu ansidecl.h, no doubt on the assumption that - all w32 compilers are ansi. - Note: This same set of tests is used by gen-psqr.c and - demos/expr/expr-impl.h, so if anything needs adding, then be sure to - update those too. */ -#if defined (__STDC__) \ - || defined (__cplusplus) \ - || defined (_AIX) \ - || defined (__DECC) \ - || (defined (__mips) && defined (_SYSTYPE_SVR4)) \ - || defined (_MSC_VER) \ - || defined (_WIN32) -#define __GMP_HAVE_CONST 1 -#define __GMP_HAVE_PROTOTYPES 1 -#define __GMP_HAVE_TOKEN_PASTE 1 -#else -#define __GMP_HAVE_CONST 0 -#define __GMP_HAVE_PROTOTYPES 0 -#define __GMP_HAVE_TOKEN_PASTE 0 -#endif -#if __GMP_HAVE_CONST -#define __gmp_const const -#define __gmp_signed signed -#else -#define __gmp_const -#define __gmp_signed -#endif -/* __GMP_DECLSPEC supports Windows DLL versions of libmpir, and is empty in - all other circumstances. - When compiling objects for libmpir, __GMP_DECLSPEC is an export directive, - or when compiling for an application it's an import directive. The two - cases are differentiated by __GMP_WITHIN_GMP defined by the GMP Makefiles - (and not defined from an application). - __GMP_DECLSPEC_XX is similarly used for libmpirxx. __GMP_WITHIN_GMPXX - indicates when building libmpirxx, and in that case libmpirxx functions are - exports, but libmpir functions which might get called are imports. - libmp.la uses __GMP_DECLSPEC, just as if it were libmpir.la. libmpir and - libmp don't call each other, so there's no conflict or confusion. - Libtool DLL_EXPORT define is not used. - There's no attempt to support GMP built both static and DLL. Doing so - would mean applications would have to tell us which of the two is going - to be used when linking, and that seems very tedious and error prone if - using GMP by hand, and equally tedious from a package since autoconf and - automake don't give much help. - __GMP_DECLSPEC is required on all documented global functions and - variables, the various internals in gmp-impl.h etc can be left unadorned. - But internals used by the test programs or speed measuring programs - should have __GMP_DECLSPEC, and certainly constants or variables must - have it or the wrong address will be resolved. - In gcc __declspec can go at either the start or end of a prototype. - In Microsoft C __declspec must go at the start, or after the type like - void __declspec(...) *foo()". There's no __dllexport or anything to - guard against someone foolish #defining dllexport. _export used to be - available, but no longer. - In Borland C _export still exists, but needs to go after the type, like - "void _export foo();". Would have to change the __GMP_DECLSPEC syntax to - make use of that. Probably more trouble than it's worth. */ -#if defined (__GNUC__) -#define __GMP_DECLSPEC_EXPORT __declspec(__dllexport__) -#define __GMP_DECLSPEC_IMPORT __declspec(__dllimport__) -#endif -#if defined (_MSC_VER) || defined (__BORLANDC__) -#define __GMP_DECLSPEC_EXPORT __declspec(dllexport) -#define __GMP_DECLSPEC_IMPORT __declspec(dllimport) -#endif -#ifdef __WATCOMC__ -#define __GMP_DECLSPEC_EXPORT __export -#define __GMP_DECLSPEC_IMPORT __import -#endif -#ifdef __IBMC__ -#define __GMP_DECLSPEC_EXPORT _Export -#define __GMP_DECLSPEC_IMPORT _Import -#endif -#if __GMP_LIBGMP_DLL -#if __GMP_WITHIN_GMP -/* compiling to go into a DLL libmpir */ -#define __GMP_DECLSPEC __GMP_DECLSPEC_EXPORT -#else -/* compiling to go into an application which will link to a DLL libmpir */ -#define __GMP_DECLSPEC __GMP_DECLSPEC_IMPORT -#endif -#else -/* all other cases */ -#define __GMP_DECLSPEC -#endif -#ifdef __GMP_SHORT_LIMB -typedef unsigned int mp_limb_t; -typedef int mp_limb_signed_t; -#else -#ifdef _LONG_LONG_LIMB -typedef unsigned long long int mp_limb_t; -typedef long long int mp_limb_signed_t; -#else -typedef unsigned long int mp_limb_t; -typedef long int mp_limb_signed_t; -#endif -#endif -#ifdef _WIN64 -typedef unsigned long long int mp_bitcnt_t; -#else -typedef unsigned long int mp_bitcnt_t; -#endif -/* For reference, note that the name __mpz_struct gets into C++ mangled - function names, which means although the "__" suggests an internal, we - must leave this name for binary compatibility. */ -typedef struct -{ - int _mp_alloc; /* Number of *limbs* allocated and pointed - to by the _mp_d field. */ - int _mp_size; /* abs(_mp_size) is the number of limbs the - last field points to. If _mp_size is - negative this is a negative number. */ - mp_limb_t *_mp_d; /* Pointer to the limbs. */ -} __mpz_struct; -#endif /* __GNU_MP__ */ -typedef __mpz_struct mpz_t[1]; -typedef mp_limb_t * mp_ptr; -typedef __gmp_const mp_limb_t * mp_srcptr; -#if defined( _WIN64) -#define __GMP_MP_SIZE_T_INT 0 -typedef long long int mp_size_t; -typedef long int mp_exp_t; -#else -#define __GMP_MP_SIZE_T_INT 0 -typedef long int mp_size_t; -typedef long int mp_exp_t; -#endif -typedef struct -{ - __mpz_struct _mp_num; - __mpz_struct _mp_den; -} __mpq_struct; -typedef __mpq_struct mpq_t[1]; -typedef struct -{ - int _mp_prec; /* Max precision, in number of `mp_limb_t's. - Set by mpf_init and modified by - mpf_set_prec. The area pointed to by the - _mp_d field contains `prec' + 1 limbs. */ - int _mp_size; /* abs(_mp_size) is the number of limbs the - last field points to. If _mp_size is - negative this is a negative number. */ - mp_exp_t _mp_exp; /* Exponent, in the base of `mp_limb_t'. */ - mp_limb_t *_mp_d; /* Pointer to the limbs. */ -} __mpf_struct; -typedef __mpf_struct mpf_t[1]; -/* Available random number generation algorithms. */ -typedef enum -{ - GMP_RAND_ALG_DEFAULT = 0, - GMP_RAND_ALG_LC = GMP_RAND_ALG_DEFAULT /* Linear congruential. */ -} gmp_randalg_t; -/* Random state struct. */ -typedef struct -{ - mpz_t _mp_seed; /* _mp_d member points to state of the generator. */ - gmp_randalg_t _mp_alg; /* Currently unused. */ - union { - void *_mp_lc; /* Pointer to function pointers structure. */ - } _mp_algdata; -} __gmp_randstate_struct; -typedef __gmp_randstate_struct gmp_randstate_t[1]; -/* Types for function declarations in gmp files. */ -/* ??? Should not pollute user name space with these ??? */ -typedef __gmp_const __mpz_struct *mpz_srcptr; -typedef __mpz_struct *mpz_ptr; -typedef __gmp_const __mpf_struct *mpf_srcptr; -typedef __mpf_struct *mpf_ptr; -typedef __gmp_const __mpq_struct *mpq_srcptr; -typedef __mpq_struct *mpq_ptr; -/* This is not wanted in mp.h, so put it outside the __GNU_MP__ common - section. */ -#if __GMP_LIBGMP_DLL -#if __GMP_WITHIN_GMPXX -/* compiling to go into a DLL libmpirxx */ -#define __GMP_DECLSPEC_XX __GMP_DECLSPEC_EXPORT -#else -/* compiling to go into a application which will link to a DLL libmpirxx */ -#define __GMP_DECLSPEC_XX __GMP_DECLSPEC_IMPORT -#endif -#else -/* all other cases */ -#define __GMP_DECLSPEC_XX -#endif -#if __GMP_HAVE_PROTOTYPES -#define __GMP_PROTO(x) x -#else -#define __GMP_PROTO(x) () -#endif -#ifndef __MPN -#if __GMP_HAVE_TOKEN_PASTE -#define __MPN(x) __gmpn_##x -#else -#define __MPN(x) __gmpn_/**/x -#endif -#endif -/* For reference, "defined(EOF)" cannot be used here. In g++ 2.95.4, - defines EOF but not FILE. */ -#if defined (FILE) \ - || defined (H_STDIO) \ - || defined (_H_STDIO) /* AIX */ \ - || defined (_STDIO_H) /* glibc, Sun, SCO */ \ - || defined (_STDIO_H_) /* BSD, OSF */ \ - || defined (__STDIO_H) /* Borland */ \ - || defined (__STDIO_H__) /* IRIX */ \ - || defined (_STDIO_INCLUDED) /* HPUX */ \ - || defined (_FILE_DEFINED) /* Microsoft */ \ - || defined (__STDIO__) /* Apple MPW MrC */ \ - || defined (_MSL_STDIO_H) /* Metrowerks */ \ - || defined (_STDIO_H_INCLUDED) /* QNX4 */ \ - || defined (_ISO_STDIO_ISO_H) /* Sun C++ */ -#define _GMP_H_HAVE_FILE 1 -#endif -/* In ISO C, if a prototype involving "struct obstack *" is given without - that structure defined, then the struct is scoped down to just the - prototype, causing a conflict if it's subsequently defined for real. So - only give prototypes if we've got obstack.h. */ -#if defined (_OBSTACK_H) /* glibc */ -#define _GMP_H_HAVE_OBSTACK 1 -#endif -/* The prototypes for gmp_vprintf etc are provided only if va_list is - available, via an application having included or . - Usually va_list is a typedef so can't be tested directly, but C99 - specifies that va_start is a macro (and it was normally a macro on past - systems too), so look for that. - will define some sort of va_list for vprintf and vfprintf, but - let's not bother trying to use that since it's not standard and since - application uses for gmp_vprintf etc will almost certainly require the - whole or anyway. */ -#ifdef va_start -#define _GMP_H_HAVE_VA_LIST 1 -#endif -/* Test for gcc >= maj.min, as per __GNUC_PREREQ in glibc */ -#if defined (__GNUC__) && defined (__GNUC_MINOR__) -#define __GMP_GNUC_PREREQ(maj, min) \ - ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min)) -#else -#define __GMP_GNUC_PREREQ(maj, min) 0 -#endif -/* "pure" is in gcc 2.96 and up, see "(gcc)Function Attributes". Basically - it means a function does nothing but examine its arguments and memory - (global or via arguments) to generate a return value, but changes nothing - and has no side-effects. __GMP_NO_ATTRIBUTE_CONST_PURE lets - tune/common.c etc turn this off when trying to write timing loops. */ -#if __GMP_GNUC_PREREQ (2,96) && ! defined (__GMP_NO_ATTRIBUTE_CONST_PURE) -#define __GMP_ATTRIBUTE_PURE __attribute__ ((__pure__)) -#else -#define __GMP_ATTRIBUTE_PURE -#endif -/* __GMP_CAST allows us to use static_cast in C++, so our macros are clean - to "g++ -Wold-style-cast". - Casts in "extern inline" code within an extern "C" block don't induce - these warnings, so __GMP_CAST only needs to be used on documented - macros. */ -#ifdef __cplusplus -#define __GMP_CAST(type, expr) (static_cast (expr)) -#else -#define __GMP_CAST(type, expr) ((type) (expr)) -#endif -/* An empty "throw ()" means the function doesn't throw any C++ exceptions, - this can save some stack frame info in applications. - Currently it's given only on functions which never divide-by-zero etc, - don't allocate memory, and are expected to never need to allocate memory. - This leaves open the possibility of a C++ throw from a future GMP - exceptions scheme. - mpz_set_ui etc are omitted to leave open the lazy allocation scheme - described in doc/tasks.html. mpz_get_d etc are omitted to leave open - exceptions for float overflows. - Note that __GMP_NOTHROW must be given on any inlines the same as on their - prototypes (for g++ at least, where they're used together). Note also - that g++ 3.0 demands that __GMP_NOTHROW is before other attributes like - __GMP_ATTRIBUTE_PURE. */ -#if defined (__cplusplus) -#define __GMP_NOTHROW throw () -#else -#define __GMP_NOTHROW -#endif -/* PORTME: What other compilers have a useful "extern inline"? "static - inline" would be an acceptable substitute if the compiler (or linker) - discards unused statics. */ -/* gcc has __inline__ in all modes, including strict ansi. Give a prototype - for an inline too, so as to correctly specify "dllimport" on windows, in - case the function is called rather than inlined. */ -#ifdef __GNUC__ -#if defined(__APPLE_CC__) && (__APPLE_CC__ != 1) /* FSF GCC sets this flag to 1 on Apple machines */ -#if ! (__APPLE_CC__ >= 5465 && __STDC_VERSION__ >= 199901L) -#define __GMP_EXTERN_INLINE extern __inline__ -#define __GMP_INLINE_PROTOTYPES 1 -#endif -#else /*GNU CC*/ -#if defined(__GNUC_STDC_INLINE__) || defined (__GNUC_GNU_INLINE__) -#define __GMP_EXTERN_INLINE extern __inline__ __attribute__((__gnu_inline__)) -#else -#define __GMP_EXTERN_INLINE extern __inline__ -#endif -#define __GMP_INLINE_PROTOTYPES 1 -#endif -#endif -/* DEC C (eg. version 5.9) supports "static __inline foo()", even in -std1 - strict ANSI mode. Inlining is done even when not optimizing (ie. -O0 - mode, which is the default), but an unnecessary local copy of foo is - emitted unless -O is used. "extern __inline" is accepted, but the - "extern" appears to be ignored, ie. it becomes a plain global function - but which is inlined within its file. Don't know if all old versions of - DEC C supported __inline, but as a start let's do the right thing for - current versions. */ -#ifdef __DECC -#define __GMP_EXTERN_INLINE static __inline -#endif -/* SCO OpenUNIX 8 cc supports "static inline foo()" but not in -Xc strict - ANSI mode (__STDC__ is 1 in that mode). Inlining only actually takes - place under -O. Without -O "foo" seems to be emitted whether it's used - or not, which is wasteful. "extern inline foo()" isn't useful, the - "extern" is apparently ignored, so foo is inlined if possible but also - emitted as a global, which causes multiple definition errors when - building a shared libmpir. */ -#ifdef __SCO_VERSION__ -#if __SCO_VERSION__ > 400000000 && __STDC__ != 1 \ - && ! defined (__GMP_EXTERN_INLINE) -#define __GMP_EXTERN_INLINE static inline -#endif -#endif -#if defined _MSC_VER -#define __GMP_EXTERN_INLINE static __inline -#endif -/* C++ always has "inline" and since it's a normal feature the linker should - discard duplicate non-inlined copies, or if it doesn't then that's a - problem for everyone, not just GMP. */ -#if defined (__cplusplus) && ! defined (__GMP_EXTERN_INLINE) -#define __GMP_EXTERN_INLINE inline -#endif -/* Don't do any inlining within a configure run, since if the compiler ends - up emitting copies of the code into the object file it can end up - demanding the various support routines (like mpn_popcount) for linking, - making the "alloca" test and perhaps others fail. And on hppa ia64 a - pre-release gcc 3.2 was seen not respecting the "extern" in "extern - __inline__", triggering this problem too. */ -#if defined (__GMP_WITHIN_CONFIGURE) && ! __GMP_WITHIN_CONFIGURE_INLINE -#undef __GMP_EXTERN_INLINE -#endif -/* By default, don't give a prototype when there's going to be an inline - version. Note in particular that Cray C++ objects to the combination of - prototype and inline. */ -#ifdef __GMP_EXTERN_INLINE -#ifndef __GMP_INLINE_PROTOTYPES -#define __GMP_INLINE_PROTOTYPES 0 -#endif -#else -#define __GMP_INLINE_PROTOTYPES 1 -#endif -#define __GMP_ABS(x) ((x) >= 0 ? (x) : -(x)) -#define __GMP_MAX(h,i) ((h) > (i) ? (h) : (i)) -/* __GMP_USHRT_MAX is not "~ (unsigned short) 0" because short is promoted - to int by "~". */ -#define __GMP_UINT_MAX (~ (unsigned) 0) -#define __GMP_ULONG_MAX (~ (unsigned long) 0) -#define __GMP_USHRT_MAX ((unsigned short) ~0) -/* __builtin_expect is in gcc 3.0, and not in 2.95. */ -#if __GMP_GNUC_PREREQ (3,0) -#define __GMP_LIKELY(cond) __builtin_expect ((cond) != 0, 1) -#define __GMP_UNLIKELY(cond) __builtin_expect ((cond) != 0, 0) -#else -#define __GMP_LIKELY(cond) (cond) -#define __GMP_UNLIKELY(cond) (cond) -#endif -/* Allow direct user access to numerator and denominator of a mpq_t object. */ -#define mpq_numref(Q) (&((Q)->_mp_num)) -#define mpq_denref(Q) (&((Q)->_mp_den)) -#if defined (__cplusplus) -extern "C" { -using std::FILE; -#endif -#define mp_set_memory_functions __gmp_set_memory_functions -__GMP_DECLSPEC void mp_set_memory_functions __GMP_PROTO ((void *(*) (size_t), - void *(*) (void *, size_t, size_t), - void (*) (void *, size_t))) __GMP_NOTHROW; -#define mp_get_memory_functions __gmp_get_memory_functions -__GMP_DECLSPEC void mp_get_memory_functions __GMP_PROTO ((void *(**) (size_t), - void *(**) (void *, size_t, size_t), - void (**) (void *, size_t))) __GMP_NOTHROW; -#define mp_bits_per_limb __gmp_bits_per_limb -__GMP_DECLSPEC extern __gmp_const int mp_bits_per_limb; -#define gmp_errno __gmp_errno -__GMP_DECLSPEC extern int gmp_errno; -#define gmp_version __gmp_version -__GMP_DECLSPEC extern __gmp_const char * __gmp_const gmp_version; -#define mpir_version __mpir_version -__GMP_DECLSPEC extern __gmp_const char * __gmp_const mpir_version; -/**************** Random number routines. ****************/ -#define gmp_randinit_default __gmp_randinit_default -__GMP_DECLSPEC void gmp_randinit_default __GMP_PROTO ((gmp_randstate_t)); -#define gmp_randinit_lc_2exp __gmp_randinit_lc_2exp -__GMP_DECLSPEC void gmp_randinit_lc_2exp __GMP_PROTO ((gmp_randstate_t, - mpz_srcptr, unsigned long int, - mp_bitcnt_t)); -#define gmp_randinit_lc_2exp_size __gmp_randinit_lc_2exp_size -__GMP_DECLSPEC int gmp_randinit_lc_2exp_size __GMP_PROTO ((gmp_randstate_t, mp_bitcnt_t)); -#define gmp_randinit_mt __gmp_randinit_mt -__GMP_DECLSPEC void gmp_randinit_mt __GMP_PROTO ((gmp_randstate_t)); -#define gmp_randinit_set __gmp_randinit_set -__GMP_DECLSPEC void gmp_randinit_set __GMP_PROTO ((gmp_randstate_t, __gmp_const __gmp_randstate_struct *)); -#define gmp_randseed __gmp_randseed -__GMP_DECLSPEC void gmp_randseed __GMP_PROTO ((gmp_randstate_t, mpz_srcptr)); -#define gmp_randseed_ui __gmp_randseed_ui -__GMP_DECLSPEC void gmp_randseed_ui __GMP_PROTO ((gmp_randstate_t, unsigned long int)); -#define gmp_randclear __gmp_randclear -__GMP_DECLSPEC void gmp_randclear __GMP_PROTO ((gmp_randstate_t)); -#define gmp_urandomb_ui __gmp_urandomb_ui -__GMP_DECLSPEC unsigned long gmp_urandomb_ui __GMP_PROTO ((gmp_randstate_t, unsigned long)); -#define gmp_urandomm_ui __gmp_urandomm_ui -__GMP_DECLSPEC unsigned long gmp_urandomm_ui __GMP_PROTO ((gmp_randstate_t, unsigned long)); -/**************** Formatted output routines. ****************/ -#define gmp_asprintf __gmp_asprintf -__GMP_DECLSPEC int gmp_asprintf __GMP_PROTO ((char **, __gmp_const char *, ...)); -#define gmp_fprintf __gmp_fprintf -#ifdef _GMP_H_HAVE_FILE -__GMP_DECLSPEC int gmp_fprintf __GMP_PROTO ((FILE *, __gmp_const char *, ...)); -#endif -#define gmp_obstack_printf __gmp_obstack_printf -#if defined (_GMP_H_HAVE_OBSTACK) -__GMP_DECLSPEC int gmp_obstack_printf __GMP_PROTO ((struct obstack *, __gmp_const char *, ...)); -#endif -#define gmp_obstack_vprintf __gmp_obstack_vprintf -#if defined (_GMP_H_HAVE_OBSTACK) && defined (_GMP_H_HAVE_VA_LIST) -__GMP_DECLSPEC int gmp_obstack_vprintf __GMP_PROTO ((struct obstack *, __gmp_const char *, va_list)); -#endif -#define gmp_printf __gmp_printf -__GMP_DECLSPEC int gmp_printf __GMP_PROTO ((__gmp_const char *, ...)); -#define gmp_snprintf __gmp_snprintf -__GMP_DECLSPEC int gmp_snprintf __GMP_PROTO ((char *, size_t, __gmp_const char *, ...)); -#define gmp_sprintf __gmp_sprintf -__GMP_DECLSPEC int gmp_sprintf __GMP_PROTO ((char *, __gmp_const char *, ...)); -#define gmp_vasprintf __gmp_vasprintf -#if defined (_GMP_H_HAVE_VA_LIST) -__GMP_DECLSPEC int gmp_vasprintf __GMP_PROTO ((char **, __gmp_const char *, va_list)); -#endif -#define gmp_vfprintf __gmp_vfprintf -#if defined (_GMP_H_HAVE_FILE) && defined (_GMP_H_HAVE_VA_LIST) -__GMP_DECLSPEC int gmp_vfprintf __GMP_PROTO ((FILE *, __gmp_const char *, va_list)); -#endif -#define gmp_vprintf __gmp_vprintf -#if defined (_GMP_H_HAVE_VA_LIST) -__GMP_DECLSPEC int gmp_vprintf __GMP_PROTO ((__gmp_const char *, va_list)); -#endif -#define gmp_vsnprintf __gmp_vsnprintf -#if defined (_GMP_H_HAVE_VA_LIST) -__GMP_DECLSPEC int gmp_vsnprintf __GMP_PROTO ((char *, size_t, __gmp_const char *, va_list)); -#endif -#define gmp_vsprintf __gmp_vsprintf -#if defined (_GMP_H_HAVE_VA_LIST) -__GMP_DECLSPEC int gmp_vsprintf __GMP_PROTO ((char *, __gmp_const char *, va_list)); -#endif -/**************** Formatted input routines. ****************/ -#define gmp_fscanf __gmp_fscanf -#ifdef _GMP_H_HAVE_FILE -__GMP_DECLSPEC int gmp_fscanf __GMP_PROTO ((FILE *, __gmp_const char *, ...)); -#endif -#define gmp_scanf __gmp_scanf -__GMP_DECLSPEC int gmp_scanf __GMP_PROTO ((__gmp_const char *, ...)); -#define gmp_sscanf __gmp_sscanf -__GMP_DECLSPEC int gmp_sscanf __GMP_PROTO ((__gmp_const char *, __gmp_const char *, ...)); -#define gmp_vfscanf __gmp_vfscanf -#if defined (_GMP_H_HAVE_FILE) && defined (_GMP_H_HAVE_VA_LIST) -__GMP_DECLSPEC int gmp_vfscanf __GMP_PROTO ((FILE *, __gmp_const char *, va_list)); -#endif -#define gmp_vscanf __gmp_vscanf -#if defined (_GMP_H_HAVE_VA_LIST) -__GMP_DECLSPEC int gmp_vscanf __GMP_PROTO ((__gmp_const char *, va_list)); -#endif -#define gmp_vsscanf __gmp_vsscanf -#if defined (_GMP_H_HAVE_VA_LIST) -__GMP_DECLSPEC int gmp_vsscanf __GMP_PROTO ((__gmp_const char *, __gmp_const char *, va_list)); -#endif -/**************** Integer (i.e. Z) routines. ****************/ -#define __GMP_BITS_PER_ULONG (8*sizeof(unsigned long)) -#define _mpz_realloc __gmpz_realloc -#define mpz_realloc __gmpz_realloc -__GMP_DECLSPEC void *_mpz_realloc __GMP_PROTO ((mpz_ptr, mp_size_t)); -#define mpz_abs __gmpz_abs -#define __GMP_MPZ_ABS_MIN_ALLOC(x,y) (__GMP_ABS(y->_mp_size)) -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_abs) -__GMP_DECLSPEC void mpz_abs __GMP_PROTO ((mpz_ptr, mpz_srcptr)); -#endif -#define __GMP_MPZ_ADD_MIN_ALLOC(x,y,z) (__GMP_MAX(__GMP_ABS(y->_mp_size),__GMP_ABS(z->_mp_size))+1) -#define mpz_add __gmpz_add -__GMP_DECLSPEC void mpz_add __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); -#define __GMP_MPZ_ADD_UI_MIN_ALLOC(x,y,z) (__GMP_MAX(__GMP_ABS(y->_mp_size),1+(__GMP_BITS_PER_ULONG-1)/GMP_NUMB_BITS)+1) -#define mpz_add_ui __gmpz_add_ui -__GMP_DECLSPEC void mpz_add_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); -#define mpz_addmul __gmpz_addmul -__GMP_DECLSPEC void mpz_addmul __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); -#define mpz_addmul_ui __gmpz_addmul_ui -__GMP_DECLSPEC void mpz_addmul_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); -#define mpz_and __gmpz_and -__GMP_DECLSPEC void mpz_and __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); -#define mpz_array_init __gmpz_array_init -__GMP_DECLSPEC void mpz_array_init __GMP_PROTO ((mpz_ptr, mp_size_t, mp_size_t)); -#define mpz_bin_ui __gmpz_bin_ui -__GMP_DECLSPEC void mpz_bin_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); -#define mpz_bin_uiui __gmpz_bin_uiui -__GMP_DECLSPEC void mpz_bin_uiui __GMP_PROTO ((mpz_ptr, unsigned long int, unsigned long int)); -#define mpz_cdiv_q __gmpz_cdiv_q -__GMP_DECLSPEC void mpz_cdiv_q __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); -#define mpz_cdiv_q_2exp __gmpz_cdiv_q_2exp -__GMP_DECLSPEC void mpz_cdiv_q_2exp __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long)); -#define mpz_cdiv_q_ui __gmpz_cdiv_q_ui -__GMP_DECLSPEC unsigned long int mpz_cdiv_q_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); -#define mpz_cdiv_qr __gmpz_cdiv_qr -__GMP_DECLSPEC void mpz_cdiv_qr __GMP_PROTO ((mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr)); -#define mpz_cdiv_qr_ui __gmpz_cdiv_qr_ui -__GMP_DECLSPEC unsigned long int mpz_cdiv_qr_ui __GMP_PROTO ((mpz_ptr, mpz_ptr, mpz_srcptr, unsigned long int)); -#define mpz_cdiv_r __gmpz_cdiv_r -__GMP_DECLSPEC void mpz_cdiv_r __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); -#define mpz_cdiv_r_2exp __gmpz_cdiv_r_2exp -__GMP_DECLSPEC void mpz_cdiv_r_2exp __GMP_PROTO ((mpz_ptr, mpz_srcptr, mp_bitcnt_t)); -#define mpz_cdiv_r_ui __gmpz_cdiv_r_ui -__GMP_DECLSPEC unsigned long int mpz_cdiv_r_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); -#define mpz_cdiv_ui __gmpz_cdiv_ui -__GMP_DECLSPEC unsigned long int mpz_cdiv_ui __GMP_PROTO ((mpz_srcptr, unsigned long int)) __GMP_ATTRIBUTE_PURE; -#define mpz_clear __gmpz_clear -__GMP_DECLSPEC void mpz_clear __GMP_PROTO ((mpz_ptr)); -#define mpz_clears __gmpz_clears -__GMP_DECLSPEC void mpz_clears __GMP_PROTO ((mpz_ptr, ...)); -#define mpz_clrbit __gmpz_clrbit -__GMP_DECLSPEC void mpz_clrbit __GMP_PROTO ((mpz_ptr, mp_bitcnt_t)); -#define mpz_cmp __gmpz_cmp -__GMP_DECLSPEC int mpz_cmp __GMP_PROTO ((mpz_srcptr, mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#define mpz_cmp_d __gmpz_cmp_d -__GMP_DECLSPEC int mpz_cmp_d __GMP_PROTO ((mpz_srcptr, double)) __GMP_ATTRIBUTE_PURE; -#define _mpz_cmp_si __gmpz_cmp_si -__GMP_DECLSPEC int _mpz_cmp_si __GMP_PROTO ((mpz_srcptr, signed long int)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#define _mpz_cmp_ui __gmpz_cmp_ui -__GMP_DECLSPEC int _mpz_cmp_ui __GMP_PROTO ((mpz_srcptr, unsigned long int)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#define mpz_cmpabs __gmpz_cmpabs -__GMP_DECLSPEC int mpz_cmpabs __GMP_PROTO ((mpz_srcptr, mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#define mpz_cmpabs_d __gmpz_cmpabs_d -__GMP_DECLSPEC int mpz_cmpabs_d __GMP_PROTO ((mpz_srcptr, double)) __GMP_ATTRIBUTE_PURE; -#define mpz_cmpabs_ui __gmpz_cmpabs_ui -__GMP_DECLSPEC int mpz_cmpabs_ui __GMP_PROTO ((mpz_srcptr, unsigned long int)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#define mpz_com __gmpz_com -__GMP_DECLSPEC void mpz_com __GMP_PROTO ((mpz_ptr, mpz_srcptr)); -#define mpz_combit __gmpz_combit -__GMP_DECLSPEC void mpz_combit __GMP_PROTO ((mpz_ptr, mp_bitcnt_t)); -#define mpz_congruent_p __gmpz_congruent_p -__GMP_DECLSPEC int mpz_congruent_p __GMP_PROTO ((mpz_srcptr, mpz_srcptr, mpz_srcptr)) __GMP_ATTRIBUTE_PURE; -#define mpz_congruent_2exp_p __gmpz_congruent_2exp_p -__GMP_DECLSPEC int mpz_congruent_2exp_p __GMP_PROTO ((mpz_srcptr, mpz_srcptr, mp_bitcnt_t)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#define mpz_congruent_ui_p __gmpz_congruent_ui_p -__GMP_DECLSPEC int mpz_congruent_ui_p __GMP_PROTO ((mpz_srcptr, unsigned long, unsigned long)) __GMP_ATTRIBUTE_PURE; -#define mpz_divexact __gmpz_divexact -__GMP_DECLSPEC void mpz_divexact __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); -#define mpz_divexact_ui __gmpz_divexact_ui -__GMP_DECLSPEC void mpz_divexact_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long)); -#define mpz_divisible_p __gmpz_divisible_p -__GMP_DECLSPEC int mpz_divisible_p __GMP_PROTO ((mpz_srcptr, mpz_srcptr)) __GMP_ATTRIBUTE_PURE; -#define mpz_divisible_ui_p __gmpz_divisible_ui_p -__GMP_DECLSPEC int mpz_divisible_ui_p __GMP_PROTO ((mpz_srcptr, unsigned long)) __GMP_ATTRIBUTE_PURE; -#define mpz_divisible_2exp_p __gmpz_divisible_2exp_p -__GMP_DECLSPEC int mpz_divisible_2exp_p __GMP_PROTO ((mpz_srcptr, mp_bitcnt_t)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#define mpz_dump __gmpz_dump -__GMP_DECLSPEC void mpz_dump __GMP_PROTO ((mpz_srcptr)); -#define mpz_export __gmpz_export -__GMP_DECLSPEC void *mpz_export __GMP_PROTO ((void *, size_t *, int, size_t, int, size_t, mpz_srcptr)); -#define mpz_fac_ui __gmpz_fac_ui -__GMP_DECLSPEC void mpz_fac_ui __GMP_PROTO ((mpz_ptr, unsigned long int)); -#define mpz_fdiv_q __gmpz_fdiv_q -__GMP_DECLSPEC void mpz_fdiv_q __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); -#define mpz_fdiv_q_2exp __gmpz_fdiv_q_2exp -__GMP_DECLSPEC void mpz_fdiv_q_2exp __GMP_PROTO ((mpz_ptr, mpz_srcptr, mp_bitcnt_t)); -#define mpz_fdiv_q_ui __gmpz_fdiv_q_ui -__GMP_DECLSPEC unsigned long int mpz_fdiv_q_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); -#define mpz_fdiv_qr __gmpz_fdiv_qr -__GMP_DECLSPEC void mpz_fdiv_qr __GMP_PROTO ((mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr)); -#define mpz_fdiv_qr_ui __gmpz_fdiv_qr_ui -__GMP_DECLSPEC unsigned long int mpz_fdiv_qr_ui __GMP_PROTO ((mpz_ptr, mpz_ptr, mpz_srcptr, unsigned long int)); -#define mpz_fdiv_r __gmpz_fdiv_r -__GMP_DECLSPEC void mpz_fdiv_r __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); -#define mpz_fdiv_r_2exp __gmpz_fdiv_r_2exp -__GMP_DECLSPEC void mpz_fdiv_r_2exp __GMP_PROTO ((mpz_ptr, mpz_srcptr, mp_bitcnt_t)); -#define mpz_fdiv_r_ui __gmpz_fdiv_r_ui -__GMP_DECLSPEC unsigned long int mpz_fdiv_r_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); -#define mpz_fdiv_ui __gmpz_fdiv_ui -__GMP_DECLSPEC unsigned long int mpz_fdiv_ui __GMP_PROTO ((mpz_srcptr, unsigned long int)) __GMP_ATTRIBUTE_PURE; -#define mpz_fib_ui __gmpz_fib_ui -__GMP_DECLSPEC void mpz_fib_ui __GMP_PROTO ((mpz_ptr, unsigned long int)); -#define mpz_fib2_ui __gmpz_fib2_ui -__GMP_DECLSPEC void mpz_fib2_ui __GMP_PROTO ((mpz_ptr, mpz_ptr, unsigned long int)); -#define mpz_fits_sint_p __gmpz_fits_sint_p -__GMP_DECLSPEC int mpz_fits_sint_p __GMP_PROTO ((mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#define mpz_fits_slong_p __gmpz_fits_slong_p -__GMP_DECLSPEC int mpz_fits_slong_p __GMP_PROTO ((mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#define mpz_fits_sshort_p __gmpz_fits_sshort_p -__GMP_DECLSPEC int mpz_fits_sshort_p __GMP_PROTO ((mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#define mpz_fits_uint_p __gmpz_fits_uint_p -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_fits_uint_p) -__GMP_DECLSPEC int mpz_fits_uint_p __GMP_PROTO ((mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#endif -#define mpz_fits_ulong_p __gmpz_fits_ulong_p -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_fits_ulong_p) -__GMP_DECLSPEC int mpz_fits_ulong_p __GMP_PROTO ((mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#endif -#define mpz_fits_ushort_p __gmpz_fits_ushort_p -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_fits_ushort_p) -__GMP_DECLSPEC int mpz_fits_ushort_p __GMP_PROTO ((mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#endif -#define mpz_gcd __gmpz_gcd -__GMP_DECLSPEC void mpz_gcd __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); -#define mpz_gcd_ui __gmpz_gcd_ui -__GMP_DECLSPEC unsigned long int mpz_gcd_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); -#define mpz_gcdext __gmpz_gcdext -__GMP_DECLSPEC void mpz_gcdext __GMP_PROTO ((mpz_ptr, mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr)); -#define mpz_get_d __gmpz_get_d -__GMP_DECLSPEC double mpz_get_d __GMP_PROTO ((mpz_srcptr)) __GMP_ATTRIBUTE_PURE; -#define mpz_get_d_2exp __gmpz_get_d_2exp -__GMP_DECLSPEC double mpz_get_d_2exp __GMP_PROTO ((signed long int *, mpz_srcptr)); -#define mpz_get_si __gmpz_get_si -__GMP_DECLSPEC /* signed */ long int mpz_get_si __GMP_PROTO ((mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#define mpz_get_str __gmpz_get_str -__GMP_DECLSPEC char *mpz_get_str __GMP_PROTO ((char *, int, mpz_srcptr)); -#define mpz_get_ui __gmpz_get_ui -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_get_ui) -__GMP_DECLSPEC unsigned long int mpz_get_ui __GMP_PROTO ((mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#endif -#define mpz_getlimbn __gmpz_getlimbn -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_getlimbn) -__GMP_DECLSPEC mp_limb_t mpz_getlimbn __GMP_PROTO ((mpz_srcptr, mp_size_t)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#endif -#define mpz_hamdist __gmpz_hamdist -__GMP_DECLSPEC mp_bitcnt_t mpz_hamdist __GMP_PROTO ((mpz_srcptr, mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#define mpz_import __gmpz_import -__GMP_DECLSPEC void mpz_import __GMP_PROTO ((mpz_ptr, size_t, int, size_t, int, size_t, __gmp_const void *)); -#define mpz_init __gmpz_init -__GMP_DECLSPEC void mpz_init __GMP_PROTO ((mpz_ptr)); -#define mpz_init2 __gmpz_init2 -__GMP_DECLSPEC void mpz_init2 __GMP_PROTO ((mpz_ptr, mp_bitcnt_t)); -#define mpz_inits __gmpz_inits -__GMP_DECLSPEC void mpz_inits __GMP_PROTO ((mpz_ptr, ...)); -#define mpz_init_set __gmpz_init_set -__GMP_DECLSPEC void mpz_init_set __GMP_PROTO ((mpz_ptr, mpz_srcptr)); -#define mpz_init_set_d __gmpz_init_set_d -__GMP_DECLSPEC void mpz_init_set_d __GMP_PROTO ((mpz_ptr, double)); -#define mpz_init_set_si __gmpz_init_set_si -__GMP_DECLSPEC void mpz_init_set_si __GMP_PROTO ((mpz_ptr, signed long int)); -#define mpz_init_set_str __gmpz_init_set_str -__GMP_DECLSPEC int mpz_init_set_str __GMP_PROTO ((mpz_ptr, __gmp_const char *, int)); -#define mpz_init_set_ui __gmpz_init_set_ui -__GMP_DECLSPEC void mpz_init_set_ui __GMP_PROTO ((mpz_ptr, unsigned long int)); -#define mpz_inp_raw __gmpz_inp_raw -#ifdef _GMP_H_HAVE_FILE -__GMP_DECLSPEC size_t mpz_inp_raw __GMP_PROTO ((mpz_ptr, FILE *)); -#endif -#define mpz_inp_str __gmpz_inp_str -#ifdef _GMP_H_HAVE_FILE -__GMP_DECLSPEC size_t mpz_inp_str __GMP_PROTO ((mpz_ptr, FILE *, int)); -#endif -#define mpz_invert __gmpz_invert -__GMP_DECLSPEC int mpz_invert __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); -#define mpz_ior __gmpz_ior -__GMP_DECLSPEC void mpz_ior __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); -#define mpz_jacobi __gmpz_jacobi -__GMP_DECLSPEC int mpz_jacobi __GMP_PROTO ((mpz_srcptr, mpz_srcptr)) __GMP_ATTRIBUTE_PURE; -#define mpz_kronecker mpz_jacobi /* alias */ -#define mpz_kronecker_si __gmpz_kronecker_si -__GMP_DECLSPEC int mpz_kronecker_si __GMP_PROTO ((mpz_srcptr, long)) __GMP_ATTRIBUTE_PURE; -#define mpz_kronecker_ui __gmpz_kronecker_ui -__GMP_DECLSPEC int mpz_kronecker_ui __GMP_PROTO ((mpz_srcptr, unsigned long)) __GMP_ATTRIBUTE_PURE; -#define mpz_si_kronecker __gmpz_si_kronecker -__GMP_DECLSPEC int mpz_si_kronecker __GMP_PROTO ((long, mpz_srcptr)) __GMP_ATTRIBUTE_PURE; -#define mpz_ui_kronecker __gmpz_ui_kronecker -__GMP_DECLSPEC int mpz_ui_kronecker __GMP_PROTO ((unsigned long, mpz_srcptr)) __GMP_ATTRIBUTE_PURE; -#define mpz_lcm __gmpz_lcm -__GMP_DECLSPEC void mpz_lcm __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); -#define mpz_lcm_ui __gmpz_lcm_ui -__GMP_DECLSPEC void mpz_lcm_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long)); -#define mpz_legendre mpz_jacobi /* alias */ -#define mpz_lucnum_ui __gmpz_lucnum_ui -__GMP_DECLSPEC void mpz_lucnum_ui __GMP_PROTO ((mpz_ptr, unsigned long int)); -#define mpz_lucnum2_ui __gmpz_lucnum2_ui -__GMP_DECLSPEC void mpz_lucnum2_ui __GMP_PROTO ((mpz_ptr, mpz_ptr, unsigned long int)); -#define mpz_millerrabin __gmpz_millerrabin -__GMP_DECLSPEC int mpz_millerrabin __GMP_PROTO ((mpz_srcptr, int)) __GMP_ATTRIBUTE_PURE; -#define mpz_mod __gmpz_mod -__GMP_DECLSPEC void mpz_mod __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); -#define mpz_mod_ui mpz_fdiv_r_ui /* same as fdiv_r because divisor unsigned */ -#define __GMP_MPZ_MUL_MIN_ALLOC(x,y,z) (__GMP_ABS(y->_mp_size)+__GMP_ABS(z->_mp_size)+1) -#define mpz_mul __gmpz_mul -__GMP_DECLSPEC void mpz_mul __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); -#define mpz_mul_2exp __gmpz_mul_2exp -__GMP_DECLSPEC void mpz_mul_2exp __GMP_PROTO ((mpz_ptr, mpz_srcptr, mp_bitcnt_t)); -#define __GMP_MPZ_MUL_SI_MIN_ALLOC(x,y,z) (__GMP_ABS(y->_mp_size)+(__GMP_BITS_PER_ULONG-1)/GMP_NUMB_BITS+1) -#define mpz_mul_si __gmpz_mul_si -__GMP_DECLSPEC void mpz_mul_si __GMP_PROTO ((mpz_ptr, mpz_srcptr, long int)); -#define __GMP_MPZ_MUL_UI_MIN_ALLOC(x,y,z) (__GMP_ABS(y->_mp_size)+(__GMP_BITS_PER_ULONG-1)/GMP_NUMB_BITS+1) -#define mpz_mul_ui __gmpz_mul_ui -__GMP_DECLSPEC void mpz_mul_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); -#define mpz_neg __gmpz_neg -#define __GMP_MPZ_NEG_MIN_ALLOC(x,y) (__GMP_ABS(y->_mp_size)) -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_neg) -__GMP_DECLSPEC void mpz_neg __GMP_PROTO ((mpz_ptr, mpz_srcptr)); -#endif -#define mpz_nextprime __gmpz_nextprime -__GMP_DECLSPEC void mpz_nextprime __GMP_PROTO ((mpz_ptr, mpz_srcptr)); -#define mpz_next_likely_prime __gmpz_next_likely_prime -__GMP_DECLSPEC void mpz_next_likely_prime __GMP_PROTO ((mpz_ptr, mpz_srcptr,gmp_randstate_t)); -#define mpz_out_raw __gmpz_out_raw -#ifdef _GMP_H_HAVE_FILE -__GMP_DECLSPEC size_t mpz_out_raw __GMP_PROTO ((FILE *, mpz_srcptr)); -#endif -#define mpz_out_str __gmpz_out_str -#ifdef _GMP_H_HAVE_FILE -__GMP_DECLSPEC size_t mpz_out_str __GMP_PROTO ((FILE *, int, mpz_srcptr)); -#endif -#define mpz_perfect_power_p __gmpz_perfect_power_p -__GMP_DECLSPEC int mpz_perfect_power_p __GMP_PROTO ((mpz_srcptr)) __GMP_ATTRIBUTE_PURE; -#define mpz_perfect_square_p __gmpz_perfect_square_p -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_perfect_square_p) -__GMP_DECLSPEC int mpz_perfect_square_p __GMP_PROTO ((mpz_srcptr)) __GMP_ATTRIBUTE_PURE; -#endif -#define mpz_popcount __gmpz_popcount -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_popcount) -__GMP_DECLSPEC mp_bitcnt_t mpz_popcount __GMP_PROTO ((mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#endif -#define mpz_pow_ui __gmpz_pow_ui -__GMP_DECLSPEC void mpz_pow_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); -#define mpz_powm __gmpz_powm -__GMP_DECLSPEC void mpz_powm __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr, mpz_srcptr)); -#define mpz_powm_ui __gmpz_powm_ui -__GMP_DECLSPEC void mpz_powm_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int, mpz_srcptr)); -#define mpz_probab_prime_p __gmpz_probab_prime_p -__GMP_DECLSPEC int mpz_probab_prime_p __GMP_PROTO ((mpz_srcptr, int)) __GMP_ATTRIBUTE_PURE; -#define mpz_probable_prime_p __gmpz_probable_prime_p -__GMP_DECLSPEC int mpz_probable_prime_p __GMP_PROTO ((mpz_srcptr,gmp_randstate_t, int,unsigned long)); -#define mpz_likely_prime_p __gmpz_likely_prime_p -__GMP_DECLSPEC int mpz_likely_prime_p __GMP_PROTO ((mpz_srcptr,gmp_randstate_t, unsigned long)); -#define mpz_realloc2 __gmpz_realloc2 -__GMP_DECLSPEC void mpz_realloc2 __GMP_PROTO ((mpz_ptr, mp_bitcnt_t)); -#define mpz_remove __gmpz_remove -__GMP_DECLSPEC unsigned long int mpz_remove __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); -#define mpz_root __gmpz_root -__GMP_DECLSPEC int mpz_root __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); -#define mpz_nthroot __gmpz_nthroot -__GMP_DECLSPEC void mpz_nthroot __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); -#define mpz_rootrem __gmpz_rootrem -__GMP_DECLSPEC void mpz_rootrem __GMP_PROTO ((mpz_ptr,mpz_ptr, mpz_srcptr, unsigned long int)); -#define mpz_rrandomb __gmpz_rrandomb -__GMP_DECLSPEC void mpz_rrandomb __GMP_PROTO ((mpz_ptr, gmp_randstate_t, mp_bitcnt_t)); -#define mpz_scan0 __gmpz_scan0 -__GMP_DECLSPEC mp_bitcnt_t mpz_scan0 __GMP_PROTO ((mpz_srcptr, mp_bitcnt_t)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#define mpz_scan1 __gmpz_scan1 -__GMP_DECLSPEC mp_bitcnt_t mpz_scan1 __GMP_PROTO ((mpz_srcptr, mp_bitcnt_t)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#define __GMP_MPZ_SET_MIN_ALLOC(x,y) __GMP_ABS(y->_mp_size) -#define mpz_set __gmpz_set -__GMP_DECLSPEC void mpz_set __GMP_PROTO ((mpz_ptr, mpz_srcptr)); -#define mpz_set_d __gmpz_set_d -__GMP_DECLSPEC void mpz_set_d __GMP_PROTO ((mpz_ptr, double)); -#define mpz_set_f __gmpz_set_f -__GMP_DECLSPEC void mpz_set_f __GMP_PROTO ((mpz_ptr, mpf_srcptr)); -#define mpz_set_q __gmpz_set_q -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_set_q) -__GMP_DECLSPEC void mpz_set_q __GMP_PROTO ((mpz_ptr, mpq_srcptr)); -#endif -#define __GMP_MPZ_SET_SI_MIN_ALLOC(x,y) (1+(__GMP_BITS_PER_ULONG-1)/GMP_NUMB_BITS) -#define mpz_set_si __gmpz_set_si -__GMP_DECLSPEC void mpz_set_si __GMP_PROTO ((mpz_ptr, signed long int)); -#define mpz_set_str __gmpz_set_str -__GMP_DECLSPEC int mpz_set_str __GMP_PROTO ((mpz_ptr, __gmp_const char *, int)); -#define __GMP_MPZ_SET_UI_MIN_ALLOC(x,y) (1+(__GMP_BITS_PER_ULONG-1)/GMP_NUMB_BITS) -#define mpz_set_ui __gmpz_set_ui -__GMP_DECLSPEC void mpz_set_ui __GMP_PROTO ((mpz_ptr, unsigned long int)); -#define mpz_setbit __gmpz_setbit -__GMP_DECLSPEC void mpz_setbit __GMP_PROTO ((mpz_ptr, mp_bitcnt_t)); -#define mpz_size __gmpz_size -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_size) -__GMP_DECLSPEC size_t mpz_size __GMP_PROTO ((mpz_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#endif -#define mpz_sizeinbase __gmpz_sizeinbase -__GMP_DECLSPEC size_t mpz_sizeinbase __GMP_PROTO ((mpz_srcptr, int)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#define mpz_sqrt __gmpz_sqrt -__GMP_DECLSPEC void mpz_sqrt __GMP_PROTO ((mpz_ptr, mpz_srcptr)); -#define mpz_sqrtrem __gmpz_sqrtrem -__GMP_DECLSPEC void mpz_sqrtrem __GMP_PROTO ((mpz_ptr, mpz_ptr, mpz_srcptr)); -#define __GMP_MPZ_SUB_MIN_ALLOC(x,y,z) (__GMP_MAX(__GMP_ABS(y->_mp_size),__GMP_ABS(z->_mp_size))+1) -#define mpz_sub __gmpz_sub -__GMP_DECLSPEC void mpz_sub __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); -#define __GMP_MPZ_SUB_UI_MIN_ALLOC(x,y,z) (__GMP_MAX(__GMP_ABS(y->_mp_size),1+(__GMP_BITS_PER_ULONG-1)/GMP_NUMB_BITS)+1) -#define mpz_sub_ui __gmpz_sub_ui -__GMP_DECLSPEC void mpz_sub_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); -#define __GMP_MPZ_UI_SUB_MIN_ALLOC(x,y,z) (__GMP_MAX(__GMP_ABS(z->_mp_size),1+(__GMP_BITS_PER_ULONG-1)/GMP_NUMB_BITS)+1) -#define mpz_ui_sub __gmpz_ui_sub -__GMP_DECLSPEC void mpz_ui_sub __GMP_PROTO ((mpz_ptr, unsigned long int, mpz_srcptr)); -#define mpz_submul __gmpz_submul -__GMP_DECLSPEC void mpz_submul __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); -#define mpz_submul_ui __gmpz_submul_ui -__GMP_DECLSPEC void mpz_submul_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); -#define mpz_swap __gmpz_swap -__GMP_DECLSPEC void mpz_swap __GMP_PROTO ((mpz_ptr, mpz_ptr)) __GMP_NOTHROW; -#define mpz_tdiv_ui __gmpz_tdiv_ui -__GMP_DECLSPEC unsigned long int mpz_tdiv_ui __GMP_PROTO ((mpz_srcptr, unsigned long int)) __GMP_ATTRIBUTE_PURE; -#define mpz_tdiv_q __gmpz_tdiv_q -__GMP_DECLSPEC void mpz_tdiv_q __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); -#define mpz_tdiv_q_2exp __gmpz_tdiv_q_2exp -__GMP_DECLSPEC void mpz_tdiv_q_2exp __GMP_PROTO ((mpz_ptr, mpz_srcptr, mp_bitcnt_t)); -#define mpz_tdiv_q_ui __gmpz_tdiv_q_ui -__GMP_DECLSPEC unsigned long int mpz_tdiv_q_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); -#define mpz_tdiv_qr __gmpz_tdiv_qr -__GMP_DECLSPEC void mpz_tdiv_qr __GMP_PROTO ((mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr)); -#define mpz_tdiv_qr_ui __gmpz_tdiv_qr_ui -__GMP_DECLSPEC unsigned long int mpz_tdiv_qr_ui __GMP_PROTO ((mpz_ptr, mpz_ptr, mpz_srcptr, unsigned long int)); -#define mpz_tdiv_r __gmpz_tdiv_r -__GMP_DECLSPEC void mpz_tdiv_r __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); -#define mpz_tdiv_r_2exp __gmpz_tdiv_r_2exp -__GMP_DECLSPEC void mpz_tdiv_r_2exp __GMP_PROTO ((mpz_ptr, mpz_srcptr, mp_bitcnt_t)); -#define mpz_tdiv_r_ui __gmpz_tdiv_r_ui -__GMP_DECLSPEC unsigned long int mpz_tdiv_r_ui __GMP_PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); -#define mpz_tstbit __gmpz_tstbit -__GMP_DECLSPEC int mpz_tstbit __GMP_PROTO ((mpz_srcptr, mp_bitcnt_t)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#define mpz_ui_pow_ui __gmpz_ui_pow_ui -__GMP_DECLSPEC void mpz_ui_pow_ui __GMP_PROTO ((mpz_ptr, unsigned long int, unsigned long int)); -#define mpz_urandomb __gmpz_urandomb -__GMP_DECLSPEC void mpz_urandomb __GMP_PROTO ((mpz_ptr, gmp_randstate_t, mp_bitcnt_t)); -#define mpz_urandomm __gmpz_urandomm -__GMP_DECLSPEC void mpz_urandomm __GMP_PROTO ((mpz_ptr, gmp_randstate_t, mpz_srcptr)); -#define mpz_xor __gmpz_xor -#define mpz_eor __gmpz_xor -__GMP_DECLSPEC void mpz_xor __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); -/**************** Rational (i.e. Q) routines. ****************/ -#define mpq_abs __gmpq_abs -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpq_abs) -__GMP_DECLSPEC void mpq_abs __GMP_PROTO ((mpq_ptr, mpq_srcptr)); -#endif -#define mpq_add __gmpq_add -__GMP_DECLSPEC void mpq_add __GMP_PROTO ((mpq_ptr, mpq_srcptr, mpq_srcptr)); -#define mpq_canonicalize __gmpq_canonicalize -__GMP_DECLSPEC void mpq_canonicalize __GMP_PROTO ((mpq_ptr)); -#define mpq_clear __gmpq_clear -__GMP_DECLSPEC void mpq_clear __GMP_PROTO ((mpq_ptr)); -#define mpq_clears __gmpq_clears -__GMP_DECLSPEC void mpq_clears __GMP_PROTO ((mpq_ptr, ...)); -#define mpq_cmp __gmpq_cmp -__GMP_DECLSPEC int mpq_cmp __GMP_PROTO ((mpq_srcptr, mpq_srcptr)) __GMP_ATTRIBUTE_PURE; -#define _mpq_cmp_si __gmpq_cmp_si -__GMP_DECLSPEC int _mpq_cmp_si __GMP_PROTO ((mpq_srcptr, long, unsigned long)) __GMP_ATTRIBUTE_PURE; -#define _mpq_cmp_ui __gmpq_cmp_ui -__GMP_DECLSPEC int _mpq_cmp_ui __GMP_PROTO ((mpq_srcptr, unsigned long int, unsigned long int)) __GMP_ATTRIBUTE_PURE; -#define mpq_div __gmpq_div -__GMP_DECLSPEC void mpq_div __GMP_PROTO ((mpq_ptr, mpq_srcptr, mpq_srcptr)); -#define mpq_div_2exp __gmpq_div_2exp -__GMP_DECLSPEC void mpq_div_2exp __GMP_PROTO ((mpq_ptr, mpq_srcptr, mp_bitcnt_t)); -#define mpq_equal __gmpq_equal -__GMP_DECLSPEC int mpq_equal __GMP_PROTO ((mpq_srcptr, mpq_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#define mpq_get_num __gmpq_get_num -__GMP_DECLSPEC void mpq_get_num __GMP_PROTO ((mpz_ptr, mpq_srcptr)); -#define mpq_get_den __gmpq_get_den -__GMP_DECLSPEC void mpq_get_den __GMP_PROTO ((mpz_ptr, mpq_srcptr)); -#define mpq_get_d __gmpq_get_d -__GMP_DECLSPEC double mpq_get_d __GMP_PROTO ((mpq_srcptr)) __GMP_ATTRIBUTE_PURE; -#define mpq_get_str __gmpq_get_str -__GMP_DECLSPEC char *mpq_get_str __GMP_PROTO ((char *, int, mpq_srcptr)); -#define mpq_init __gmpq_init -__GMP_DECLSPEC void mpq_init __GMP_PROTO ((mpq_ptr)); -#define mpq_inits __gmpq_inits -__GMP_DECLSPEC void mpq_inits __GMP_PROTO ((mpq_ptr, ...)); -#define mpq_inp_str __gmpq_inp_str -#ifdef _GMP_H_HAVE_FILE -__GMP_DECLSPEC size_t mpq_inp_str __GMP_PROTO ((mpq_ptr, FILE *, int)); -#endif -#define mpq_inv __gmpq_inv -__GMP_DECLSPEC void mpq_inv __GMP_PROTO ((mpq_ptr, mpq_srcptr)); -#define mpq_mul __gmpq_mul -__GMP_DECLSPEC void mpq_mul __GMP_PROTO ((mpq_ptr, mpq_srcptr, mpq_srcptr)); -#define mpq_mul_2exp __gmpq_mul_2exp -__GMP_DECLSPEC void mpq_mul_2exp __GMP_PROTO ((mpq_ptr, mpq_srcptr, mp_bitcnt_t)); -#define mpq_neg __gmpq_neg -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpq_neg) -__GMP_DECLSPEC void mpq_neg __GMP_PROTO ((mpq_ptr, mpq_srcptr)); -#endif -#define mpq_out_str __gmpq_out_str -#ifdef _GMP_H_HAVE_FILE -__GMP_DECLSPEC size_t mpq_out_str __GMP_PROTO ((FILE *, int, mpq_srcptr)); -#endif -#define mpq_set __gmpq_set -__GMP_DECLSPEC void mpq_set __GMP_PROTO ((mpq_ptr, mpq_srcptr)); -#define mpq_set_d __gmpq_set_d -__GMP_DECLSPEC void mpq_set_d __GMP_PROTO ((mpq_ptr, double)); -#define mpq_set_den __gmpq_set_den -__GMP_DECLSPEC void mpq_set_den __GMP_PROTO ((mpq_ptr, mpz_srcptr)); -#define mpq_set_f __gmpq_set_f -__GMP_DECLSPEC void mpq_set_f __GMP_PROTO ((mpq_ptr, mpf_srcptr)); -#define mpq_set_num __gmpq_set_num -__GMP_DECLSPEC void mpq_set_num __GMP_PROTO ((mpq_ptr, mpz_srcptr)); -#define mpq_set_si __gmpq_set_si -__GMP_DECLSPEC void mpq_set_si __GMP_PROTO ((mpq_ptr, signed long int, unsigned long int)); -#define mpq_set_str __gmpq_set_str -__GMP_DECLSPEC int mpq_set_str __GMP_PROTO ((mpq_ptr, __gmp_const char *, int)); -#define mpq_set_ui __gmpq_set_ui -__GMP_DECLSPEC void mpq_set_ui __GMP_PROTO ((mpq_ptr, unsigned long int, unsigned long int)); -#define mpq_set_z __gmpq_set_z -__GMP_DECLSPEC void mpq_set_z __GMP_PROTO ((mpq_ptr, mpz_srcptr)); -#define mpq_sub __gmpq_sub -__GMP_DECLSPEC void mpq_sub __GMP_PROTO ((mpq_ptr, mpq_srcptr, mpq_srcptr)); -#define mpq_swap __gmpq_swap -__GMP_DECLSPEC void mpq_swap __GMP_PROTO ((mpq_ptr, mpq_ptr)) __GMP_NOTHROW; -/**************** Float (i.e. F) routines. ****************/ -#define mpf_abs __gmpf_abs -__GMP_DECLSPEC void mpf_abs __GMP_PROTO ((mpf_ptr, mpf_srcptr)); -#define mpf_add __gmpf_add -__GMP_DECLSPEC void mpf_add __GMP_PROTO ((mpf_ptr, mpf_srcptr, mpf_srcptr)); -#define mpf_add_ui __gmpf_add_ui -__GMP_DECLSPEC void mpf_add_ui __GMP_PROTO ((mpf_ptr, mpf_srcptr, unsigned long int)); -#define mpf_ceil __gmpf_ceil -__GMP_DECLSPEC void mpf_ceil __GMP_PROTO ((mpf_ptr, mpf_srcptr)); -#define mpf_clear __gmpf_clear -__GMP_DECLSPEC void mpf_clear __GMP_PROTO ((mpf_ptr)); -#define mpf_clears __gmpf_clears -__GMP_DECLSPEC void mpf_clears __GMP_PROTO ((mpf_ptr, ...)); -#define mpf_cmp __gmpf_cmp -__GMP_DECLSPEC int mpf_cmp __GMP_PROTO ((mpf_srcptr, mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#define mpf_cmp_d __gmpf_cmp_d -__GMP_DECLSPEC int mpf_cmp_d __GMP_PROTO ((mpf_srcptr, double)) __GMP_ATTRIBUTE_PURE; -#define mpf_cmp_si __gmpf_cmp_si -__GMP_DECLSPEC int mpf_cmp_si __GMP_PROTO ((mpf_srcptr, signed long int)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#define mpf_cmp_ui __gmpf_cmp_ui -__GMP_DECLSPEC int mpf_cmp_ui __GMP_PROTO ((mpf_srcptr, unsigned long int)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#define mpf_div __gmpf_div -__GMP_DECLSPEC void mpf_div __GMP_PROTO ((mpf_ptr, mpf_srcptr, mpf_srcptr)); -#define mpf_div_2exp __gmpf_div_2exp -__GMP_DECLSPEC void mpf_div_2exp __GMP_PROTO ((mpf_ptr, mpf_srcptr, mp_bitcnt_t)); -#define mpf_div_ui __gmpf_div_ui -__GMP_DECLSPEC void mpf_div_ui __GMP_PROTO ((mpf_ptr, mpf_srcptr, unsigned long int)); -#define mpf_dump __gmpf_dump -__GMP_DECLSPEC void mpf_dump __GMP_PROTO ((mpf_srcptr)); -#define mpf_eq __gmpf_eq -__GMP_DECLSPEC int mpf_eq __GMP_PROTO ((mpf_srcptr, mpf_srcptr, unsigned long int)) __GMP_ATTRIBUTE_PURE; -#define mpf_fits_sint_p __gmpf_fits_sint_p -__GMP_DECLSPEC int mpf_fits_sint_p __GMP_PROTO ((mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#define mpf_fits_slong_p __gmpf_fits_slong_p -__GMP_DECLSPEC int mpf_fits_slong_p __GMP_PROTO ((mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#define mpf_fits_sshort_p __gmpf_fits_sshort_p -__GMP_DECLSPEC int mpf_fits_sshort_p __GMP_PROTO ((mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#define mpf_fits_uint_p __gmpf_fits_uint_p -__GMP_DECLSPEC int mpf_fits_uint_p __GMP_PROTO ((mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#define mpf_fits_ulong_p __gmpf_fits_ulong_p -__GMP_DECLSPEC int mpf_fits_ulong_p __GMP_PROTO ((mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#define mpf_fits_ushort_p __gmpf_fits_ushort_p -__GMP_DECLSPEC int mpf_fits_ushort_p __GMP_PROTO ((mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#define mpf_floor __gmpf_floor -__GMP_DECLSPEC void mpf_floor __GMP_PROTO ((mpf_ptr, mpf_srcptr)); -#define mpf_get_d __gmpf_get_d -__GMP_DECLSPEC double mpf_get_d __GMP_PROTO ((mpf_srcptr)) __GMP_ATTRIBUTE_PURE; -#define mpf_get_d_2exp __gmpf_get_d_2exp -__GMP_DECLSPEC double mpf_get_d_2exp __GMP_PROTO ((signed long int *, mpf_srcptr)); -#define mpf_get_default_prec __gmpf_get_default_prec -__GMP_DECLSPEC mp_bitcnt_t mpf_get_default_prec __GMP_PROTO ((void)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#define mpf_get_prec __gmpf_get_prec -__GMP_DECLSPEC mp_bitcnt_t mpf_get_prec __GMP_PROTO ((mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#define mpf_get_si __gmpf_get_si -__GMP_DECLSPEC long mpf_get_si __GMP_PROTO ((mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#define mpf_get_str __gmpf_get_str -__GMP_DECLSPEC char *mpf_get_str __GMP_PROTO ((char *, mp_exp_t *, int, size_t, mpf_srcptr)); -#define mpf_get_ui __gmpf_get_ui -__GMP_DECLSPEC unsigned long mpf_get_ui __GMP_PROTO ((mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#define mpf_init __gmpf_init -__GMP_DECLSPEC void mpf_init __GMP_PROTO ((mpf_ptr)); -#define mpf_init2 __gmpf_init2 -__GMP_DECLSPEC void mpf_init2 __GMP_PROTO ((mpf_ptr, mp_bitcnt_t)); -#define mpf_inits __gmpf_inits -__GMP_DECLSPEC void mpf_inits __GMP_PROTO ((mpf_ptr, ...)); -#define mpf_init_set __gmpf_init_set -__GMP_DECLSPEC void mpf_init_set __GMP_PROTO ((mpf_ptr, mpf_srcptr)); -#define mpf_init_set_d __gmpf_init_set_d -__GMP_DECLSPEC void mpf_init_set_d __GMP_PROTO ((mpf_ptr, double)); -#define mpf_init_set_si __gmpf_init_set_si -__GMP_DECLSPEC void mpf_init_set_si __GMP_PROTO ((mpf_ptr, signed long int)); -#define mpf_init_set_str __gmpf_init_set_str -__GMP_DECLSPEC int mpf_init_set_str __GMP_PROTO ((mpf_ptr, __gmp_const char *, int)); -#define mpf_init_set_ui __gmpf_init_set_ui -__GMP_DECLSPEC void mpf_init_set_ui __GMP_PROTO ((mpf_ptr, unsigned long int)); -#define mpf_inp_str __gmpf_inp_str -#ifdef _GMP_H_HAVE_FILE -__GMP_DECLSPEC size_t mpf_inp_str __GMP_PROTO ((mpf_ptr, FILE *, int)); -#endif -#define mpf_integer_p __gmpf_integer_p -__GMP_DECLSPEC int mpf_integer_p __GMP_PROTO ((mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#define mpf_mul __gmpf_mul -__GMP_DECLSPEC void mpf_mul __GMP_PROTO ((mpf_ptr, mpf_srcptr, mpf_srcptr)); -#define mpf_mul_2exp __gmpf_mul_2exp -__GMP_DECLSPEC void mpf_mul_2exp __GMP_PROTO ((mpf_ptr, mpf_srcptr, mp_bitcnt_t)); -#define mpf_mul_ui __gmpf_mul_ui -__GMP_DECLSPEC void mpf_mul_ui __GMP_PROTO ((mpf_ptr, mpf_srcptr, unsigned long int)); -#define mpf_neg __gmpf_neg -__GMP_DECLSPEC void mpf_neg __GMP_PROTO ((mpf_ptr, mpf_srcptr)); -#define mpf_out_str __gmpf_out_str -#ifdef _GMP_H_HAVE_FILE -__GMP_DECLSPEC size_t mpf_out_str __GMP_PROTO ((FILE *, int, size_t, mpf_srcptr)); -#endif -#define mpf_pow_ui __gmpf_pow_ui -__GMP_DECLSPEC void mpf_pow_ui __GMP_PROTO ((mpf_ptr, mpf_srcptr, unsigned long int)); -#define mpf_random2 __gmpf_random2 -__GMP_DECLSPEC void mpf_random2 __GMP_PROTO ((mpf_ptr, mp_size_t, mp_exp_t)); -#define mpf_rrandomb __gmpf_rrandomb -__GMP_DECLSPEC void mpf_rrandomb __GMP_PROTO ((mpf_ptr, gmp_randstate_t, mp_size_t, mp_exp_t)); -#define mpf_reldiff __gmpf_reldiff -__GMP_DECLSPEC void mpf_reldiff __GMP_PROTO ((mpf_ptr, mpf_srcptr, mpf_srcptr)); -#define mpf_set __gmpf_set -__GMP_DECLSPEC void mpf_set __GMP_PROTO ((mpf_ptr, mpf_srcptr)); -#define mpf_set_d __gmpf_set_d -__GMP_DECLSPEC void mpf_set_d __GMP_PROTO ((mpf_ptr, double)); -#define mpf_set_default_prec __gmpf_set_default_prec -__GMP_DECLSPEC void mpf_set_default_prec __GMP_PROTO ((mp_bitcnt_t)) __GMP_NOTHROW; -#define mpf_set_prec __gmpf_set_prec -__GMP_DECLSPEC void mpf_set_prec __GMP_PROTO ((mpf_ptr, mp_bitcnt_t)); -#define mpf_set_prec_raw __gmpf_set_prec_raw -__GMP_DECLSPEC void mpf_set_prec_raw __GMP_PROTO ((mpf_ptr, mp_bitcnt_t)) __GMP_NOTHROW; -#define mpf_set_q __gmpf_set_q -__GMP_DECLSPEC void mpf_set_q __GMP_PROTO ((mpf_ptr, mpq_srcptr)); -#define mpf_set_si __gmpf_set_si -__GMP_DECLSPEC void mpf_set_si __GMP_PROTO ((mpf_ptr, signed long int)); -#define mpf_set_str __gmpf_set_str -__GMP_DECLSPEC int mpf_set_str __GMP_PROTO ((mpf_ptr, __gmp_const char *, int)); -#define mpf_set_ui __gmpf_set_ui -__GMP_DECLSPEC void mpf_set_ui __GMP_PROTO ((mpf_ptr, unsigned long int)); -#define mpf_set_z __gmpf_set_z -__GMP_DECLSPEC void mpf_set_z __GMP_PROTO ((mpf_ptr, mpz_srcptr)); -#define mpf_size __gmpf_size -__GMP_DECLSPEC size_t mpf_size __GMP_PROTO ((mpf_srcptr)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#define mpf_sqrt __gmpf_sqrt -__GMP_DECLSPEC void mpf_sqrt __GMP_PROTO ((mpf_ptr, mpf_srcptr)); -#define mpf_sqrt_ui __gmpf_sqrt_ui -__GMP_DECLSPEC void mpf_sqrt_ui __GMP_PROTO ((mpf_ptr, unsigned long int)); -#define mpf_sub __gmpf_sub -__GMP_DECLSPEC void mpf_sub __GMP_PROTO ((mpf_ptr, mpf_srcptr, mpf_srcptr)); -#define mpf_sub_ui __gmpf_sub_ui -__GMP_DECLSPEC void mpf_sub_ui __GMP_PROTO ((mpf_ptr, mpf_srcptr, unsigned long int)); -#define mpf_swap __gmpf_swap -__GMP_DECLSPEC void mpf_swap __GMP_PROTO ((mpf_ptr, mpf_ptr)) __GMP_NOTHROW; -#define mpf_trunc __gmpf_trunc -__GMP_DECLSPEC void mpf_trunc __GMP_PROTO ((mpf_ptr, mpf_srcptr)); -#define mpf_ui_div __gmpf_ui_div -__GMP_DECLSPEC void mpf_ui_div __GMP_PROTO ((mpf_ptr, unsigned long int, mpf_srcptr)); -#define mpf_ui_sub __gmpf_ui_sub -__GMP_DECLSPEC void mpf_ui_sub __GMP_PROTO ((mpf_ptr, unsigned long int, mpf_srcptr)); -#define mpf_urandomb __gmpf_urandomb -__GMP_DECLSPEC void mpf_urandomb __GMP_PROTO ((mpf_t, gmp_randstate_t, mp_bitcnt_t)); -/************ Low level positive-integer (i.e. N) routines. ************/ -/* This is ugly, but we need to make user calls reach the prefixed function. */ -#define mpn_add __MPN(add) -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpn_add) -__GMP_DECLSPEC mp_limb_t mpn_add __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_srcptr,mp_size_t)); -#endif -#define mpn_add_1 __MPN(add_1) -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpn_add_1) -__GMP_DECLSPEC mp_limb_t mpn_add_1 __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_limb_t)) __GMP_NOTHROW; -#endif -#define mpn_add_n __MPN(add_n) -__GMP_DECLSPEC mp_limb_t mpn_add_n __GMP_PROTO ((mp_ptr, mp_srcptr, mp_srcptr, mp_size_t)); -#define mpn_addmul_1 __MPN(addmul_1) -__GMP_DECLSPEC mp_limb_t mpn_addmul_1 __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_limb_t)); -#define mpn_bdivmod __MPN(bdivmod) -__GMP_DECLSPEC mp_limb_t mpn_bdivmod __GMP_PROTO ((mp_ptr, mp_ptr, mp_size_t, mp_srcptr, mp_size_t, unsigned long int)); -#define mpn_divrem __MPN(divrem) -__GMP_DECLSPEC mp_limb_t mpn_divrem __GMP_PROTO ((mp_ptr, mp_size_t, mp_ptr, mp_size_t, mp_srcptr, mp_size_t)); -#define mpn_mulmod_2expp1 __MPN(mulmod_2expp1) -__GMP_DECLSPEC int mpn_mulmod_2expp1 __GMP_PROTO ((mp_ptr, mp_srcptr, mp_srcptr,int,unsigned long, mp_ptr)); -#define mpn_mulmod_2expm1 __MPN(mulmod_2expm1) -__GMP_DECLSPEC void mpn_mulmod_2expm1 __GMP_PROTO ((mp_ptr, mp_ptr, mp_ptr,unsigned long, mp_ptr)); -#define mpn_cmp __MPN(cmp) -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpn_cmp) -__GMP_DECLSPEC int mpn_cmp __GMP_PROTO ((mp_srcptr, mp_srcptr, mp_size_t)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#endif -#define mpn_divexact_by3(dst,src,size) \ - mpn_divexact_by3c (dst, src, size, __GMP_CAST (mp_limb_t, 0)) -#define mpn_divexact_by3c __MPN(divexact_by3c) -__GMP_DECLSPEC mp_limb_t mpn_divexact_by3c __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_limb_t)); -#define mpn_divmod_1(qp,np,nsize,dlimb) \ - mpn_divrem_1 (qp, __GMP_CAST (mp_size_t, 0), np, nsize, dlimb) -#define mpn_divrem_1 __MPN(divrem_1) -__GMP_DECLSPEC mp_limb_t mpn_divrem_1 __GMP_PROTO ((mp_ptr, mp_size_t, mp_srcptr, mp_size_t, mp_limb_t)); -#define mpn_divrem_2 __MPN(divrem_2) -__GMP_DECLSPEC mp_limb_t mpn_divrem_2 __GMP_PROTO ((mp_ptr, mp_size_t, mp_ptr, mp_size_t, mp_srcptr)); -#define mpn_invert __MPN(invert) -__GMP_DECLSPEC void mpn_invert __GMP_PROTO ((mp_ptr xp, mp_srcptr ap, mp_size_t n)); -#define mpn_sb_divappr_q __MPN(sb_divappr_q) -__GMP_DECLSPEC mp_limb_t mpn_sb_divappr_q __GMP_PROTO ((mp_ptr qp, mp_ptr np, mp_size_t nn, - mp_srcptr dp, mp_size_t dn, mp_limb_t dip)); -#define mpn_dc_divappr_q_n __MPN(dc_divappr_q_n) -__GMP_DECLSPEC mp_limb_t mpn_dc_divappr_q_n __GMP_PROTO ((mp_ptr qp, mp_ptr np, mp_srcptr dp, mp_size_t n, - mp_limb_t dip, mp_ptr tp)); -#define mpn_dc_bdiv_q_n __MPN(dc_bdiv_q_n) -__GMP_DECLSPEC void mpn_dc_bdiv_q_n __GMP_PROTO ((mp_ptr qp, mp_ptr wp, mp_ptr np, mp_srcptr dp, mp_size_t n, - mp_limb_t dinv, mp_ptr scratch)); -#define mpn_inv_divappr_q_n __MPN(inv_divappr_q_n) -__GMP_DECLSPEC mp_limb_t mpn_inv_divappr_q_n __GMP_PROTO ((mp_ptr qp, mp_ptr np, mp_srcptr dp, mp_size_t n, - mp_srcptr dip)); -#define mpn_dc_divappr_q __MPN(dc_divappr_q) -__GMP_DECLSPEC mp_limb_t mpn_dc_divappr_q __GMP_PROTO ((mp_ptr qp, mp_ptr np, mp_size_t nn, mp_srcptr dp, mp_size_t n, - mp_limb_t dinv)); -#define mpn_dc_div_q __MPN(dc_div_q) -__GMP_DECLSPEC mp_limb_t mpn_dc_div_q __GMP_PROTO ((mp_ptr qp, mp_ptr np, mp_size_t nn, - mp_srcptr dp, mp_size_t dn, mp_limb_t dinv)); -#define mpn_inv_divappr_q __MPN(inv_divappr_q) -__GMP_DECLSPEC mp_limb_t mpn_inv_divappr_q __GMP_PROTO ((mp_ptr qp, mp_ptr np, mp_size_t nn, mp_srcptr dp, mp_size_t n, - mp_srcptr dinv)); -#define mpn_inv_div_q __MPN(inv_div_q) -__GMP_DECLSPEC mp_limb_t mpn_inv_div_q __GMP_PROTO ((mp_ptr qp, mp_ptr np, mp_size_t nn, - mp_srcptr dp, mp_size_t dn, mp_srcptr dinv)); -#define mpn_inv_div_qr __MPN(inv_div_qr) -__GMP_DECLSPEC mp_limb_t mpn_inv_div_qr __GMP_PROTO ((mp_ptr qp, mp_ptr np, mp_size_t nn, - mp_srcptr dp, mp_size_t dn, mp_srcptr dinv)); -#define mpn_inv_div_qr_n __MPN(inv_div_qr_n) -__GMP_DECLSPEC mp_limb_t mpn_inv_div_qr_n __GMP_PROTO ((mp_ptr qp, mp_ptr np, - mp_srcptr dp, mp_size_t dn, mp_srcptr dinv)); -#define mpn_dc_div_qr __MPN(dc_div_qr) -__GMP_DECLSPEC mp_limb_t mpn_dc_div_qr __GMP_PROTO ((mp_ptr qp, mp_ptr np, mp_size_t nn, - mp_srcptr dp, mp_size_t dn, mp_limb_t dinv)); -#define mpn_dc_div_qr_n __MPN(dc_div_qr_n) -__GMP_DECLSPEC mp_limb_t mpn_dc_div_qr_n __GMP_PROTO ((mp_ptr qp, mp_ptr np, mp_srcptr dp, mp_size_t n, - mp_limb_t dinv, mp_ptr tp)); -#define mpn_sb_div_q __MPN(sb_div_q) -__GMP_DECLSPEC mp_limb_t mpn_sb_div_q __GMP_PROTO ((mp_ptr qp, mp_ptr np, mp_size_t nn, - mp_srcptr dp, mp_size_t dn, mp_limb_t dinv)); -#define mpn_sb_bdiv_q __MPN(sb_bdiv_q) -__GMP_DECLSPEC void mpn_sb_bdiv_q __GMP_PROTO ((mp_ptr qp, mp_ptr wp, mp_ptr np, mp_size_t nn, - mp_srcptr dp, mp_size_t dn, mp_limb_t dinv)); -#define mpn_dc_bdiv_q __MPN(dc_bdiv_q) -__GMP_DECLSPEC void mpn_dc_bdiv_q __GMP_PROTO ((mp_ptr qp, mp_ptr np, mp_size_t nn, - mp_srcptr dp, mp_size_t dn, mp_limb_t dinv)); -#define mpn_dc_bdiv_qr __MPN(dc_bdiv_qr) -__GMP_DECLSPEC mp_limb_t mpn_dc_bdiv_qr __GMP_PROTO ((mp_ptr qp, mp_ptr np, mp_size_t nn, - mp_srcptr dp, mp_size_t dn, mp_limb_t dinv)); -#define mpn_dc_bdiv_qr_n __MPN(dc_bdiv_qr_n) -__GMP_DECLSPEC mp_limb_t mpn_dc_bdiv_qr_n __GMP_PROTO ((mp_ptr qp, mp_ptr np, - mp_srcptr dp, mp_size_t n, mp_limb_t dinv, mp_ptr tp)); -#define mpn_sb_div_qr __MPN(sb_div_qr) -__GMP_DECLSPEC mp_limb_t mpn_sb_div_qr __GMP_PROTO ((mp_ptr qp, mp_ptr np, mp_size_t nn, - mp_srcptr dp, mp_size_t dn, mp_limb_t dinv)); -#define mpn_sb_bdiv_qr __MPN(sb_bdiv_qr) -__GMP_DECLSPEC mp_limb_t mpn_sb_bdiv_qr __GMP_PROTO ((mp_ptr qp, mp_ptr np, mp_size_t nn, - mp_srcptr dp, mp_size_t dn, mp_limb_t dinv)); -#define mpn_tdiv_q __MPN(tdiv_q) -__GMP_DECLSPEC void mpn_tdiv_q __GMP_PROTO ((mp_ptr qp, mp_srcptr np, mp_size_t nn, - mp_srcptr dp, mp_size_t dn)); -#define mpn_divexact __MPN(divexact) -__GMP_DECLSPEC void mpn_divexact __GMP_PROTO ((mp_ptr qp, - mp_srcptr np, mp_size_t nn, mp_srcptr dp, mp_size_t dn)); -#define mpn_redc_1 __MPN(redc_1) -__GMP_DECLSPEC void mpn_redc_1 __GMP_PROTO ((mp_ptr, mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);) -#define mpn_gcd __MPN(gcd) -__GMP_DECLSPEC mp_size_t mpn_gcd __GMP_PROTO ((mp_ptr, mp_ptr, mp_size_t, mp_ptr, mp_size_t)); -#define mpn_gcd_1 __MPN(gcd_1) -__GMP_DECLSPEC mp_limb_t mpn_gcd_1 __GMP_PROTO ((mp_srcptr, mp_size_t, mp_limb_t)) __GMP_ATTRIBUTE_PURE; -#define mpn_gcdext __MPN(gcdext) -__GMP_DECLSPEC mp_size_t mpn_gcdext __GMP_PROTO ((mp_ptr, mp_ptr, mp_size_t *, mp_ptr, mp_size_t, mp_ptr, mp_size_t)); -#define mpn_get_str __MPN(get_str) -__GMP_DECLSPEC size_t mpn_get_str __GMP_PROTO ((unsigned char *, int, mp_ptr, mp_size_t)); -#define mpn_hamdist __MPN(hamdist) -__GMP_DECLSPEC mp_bitcnt_t mpn_hamdist __GMP_PROTO ((mp_srcptr, mp_srcptr, mp_size_t)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#define mpn_lshift __MPN(lshift) -__GMP_DECLSPEC mp_limb_t mpn_lshift __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, unsigned int)); -#define mpn_mod_1 __MPN(mod_1) -__GMP_DECLSPEC mp_limb_t mpn_mod_1 __GMP_PROTO ((mp_srcptr, mp_size_t, mp_limb_t)) __GMP_ATTRIBUTE_PURE; -#define mpn_mul __MPN(mul) -__GMP_DECLSPEC mp_limb_t mpn_mul __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t)); -#define mpn_mul_1 __MPN(mul_1) -__GMP_DECLSPEC mp_limb_t mpn_mul_1 __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_limb_t)); -#define mpn_mul_n __MPN(mul_n) -__GMP_DECLSPEC void mpn_mul_n __GMP_PROTO ((mp_ptr, mp_srcptr, mp_srcptr, mp_size_t)); -#define mpn_sqr __MPN(sqr) -__GMP_DECLSPEC void mpn_sqr __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t)); -#define mpn_neg_n __MPN(neg_n) -#define mpn_neg __MPN(neg_n) -__GMP_DECLSPEC mp_limb_t mpn_neg_n __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t)); -#define mpn_com_n __MPN(com_n) -#define mpn_com __MPN(com_n) -__GMP_DECLSPEC void mpn_com_n __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t)); -#define mpn_perfect_square_p __MPN(perfect_square_p) -__GMP_DECLSPEC int mpn_perfect_square_p __GMP_PROTO ((mp_srcptr, mp_size_t)) __GMP_ATTRIBUTE_PURE; -#define mpn_popcount __MPN(popcount) -__GMP_DECLSPEC mp_bitcnt_t mpn_popcount __GMP_PROTO ((mp_srcptr, mp_size_t)) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; -#define mpn_pow_1 __MPN(pow_1) -__GMP_DECLSPEC mp_size_t mpn_pow_1 __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_limb_t, mp_ptr)); -/* undocumented now, but retained here for upward compatibility */ -#define mpn_preinv_mod_1 __MPN(preinv_mod_1) -__GMP_DECLSPEC mp_limb_t mpn_preinv_mod_1 __GMP_PROTO ((mp_srcptr, mp_size_t, mp_limb_t, mp_limb_t)) __GMP_ATTRIBUTE_PURE; -#define mpn_random __MPN(random) -__GMP_DECLSPEC void mpn_random __GMP_PROTO ((mp_ptr, mp_size_t)); -#define mpn_random2 __MPN(random2) -__GMP_DECLSPEC void mpn_random2 __GMP_PROTO ((mp_ptr, mp_size_t)); -#define mpn_urandomb __MPN(urandomb) -__GMP_DECLSPEC void mpn_urandomb __GMP_PROTO ((mp_ptr, gmp_randstate_t, unsigned long)); -#define mpn_urandomm __MPN(urandomm) -__GMP_DECLSPEC void mpn_urandomm __GMP_PROTO ((mp_ptr, gmp_randstate_t, mp_srcptr, mp_size_t)); -#define mpn_randomb __MPN(randomb) -__GMP_DECLSPEC void mpn_randomb __GMP_PROTO ((mp_ptr, gmp_randstate_t, mp_size_t)); -#define mpn_rrandom __MPN(rrandom) -__GMP_DECLSPEC void mpn_rrandom __GMP_PROTO ((mp_ptr, gmp_randstate_t, mp_size_t)); -#define mpn_rshift __MPN(rshift) -__GMP_DECLSPEC mp_limb_t mpn_rshift __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, unsigned int)); -#define mpn_scan0 __MPN(scan0) -__GMP_DECLSPEC mp_bitcnt_t mpn_scan0 __GMP_PROTO ((mp_srcptr, mp_bitcnt_t)) __GMP_ATTRIBUTE_PURE; -#define mpn_scan1 __MPN(scan1) -__GMP_DECLSPEC mp_bitcnt_t mpn_scan1 __GMP_PROTO ((mp_srcptr, mp_bitcnt_t)) __GMP_ATTRIBUTE_PURE; -#define mpn_set_str __MPN(set_str) -__GMP_DECLSPEC mp_size_t mpn_set_str __GMP_PROTO ((mp_ptr, __gmp_const unsigned char *, size_t, int)); -#define mpn_sqrtrem __MPN(sqrtrem) -__GMP_DECLSPEC mp_size_t mpn_sqrtrem __GMP_PROTO ((mp_ptr, mp_ptr, mp_srcptr, mp_size_t)); -#define mpn_sub __MPN(sub) -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpn_sub) -__GMP_DECLSPEC mp_limb_t mpn_sub __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_srcptr,mp_size_t)); -#endif -#define mpn_sub_1 __MPN(sub_1) -#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpn_sub_1) -__GMP_DECLSPEC mp_limb_t mpn_sub_1 __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_limb_t)) __GMP_NOTHROW; -#endif -#define mpn_sub_n __MPN(sub_n) -__GMP_DECLSPEC mp_limb_t mpn_sub_n __GMP_PROTO ((mp_ptr, mp_srcptr, mp_srcptr, mp_size_t)); -#define mpn_submul_1 __MPN(submul_1) -__GMP_DECLSPEC mp_limb_t mpn_submul_1 __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_limb_t)); -#define mpn_tdiv_qr __MPN(tdiv_qr) -__GMP_DECLSPEC void mpn_tdiv_qr __GMP_PROTO ((mp_ptr, mp_ptr, mp_size_t, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t)); -#define mpn_and_n __MPN(and_n) -__GMP_DECLSPEC void mpn_and_n __GMP_PROTO ((mp_ptr, mp_srcptr, mp_srcptr, mp_size_t)); -#define mpn_andn_n __MPN(andn_n) -__GMP_DECLSPEC void mpn_andn_n __GMP_PROTO ((mp_ptr, mp_srcptr, mp_srcptr, mp_size_t)); -#define mpn_nand_n __MPN(nand_n) -__GMP_DECLSPEC void mpn_nand_n __GMP_PROTO ((mp_ptr, mp_srcptr, mp_srcptr, mp_size_t)); -#define mpn_ior_n __MPN(ior_n) -__GMP_DECLSPEC void mpn_ior_n __GMP_PROTO ((mp_ptr, mp_srcptr, mp_srcptr, mp_size_t)); -#define mpn_iorn_n __MPN(iorn_n) -__GMP_DECLSPEC void mpn_iorn_n __GMP_PROTO ((mp_ptr, mp_srcptr, mp_srcptr, mp_size_t)); -#define mpn_nior_n __MPN(nior_n) -__GMP_DECLSPEC void mpn_nior_n __GMP_PROTO ((mp_ptr, mp_srcptr, mp_srcptr, mp_size_t)); -#define mpn_xor_n __MPN(xor_n) -__GMP_DECLSPEC void mpn_xor_n __GMP_PROTO ((mp_ptr, mp_srcptr, mp_srcptr, mp_size_t)); -#define mpn_xnor_n __MPN(xnor_n) -__GMP_DECLSPEC void mpn_xnor_n __GMP_PROTO ((mp_ptr, mp_srcptr, mp_srcptr, mp_size_t)); -#define mpn_copyi __MPN(copyi) -__GMP_DECLSPEC void mpn_copyi __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t)); -#define mpn_copyd __MPN(copyd) -__GMP_DECLSPEC void mpn_copyd __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t)); -#define mpn_zero __MPN(zero) -__GMP_DECLSPEC void mpn_zero __GMP_PROTO ((mp_ptr, mp_size_t)); -/**************** mpz inlines ****************/ -/* The following are provided as inlines where possible, but always exist as - library functions too, for binary compatibility. - Within gmp itself this inlining generally isn't relied on, since it - doesn't get done for all compilers, whereas if something is worth - inlining then it's worth arranging always. - There are two styles of inlining here. When the same bit of code is - wanted for the inline as for the library version, then __GMP_FORCE_foo - arranges for that code to be emitted and the __GMP_EXTERN_INLINE - directive suppressed, eg. mpz_fits_uint_p. When a different bit of code - is wanted for the inline than for the library version, then - __GMP_FORCE_foo arranges the inline to be suppressed, eg. mpz_abs. */ -#if defined (__GMP_EXTERN_INLINE) && ! defined (__GMP_FORCE_mpz_abs) -__GMP_EXTERN_INLINE void -mpz_abs (mpz_ptr __gmp_w, mpz_srcptr __gmp_u) -{ - if (__gmp_w != __gmp_u) - mpz_set (__gmp_w, __gmp_u); - __gmp_w->_mp_size = __GMP_ABS (__gmp_w->_mp_size); -} -#endif -#if GMP_NAIL_BITS == 0 -#define __GMPZ_FITS_UTYPE_P(z,maxval) \ - mp_size_t __gmp_n = z->_mp_size; \ - mp_ptr __gmp_p = z->_mp_d; \ - return (__gmp_n == 0 || (__gmp_n == 1 && __gmp_p[0] <= maxval)); -#else -#define __GMPZ_FITS_UTYPE_P(z,maxval) \ - mp_size_t __gmp_n = z->_mp_size; \ - mp_ptr __gmp_p = z->_mp_d; \ - return (__gmp_n == 0 || (__gmp_n == 1 && __gmp_p[0] <= maxval) \ - || (__gmp_n == 2 && __gmp_p[1] <= ((mp_limb_t) maxval >> GMP_NUMB_BITS))); -#endif -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_fits_uint_p) -#if ! defined (__GMP_FORCE_mpz_fits_uint_p) -__GMP_EXTERN_INLINE -#endif -int -mpz_fits_uint_p (mpz_srcptr __gmp_z) __GMP_NOTHROW -{ - __GMPZ_FITS_UTYPE_P (__gmp_z, __GMP_UINT_MAX); -} -#endif -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_fits_ulong_p) -#if ! defined (__GMP_FORCE_mpz_fits_ulong_p) -__GMP_EXTERN_INLINE -#endif -int -mpz_fits_ulong_p (mpz_srcptr __gmp_z) __GMP_NOTHROW -{ - __GMPZ_FITS_UTYPE_P (__gmp_z, __GMP_ULONG_MAX); -} -#endif -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_fits_ushort_p) -#if ! defined (__GMP_FORCE_mpz_fits_ushort_p) -__GMP_EXTERN_INLINE -#endif -int -mpz_fits_ushort_p (mpz_srcptr __gmp_z) __GMP_NOTHROW -{ - __GMPZ_FITS_UTYPE_P (__gmp_z, __GMP_USHRT_MAX); -} -#endif -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_get_ui) -#if ! defined (__GMP_FORCE_mpz_get_ui) -__GMP_EXTERN_INLINE -#endif -unsigned long -mpz_get_ui (mpz_srcptr __gmp_z) __GMP_NOTHROW -{ - mp_ptr __gmp_p = __gmp_z->_mp_d; - mp_size_t __gmp_n = __gmp_z->_mp_size; - mp_limb_t __gmp_l = __gmp_p[0]; - /* This is a "#if" rather than a plain "if" so as to avoid gcc warnings - about "<< GMP_NUMB_BITS" exceeding the type size, and to avoid Borland - C++ 6.0 warnings about condition always true for something like - "__GMP_ULONG_MAX < GMP_NUMB_MASK". */ -#if GMP_NAIL_BITS == 0 || defined (_LONG_LONG_LIMB) - /* limb==long and no nails, or limb==longlong, one limb is enough */ - return (unsigned long)(__gmp_n != 0 ? __gmp_l : 0); -#else - /* limb==long and nails, need two limbs when available */ - __gmp_n = __GMP_ABS (__gmp_n); - if (__gmp_n <= 1) - return (__gmp_n != 0 ? __gmp_l : 0); - else - return __gmp_l + (__gmp_p[1] << GMP_NUMB_BITS); -#endif -} -#endif -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_getlimbn) -#if ! defined (__GMP_FORCE_mpz_getlimbn) -__GMP_EXTERN_INLINE -#endif -mp_limb_t -mpz_getlimbn (mpz_srcptr __gmp_z, mp_size_t __gmp_n) __GMP_NOTHROW -{ - mp_limb_t __gmp_result = 0; - if (__GMP_LIKELY (__gmp_n >= 0 && __gmp_n < __GMP_ABS (__gmp_z->_mp_size))) - __gmp_result = __gmp_z->_mp_d[__gmp_n]; - return __gmp_result; -} -#endif -#if defined (__GMP_EXTERN_INLINE) && ! defined (__GMP_FORCE_mpz_neg) -__GMP_EXTERN_INLINE void -mpz_neg (mpz_ptr __gmp_w, mpz_srcptr __gmp_u) -{ - if (__gmp_w != __gmp_u) - mpz_set (__gmp_w, __gmp_u); - __gmp_w->_mp_size = - __gmp_w->_mp_size; -} -#endif -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_perfect_square_p) -#if ! defined (__GMP_FORCE_mpz_perfect_square_p) -__GMP_EXTERN_INLINE -#endif -int -mpz_perfect_square_p (mpz_srcptr __gmp_a) -{ - mp_size_t __gmp_asize; - int __gmp_result; - __gmp_asize = __gmp_a->_mp_size; - __gmp_result = (__gmp_asize >= 0); /* zero is a square, negatives are not */ - if (__GMP_LIKELY (__gmp_asize > 0)) - __gmp_result = mpn_perfect_square_p (__gmp_a->_mp_d, __gmp_asize); - return __gmp_result; -} -#endif -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_popcount) -#if ! defined (__GMP_FORCE_mpz_popcount) -__GMP_EXTERN_INLINE -#endif -mp_bitcnt_t -mpz_popcount (mpz_srcptr __gmp_u) __GMP_NOTHROW -{ - mp_size_t __gmp_usize; - mp_bitcnt_t __gmp_result; - __gmp_usize = __gmp_u->_mp_size; - __gmp_result = (__gmp_usize < 0 ? __GMP_ULONG_MAX : 0); - if (__GMP_LIKELY (__gmp_usize > 0)) - __gmp_result = mpn_popcount (__gmp_u->_mp_d, __gmp_usize); - return __gmp_result; -} -#endif -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_set_q) -#if ! defined (__GMP_FORCE_mpz_set_q) -__GMP_EXTERN_INLINE -#endif -void -mpz_set_q (mpz_ptr __gmp_w, mpq_srcptr __gmp_u) -{ - mpz_tdiv_q (__gmp_w, mpq_numref (__gmp_u), mpq_denref (__gmp_u)); -} -#endif -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_size) -#if ! defined (__GMP_FORCE_mpz_size) -__GMP_EXTERN_INLINE -#endif -size_t -mpz_size (mpz_srcptr __gmp_z) __GMP_NOTHROW -{ - return __GMP_ABS (__gmp_z->_mp_size); -} -#endif -/**************** mpq inlines ****************/ -#if defined (__GMP_EXTERN_INLINE) && ! defined (__GMP_FORCE_mpq_abs) -__GMP_EXTERN_INLINE void -mpq_abs (mpq_ptr __gmp_w, mpq_srcptr __gmp_u) -{ - if (__gmp_w != __gmp_u) - mpq_set (__gmp_w, __gmp_u); - __gmp_w->_mp_num._mp_size = __GMP_ABS (__gmp_w->_mp_num._mp_size); -} -#endif -#if defined (__GMP_EXTERN_INLINE) && ! defined (__GMP_FORCE_mpq_neg) -__GMP_EXTERN_INLINE void -mpq_neg (mpq_ptr __gmp_w, mpq_srcptr __gmp_u) -{ - if (__gmp_w != __gmp_u) - mpq_set (__gmp_w, __gmp_u); - __gmp_w->_mp_num._mp_size = - __gmp_w->_mp_num._mp_size; -} -#endif -/**************** mpn inlines ****************/ -/* The comments with __GMPN_ADD_1 below apply here too. - The test for FUNCTION returning 0 should predict well. If it's assumed - {yp,ysize} will usually have a random number of bits then the high limb - won't be full and a carry out will occur a good deal less than 50% of the - time. - ysize==0 isn't a documented feature, but is used internally in a few - places. - Producing cout last stops it using up a register during the main part of - the calculation, though gcc (as of 3.0) on an "if (mpn_add (...))" - doesn't seem able to move the true and false legs of the conditional up - to the two places cout is generated. */ -#define __GMPN_AORS(cout, wp, xp, xsize, yp, ysize, FUNCTION, TEST) \ - do { \ - mp_size_t __gmp_i; \ - mp_limb_t __gmp_x; \ - \ - /* ASSERT ((ysize) >= 0); */ \ - /* ASSERT ((xsize) >= (ysize)); */ \ - /* ASSERT (MPN_SAME_OR_SEPARATE2_P (wp, xsize, xp, xsize)); */ \ - /* ASSERT (MPN_SAME_OR_SEPARATE2_P (wp, xsize, yp, ysize)); */ \ - \ - __gmp_i = (ysize); \ - if (__gmp_i != 0) \ - { \ - if (FUNCTION (wp, xp, yp, __gmp_i)) \ - { \ - do \ - { \ - if (__gmp_i >= (xsize)) \ - { \ - (cout) = 1; \ - goto __gmp_done; \ - } \ - __gmp_x = (xp)[__gmp_i]; \ - } \ - while (TEST); \ - } \ - } \ - if ((wp) != (xp)) \ - __GMPN_COPY_REST (wp, xp, xsize, __gmp_i); \ - (cout) = 0; \ - __gmp_done: \ - ; \ - } while (0) -#define __GMPN_ADD(cout, wp, xp, xsize, yp, ysize) \ - __GMPN_AORS (cout, wp, xp, xsize, yp, ysize, mpn_add_n, \ - (((wp)[__gmp_i++] = (__gmp_x + 1) & GMP_NUMB_MASK) == 0)) -#define __GMPN_SUB(cout, wp, xp, xsize, yp, ysize) \ - __GMPN_AORS (cout, wp, xp, xsize, yp, ysize, mpn_sub_n, \ - (((wp)[__gmp_i++] = (__gmp_x - 1) & GMP_NUMB_MASK), __gmp_x == 0)) -/* The use of __gmp_i indexing is designed to ensure a compile time src==dst - remains nice and clear to the compiler, so that __GMPN_COPY_REST can - disappear, and the load/add/store gets a chance to become a - read-modify-write on CISC CPUs. - Alternatives: - Using a pair of pointers instead of indexing would be possible, but gcc - isn't able to recognise compile-time src==dst in that case, even when the - pointers are incremented more or less together. Other compilers would - very likely have similar difficulty. - gcc could use "if (__builtin_constant_p(src==dst) && src==dst)" or - similar to detect a compile-time src==dst. This works nicely on gcc - 2.95.x, it's not good on gcc 3.0 where __builtin_constant_p(p==p) seems - to be always false, for a pointer p. But the current code form seems - good enough for src==dst anyway. - gcc on x86 as usual doesn't give particularly good flags handling for the - carry/borrow detection. It's tempting to want some multi instruction asm - blocks to help it, and this was tried, but in truth there's only a few - instructions to save and any gain is all too easily lost by register - juggling setting up for the asm. */ -#if GMP_NAIL_BITS == 0 -#define __GMPN_AORS_1(cout, dst, src, n, v, OP, CB) \ - do { \ - mp_size_t __gmp_i; \ - mp_limb_t __gmp_x, __gmp_r; \ - \ - /* ASSERT ((n) >= 1); */ \ - /* ASSERT (MPN_SAME_OR_SEPARATE_P (dst, src, n)); */ \ - \ - __gmp_x = (src)[0]; \ - __gmp_r = __gmp_x OP (v); \ - (dst)[0] = __gmp_r; \ - if (CB (__gmp_r, __gmp_x, (v))) \ - { \ - (cout) = 1; \ - for (__gmp_i = 1; __gmp_i < (n);) \ - { \ - __gmp_x = (src)[__gmp_i]; \ - __gmp_r = __gmp_x OP 1; \ - (dst)[__gmp_i] = __gmp_r; \ - ++__gmp_i; \ - if (!CB (__gmp_r, __gmp_x, 1)) \ - { \ - if ((src) != (dst)) \ - __GMPN_COPY_REST (dst, src, n, __gmp_i); \ - (cout) = 0; \ - break; \ - } \ - } \ - } \ - else \ - { \ - if ((src) != (dst)) \ - __GMPN_COPY_REST (dst, src, n, 1); \ - (cout) = 0; \ - } \ - } while (0) -#endif -#if GMP_NAIL_BITS >= 1 -#define __GMPN_AORS_1(cout, dst, src, n, v, OP, CB) \ - do { \ - mp_size_t __gmp_i; \ - mp_limb_t __gmp_x, __gmp_r; \ - \ - /* ASSERT ((n) >= 1); */ \ - /* ASSERT (MPN_SAME_OR_SEPARATE_P (dst, src, n)); */ \ - \ - __gmp_x = (src)[0]; \ - __gmp_r = __gmp_x OP (v); \ - (dst)[0] = __gmp_r & GMP_NUMB_MASK; \ - if (__gmp_r >> GMP_NUMB_BITS != 0) \ - { \ - (cout) = 1; \ - for (__gmp_i = 1; __gmp_i < (n);) \ - { \ - __gmp_x = (src)[__gmp_i]; \ - __gmp_r = __gmp_x OP 1; \ - (dst)[__gmp_i] = __gmp_r & GMP_NUMB_MASK; \ - ++__gmp_i; \ - if (__gmp_r >> GMP_NUMB_BITS == 0) \ - { \ - if ((src) != (dst)) \ - __GMPN_COPY_REST (dst, src, n, __gmp_i); \ - (cout) = 0; \ - break; \ - } \ - } \ - } \ - else \ - { \ - if ((src) != (dst)) \ - __GMPN_COPY_REST (dst, src, n, 1); \ - (cout) = 0; \ - } \ - } while (0) -#endif -#define __GMPN_ADDCB(r,x,y) ((r) < (y)) -#define __GMPN_SUBCB(r,x,y) ((x) < (y)) -#define __GMPN_ADD_1(cout, dst, src, n, v) \ - __GMPN_AORS_1(cout, dst, src, n, v, +, __GMPN_ADDCB) -#define __GMPN_SUB_1(cout, dst, src, n, v) \ - __GMPN_AORS_1(cout, dst, src, n, v, -, __GMPN_SUBCB) -/* Compare {xp,size} and {yp,size}, setting "result" to positive, zero or - negative. size==0 is allowed. On random data usually only one limb will - need to be examined to get a result, so it's worth having it inline. */ -#define __GMPN_CMP(result, xp, yp, size) \ - do { \ - mp_size_t __gmp_i; \ - mp_limb_t __gmp_x, __gmp_y; \ - \ - /* ASSERT ((size) >= 0); */ \ - \ - (result) = 0; \ - __gmp_i = (size); \ - while (--__gmp_i >= 0) \ - { \ - __gmp_x = (xp)[__gmp_i]; \ - __gmp_y = (yp)[__gmp_i]; \ - if (__gmp_x != __gmp_y) \ - { \ - /* Cannot use __gmp_x - __gmp_y, may overflow an "int" */ \ - (result) = (__gmp_x > __gmp_y ? 1 : -1); \ - break; \ - } \ - } \ - } while (0) -#if defined (__GMPN_COPY) && ! defined (__GMPN_COPY_REST) -#define __GMPN_COPY_REST(dst, src, size, start) \ - do { \ - /* ASSERT ((start) >= 0); */ \ - /* ASSERT ((start) <= (size)); */ \ - __GMPN_COPY ((dst)+(start), (src)+(start), (size)-(start)); \ - } while (0) -#endif -/* Copy {src,size} to {dst,size}, starting at "start". This is designed to - keep the indexing dst[j] and src[j] nice and simple for __GMPN_ADD_1, - __GMPN_ADD, etc. */ -#if ! defined (__GMPN_COPY_REST) -#define __GMPN_COPY_REST(dst, src, size, start) \ - do { \ - mp_size_t __gmp_j; \ - /* ASSERT ((size) >= 0); */ \ - /* ASSERT ((start) >= 0); */ \ - /* ASSERT ((start) <= (size)); */ \ - /* ASSERT (MPN_SAME_OR_SEPARATE_P (dst, src, size)); */ \ - for (__gmp_j = (start); __gmp_j < (size); __gmp_j++) \ - (dst)[__gmp_j] = (src)[__gmp_j]; \ - } while (0) -#endif -/* Enhancement: Use some of the smarter code from gmp-impl.h. Maybe use - mpn_copyi if there's a native version, and if we don't mind demanding - binary compatibility for it (on targets which use it). */ -#if ! defined (__GMPN_COPY) -#define __GMPN_COPY(dst, src, size) __GMPN_COPY_REST (dst, src, size, 0) -#endif -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpn_add) -#if ! defined (__GMP_FORCE_mpn_add) -__GMP_EXTERN_INLINE -#endif -mp_limb_t -mpn_add (mp_ptr __gmp_wp, mp_srcptr __gmp_xp, mp_size_t __gmp_xsize, mp_srcptr __gmp_yp, mp_size_t __gmp_ysize) -{ - mp_limb_t __gmp_c; - __GMPN_ADD (__gmp_c, __gmp_wp, __gmp_xp, __gmp_xsize, __gmp_yp, __gmp_ysize); - return __gmp_c; -} -#endif -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpn_add_1) -#if ! defined (__GMP_FORCE_mpn_add_1) -__GMP_EXTERN_INLINE -#endif -mp_limb_t -mpn_add_1 (mp_ptr __gmp_dst, mp_srcptr __gmp_src, mp_size_t __gmp_size, mp_limb_t __gmp_n) __GMP_NOTHROW -{ - mp_limb_t __gmp_c; - __GMPN_ADD_1 (__gmp_c, __gmp_dst, __gmp_src, __gmp_size, __gmp_n); - return __gmp_c; -} -#endif -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpn_cmp) -#if ! defined (__GMP_FORCE_mpn_cmp) -__GMP_EXTERN_INLINE -#endif -int -mpn_cmp (mp_srcptr __gmp_xp, mp_srcptr __gmp_yp, mp_size_t __gmp_size) __GMP_NOTHROW -{ - int __gmp_result; - __GMPN_CMP (__gmp_result, __gmp_xp, __gmp_yp, __gmp_size); - return __gmp_result; -} -#endif -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpn_sub) -#if ! defined (__GMP_FORCE_mpn_sub) -__GMP_EXTERN_INLINE -#endif -mp_limb_t -mpn_sub (mp_ptr __gmp_wp, mp_srcptr __gmp_xp, mp_size_t __gmp_xsize, mp_srcptr __gmp_yp, mp_size_t __gmp_ysize) -{ - mp_limb_t __gmp_c; - __GMPN_SUB (__gmp_c, __gmp_wp, __gmp_xp, __gmp_xsize, __gmp_yp, __gmp_ysize); - return __gmp_c; -} -#endif -#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpn_sub_1) -#if ! defined (__GMP_FORCE_mpn_sub_1) -__GMP_EXTERN_INLINE -#endif -mp_limb_t -mpn_sub_1 (mp_ptr __gmp_dst, mp_srcptr __gmp_src, mp_size_t __gmp_size, mp_limb_t __gmp_n) __GMP_NOTHROW -{ - mp_limb_t __gmp_c; - __GMPN_SUB_1 (__gmp_c, __gmp_dst, __gmp_src, __gmp_size, __gmp_n); - return __gmp_c; -} -#endif -#if defined (__cplusplus) -} -#endif -/* Allow faster testing for negative, zero, and positive. */ -#define mpz_sgn(Z) ((Z)->_mp_size < 0 ? -1 : (Z)->_mp_size > 0) -#define mpf_sgn(F) ((F)->_mp_size < 0 ? -1 : (F)->_mp_size > 0) -#define mpq_sgn(Q) ((Q)->_mp_num._mp_size < 0 ? -1 : (Q)->_mp_num._mp_size > 0) -/* When using GCC, optimize certain common comparisons. */ -#if defined (__GNUC__) -#define mpz_cmp_ui(Z,UI) \ - (__builtin_constant_p (UI) && (UI) == 0 \ - ? mpz_sgn (Z) : _mpz_cmp_ui (Z,UI)) -#define mpz_cmp_si(Z,SI) \ - (__builtin_constant_p (SI) && (SI) == 0 ? mpz_sgn (Z) \ - : __builtin_constant_p (SI) && (SI) > 0 \ - ? _mpz_cmp_ui (Z, __GMP_CAST (unsigned long int, SI)) \ - : _mpz_cmp_si (Z,SI)) -#define mpq_cmp_ui(Q,NUI,DUI) \ - (__builtin_constant_p (NUI) && (NUI) == 0 \ - ? mpq_sgn (Q) : _mpq_cmp_ui (Q,NUI,DUI)) -#define mpq_cmp_si(q,n,d) \ - (__builtin_constant_p ((n) >= 0) && (n) >= 0 \ - ? mpq_cmp_ui (q, __GMP_CAST (unsigned long, n), d) \ - : _mpq_cmp_si (q, n, d)) -#else -#define mpz_cmp_ui(Z,UI) _mpz_cmp_ui (Z,UI) -#define mpz_cmp_si(Z,UI) _mpz_cmp_si (Z,UI) -#define mpq_cmp_ui(Q,NUI,DUI) _mpq_cmp_ui (Q,NUI,DUI) -#define mpq_cmp_si(q,n,d) _mpq_cmp_si(q,n,d) -#endif -/* Using "&" rather than "&&" means these can come out branch-free. Every - mpz_t has at least one limb allocated, so fetching the low limb is always - allowed. */ -#define mpz_odd_p(z) (((z)->_mp_size != 0) & __GMP_CAST (int, (z)->_mp_d[0])) -#define mpz_even_p(z) (! mpz_odd_p (z)) -/**************** C++ routines ****************/ -#ifdef __cplusplus -__GMP_DECLSPEC_XX std::ostream& operator<< (std::ostream &, mpz_srcptr); -__GMP_DECLSPEC_XX std::ostream& operator<< (std::ostream &, mpq_srcptr); -__GMP_DECLSPEC_XX std::ostream& operator<< (std::ostream &, mpf_srcptr); -__GMP_DECLSPEC_XX std::istream& operator>> (std::istream &, mpz_ptr); -__GMP_DECLSPEC_XX std::istream& operator>> (std::istream &, mpq_ptr); -__GMP_DECLSPEC_XX std::istream& operator>> (std::istream &, mpf_ptr); -#endif -/* Source-level compatibility with GMP 1. */ -#define mpz_mdiv mpz_fdiv_q -#define mpz_mdivmod mpz_fdiv_qr -#define mpz_mmod mpz_fdiv_r -#define mpz_mdiv_ui mpz_fdiv_q_ui -#define mpz_mdivmod_ui(q,r,n,d) \ - (((r) == 0) ? mpz_fdiv_q_ui (q,n,d) : mpz_fdiv_qr_ui (q,r,n,d)) -#define mpz_mmod_ui(r,n,d) \ - (((r) == 0) ? mpz_fdiv_ui (n,d) : mpz_fdiv_r_ui (r,n,d)) -#define gmp_randinit(x,y,z) gmp_randinit_lc_2exp_size(x,z) -typedef __mpz_struct MP_INT; /* gmp 1 source compatibility */ -typedef __mpq_struct MP_RAT; /* gmp 1 source compatibility */ -#define mpz_div mpz_fdiv_q -#define mpz_divmod mpz_fdiv_qr -#define mpz_div_ui mpz_fdiv_q_ui -#define mpz_divmod_ui mpz_fdiv_qr_ui -#define mpz_div_2exp mpz_fdiv_q_2exp -#define mpz_mod_2exp mpz_fdiv_r_2exp -enum -{ - GMP_ERROR_NONE = 0, - GMP_ERROR_UNSUPPORTED_ARGUMENT = 1, - GMP_ERROR_DIVISION_BY_ZERO = 2, - GMP_ERROR_SQRT_OF_NEGATIVE = 4, - GMP_ERROR_INVALID_ARGUMENT = 8 -}; -/* Major version number is the value of __GNU_MP__ too, above and in mp.h. */ -#define __GNU_MP_VERSION 5 -#define __GNU_MP_VERSION_MINOR 0 -#define __GNU_MP_VERSION_PATCHLEVEL 1 -#define GMP_VERSION "5.0.1" -#define __MPIR_VERSION 2 -#define __MPIR_VERSION_MINOR 2 -#define __MPIR_VERSION_PATCHLEVEL 1 -#if defined( _MSC_VER ) -#define _MSC_MPIR_VERSION "2.2.1" -#endif -/* These are for programs like MPFR to use the same CC and CFLAGS as MPIR */ -#if ! defined (__GMP_WITHIN_CONFIGURE) -#endif -#define __GMP_H__ -#endif /* __GMP_H__ */ diff --git a/src/external/inc/win32-msvc/mpir-2.2.1_x64/mpirxx.h b/src/external/inc/win32-msvc/mpir-2.2.1_x64/mpirxx.h deleted file mode 100644 index 3ad1dcf6f..000000000 --- a/src/external/inc/win32-msvc/mpir-2.2.1_x64/mpirxx.h +++ /dev/null @@ -1,3403 +0,0 @@ -/* mpirxx.h -- C++ class wrapper for GMP types. -*- C++ -*- - -Copyright 2001, 2002, 2003, 2006, 2008 Free Software Foundation, Inc. - -Copyright 2009 William Hart - -This file is part of the GNU MP Library. - -The GNU MP Library is free software; you can redistribute it and/or modify -it under the terms of the GNU Lesser General Public License as published by -the Free Software Foundation; either version 3 of the License, or (at your -option) any later version. - -The GNU MP Library is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public -License for more details. - -You should have received a copy of the GNU Lesser General Public License -along with the GNU MP Library. If not, see http://www.gnu.org/licenses/. */ - -/* the C++ compiler must implement the following features: - - member templates - - partial specialization of templates - - namespace support - for g++, this means version 2.91 or higher - for other compilers, I don't know */ -#ifdef __GNUC__ -#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 91) -#error mpirxx.h requires g++ version 2.91 (egcs 1.1.2) or higher -#endif -#endif - -#ifndef __GMP_PLUSPLUS__ -#define __GMP_PLUSPLUS__ - -#include - -#include /* for strlen */ -#include -#include -#include -#include - - -/**************** Function objects ****************/ -/* Any evaluation of a __gmp_expr ends up calling one of these functions - all intermediate functions being inline, the evaluation should optimize - to a direct call to the relevant function, thus yielding no overhead - over the C interface. */ - -struct __gmp_unary_plus -{ - static void eval(mpz_ptr z, mpz_srcptr w) { mpz_set(z, w); } - static void eval(mpq_ptr q, mpq_srcptr r) { mpq_set(q, r); } - static void eval(mpf_ptr f, mpf_srcptr g) { mpf_set(f, g); } -}; - -struct __gmp_unary_minus -{ - static void eval(mpz_ptr z, mpz_srcptr w) { mpz_neg(z, w); } - static void eval(mpq_ptr q, mpq_srcptr r) { mpq_neg(q, r); } - static void eval(mpf_ptr f, mpf_srcptr g) { mpf_neg(f, g); } -}; - -struct __gmp_unary_com -{ - static void eval(mpz_ptr z, mpz_srcptr w) { mpz_com(z, w); } -}; - -struct __gmp_binary_plus -{ - static void eval(mpz_ptr z, mpz_srcptr w, mpz_srcptr v) - { mpz_add(z, w, v); } - - static void eval(mpz_ptr z, mpz_srcptr w, unsigned long int l) - { mpz_add_ui(z, w, l); } - static void eval(mpz_ptr z, unsigned long int l, mpz_srcptr w) - { mpz_add_ui(z, w, l); } - static void eval(mpz_ptr z, mpz_srcptr w, signed long int l) - { - if (l >= 0) - mpz_add_ui(z, w, l); - else - mpz_sub_ui(z, w, -l); - } - static void eval(mpz_ptr z, signed long int l, mpz_srcptr w) - { - if (l >= 0) - mpz_add_ui(z, w, l); - else - mpz_sub_ui(z, w, -l); - } - static void eval(mpz_ptr z, mpz_srcptr w, double d) - { - mpz_t temp; - mpz_init_set_d(temp, d); - mpz_add(z, w, temp); - mpz_clear(temp); - } - static void eval(mpz_ptr z, double d, mpz_srcptr w) - { - mpz_t temp; - mpz_init_set_d(temp, d); - mpz_add(z, temp, w); - mpz_clear(temp); - } - - static void eval(mpq_ptr q, mpq_srcptr r, mpq_srcptr s) - { mpq_add(q, r, s); } - - static void eval(mpq_ptr q, mpq_srcptr r, unsigned long int l) - { mpq_set(q, r); mpz_addmul_ui(mpq_numref(q), mpq_denref(q), l); } - static void eval(mpq_ptr q, unsigned long int l, mpq_srcptr r) - { mpq_set(q, r); mpz_addmul_ui(mpq_numref(q), mpq_denref(q), l); } - static void eval(mpq_ptr q, mpq_srcptr r, signed long int l) - { - mpq_set(q, r); - if (l >= 0) - mpz_addmul_ui(mpq_numref(q), mpq_denref(q), l); - else - mpz_submul_ui(mpq_numref(q), mpq_denref(q), -l); - } - static void eval(mpq_ptr q, signed long int l, mpq_srcptr r) - { - mpq_set(q, r); - if (l >= 0) - mpz_addmul_ui(mpq_numref(q), mpq_denref(q), l); - else - mpz_submul_ui(mpq_numref(q), mpq_denref(q), -l); - } - static void eval(mpq_ptr q, mpq_srcptr r, double d) - { - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - mpq_add(q, r, temp); - mpq_clear(temp); - } - static void eval(mpq_ptr q, double d, mpq_srcptr r) - { - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - mpq_add(q, temp, r); - mpq_clear(temp); - } - - static void eval(mpq_ptr q, mpq_srcptr r, mpz_srcptr z) - { mpq_set(q, r); mpz_addmul(mpq_numref(q), mpq_denref(q), z); } - static void eval(mpq_ptr q, mpz_srcptr z, mpq_srcptr r) - { mpq_set(q, r); mpz_addmul(mpq_numref(q), mpq_denref(q), z); } - - static void eval(mpf_ptr f, mpf_srcptr g, mpf_srcptr h) - { mpf_add(f, g, h); } - - static void eval(mpf_ptr f, mpf_srcptr g, unsigned long int l) - { mpf_add_ui(f, g, l); } - static void eval(mpf_ptr f, unsigned long int l, mpf_srcptr g) - { mpf_add_ui(f, g, l); } - static void eval(mpf_ptr f, mpf_srcptr g, signed long int l) - { - if (l >= 0) - mpf_add_ui(f, g, l); - else - mpf_sub_ui(f, g, -l); - } - static void eval(mpf_ptr f, signed long int l, mpf_srcptr g) - { - if (l >= 0) - mpf_add_ui(f, g, l); - else - mpf_sub_ui(f, g, -l); - } - static void eval(mpf_ptr f, mpf_srcptr g, double d) - { - mpf_t temp; - mpf_init2(temp, 8*sizeof(double)); - mpf_set_d(temp, d); - mpf_add(f, g, temp); - mpf_clear(temp); - } - static void eval(mpf_ptr f, double d, mpf_srcptr g) - { - mpf_t temp; - mpf_init2(temp, 8*sizeof(double)); - mpf_set_d(temp, d); - mpf_add(f, temp, g); - mpf_clear(temp); - } -}; - -struct __gmp_binary_minus -{ - static void eval(mpz_ptr z, mpz_srcptr w, mpz_srcptr v) - { mpz_sub(z, w, v); } - - static void eval(mpz_ptr z, mpz_srcptr w, unsigned long int l) - { mpz_sub_ui(z, w, l); } - static void eval(mpz_ptr z, unsigned long int l, mpz_srcptr w) - { mpz_ui_sub(z, l, w); } - static void eval(mpz_ptr z, mpz_srcptr w, signed long int l) - { - if (l >= 0) - mpz_sub_ui(z, w, l); - else - mpz_add_ui(z, w, -l); - } - static void eval(mpz_ptr z, signed long int l, mpz_srcptr w) - { - if (l >= 0) - mpz_ui_sub(z, l, w); - else - { - mpz_add_ui(z, w, -l); - mpz_neg(z, z); - } - } - static void eval(mpz_ptr z, mpz_srcptr w, double d) - { - mpz_t temp; - mpz_init_set_d(temp, d); - mpz_sub(z, w, temp); - mpz_clear(temp); - } - static void eval(mpz_ptr z, double d, mpz_srcptr w) - { - mpz_t temp; - mpz_init_set_d(temp, d); - mpz_sub(z, temp, w); - mpz_clear(temp); - } - - static void eval(mpq_ptr q, mpq_srcptr r, mpq_srcptr s) - { mpq_sub(q, r, s); } - - static void eval(mpq_ptr q, mpq_srcptr r, unsigned long int l) - { mpq_set(q, r); mpz_submul_ui(mpq_numref(q), mpq_denref(q), l); } - static void eval(mpq_ptr q, unsigned long int l, mpq_srcptr r) - { mpq_neg(q, r); mpz_addmul_ui(mpq_numref(q), mpq_denref(q), l); } - static void eval(mpq_ptr q, mpq_srcptr r, signed long int l) - { - mpq_set(q, r); - if (l >= 0) - mpz_submul_ui(mpq_numref(q), mpq_denref(q), l); - else - mpz_addmul_ui(mpq_numref(q), mpq_denref(q), -l); - } - static void eval(mpq_ptr q, signed long int l, mpq_srcptr r) - { - mpq_neg(q, r); - if (l >= 0) - mpz_addmul_ui(mpq_numref(q), mpq_denref(q), l); - else - mpz_submul_ui(mpq_numref(q), mpq_denref(q), -l); - } - static void eval(mpq_ptr q, mpq_srcptr r, double d) - { - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - mpq_sub(q, r, temp); - mpq_clear(temp); - } - static void eval(mpq_ptr q, double d, mpq_srcptr r) - { - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - mpq_sub(q, temp, r); - mpq_clear(temp); - } - - static void eval(mpq_ptr q, mpq_srcptr r, mpz_srcptr z) - { mpq_set(q, r); mpz_submul(mpq_numref(q), mpq_denref(q), z); } - static void eval(mpq_ptr q, mpz_srcptr z, mpq_srcptr r) - { mpq_neg(q, r); mpz_addmul(mpq_numref(q), mpq_denref(q), z); } - - static void eval(mpf_ptr f, mpf_srcptr g, mpf_srcptr h) - { mpf_sub(f, g, h); } - - static void eval(mpf_ptr f, mpf_srcptr g, unsigned long int l) - { mpf_sub_ui(f, g, l); } - static void eval(mpf_ptr f, unsigned long int l, mpf_srcptr g) - { mpf_ui_sub(f, l, g); } - static void eval(mpf_ptr f, mpf_srcptr g, signed long int l) - { - if (l >= 0) - mpf_sub_ui(f, g, l); - else - mpf_add_ui(f, g, -l); - } - static void eval(mpf_ptr f, signed long int l, mpf_srcptr g) - { - if (l >= 0) - mpf_sub_ui(f, g, l); - else - mpf_add_ui(f, g, -l); - mpf_neg(f, f); - } - static void eval(mpf_ptr f, mpf_srcptr g, double d) - { - mpf_t temp; - mpf_init2(temp, 8*sizeof(double)); - mpf_set_d(temp, d); - mpf_sub(f, g, temp); - mpf_clear(temp); - } - static void eval(mpf_ptr f, double d, mpf_srcptr g) - { - mpf_t temp; - mpf_init2(temp, 8*sizeof(double)); - mpf_set_d(temp, d); - mpf_sub(f, temp, g); - mpf_clear(temp); - } -}; - -struct __gmp_binary_multiplies -{ - static void eval(mpz_ptr z, mpz_srcptr w, mpz_srcptr v) - { mpz_mul(z, w, v); } - - static void eval(mpz_ptr z, mpz_srcptr w, unsigned long int l) - { mpz_mul_ui(z, w, l); } - static void eval(mpz_ptr z, unsigned long int l, mpz_srcptr w) - { mpz_mul_ui(z, w, l); } - static void eval(mpz_ptr z, mpz_srcptr w, signed long int l) - { mpz_mul_si (z, w, l); } - static void eval(mpz_ptr z, signed long int l, mpz_srcptr w) - { mpz_mul_si (z, w, l); } - static void eval(mpz_ptr z, mpz_srcptr w, double d) - { - mpz_t temp; - mpz_init_set_d(temp, d); - mpz_mul(z, w, temp); - mpz_clear(temp); - } - static void eval(mpz_ptr z, double d, mpz_srcptr w) - { - mpz_t temp; - mpz_init_set_d(temp, d); - mpz_mul(z, temp, w); - mpz_clear(temp); - } - - static void eval(mpq_ptr q, mpq_srcptr r, mpq_srcptr s) - { mpq_mul(q, r, s); } - - static void eval(mpq_ptr q, mpq_srcptr r, unsigned long int l) - { - mpq_t temp; - mpq_init(temp); - mpq_set_ui(temp, l, 1); - mpq_mul(q, r, temp); - mpq_clear(temp); - } - static void eval(mpq_ptr q, unsigned long int l, mpq_srcptr r) - { - mpq_t temp; - mpq_init(temp); - mpq_set_ui(temp, l, 1); - mpq_mul(q, temp, r); - mpq_clear(temp); - } - static void eval(mpq_ptr q, mpq_srcptr r, signed long int l) - { - mpq_t temp; - mpq_init(temp); - mpq_set_si(temp, l, 1); - mpq_mul(q, r, temp); - mpq_clear(temp); - } - static void eval(mpq_ptr q, signed long int l, mpq_srcptr r) - { - mpq_t temp; - mpq_init(temp); - mpq_set_si(temp, l, 1); - mpq_mul(q, temp, r); - mpq_clear(temp); - } - static void eval(mpq_ptr q, mpq_srcptr r, double d) - { - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - mpq_mul(q, r, temp); - mpq_clear(temp); - } - static void eval(mpq_ptr q, double d, mpq_srcptr r) - { - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - mpq_mul(q, temp, r); - mpq_clear(temp); - } - - static void eval(mpf_ptr f, mpf_srcptr g, mpf_srcptr h) - { mpf_mul(f, g, h); } - - static void eval(mpf_ptr f, mpf_srcptr g, unsigned long int l) - { mpf_mul_ui(f, g, l); } - static void eval(mpf_ptr f, unsigned long int l, mpf_srcptr g) - { mpf_mul_ui(f, g, l); } - static void eval(mpf_ptr f, mpf_srcptr g, signed long int l) - { - if (l >= 0) - mpf_mul_ui(f, g, l); - else - { - mpf_mul_ui(f, g, -l); - mpf_neg(f, f); - } - } - static void eval(mpf_ptr f, signed long int l, mpf_srcptr g) - { - if (l >= 0) - mpf_mul_ui(f, g, l); - else - { - mpf_mul_ui(f, g, -l); - mpf_neg(f, f); - } - } - static void eval(mpf_ptr f, mpf_srcptr g, double d) - { - mpf_t temp; - mpf_init2(temp, 8*sizeof(double)); - mpf_set_d(temp, d); - mpf_mul(f, g, temp); - mpf_clear(temp); - } - static void eval(mpf_ptr f, double d, mpf_srcptr g) - { - mpf_t temp; - mpf_init2(temp, 8*sizeof(double)); - mpf_set_d(temp, d); - mpf_mul(f, temp, g); - mpf_clear(temp); - } -}; - -struct __gmp_binary_divides -{ - static void eval(mpz_ptr z, mpz_srcptr w, mpz_srcptr v) - { mpz_tdiv_q(z, w, v); } - - static void eval(mpz_ptr z, mpz_srcptr w, unsigned long int l) - { mpz_tdiv_q_ui(z, w, l); } - static void eval(mpz_ptr z, unsigned long int l, mpz_srcptr w) - { - if (mpz_sgn(w) >= 0) - { - if (mpz_fits_ulong_p(w)) - mpz_set_ui(z, l / mpz_get_ui(w)); - else - mpz_set_ui(z, 0); - } - else - { - mpz_neg(z, w); - if (mpz_fits_ulong_p(z)) - { - mpz_set_ui(z, l / mpz_get_ui(z)); - mpz_neg(z, z); - } - else - mpz_set_ui(z, 0); - } - } - static void eval(mpz_ptr z, mpz_srcptr w, signed long int l) - { - if (l >= 0) - mpz_tdiv_q_ui(z, w, l); - else - { - mpz_tdiv_q_ui(z, w, -l); - mpz_neg(z, z); - } - } - static void eval(mpz_ptr z, signed long int l, mpz_srcptr w) - { - if (mpz_fits_slong_p(w)) - mpz_set_si(z, l / mpz_get_si(w)); - else - { - /* if w is bigger than a long then the quotient must be zero, unless - l==LONG_MIN and w==-LONG_MIN in which case the quotient is -1 */ - mpz_set_si (z, (mpz_cmpabs_ui (w, (l >= 0 ? l : -l)) == 0 ? -1 : 0)); - } - } - static void eval(mpz_ptr z, mpz_srcptr w, double d) - { - mpz_t temp; - mpz_init_set_d(temp, d); - mpz_tdiv_q(z, w, temp); - mpz_clear(temp); - } - static void eval(mpz_ptr z, double d, mpz_srcptr w) - { - mpz_t temp; - mpz_init_set_d(temp, d); - mpz_tdiv_q(z, temp, w); - mpz_clear(temp); - } - - static void eval(mpq_ptr q, mpq_srcptr r, mpq_srcptr s) - { mpq_div(q, r, s); } - - static void eval(mpq_ptr q, mpq_srcptr r, unsigned long int l) - { - mpq_t temp; - mpq_init(temp); - mpq_set_ui(temp, l, 1); - mpq_div(q, r, temp); - mpq_clear(temp); - } - static void eval(mpq_ptr q, unsigned long int l, mpq_srcptr r) - { - mpq_t temp; - mpq_init(temp); - mpq_set_ui(temp, l, 1); - mpq_div(q, temp, r); - mpq_clear(temp); - } - static void eval(mpq_ptr q, mpq_srcptr r, signed long int l) - { - mpq_t temp; - mpq_init(temp); - mpq_set_si(temp, l, 1); - mpq_div(q, r, temp); - mpq_clear(temp); - } - static void eval(mpq_ptr q, signed long int l, mpq_srcptr r) - { - mpq_t temp; - mpq_init(temp); - mpq_set_si(temp, l, 1); - mpq_div(q, temp, r); - mpq_clear(temp); - } - static void eval(mpq_ptr q, mpq_srcptr r, double d) - { - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - mpq_div(q, r, temp); - mpq_clear(temp); - } - static void eval(mpq_ptr q, double d, mpq_srcptr r) - { - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - mpq_div(q, temp, r); - mpq_clear(temp); - } - - static void eval(mpf_ptr f, mpf_srcptr g, mpf_srcptr h) - { mpf_div(f, g, h); } - - static void eval(mpf_ptr f, mpf_srcptr g, unsigned long int l) - { mpf_div_ui(f, g, l); } - static void eval(mpf_ptr f, unsigned long int l, mpf_srcptr g) - { mpf_ui_div(f, l, g); } - static void eval(mpf_ptr f, mpf_srcptr g, signed long int l) - { - if (l >= 0) - mpf_div_ui(f, g, l); - else - { - mpf_div_ui(f, g, -l); - mpf_neg(f, f); - } - } - static void eval(mpf_ptr f, signed long int l, mpf_srcptr g) - { - if (l >= 0) - mpf_ui_div(f, l, g); - else - { - mpf_ui_div(f, -l, g); - mpf_neg(f, f); - } - } - static void eval(mpf_ptr f, mpf_srcptr g, double d) - { - mpf_t temp; - mpf_init2(temp, 8*sizeof(double)); - mpf_set_d(temp, d); - mpf_div(f, g, temp); - mpf_clear(temp); - } - static void eval(mpf_ptr f, double d, mpf_srcptr g) - { - mpf_t temp; - mpf_init2(temp, 8*sizeof(double)); - mpf_set_d(temp, d); - mpf_div(f, temp, g); - mpf_clear(temp); - } -}; - -struct __gmp_binary_modulus -{ - static void eval(mpz_ptr z, mpz_srcptr w, mpz_srcptr v) - { mpz_tdiv_r(z, w, v); } - - static void eval(mpz_ptr z, mpz_srcptr w, unsigned long int l) - { mpz_tdiv_r_ui(z, w, l); } - static void eval(mpz_ptr z, unsigned long int l, mpz_srcptr w) - { - if (mpz_sgn(w) >= 0) - { - if (mpz_fits_ulong_p(w)) - mpz_set_ui(z, l % mpz_get_ui(w)); - else - mpz_set_ui(z, l); - } - else - { - mpz_neg(z, w); - if (mpz_fits_ulong_p(z)) - mpz_set_ui(z, l % mpz_get_ui(z)); - else - mpz_set_ui(z, l); - } - } - static void eval(mpz_ptr z, mpz_srcptr w, signed long int l) - { - mpz_tdiv_r_ui (z, w, (l >= 0 ? l : -l)); - } - static void eval(mpz_ptr z, signed long int l, mpz_srcptr w) - { - if (mpz_fits_slong_p(w)) - mpz_set_si(z, l % mpz_get_si(w)); - else - { - /* if w is bigger than a long then the remainder is l unchanged, - unless l==LONG_MIN and w==-LONG_MIN in which case it's 0 */ - mpz_set_si (z, mpz_cmpabs_ui (w, (l >= 0 ? l : -l)) == 0 ? 0 : l); - } - } - static void eval(mpz_ptr z, mpz_srcptr w, double d) - { - mpz_t temp; - mpz_init_set_d(temp, d); - mpz_tdiv_r(z, w, temp); - mpz_clear(temp); - } - static void eval(mpz_ptr z, double d, mpz_srcptr w) - { - mpz_t temp; - mpz_init_set_d(temp, d); - mpz_tdiv_r(z, temp, w); - mpz_clear(temp); - } -}; - -// Max allocations for plain types when converted to mpz_t -#define __GMP_DBL_LIMBS (2 + DBL_MAX_EXP / GMP_NUMB_BITS) -#define __GMP_ULI_LIMBS (1 + (8 * sizeof (long) - 1) / GMP_NUMB_BITS) - -#define __GMPXX_TMP_UI \ - mpz_t temp; \ - mp_limb_t limbs[__GMP_ULI_LIMBS]; \ - temp->_mp_d = limbs; \ - temp->_mp_alloc = __GMP_ULI_LIMBS; \ - mpz_set_ui (temp, l) -#define __GMPXX_TMP_SI \ - mpz_t temp; \ - mp_limb_t limbs[__GMP_ULI_LIMBS]; \ - temp->_mp_d = limbs; \ - temp->_mp_alloc = __GMP_ULI_LIMBS; \ - mpz_set_si (temp, l) -#define __GMPXX_TMP_D \ - mpz_t temp; \ - mp_limb_t limbs[__GMP_DBL_LIMBS]; \ - temp->_mp_d = limbs; \ - temp->_mp_alloc = __GMP_DBL_LIMBS; \ - mpz_set_d (temp, d) - -struct __gmp_binary_and -{ - static void eval(mpz_ptr z, mpz_srcptr w, mpz_srcptr v) - { mpz_and(z, w, v); } - - static void eval(mpz_ptr z, mpz_srcptr w, unsigned long int l) - { __GMPXX_TMP_UI; mpz_and (z, w, temp); } - static void eval(mpz_ptr z, unsigned long int l, mpz_srcptr w) - { __GMPXX_TMP_UI; mpz_and (z, w, temp); } - static void eval(mpz_ptr z, mpz_srcptr w, signed long int l) - { __GMPXX_TMP_SI; mpz_and (z, w, temp); } - static void eval(mpz_ptr z, signed long int l, mpz_srcptr w) - { __GMPXX_TMP_SI; mpz_and (z, w, temp); } - static void eval(mpz_ptr z, mpz_srcptr w, double d) - { __GMPXX_TMP_D; mpz_and (z, w, temp); } - static void eval(mpz_ptr z, double d, mpz_srcptr w) - { __GMPXX_TMP_D; mpz_and (z, w, temp); } -}; - -struct __gmp_binary_ior -{ - static void eval(mpz_ptr z, mpz_srcptr w, mpz_srcptr v) - { mpz_ior(z, w, v); } - static void eval(mpz_ptr z, mpz_srcptr w, unsigned long int l) - { __GMPXX_TMP_UI; mpz_ior (z, w, temp); } - static void eval(mpz_ptr z, unsigned long int l, mpz_srcptr w) - { __GMPXX_TMP_UI; mpz_ior (z, w, temp); } - static void eval(mpz_ptr z, mpz_srcptr w, signed long int l) - { __GMPXX_TMP_SI; mpz_ior (z, w, temp); } - static void eval(mpz_ptr z, signed long int l, mpz_srcptr w) - { __GMPXX_TMP_SI; mpz_ior (z, w, temp); } - static void eval(mpz_ptr z, mpz_srcptr w, double d) - { __GMPXX_TMP_D; mpz_ior (z, w, temp); } - static void eval(mpz_ptr z, double d, mpz_srcptr w) - { __GMPXX_TMP_D; mpz_ior (z, w, temp); } -}; - -struct __gmp_binary_xor -{ - static void eval(mpz_ptr z, mpz_srcptr w, mpz_srcptr v) - { mpz_xor(z, w, v); } - static void eval(mpz_ptr z, mpz_srcptr w, unsigned long int l) - { __GMPXX_TMP_UI; mpz_xor (z, w, temp); } - static void eval(mpz_ptr z, unsigned long int l, mpz_srcptr w) - { __GMPXX_TMP_UI; mpz_xor (z, w, temp); } - static void eval(mpz_ptr z, mpz_srcptr w, signed long int l) - { __GMPXX_TMP_SI; mpz_xor (z, w, temp); } - static void eval(mpz_ptr z, signed long int l, mpz_srcptr w) - { __GMPXX_TMP_SI; mpz_xor (z, w, temp); } - static void eval(mpz_ptr z, mpz_srcptr w, double d) - { __GMPXX_TMP_D; mpz_xor (z, w, temp); } - static void eval(mpz_ptr z, double d, mpz_srcptr w) - { __GMPXX_TMP_D; mpz_xor (z, w, temp); } -}; - -struct __gmp_binary_lshift -{ - static void eval(mpz_ptr z, mpz_srcptr w, unsigned long int l) - { mpz_mul_2exp(z, w, l); } - static void eval(mpq_ptr q, mpq_srcptr r, unsigned long int l) - { mpq_mul_2exp(q, r, l); } - static void eval(mpf_ptr f, mpf_srcptr g, unsigned long int l) - { mpf_mul_2exp(f, g, l); } -}; - -struct __gmp_binary_rshift -{ - static void eval(mpz_ptr z, mpz_srcptr w, unsigned long int l) - { mpz_fdiv_q_2exp(z, w, l); } - static void eval(mpq_ptr q, mpq_srcptr r, unsigned long int l) - { mpq_div_2exp(q, r, l); } - static void eval(mpf_ptr f, mpf_srcptr g, unsigned long int l) - { mpf_div_2exp(f, g, l); } -}; - -struct __gmp_binary_equal -{ - static bool eval(mpz_srcptr z, mpz_srcptr w) { return mpz_cmp(z, w) == 0; } - - static bool eval(mpz_srcptr z, unsigned long int l) - { return mpz_cmp_ui(z, l) == 0; } - static bool eval(unsigned long int l, mpz_srcptr z) - { return mpz_cmp_ui(z, l) == 0; } - static bool eval(mpz_srcptr z, signed long int l) - { return mpz_cmp_si(z, l) == 0; } - static bool eval(signed long int l, mpz_srcptr z) - { return mpz_cmp_si(z, l) == 0; } - static bool eval(mpz_srcptr z, double d) - { return mpz_cmp_d(z, d) == 0; } - static bool eval(double d, mpz_srcptr z) - { return mpz_cmp_d(z, d) == 0; } - - static bool eval(mpq_srcptr q, mpq_srcptr r) - { return mpq_equal(q, r) != 0; } - - static bool eval(mpq_srcptr q, unsigned long int l) - { return mpq_cmp_ui(q, l, 1) == 0; } - static bool eval(unsigned long int l, mpq_srcptr q) - { return mpq_cmp_ui(q, l, 1) == 0; } - static bool eval(mpq_srcptr q, signed long int l) - { return mpq_cmp_si(q, l, 1) == 0; } - static bool eval(signed long int l, mpq_srcptr q) - { return mpq_cmp_si(q, l, 1) == 0; } - static bool eval(mpq_srcptr q, double d) - { - bool b; - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - b = (mpq_equal(q, temp) != 0); - mpq_clear(temp); - return b; - } - static bool eval(double d, mpq_srcptr q) - { - bool b; - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - b = (mpq_equal(temp, q) != 0); - mpq_clear(temp); - return b; - } - - static bool eval(mpf_srcptr f, mpf_srcptr g) { return mpf_cmp(f, g) == 0; } - - static bool eval(mpf_srcptr f, unsigned long int l) - { return mpf_cmp_ui(f, l) == 0; } - static bool eval(unsigned long int l, mpf_srcptr f) - { return mpf_cmp_ui(f, l) == 0; } - static bool eval(mpf_srcptr f, signed long int l) - { return mpf_cmp_si(f, l) == 0; } - static bool eval(signed long int l, mpf_srcptr f) - { return mpf_cmp_si(f, l) == 0; } - static bool eval(mpf_srcptr f, double d) - { return mpf_cmp_d(f, d) == 0; } - static bool eval(double d, mpf_srcptr f) - { return mpf_cmp_d(f, d) == 0; } -}; - -struct __gmp_binary_not_equal -{ - static bool eval(mpz_srcptr z, mpz_srcptr w) { return mpz_cmp(z, w) != 0; } - - static bool eval(mpz_srcptr z, unsigned long int l) - { return mpz_cmp_ui(z, l) != 0; } - static bool eval(unsigned long int l, mpz_srcptr z) - { return mpz_cmp_ui(z, l) != 0; } - static bool eval(mpz_srcptr z, signed long int l) - { return mpz_cmp_si(z, l) != 0; } - static bool eval(signed long int l, mpz_srcptr z) - { return mpz_cmp_si(z, l) != 0; } - static bool eval(mpz_srcptr z, double d) - { return mpz_cmp_d(z, d) != 0; } - static bool eval(double d, mpz_srcptr z) - { return mpz_cmp_d(z, d) != 0; } - - static bool eval(mpq_srcptr q, mpq_srcptr r) - { return mpq_equal(q, r) == 0; } - - static bool eval(mpq_srcptr q, unsigned long int l) - { return mpq_cmp_ui(q, l, 1) != 0; } - static bool eval(unsigned long int l, mpq_srcptr q) - { return mpq_cmp_ui(q, l, 1) != 0; } - static bool eval(mpq_srcptr q, signed long int l) - { return mpq_cmp_si(q, l, 1) != 0; } - static bool eval(signed long int l, mpq_srcptr q) - { return mpq_cmp_si(q, l, 1) != 0; } - static bool eval(mpq_srcptr q, double d) - { - bool b; - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - b = (mpq_equal(q, temp) == 0); - mpq_clear(temp); - return b; - } - static bool eval(double d, mpq_srcptr q) - { - bool b; - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - b = (mpq_equal(temp, q) == 0); - mpq_clear(temp); - return b; - } - - static bool eval(mpf_srcptr f, mpf_srcptr g) { return mpf_cmp(f, g) != 0; } - - static bool eval(mpf_srcptr f, unsigned long int l) - { return mpf_cmp_ui(f, l) != 0; } - static bool eval(unsigned long int l, mpf_srcptr f) - { return mpf_cmp_ui(f, l) != 0; } - static bool eval(mpf_srcptr f, signed long int l) - { return mpf_cmp_si(f, l) != 0; } - static bool eval(signed long int l, mpf_srcptr f) - { return mpf_cmp_si(f, l) != 0; } - static bool eval(mpf_srcptr f, double d) - { return mpf_cmp_d(f, d) != 0; } - static bool eval(double d, mpf_srcptr f) - { return mpf_cmp_d(f, d) != 0; } -}; - -struct __gmp_binary_less -{ - static bool eval(mpz_srcptr z, mpz_srcptr w) { return mpz_cmp(z, w) < 0; } - - static bool eval(mpz_srcptr z, unsigned long int l) - { return mpz_cmp_ui(z, l) < 0; } - static bool eval(unsigned long int l, mpz_srcptr z) - { return mpz_cmp_ui(z, l) > 0; } - static bool eval(mpz_srcptr z, signed long int l) - { return mpz_cmp_si(z, l) < 0; } - static bool eval(signed long int l, mpz_srcptr z) - { return mpz_cmp_si(z, l) > 0; } - static bool eval(mpz_srcptr z, double d) - { return mpz_cmp_d(z, d) < 0; } - static bool eval(double d, mpz_srcptr z) - { return mpz_cmp_d(z, d) > 0; } - - static bool eval(mpq_srcptr q, mpq_srcptr r) { return mpq_cmp(q, r) < 0; } - - static bool eval(mpq_srcptr q, unsigned long int l) - { return mpq_cmp_ui(q, l, 1) < 0; } - static bool eval(unsigned long int l, mpq_srcptr q) - { return mpq_cmp_ui(q, l, 1) > 0; } - static bool eval(mpq_srcptr q, signed long int l) - { return mpq_cmp_si(q, l, 1) < 0; } - static bool eval(signed long int l, mpq_srcptr q) - { return mpq_cmp_si(q, l, 1) > 0; } - static bool eval(mpq_srcptr q, double d) - { - bool b; - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - b = (mpq_cmp(q, temp) < 0); - mpq_clear(temp); - return b; - } - static bool eval(double d, mpq_srcptr q) - { - bool b; - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - b = (mpq_cmp(temp, q) < 0); - mpq_clear(temp); - return b; - } - - static bool eval(mpf_srcptr f, mpf_srcptr g) { return mpf_cmp(f, g) < 0; } - - static bool eval(mpf_srcptr f, unsigned long int l) - { return mpf_cmp_ui(f, l) < 0; } - static bool eval(unsigned long int l, mpf_srcptr f) - { return mpf_cmp_ui(f, l) > 0; } - static bool eval(mpf_srcptr f, signed long int l) - { return mpf_cmp_si(f, l) < 0; } - static bool eval(signed long int l, mpf_srcptr f) - { return mpf_cmp_si(f, l) > 0; } - static bool eval(mpf_srcptr f, double d) - { return mpf_cmp_d(f, d) < 0; } - static bool eval(double d, mpf_srcptr f) - { return mpf_cmp_d(f, d) > 0; } -}; - -struct __gmp_binary_less_equal -{ - static bool eval(mpz_srcptr z, mpz_srcptr w) { return mpz_cmp(z, w) <= 0; } - - static bool eval(mpz_srcptr z, unsigned long int l) - { return mpz_cmp_ui(z, l) <= 0; } - static bool eval(unsigned long int l, mpz_srcptr z) - { return mpz_cmp_ui(z, l) >= 0; } - static bool eval(mpz_srcptr z, signed long int l) - { return mpz_cmp_si(z, l) <= 0; } - static bool eval(signed long int l, mpz_srcptr z) - { return mpz_cmp_si(z, l) >= 0; } - static bool eval(mpz_srcptr z, double d) - { return mpz_cmp_d(z, d) <= 0; } - static bool eval(double d, mpz_srcptr z) - { return mpz_cmp_d(z, d) >= 0; } - - static bool eval(mpq_srcptr q, mpq_srcptr r) { return mpq_cmp(q, r) <= 0; } - - static bool eval(mpq_srcptr q, unsigned long int l) - { return mpq_cmp_ui(q, l, 1) <= 0; } - static bool eval(unsigned long int l, mpq_srcptr q) - { return mpq_cmp_ui(q, l, 1) >= 0; } - static bool eval(mpq_srcptr q, signed long int l) - { return mpq_cmp_si(q, l, 1) <= 0; } - static bool eval(signed long int l, mpq_srcptr q) - { return mpq_cmp_si(q, l, 1) >= 0; } - static bool eval(mpq_srcptr q, double d) - { - bool b; - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - b = (mpq_cmp(q, temp) <= 0); - mpq_clear(temp); - return b; - } - static bool eval(double d, mpq_srcptr q) - { - bool b; - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - b = (mpq_cmp(temp, q) <= 0); - mpq_clear(temp); - return b; - } - - static bool eval(mpf_srcptr f, mpf_srcptr g) { return mpf_cmp(f, g) <= 0; } - - static bool eval(mpf_srcptr f, unsigned long int l) - { return mpf_cmp_ui(f, l) <= 0; } - static bool eval(unsigned long int l, mpf_srcptr f) - { return mpf_cmp_ui(f, l) >= 0; } - static bool eval(mpf_srcptr f, signed long int l) - { return mpf_cmp_si(f, l) <= 0; } - static bool eval(signed long int l, mpf_srcptr f) - { return mpf_cmp_si(f, l) >= 0; } - static bool eval(mpf_srcptr f, double d) - { return mpf_cmp_d(f, d) <= 0; } - static bool eval(double d, mpf_srcptr f) - { return mpf_cmp_d(f, d) >= 0; } -}; - -struct __gmp_binary_greater -{ - static bool eval(mpz_srcptr z, mpz_srcptr w) { return mpz_cmp(z, w) > 0; } - - static bool eval(mpz_srcptr z, unsigned long int l) - { return mpz_cmp_ui(z, l) > 0; } - static bool eval(unsigned long int l, mpz_srcptr z) - { return mpz_cmp_ui(z, l) < 0; } - static bool eval(mpz_srcptr z, signed long int l) - { return mpz_cmp_si(z, l) > 0; } - static bool eval(signed long int l, mpz_srcptr z) - { return mpz_cmp_si(z, l) < 0; } - static bool eval(mpz_srcptr z, double d) - { return mpz_cmp_d(z, d) > 0; } - static bool eval(double d, mpz_srcptr z) - { return mpz_cmp_d(z, d) < 0; } - - static bool eval(mpq_srcptr q, mpq_srcptr r) { return mpq_cmp(q, r) > 0; } - - static bool eval(mpq_srcptr q, unsigned long int l) - { return mpq_cmp_ui(q, l, 1) > 0; } - static bool eval(unsigned long int l, mpq_srcptr q) - { return mpq_cmp_ui(q, l, 1) < 0; } - static bool eval(mpq_srcptr q, signed long int l) - { return mpq_cmp_si(q, l, 1) > 0; } - static bool eval(signed long int l, mpq_srcptr q) - { return mpq_cmp_si(q, l, 1) < 0; } - static bool eval(mpq_srcptr q, double d) - { - bool b; - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - b = (mpq_cmp(q, temp) > 0); - mpq_clear(temp); - return b; - } - static bool eval(double d, mpq_srcptr q) - { - bool b; - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - b = (mpq_cmp(temp, q) > 0); - mpq_clear(temp); - return b; - } - - static bool eval(mpf_srcptr f, mpf_srcptr g) { return mpf_cmp(f, g) > 0; } - - static bool eval(mpf_srcptr f, unsigned long int l) - { return mpf_cmp_ui(f, l) > 0; } - static bool eval(unsigned long int l, mpf_srcptr f) - { return mpf_cmp_ui(f, l) < 0; } - static bool eval(mpf_srcptr f, signed long int l) - { return mpf_cmp_si(f, l) > 0; } - static bool eval(signed long int l, mpf_srcptr f) - { return mpf_cmp_si(f, l) < 0; } - static bool eval(mpf_srcptr f, double d) - { return mpf_cmp_d(f, d) > 0; } - static bool eval(double d, mpf_srcptr f) - { return mpf_cmp_d(f, d) < 0; } -}; - -struct __gmp_binary_greater_equal -{ - static bool eval(mpz_srcptr z, mpz_srcptr w) { return mpz_cmp(z, w) >= 0; } - - static bool eval(mpz_srcptr z, unsigned long int l) - { return mpz_cmp_ui(z, l) >= 0; } - static bool eval(unsigned long int l, mpz_srcptr z) - { return mpz_cmp_ui(z, l) <= 0; } - static bool eval(mpz_srcptr z, signed long int l) - { return mpz_cmp_si(z, l) >= 0; } - static bool eval(signed long int l, mpz_srcptr z) - { return mpz_cmp_si(z, l) <= 0; } - static bool eval(mpz_srcptr z, double d) - { return mpz_cmp_d(z, d) >= 0; } - static bool eval(double d, mpz_srcptr z) - { return mpz_cmp_d(z, d) <= 0; } - - static bool eval(mpq_srcptr q, mpq_srcptr r) { return mpq_cmp(q, r) >= 0; } - - static bool eval(mpq_srcptr q, unsigned long int l) - { return mpq_cmp_ui(q, l, 1) >= 0; } - static bool eval(unsigned long int l, mpq_srcptr q) - { return mpq_cmp_ui(q, l, 1) <= 0; } - static bool eval(mpq_srcptr q, signed long int l) - { return mpq_cmp_si(q, l, 1) >= 0; } - static bool eval(signed long int l, mpq_srcptr q) - { return mpq_cmp_si(q, l, 1) <= 0; } - static bool eval(mpq_srcptr q, double d) - { - bool b; - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - b = (mpq_cmp(q, temp) >= 0); - mpq_clear(temp); - return b; - } - static bool eval(double d, mpq_srcptr q) - { - bool b; - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - b = (mpq_cmp(temp, q) >= 0); - mpq_clear(temp); - return b; - } - - static bool eval(mpf_srcptr f, mpf_srcptr g) { return mpf_cmp(f, g) >= 0; } - - static bool eval(mpf_srcptr f, unsigned long int l) - { return mpf_cmp_ui(f, l) >= 0; } - static bool eval(unsigned long int l, mpf_srcptr f) - { return mpf_cmp_ui(f, l) <= 0; } - static bool eval(mpf_srcptr f, signed long int l) - { return mpf_cmp_si(f, l) >= 0; } - static bool eval(signed long int l, mpf_srcptr f) - { return mpf_cmp_si(f, l) <= 0; } - static bool eval(mpf_srcptr f, double d) - { return mpf_cmp_d(f, d) >= 0; } - static bool eval(double d, mpf_srcptr f) - { return mpf_cmp_d(f, d) <= 0; } -}; - -struct __gmp_unary_increment -{ - static void eval(mpz_ptr z) { mpz_add_ui(z, z, 1); } - static void eval(mpq_ptr q) - { mpz_add(mpq_numref(q), mpq_numref(q), mpq_denref(q)); } - static void eval(mpf_ptr f) { mpf_add_ui(f, f, 1); } -}; - -struct __gmp_unary_decrement -{ - static void eval(mpz_ptr z) { mpz_sub_ui(z, z, 1); } - static void eval(mpq_ptr q) - { mpz_sub(mpq_numref(q), mpq_numref(q), mpq_denref(q)); } - static void eval(mpf_ptr f) { mpf_sub_ui(f, f, 1); } -}; - -struct __gmp_abs_function -{ - static void eval(mpz_ptr z, mpz_srcptr w) { mpz_abs(z, w); } - static void eval(mpq_ptr q, mpq_srcptr r) { mpq_abs(q, r); } - static void eval(mpf_ptr f, mpf_srcptr g) { mpf_abs(f, g); } -}; - -struct __gmp_trunc_function -{ - static void eval(mpf_ptr f, mpf_srcptr g) { mpf_trunc(f, g); } -}; - -struct __gmp_floor_function -{ - static void eval(mpf_ptr f, mpf_srcptr g) { mpf_floor(f, g); } -}; - -struct __gmp_ceil_function -{ - static void eval(mpf_ptr f, mpf_srcptr g) { mpf_ceil(f, g); } -}; - -struct __gmp_sqrt_function -{ - static void eval(mpz_ptr z, mpz_srcptr w) { mpz_sqrt(z, w); } - static void eval(mpf_ptr f, mpf_srcptr g) { mpf_sqrt(f, g); } -}; - -struct __gmp_hypot_function -{ - static void eval(mpf_ptr f, mpf_srcptr g, mpf_srcptr h) - { - mpf_t temp; - mpf_init2(temp, mpf_get_prec(f)); - mpf_mul(temp, g, g); - mpf_mul(f, h, h); - mpf_add(f, f, temp); - mpf_sqrt(f, f); - mpf_clear(temp); - } - - static void eval(mpf_ptr f, mpf_srcptr g, unsigned long int l) - { - mpf_t temp; - mpf_init2(temp, mpf_get_prec(f)); - mpf_mul(temp, g, g); - mpf_set_ui(f, l); - mpf_mul(f, f, f); - mpf_add(f, f, temp); - mpf_sqrt(f, f); - mpf_clear(temp); - } - static void eval(mpf_ptr f, unsigned long int l, mpf_srcptr g) - { - mpf_t temp; - mpf_init2(temp, mpf_get_prec(f)); - mpf_mul(temp, g, g); - mpf_set_ui(f, l); - mpf_mul(f, f, f); - mpf_add(f, f, temp); - mpf_sqrt(f, f); - mpf_clear(temp); - } - static void eval(mpf_ptr f, mpf_srcptr g, signed long int l) - { - mpf_t temp; - mpf_init2(temp, mpf_get_prec(f)); - mpf_mul(temp, g, g); - mpf_set_si(f, l); - mpf_mul(f, f, f); - mpf_add(f, f, temp); - mpf_sqrt(f, f); - mpf_clear(temp); - } - static void eval(mpf_ptr f, signed long int l, mpf_srcptr g) - { - mpf_t temp; - mpf_init2(temp, mpf_get_prec(f)); - mpf_mul(temp, g, g); - mpf_set_si(f, l); - mpf_mul(f, f, f); - mpf_add(f, f, temp); - mpf_sqrt(f, f); - mpf_clear(temp); - } - static void eval(mpf_ptr f, mpf_srcptr g, double d) - { - mpf_t temp; - mpf_init2(temp, mpf_get_prec(f)); - mpf_mul(temp, g, g); - mpf_set_d(f, d); - mpf_mul(f, f, f); - mpf_add(f, f, temp); - mpf_sqrt(f, f); - mpf_clear(temp); - } - static void eval(mpf_ptr f, double d, mpf_srcptr g) - { - mpf_t temp; - mpf_init2(temp, mpf_get_prec(f)); - mpf_mul(temp, g, g); - mpf_set_d(f, d); - mpf_mul(f, f, f); - mpf_add(f, f, temp); - mpf_sqrt(f, f); - mpf_clear(temp); - } -}; - -struct __gmp_sgn_function -{ - static int eval(mpz_srcptr z) { return mpz_sgn(z); } - static int eval(mpq_srcptr q) { return mpq_sgn(q); } - static int eval(mpf_srcptr f) { return mpf_sgn(f); } -}; - -struct __gmp_cmp_function -{ - static int eval(mpz_srcptr z, mpz_srcptr w) { return mpz_cmp(z, w); } - - static int eval(mpz_srcptr z, unsigned long int l) - { return mpz_cmp_ui(z, l); } - static int eval(unsigned long int l, mpz_srcptr z) - { return -mpz_cmp_ui(z, l); } - static int eval(mpz_srcptr z, signed long int l) - { return mpz_cmp_si(z, l); } - static int eval(signed long int l, mpz_srcptr z) - { return -mpz_cmp_si(z, l); } - static int eval(mpz_srcptr z, double d) - { return mpz_cmp_d(z, d); } - static int eval(double d, mpz_srcptr z) - { return -mpz_cmp_d(z, d); } - - static int eval(mpq_srcptr q, mpq_srcptr r) { return mpq_cmp(q, r); } - - static int eval(mpq_srcptr q, unsigned long int l) - { return mpq_cmp_ui(q, l, 1); } - static int eval(unsigned long int l, mpq_srcptr q) - { return -mpq_cmp_ui(q, l, 1); } - static int eval(mpq_srcptr q, signed long int l) - { return mpq_cmp_si(q, l, 1); } - static int eval(signed long int l, mpq_srcptr q) - { return -mpq_cmp_si(q, l, 1); } - static int eval(mpq_srcptr q, double d) - { - int i; - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - i = mpq_cmp(q, temp); - mpq_clear(temp); - return i; - } - static int eval(double d, mpq_srcptr q) - { - int i; - mpq_t temp; - mpq_init(temp); - mpq_set_d(temp, d); - i = mpq_cmp(temp, q); - mpq_clear(temp); - return i; - } - - static int eval(mpf_srcptr f, mpf_srcptr g) { return mpf_cmp(f, g); } - - static int eval(mpf_srcptr f, unsigned long int l) - { return mpf_cmp_ui(f, l); } - static int eval(unsigned long int l, mpf_srcptr f) - { return -mpf_cmp_ui(f, l); } - static int eval(mpf_srcptr f, signed long int l) - { return mpf_cmp_si(f, l); } - static int eval(signed long int l, mpf_srcptr f) - { return -mpf_cmp_si(f, l); } - static int eval(mpf_srcptr f, double d) - { return mpf_cmp_d(f, d); } - static int eval(double d, mpf_srcptr f) - { return -mpf_cmp_d(f, d); } -}; - -struct __gmp_rand_function -{ - static void eval(mpz_ptr z, gmp_randstate_t s, unsigned long int l) - { mpz_urandomb(z, s, l); } - static void eval(mpz_ptr z, gmp_randstate_t s, mpz_srcptr w) - { mpz_urandomm(z, s, w); } - static void eval(mpf_ptr f, gmp_randstate_t s, mp_bitcnt_t prec) - { mpf_urandomb(f, s, prec); } -}; - - -/**************** Auxiliary classes ****************/ - -/* this is much the same as gmp_allocated_string in gmp-impl.h - since gmp-impl.h is not publicly available, I redefine it here - I use a different name to avoid possible clashes */ -extern "C" { -struct __gmp_alloc_cstring_c -{ - void (*free_func) (void *, size_t); -}; -} - -struct __gmp_alloc_cstring : __gmp_alloc_cstring_c -{ - char *str; - __gmp_alloc_cstring(char *s) { str = s; } - ~__gmp_alloc_cstring() - { - mp_get_memory_functions (NULL, NULL, &free_func); - (*free_func) (str, std::strlen(str)+1); - } -}; - -// general expression template class -template -class __gmp_expr; - - -// templates for resolving expression types -template -struct __gmp_resolve_ref -{ - typedef T ref_type; -}; - -template -struct __gmp_resolve_ref<__gmp_expr > -{ - typedef const __gmp_expr & ref_type; -}; - - -template -struct __gmp_resolve_expr; - -template <> -struct __gmp_resolve_expr -{ - typedef mpz_t value_type; - typedef mpz_ptr ptr_type; -}; - -template <> -struct __gmp_resolve_expr -{ - typedef mpq_t value_type; - typedef mpq_ptr ptr_type; -}; - -template <> -struct __gmp_resolve_expr -{ - typedef mpf_t value_type; - typedef mpf_ptr ptr_type; -}; - -template <> -struct __gmp_resolve_expr -{ - typedef mpq_t value_type; -}; - -template <> -struct __gmp_resolve_expr -{ - typedef mpq_t value_type; -}; - -template <> -struct __gmp_resolve_expr -{ - typedef mpf_t value_type; -}; - -template <> -struct __gmp_resolve_expr -{ - typedef mpf_t value_type; -}; - -template <> -struct __gmp_resolve_expr -{ - typedef mpf_t value_type; -}; - -template <> -struct __gmp_resolve_expr -{ - typedef mpf_t value_type; -}; - - - -template -struct __gmp_resolve_temp -{ - typedef __gmp_expr temp_type; -}; - -template -struct __gmp_resolve_temp -{ - typedef const __gmp_expr & temp_type; -}; - - -// classes for evaluating unary and binary expressions -template -struct __gmp_unary_expr -{ - const T &val; - - __gmp_unary_expr(const T &v) : val(v) { } -private: - __gmp_unary_expr(); -}; - -template -struct __gmp_binary_expr -{ - typename __gmp_resolve_ref::ref_type val1; - typename __gmp_resolve_ref::ref_type val2; - - __gmp_binary_expr(const T &v1, const U &v2) : val1(v1), val2(v2) { } -private: - __gmp_binary_expr(); -}; - - -// functions for evaluating expressions -template -void __gmp_set_expr(mpz_ptr, const __gmp_expr &); -template -void __gmp_set_expr(mpq_ptr, const __gmp_expr &); -template -void __gmp_set_expr(mpf_ptr, const __gmp_expr &); - - -/**************** Macros for in-class declarations ****************/ -/* This is just repetitive code that is easier to maintain if it's written - only once */ - -#define __GMPP_DECLARE_COMPOUND_OPERATOR(fun) \ - template \ - __gmp_expr & fun(const __gmp_expr &); - -#define __GMPN_DECLARE_COMPOUND_OPERATOR(fun) \ - __gmp_expr & fun(signed char); \ - __gmp_expr & fun(unsigned char); \ - __gmp_expr & fun(signed int); \ - __gmp_expr & fun(unsigned int); \ - __gmp_expr & fun(signed short int); \ - __gmp_expr & fun(unsigned short int); \ - __gmp_expr & fun(signed long int); \ - __gmp_expr & fun(unsigned long int); \ - __gmp_expr & fun(float); \ - __gmp_expr & fun(double); \ - __gmp_expr & fun(long double); - -#define __GMP_DECLARE_COMPOUND_OPERATOR(fun) \ -__GMPP_DECLARE_COMPOUND_OPERATOR(fun) \ -__GMPN_DECLARE_COMPOUND_OPERATOR(fun) - -#define __GMP_DECLARE_COMPOUND_OPERATOR_UI(fun) \ - __gmp_expr & fun(unsigned long int); - -#define __GMP_DECLARE_INCREMENT_OPERATOR(fun) \ - inline __gmp_expr & fun(); \ - inline __gmp_expr fun(int); - - -/**************** mpz_class -- wrapper for mpz_t ****************/ - -template <> -class __gmp_expr -{ -private: - typedef mpz_t value_type; - value_type mp; -public: - mp_bitcnt_t get_prec() const { return mpf_get_default_prec(); } - - // constructors and destructor - __gmp_expr() { mpz_init(mp); } - - __gmp_expr(const __gmp_expr &z) { mpz_init_set(mp, z.mp); } - template - __gmp_expr(const __gmp_expr &expr) - { mpz_init(mp); __gmp_set_expr(mp, expr); } - - __gmp_expr(signed char c) { mpz_init_set_si(mp, c); } - __gmp_expr(unsigned char c) { mpz_init_set_ui(mp, c); } - - __gmp_expr(signed int i) { mpz_init_set_si(mp, i); } - __gmp_expr(unsigned int i) { mpz_init_set_ui(mp, i); } - - __gmp_expr(signed short int s) { mpz_init_set_si(mp, s); } - __gmp_expr(unsigned short int s) { mpz_init_set_ui(mp, s); } - - __gmp_expr(signed long int l) { mpz_init_set_si(mp, l); } - __gmp_expr(unsigned long int l) { mpz_init_set_ui(mp, l); } - - __gmp_expr(float f) { mpz_init_set_d(mp, f); } - __gmp_expr(double d) { mpz_init_set_d(mp, d); } - // __gmp_expr(long double ld) { mpz_init_set_d(mp, ld); } - - explicit __gmp_expr(const char *s) - { - if (mpz_init_set_str (mp, s, 0) != 0) - { - mpz_clear (mp); - throw std::invalid_argument ("mpz_set_str"); - } - } - __gmp_expr(const char *s, int base) - { - if (mpz_init_set_str (mp, s, base) != 0) - { - mpz_clear (mp); - throw std::invalid_argument ("mpz_set_str"); - } - } - explicit __gmp_expr(const std::string &s) - { - if (mpz_init_set_str (mp, s.c_str(), 0) != 0) - { - mpz_clear (mp); - throw std::invalid_argument ("mpz_set_str"); - } - } - __gmp_expr(const std::string &s, int base) - { - if (mpz_init_set_str(mp, s.c_str(), base) != 0) - { - mpz_clear (mp); - throw std::invalid_argument ("mpz_set_str"); - } - } - - explicit __gmp_expr(mpz_srcptr z) { mpz_init_set(mp, z); } - - ~__gmp_expr() { mpz_clear(mp); } - - // assignment operators - __gmp_expr & operator=(const __gmp_expr &z) - { mpz_set(mp, z.mp); return *this; } - template - __gmp_expr & operator=(const __gmp_expr &expr) - { __gmp_set_expr(mp, expr); return *this; } - - __gmp_expr & operator=(signed char c) { mpz_set_si(mp, c); return *this; } - __gmp_expr & operator=(unsigned char c) { mpz_set_ui(mp, c); return *this; } - - __gmp_expr & operator=(signed int i) { mpz_set_si(mp, i); return *this; } - __gmp_expr & operator=(unsigned int i) { mpz_set_ui(mp, i); return *this; } - - __gmp_expr & operator=(signed short int s) - { mpz_set_si(mp, s); return *this; } - __gmp_expr & operator=(unsigned short int s) - { mpz_set_ui(mp, s); return *this; } - - __gmp_expr & operator=(signed long int l) - { mpz_set_si(mp, l); return *this; } - __gmp_expr & operator=(unsigned long int l) - { mpz_set_ui(mp, l); return *this; } - - __gmp_expr & operator=(float f) { mpz_set_d(mp, f); return *this; } - __gmp_expr & operator=(double d) { mpz_set_d(mp, d); return *this; } - // __gmp_expr & operator=(long double ld) - // { mpz_set_ld(mp, ld); return *this; } - - __gmp_expr & operator=(const char *s) - { - if (mpz_set_str (mp, s, 0) != 0) - throw std::invalid_argument ("mpz_set_str"); - return *this; - } - __gmp_expr & operator=(const std::string &s) - { - if (mpz_set_str(mp, s.c_str(), 0) != 0) - throw std::invalid_argument ("mpz_set_str"); - return *this; - } - - // string input/output functions - int set_str(const char *s, int base) - { return mpz_set_str(mp, s, base); } - int set_str(const std::string &s, int base) - { return mpz_set_str(mp, s.c_str(), base); } - std::string get_str(int base = 10) const - { - __gmp_alloc_cstring temp(mpz_get_str(0, base, mp)); - return std::string(temp.str); - } - - // conversion functions - mpz_srcptr __get_mp() const { return mp; } - mpz_ptr __get_mp() { return mp; } - mpz_srcptr get_mpz_t() const { return mp; } - mpz_ptr get_mpz_t() { return mp; } - - signed long int get_si() const { return mpz_get_si(mp); } - unsigned long int get_ui() const { return mpz_get_ui(mp); } - double get_d() const { return mpz_get_d(mp); } - - // bool fits_schar_p() const { return mpz_fits_schar_p(mp); } - // bool fits_uchar_p() const { return mpz_fits_uchar_p(mp); } - bool fits_sint_p() const { return mpz_fits_sint_p(mp); } - bool fits_uint_p() const { return mpz_fits_uint_p(mp); } - bool fits_sshort_p() const { return mpz_fits_sshort_p(mp); } - bool fits_ushort_p() const { return mpz_fits_ushort_p(mp); } - bool fits_slong_p() const { return mpz_fits_slong_p(mp); } - bool fits_ulong_p() const { return mpz_fits_ulong_p(mp); } - // bool fits_float_p() const { return mpz_fits_float_p(mp); } - // bool fits_double_p() const { return mpz_fits_double_p(mp); } - // bool fits_ldouble_p() const { return mpz_fits_ldouble_p(mp); } - - // member operators - __GMP_DECLARE_COMPOUND_OPERATOR(operator+=) - __GMP_DECLARE_COMPOUND_OPERATOR(operator-=) - __GMP_DECLARE_COMPOUND_OPERATOR(operator*=) - __GMP_DECLARE_COMPOUND_OPERATOR(operator/=) - __GMP_DECLARE_COMPOUND_OPERATOR(operator%=) - - __GMPP_DECLARE_COMPOUND_OPERATOR(operator&=) - __GMPP_DECLARE_COMPOUND_OPERATOR(operator|=) - __GMPP_DECLARE_COMPOUND_OPERATOR(operator^=) - - __GMP_DECLARE_COMPOUND_OPERATOR_UI(operator<<=) - __GMP_DECLARE_COMPOUND_OPERATOR_UI(operator>>=) - - __GMP_DECLARE_INCREMENT_OPERATOR(operator++) - __GMP_DECLARE_INCREMENT_OPERATOR(operator--) -}; - -typedef __gmp_expr mpz_class; - - -/**************** mpq_class -- wrapper for mpq_t ****************/ - -template <> -class __gmp_expr -{ -private: - typedef mpq_t value_type; - value_type mp; -public: - mp_bitcnt_t get_prec() const { return mpf_get_default_prec(); } - void canonicalize() { mpq_canonicalize(mp); } - - // constructors and destructor - __gmp_expr() { mpq_init(mp); } - - __gmp_expr(const __gmp_expr &q) { mpq_init(mp); mpq_set(mp, q.mp); } - template - __gmp_expr(const __gmp_expr &expr) - { mpq_init(mp); __gmp_set_expr(mp, expr); } - - __gmp_expr(signed char c) { mpq_init(mp); mpq_set_si(mp, c, 1); } - __gmp_expr(unsigned char c) { mpq_init(mp); mpq_set_ui(mp, c, 1); } - - __gmp_expr(signed int i) { mpq_init(mp); mpq_set_si(mp, i, 1); } - __gmp_expr(unsigned int i) { mpq_init(mp); mpq_set_ui(mp, i, 1); } - - __gmp_expr(signed short int s) { mpq_init(mp); mpq_set_si(mp, s, 1); } - __gmp_expr(unsigned short int s) { mpq_init(mp); mpq_set_ui(mp, s, 1); } - - __gmp_expr(signed long int l) { mpq_init(mp); mpq_set_si(mp, l, 1); } - __gmp_expr(unsigned long int l) { mpq_init(mp); mpq_set_ui(mp, l, 1); } - - __gmp_expr(float f) { mpq_init(mp); mpq_set_d(mp, f); } - __gmp_expr(double d) { mpq_init(mp); mpq_set_d(mp, d); } - // __gmp_expr(long double ld) { mpq_init(mp); mpq_set_ld(mp, ld); } - - explicit __gmp_expr(const char *s) - { - mpq_init (mp); - if (mpq_set_str (mp, s, 0) != 0) - { - mpq_clear (mp); - throw std::invalid_argument ("mpq_set_str"); - } - } - __gmp_expr(const char *s, int base) - { - mpq_init (mp); - if (mpq_set_str(mp, s, base) != 0) - { - mpq_clear (mp); - throw std::invalid_argument ("mpq_set_str"); - } - } - explicit __gmp_expr(const std::string &s) - { - mpq_init (mp); - if (mpq_set_str (mp, s.c_str(), 0) != 0) - { - mpq_clear (mp); - throw std::invalid_argument ("mpq_set_str"); - } - } - __gmp_expr(const std::string &s, int base) - { - mpq_init(mp); - if (mpq_set_str (mp, s.c_str(), base) != 0) - { - mpq_clear (mp); - throw std::invalid_argument ("mpq_set_str"); - } - } - explicit __gmp_expr(mpq_srcptr q) { mpq_init(mp); mpq_set(mp, q); } - - __gmp_expr(const mpz_class &num, const mpz_class &den) - { - mpq_init(mp); - mpz_set(mpq_numref(mp), num.get_mpz_t()); - mpz_set(mpq_denref(mp), den.get_mpz_t()); - } - - ~__gmp_expr() { mpq_clear(mp); } - - // assignment operators - __gmp_expr & operator=(const __gmp_expr &q) - { mpq_set(mp, q.mp); return *this; } - template - __gmp_expr & operator=(const __gmp_expr &expr) - { __gmp_set_expr(mp, expr); return *this; } - - __gmp_expr & operator=(signed char c) - { mpq_set_si(mp, c, 1); return *this; } - __gmp_expr & operator=(unsigned char c) - { mpq_set_ui(mp, c, 1); return *this; } - - __gmp_expr & operator=(signed int i) { mpq_set_si(mp, i, 1); return *this; } - __gmp_expr & operator=(unsigned int i) - { mpq_set_ui(mp, i, 1); return *this; } - - __gmp_expr & operator=(signed short int s) - { mpq_set_si(mp, s, 1); return *this; } - __gmp_expr & operator=(unsigned short int s) - { mpq_set_ui(mp, s, 1); return *this; } - - __gmp_expr & operator=(signed long int l) - { mpq_set_si(mp, l, 1); return *this; } - __gmp_expr & operator=(unsigned long int l) - { mpq_set_ui(mp, l, 1); return *this; } - - __gmp_expr & operator=(float f) { mpq_set_d(mp, f); return *this; } - __gmp_expr & operator=(double d) { mpq_set_d(mp, d); return *this; } - // __gmp_expr & operator=(long double ld) - // { mpq_set_ld(mp, ld); return *this; } - - __gmp_expr & operator=(const char *s) - { - if (mpq_set_str (mp, s, 0) != 0) - throw std::invalid_argument ("mpq_set_str"); - return *this; - } - __gmp_expr & operator=(const std::string &s) - { - if (mpq_set_str(mp, s.c_str(), 0) != 0) - throw std::invalid_argument ("mpq_set_str"); - return *this; - } - - // string input/output functions - int set_str(const char *s, int base) - { return mpq_set_str(mp, s, base); } - int set_str(const std::string &s, int base) - { return mpq_set_str(mp, s.c_str(), base); } - std::string get_str(int base = 10) const - { - __gmp_alloc_cstring temp(mpq_get_str(0, base, mp)); - return std::string(temp.str); - } - - // conversion functions - - // casting a reference to an mpz_t to mpz_class & is a dirty hack, - // but works because the internal representation of mpz_class is - // exactly an mpz_t - const mpz_class & get_num() const - { return reinterpret_cast(*mpq_numref(mp)); } - mpz_class & get_num() - { return reinterpret_cast(*mpq_numref(mp)); } - const mpz_class & get_den() const - { return reinterpret_cast(*mpq_denref(mp)); } - mpz_class & get_den() - { return reinterpret_cast(*mpq_denref(mp)); } - - mpq_srcptr __get_mp() const { return mp; } - mpq_ptr __get_mp() { return mp; } - mpq_srcptr get_mpq_t() const { return mp; } - mpq_ptr get_mpq_t() { return mp; } - - mpz_srcptr get_num_mpz_t() const { return mpq_numref(mp); } - mpz_ptr get_num_mpz_t() { return mpq_numref(mp); } - mpz_srcptr get_den_mpz_t() const { return mpq_denref(mp); } - mpz_ptr get_den_mpz_t() { return mpq_denref(mp); } - - double get_d() const { return mpq_get_d(mp); } - - // compound assignments - __GMP_DECLARE_COMPOUND_OPERATOR(operator+=) - __GMP_DECLARE_COMPOUND_OPERATOR(operator-=) - __GMP_DECLARE_COMPOUND_OPERATOR(operator*=) - __GMP_DECLARE_COMPOUND_OPERATOR(operator/=) - - __GMP_DECLARE_COMPOUND_OPERATOR_UI(operator<<=) - __GMP_DECLARE_COMPOUND_OPERATOR_UI(operator>>=) - - __GMP_DECLARE_INCREMENT_OPERATOR(operator++) - __GMP_DECLARE_INCREMENT_OPERATOR(operator--) -}; - -typedef __gmp_expr mpq_class; - - -/**************** mpf_class -- wrapper for mpf_t ****************/ - -template <> -class __gmp_expr -{ -private: - typedef mpf_t value_type; - value_type mp; -public: - mp_bitcnt_t get_prec() const { return mpf_get_prec(mp); } - - void set_prec(mp_bitcnt_t prec) { mpf_set_prec(mp, prec); } - void set_prec_raw(mp_bitcnt_t prec) { mpf_set_prec_raw(mp, prec); } - - // constructors and destructor - __gmp_expr() { mpf_init(mp); } - - __gmp_expr(const __gmp_expr &f) - { mpf_init2(mp, f.get_prec()); mpf_set(mp, f.mp); } - __gmp_expr(const __gmp_expr &f, mp_bitcnt_t prec) - { mpf_init2(mp, prec); mpf_set(mp, f.mp); } - template - __gmp_expr(const __gmp_expr &expr) - { mpf_init2(mp, expr.get_prec()); __gmp_set_expr(mp, expr); } - template - __gmp_expr(const __gmp_expr &expr, mp_bitcnt_t prec) - { mpf_init2(mp, prec); __gmp_set_expr(mp, expr); } - - __gmp_expr(signed char c) { mpf_init_set_si(mp, c); } - __gmp_expr(signed char c, mp_bitcnt_t prec) - { mpf_init2(mp, prec); mpf_set_si(mp, c); } - __gmp_expr(unsigned char c) { mpf_init_set_ui(mp, c); } - __gmp_expr(unsigned char c, mp_bitcnt_t prec) - { mpf_init2(mp, prec); mpf_set_ui(mp, c); } - - __gmp_expr(signed int i) { mpf_init_set_si(mp, i); } - __gmp_expr(signed int i, mp_bitcnt_t prec) - { mpf_init2(mp, prec); mpf_set_si(mp, i); } - __gmp_expr(unsigned int i) { mpf_init_set_ui(mp, i); } - __gmp_expr(unsigned int i, mp_bitcnt_t prec) - { mpf_init2(mp, prec); mpf_set_ui(mp, i); } - - __gmp_expr(signed short int s) { mpf_init_set_si(mp, s); } - __gmp_expr(signed short int s, mp_bitcnt_t prec) - { mpf_init2(mp, prec); mpf_set_si(mp, s); } - __gmp_expr(unsigned short int s) { mpf_init_set_ui(mp, s); } - __gmp_expr(unsigned short int s, mp_bitcnt_t prec) - { mpf_init2(mp, prec); mpf_set_ui(mp, s); } - - __gmp_expr(signed long int l) { mpf_init_set_si(mp, l); } - __gmp_expr(signed long int l, mp_bitcnt_t prec) - { mpf_init2(mp, prec); mpf_set_si(mp, l); } - __gmp_expr(unsigned long int l) { mpf_init_set_ui(mp, l); } - __gmp_expr(unsigned long int l, mp_bitcnt_t prec) - { mpf_init2(mp, prec); mpf_set_ui(mp, l); } - - __gmp_expr(float f) { mpf_init_set_d(mp, f); } - __gmp_expr(float f, mp_bitcnt_t prec) - { mpf_init2(mp, prec); mpf_set_d(mp, f); } - __gmp_expr(double d) { mpf_init_set_d(mp, d); } - __gmp_expr(double d, mp_bitcnt_t prec) - { mpf_init2(mp, prec); mpf_set_d(mp, d); } - // __gmp_expr(long double ld) { mpf_init_set_d(mp, ld); } - // __gmp_expr(long double ld, mp_bitcnt_t prec) - // { mpf_init2(mp, prec); mpf_set_d(mp, ld); } - - explicit __gmp_expr(const char *s) - { - if (mpf_init_set_str (mp, s, 0) != 0) - { - mpf_clear (mp); - throw std::invalid_argument ("mpf_set_str"); - } - } - __gmp_expr(const char *s, mp_bitcnt_t prec, int base = 0) - { - mpf_init2(mp, prec); - if (mpf_set_str(mp, s, base) != 0) - { - mpf_clear (mp); - throw std::invalid_argument ("mpf_set_str"); - } - } - explicit __gmp_expr(const std::string &s) - { - if (mpf_init_set_str(mp, s.c_str(), 0) != 0) - { - mpf_clear (mp); - throw std::invalid_argument ("mpf_set_str"); - } - } - __gmp_expr(const std::string &s, mp_bitcnt_t prec, int base = 0) - { - mpf_init2(mp, prec); - if (mpf_set_str(mp, s.c_str(), base) != 0) - { - mpf_clear (mp); - throw std::invalid_argument ("mpf_set_str"); - } - } - - explicit __gmp_expr(mpf_srcptr f) - { mpf_init2(mp, mpf_get_prec(f)); mpf_set(mp, f); } - __gmp_expr(mpf_srcptr f, mp_bitcnt_t prec) - { mpf_init2(mp, prec); mpf_set(mp, f); } - - ~__gmp_expr() { mpf_clear(mp); } - - // assignment operators - __gmp_expr & operator=(const __gmp_expr &f) - { mpf_set(mp, f.mp); return *this; } - template - __gmp_expr & operator=(const __gmp_expr &expr) - { __gmp_set_expr(mp, expr); return *this; } - - __gmp_expr & operator=(signed char c) { mpf_set_si(mp, c); return *this; } - __gmp_expr & operator=(unsigned char c) { mpf_set_ui(mp, c); return *this; } - - __gmp_expr & operator=(signed int i) { mpf_set_si(mp, i); return *this; } - __gmp_expr & operator=(unsigned int i) { mpf_set_ui(mp, i); return *this; } - - __gmp_expr & operator=(signed short int s) - { mpf_set_si(mp, s); return *this; } - __gmp_expr & operator=(unsigned short int s) - { mpf_set_ui(mp, s); return *this; } - - __gmp_expr & operator=(signed long int l) - { mpf_set_si(mp, l); return *this; } - __gmp_expr & operator=(unsigned long int l) - { mpf_set_ui(mp, l); return *this; } - - __gmp_expr & operator=(float f) { mpf_set_d(mp, f); return *this; } - __gmp_expr & operator=(double d) { mpf_set_d(mp, d); return *this; } - // __gmp_expr & operator=(long double ld) - // { mpf_set_ld(mp, ld); return *this; } - - __gmp_expr & operator=(const char *s) - { - if (mpf_set_str (mp, s, 0) != 0) - throw std::invalid_argument ("mpf_set_str"); - return *this; - } - __gmp_expr & operator=(const std::string &s) - { - if (mpf_set_str(mp, s.c_str(), 0) != 0) - throw std::invalid_argument ("mpf_set_str"); - return *this; - } - - // string input/output functions - int set_str(const char *s, int base) - { return mpf_set_str(mp, s, base); } - int set_str(const std::string &s, int base) - { return mpf_set_str(mp, s.c_str(), base); } - std::string get_str(mp_exp_t &expo, int base = 10, size_t size = 0) const - { - __gmp_alloc_cstring temp(mpf_get_str(0, &expo, base, size, mp)); - return std::string(temp.str); - } - - // conversion functions - mpf_srcptr __get_mp() const { return mp; } - mpf_ptr __get_mp() { return mp; } - mpf_srcptr get_mpf_t() const { return mp; } - mpf_ptr get_mpf_t() { return mp; } - - signed long int get_si() const { return mpf_get_si(mp); } - unsigned long int get_ui() const { return mpf_get_ui(mp); } - double get_d() const { return mpf_get_d(mp); } - - // bool fits_schar_p() const { return mpf_fits_schar_p(mp); } - // bool fits_uchar_p() const { return mpf_fits_uchar_p(mp); } - bool fits_sint_p() const { return mpf_fits_sint_p(mp); } - bool fits_uint_p() const { return mpf_fits_uint_p(mp); } - bool fits_sshort_p() const { return mpf_fits_sshort_p(mp); } - bool fits_ushort_p() const { return mpf_fits_ushort_p(mp); } - bool fits_slong_p() const { return mpf_fits_slong_p(mp); } - bool fits_ulong_p() const { return mpf_fits_ulong_p(mp); } - // bool fits_float_p() const { return mpf_fits_float_p(mp); } - // bool fits_double_p() const { return mpf_fits_double_p(mp); } - // bool fits_ldouble_p() const { return mpf_fits_ldouble_p(mp); } - - // compound assignments - __GMP_DECLARE_COMPOUND_OPERATOR(operator+=) - __GMP_DECLARE_COMPOUND_OPERATOR(operator-=) - __GMP_DECLARE_COMPOUND_OPERATOR(operator*=) - __GMP_DECLARE_COMPOUND_OPERATOR(operator/=) - - __GMP_DECLARE_COMPOUND_OPERATOR_UI(operator<<=) - __GMP_DECLARE_COMPOUND_OPERATOR_UI(operator>>=) - - __GMP_DECLARE_INCREMENT_OPERATOR(operator++) - __GMP_DECLARE_INCREMENT_OPERATOR(operator--) -}; - -typedef __gmp_expr mpf_class; - - - -/**************** I/O operators ****************/ - -// these should (and will) be provided separately - -template -inline std::ostream & operator<< -(std::ostream &o, const __gmp_expr &expr) -{ - return o << expr.__get_mp(); -} - -template -inline std::ostream & operator<< -(std::ostream &o, const __gmp_expr &expr) -{ - __gmp_expr temp(expr); - return o << temp.__get_mp(); -} - - -template -inline std::istream & operator>>(std::istream &i, __gmp_expr &expr) -{ - return i >> expr.__get_mp(); -} - -inline std::istream & operator>>(std::istream &i, mpq_class &q) -{ - i >> q.get_mpq_t(); - // q.canonicalize(); // you might want to uncomment this - return i; -} - - -/**************** Functions for type conversion ****************/ - -template <> -inline void __gmp_set_expr(mpz_ptr z, const mpz_class &w) -{ - mpz_set(z, w.get_mpz_t()); -} - -template -inline void __gmp_set_expr(mpz_ptr z, const __gmp_expr &expr) -{ - expr.eval(z); -} - -template <> -inline void __gmp_set_expr(mpz_ptr z, const mpq_class &q) -{ - mpz_set_q(z, q.get_mpq_t()); -} - -template -inline void __gmp_set_expr(mpz_ptr z, const __gmp_expr &expr) -{ - mpq_class temp(expr); - mpz_set_q(z, temp.get_mpq_t()); -} - -template -inline void __gmp_set_expr(mpz_ptr z, const mpf_class &f) -{ - mpz_set_f(z, f.get_mpf_t()); -} - -template -inline void __gmp_set_expr(mpz_ptr z, const __gmp_expr &expr) -{ - mpf_class temp(expr); - mpz_set_f(z, temp.get_mpf_t()); -} - -template <> -inline void __gmp_set_expr(mpq_ptr q, const mpz_class &z) -{ - mpq_set_z(q, z.get_mpz_t()); -} - -template -inline void __gmp_set_expr(mpq_ptr q, const __gmp_expr &expr) -{ - mpz_class temp(expr); - mpq_set_z(q, temp.get_mpz_t()); -} - -template <> -inline void __gmp_set_expr(mpq_ptr q, const mpq_class &r) -{ - mpq_set(q, r.get_mpq_t()); -} - -template -inline void __gmp_set_expr(mpq_ptr q, const __gmp_expr &expr) -{ - expr.eval(q); -} - -template -inline void __gmp_set_expr(mpq_ptr q, const mpf_class &f) -{ - mpq_set_f(q, f.get_mpf_t()); -} - -template -inline void __gmp_set_expr(mpq_ptr q, const __gmp_expr &expr) -{ - mpf_class temp(expr); - mpq_set_f(q, temp.get_mpf_t()); -} - -template -inline void __gmp_set_expr(mpf_ptr f, const mpz_class &z) -{ - mpf_set_z(f, z.get_mpz_t()); -} - -template -inline void __gmp_set_expr(mpf_ptr f, const __gmp_expr &expr) -{ - mpz_class temp(expr); - mpf_set_z(f, temp.get_mpz_t()); -} - -template -inline void __gmp_set_expr(mpf_ptr f, const mpq_class &q) -{ - mpf_set_q(f, q.get_mpq_t()); -} - -template -inline void __gmp_set_expr(mpf_ptr f, const __gmp_expr &expr) -{ - mpq_class temp(expr); - mpf_set_q(f, temp.get_mpq_t()); -} - -template <> -inline void __gmp_set_expr(mpf_ptr f, const mpf_class &g) -{ - mpf_set(f, g.get_mpf_t()); -} - -template -inline void __gmp_set_expr(mpf_ptr f, const __gmp_expr &expr) -{ - expr.eval(f, mpf_get_prec(f)); -} - - -/**************** Specializations of __gmp_expr ****************/ -/* The eval() method of __gmp_expr evaluates the corresponding - expression and assigns the result to its argument, which is either an - mpz_t, mpq_t, or mpf_t as specified by the T argument. - Compound expressions are evaluated recursively (temporaries are created - to hold intermediate values), while for simple expressions the eval() - method of the appropriate function object (available as the Op argument - of either __gmp_unary_expr or __gmp_binary_expr) is - called. */ - - -/**************** Unary expressions ****************/ -/* cases: - - simple: argument is mp*_class, that is, __gmp_expr - - compound: argument is __gmp_expr (with U not equal to T) */ - - -// simple expressions - -template -class __gmp_expr, Op> > -{ -private: - typedef __gmp_expr val_type; - - __gmp_unary_expr expr; -public: - __gmp_expr(const val_type &val) : expr(val) { } - void eval(typename __gmp_resolve_expr::ptr_type p, - unsigned long int = 0) const - { Op::eval(p, expr.val.__get_mp()); } - const val_type & get_val() const { return expr.val; } - unsigned long int get_prec() const { return expr.val.get_prec(); } -}; - - -// compound expressions - -template -class __gmp_expr, Op> > -{ -private: - typedef __gmp_expr val_type; - - __gmp_unary_expr expr; -public: - __gmp_expr(const val_type &val) : expr(val) { } - void eval(typename __gmp_resolve_expr::ptr_type p) const - { __gmp_expr temp(expr.val); Op::eval(p, temp.__get_mp()); } - void eval(typename __gmp_resolve_expr::ptr_type p, - mp_bitcnt_t prec) const - { __gmp_expr temp(expr.val, prec); Op::eval(p, temp.__get_mp()); } - const val_type & get_val() const { return expr.val; } - unsigned long int get_prec() const { return expr.val.get_prec(); } -}; - - -/**************** Binary expressions ****************/ -/* simple: - - arguments are both mp*_class - - one argument is mp*_class, one is a built-in type - compound: - - one is mp*_class, one is __gmp_expr - - one is __gmp_expr, one is built-in - - both arguments are __gmp_expr<...> */ - - -// simple expressions - -template -class __gmp_expr -, __gmp_expr, Op> > -{ -private: - typedef __gmp_expr val1_type; - typedef __gmp_expr val2_type; - - __gmp_binary_expr expr; -public: - __gmp_expr(const val1_type &val1, const val2_type &val2) - : expr(val1, val2) { } - void eval(typename __gmp_resolve_expr::ptr_type p, - unsigned long int = 0) const - { Op::eval(p, expr.val1.__get_mp(), expr.val2.__get_mp()); } - const val1_type & get_val1() const { return expr.val1; } - const val2_type & get_val2() const { return expr.val2; } - unsigned long int get_prec() const - { - mp_bitcnt_t prec1 = expr.val1.get_prec(), - prec2 = expr.val2.get_prec(); - return (prec1 > prec2) ? prec1 : prec2; - } -}; - - -// simple expressions, T is a built-in numerical type - -template -class __gmp_expr, U, Op> > -{ -private: - typedef __gmp_expr val1_type; - typedef U val2_type; - - __gmp_binary_expr expr; -public: - __gmp_expr(const val1_type &val1, const val2_type &val2) - : expr(val1, val2) { } - void eval(typename __gmp_resolve_expr::ptr_type p, - unsigned long int = 0) const - { Op::eval(p, expr.val1.__get_mp(), expr.val2); } - const val1_type & get_val1() const { return expr.val1; } - const val2_type & get_val2() const { return expr.val2; } - unsigned long int get_prec() const { return expr.val1.get_prec(); } -}; - -template -class __gmp_expr, Op> > -{ -private: - typedef U val1_type; - typedef __gmp_expr val2_type; - - __gmp_binary_expr expr; -public: - __gmp_expr(const val1_type &val1, const val2_type &val2) - : expr(val1, val2) { } - void eval(typename __gmp_resolve_expr::ptr_type p, - unsigned long int = 0) const - { Op::eval(p, expr.val1, expr.val2.__get_mp()); } - const val1_type & get_val1() const { return expr.val1; } - const val2_type & get_val2() const { return expr.val2; } - unsigned long int get_prec() const { return expr.val2.get_prec(); } -}; - - -// compound expressions, one argument is a subexpression - -template -class __gmp_expr -, __gmp_expr, Op> > -{ -private: - typedef __gmp_expr val1_type; - typedef __gmp_expr val2_type; - - __gmp_binary_expr expr; -public: - __gmp_expr(const val1_type &val1, const val2_type &val2) - : expr(val1, val2) { } - void eval(typename __gmp_resolve_expr::ptr_type p) const - { - __gmp_expr temp(expr.val2); - Op::eval(p, expr.val1.__get_mp(), temp.__get_mp()); - } - void eval(typename __gmp_resolve_expr::ptr_type p, - mp_bitcnt_t prec) const - { - __gmp_expr temp(expr.val2, prec); - Op::eval(p, expr.val1.__get_mp(), temp.__get_mp()); - } - const val1_type & get_val1() const { return expr.val1; } - const val2_type & get_val2() const { return expr.val2; } - unsigned long int get_prec() const - { - mp_bitcnt_t prec1 = expr.val1.get_prec(), - prec2 = expr.val2.get_prec(); - return (prec1 > prec2) ? prec1 : prec2; - } -}; - -template -class __gmp_expr -, __gmp_expr, Op> > -{ -private: - typedef __gmp_expr val1_type; - typedef __gmp_expr val2_type; - - __gmp_binary_expr expr; -public: - __gmp_expr(const val1_type &val1, const val2_type &val2) - : expr(val1, val2) { } - void eval(typename __gmp_resolve_expr::ptr_type p) const - { - __gmp_expr temp(expr.val1); - Op::eval(p, temp.__get_mp(), expr.val2.__get_mp()); - } - void eval(typename __gmp_resolve_expr::ptr_type p, - mp_bitcnt_t prec) const - { - __gmp_expr temp(expr.val1, prec); - Op::eval(p, temp.__get_mp(), expr.val2.__get_mp()); - } - const val1_type & get_val1() const { return expr.val1; } - const val2_type & get_val2() const { return expr.val2; } - unsigned long int get_prec() const - { - mp_bitcnt_t prec1 = expr.val1.get_prec(), - prec2 = expr.val2.get_prec(); - return (prec1 > prec2) ? prec1 : prec2; - } -}; - -template -class __gmp_expr -, __gmp_expr, Op> > -{ -private: - typedef __gmp_expr val1_type; - typedef __gmp_expr val2_type; - - __gmp_binary_expr expr; -public: - __gmp_expr(const val1_type &val1, const val2_type &val2) - : expr(val1, val2) { } - void eval(typename __gmp_resolve_expr::ptr_type p) const - { - __gmp_expr temp(expr.val2); - Op::eval(p, expr.val1.__get_mp(), temp.__get_mp()); - } - void eval(typename __gmp_resolve_expr::ptr_type p, - mp_bitcnt_t prec) const - { - __gmp_expr temp(expr.val2, prec); - Op::eval(p, expr.val1.__get_mp(), temp.__get_mp()); - } - const val1_type & get_val1() const { return expr.val1; } - const val2_type & get_val2() const { return expr.val2; } - unsigned long int get_prec() const - { - mp_bitcnt_t prec1 = expr.val1.get_prec(), - prec2 = expr.val2.get_prec(); - return (prec1 > prec2) ? prec1 : prec2; - } -}; - -template -class __gmp_expr -, __gmp_expr, Op> > -{ -private: - typedef __gmp_expr val1_type; - typedef __gmp_expr val2_type; - - __gmp_binary_expr expr; -public: - __gmp_expr(const val1_type &val1, const val2_type &val2) - : expr(val1, val2) { } - void eval(typename __gmp_resolve_expr::ptr_type p) const - { - __gmp_expr temp(expr.val1); - Op::eval(p, temp.__get_mp(), expr.val2.__get_mp()); - } - void eval(typename __gmp_resolve_expr::ptr_type p, - mp_bitcnt_t prec) const - { - __gmp_expr temp(expr.val1, prec); - Op::eval(p, temp.__get_mp(), expr.val2.__get_mp()); - } - const val1_type & get_val1() const { return expr.val1; } - const val2_type & get_val2() const { return expr.val2; } - unsigned long int get_prec() const - { - mp_bitcnt_t prec1 = expr.val1.get_prec(), - prec2 = expr.val2.get_prec(); - return (prec1 > prec2) ? prec1 : prec2; - } -}; - - -// one argument is a subexpression, one is a built-in - -template -class __gmp_expr, V, Op> > -{ -private: - typedef __gmp_expr val1_type; - typedef V val2_type; - - __gmp_binary_expr expr; -public: - __gmp_expr(const val1_type &val1, const val2_type &val2) - : expr(val1, val2) { } - void eval(typename __gmp_resolve_expr::ptr_type p) const - { - __gmp_expr temp(expr.val1); - Op::eval(p, temp.__get_mp(), expr.val2); - } - void eval(typename __gmp_resolve_expr::ptr_type p, - mp_bitcnt_t prec) const - { - __gmp_expr temp(expr.val1, prec); - Op::eval(p, temp.__get_mp(), expr.val2); - } - const val1_type & get_val1() const { return expr.val1; } - const val2_type & get_val2() const { return expr.val2; } - unsigned long int get_prec() const { return expr.val1.get_prec(); } -}; - -template -class __gmp_expr, Op> > -{ -private: - typedef U val1_type; - typedef __gmp_expr val2_type; - - __gmp_binary_expr expr; -public: - __gmp_expr(const val1_type &val1, const val2_type &val2) - : expr(val1, val2) { } - void eval(typename __gmp_resolve_expr::ptr_type p) const - { - __gmp_expr temp(expr.val2); - Op::eval(p, expr.val1, temp.__get_mp()); - } - void eval(typename __gmp_resolve_expr::ptr_type p, - mp_bitcnt_t prec) const - { - __gmp_expr temp(expr.val2, prec); - Op::eval(p, expr.val1, temp.__get_mp()); - } - const val1_type & get_val1() const { return expr.val1; } - const val2_type & get_val2() const { return expr.val2; } - unsigned long int get_prec() const { return expr.val2.get_prec(); } -}; - - -// both arguments are subexpressions - -template -class __gmp_expr -, __gmp_expr, Op> > -{ -private: - typedef __gmp_expr val1_type; - typedef __gmp_expr val2_type; - - __gmp_binary_expr expr; -public: - __gmp_expr(const val1_type &val1, const val2_type &val2) - : expr(val1, val2) { } - void eval(typename __gmp_resolve_expr::ptr_type p) const - { - __gmp_expr temp1(expr.val1), temp2(expr.val2); - Op::eval(p, temp1.__get_mp(), temp2.__get_mp()); - } - void eval(typename __gmp_resolve_expr::ptr_type p, - mp_bitcnt_t prec) const - { - __gmp_expr temp1(expr.val1, prec), temp2(expr.val2, prec); - Op::eval(p, temp1.__get_mp(), temp2.__get_mp()); - } - const val1_type & get_val1() const { return expr.val1; } - const val2_type & get_val2() const { return expr.val2; } - unsigned long int get_prec() const - { - mp_bitcnt_t prec1 = expr.val1.get_prec(), - prec2 = expr.val2.get_prec(); - return (prec1 > prec2) ? prec1 : prec2; - } -}; - -template -class __gmp_expr -, __gmp_expr, Op> > -{ -private: - typedef __gmp_expr val1_type; - typedef __gmp_expr val2_type; - - __gmp_binary_expr expr; -public: - __gmp_expr(const val1_type &val1, const val2_type &val2) - : expr(val1, val2) { } - void eval(typename __gmp_resolve_expr::ptr_type p) const - { - __gmp_expr temp1(expr.val1), temp2(expr.val2); - Op::eval(p, temp1.__get_mp(), temp2.__get_mp()); - } - void eval(typename __gmp_resolve_expr::ptr_type p, - mp_bitcnt_t prec) const - { - __gmp_expr temp1(expr.val1, prec), temp2(expr.val2, prec); - Op::eval(p, temp1.__get_mp(), temp2.__get_mp()); - } - const val1_type & get_val1() const { return expr.val1; } - const val2_type & get_val2() const { return expr.val2; } - unsigned long int get_prec() const - { - mp_bitcnt_t prec1 = expr.val1.get_prec(), - prec2 = expr.val2.get_prec(); - return (prec1 > prec2) ? prec1 : prec2; - } -}; - -template -class __gmp_expr -, __gmp_expr, Op> > -{ -private: - typedef __gmp_expr val1_type; - typedef __gmp_expr val2_type; - - __gmp_binary_expr expr; -public: - __gmp_expr(const val1_type &val1, const val2_type &val2) - : expr(val1, val2) { } - void eval(typename __gmp_resolve_expr::ptr_type p) const - { - __gmp_expr temp1(expr.val1), temp2(expr.val2); - Op::eval(p, temp1.__get_mp(), temp2.__get_mp()); - } - void eval(typename __gmp_resolve_expr::ptr_type p, - mp_bitcnt_t prec) const - { - __gmp_expr temp1(expr.val1, prec), temp2(expr.val2, prec); - Op::eval(p, temp1.__get_mp(), temp2.__get_mp()); - } - const val1_type & get_val1() const { return expr.val1; } - const val2_type & get_val2() const { return expr.val2; } - unsigned long int get_prec() const - { - mp_bitcnt_t prec1 = expr.val1.get_prec(), - prec2 = expr.val2.get_prec(); - return (prec1 > prec2) ? prec1 : prec2; - } -}; - - -/**************** Special cases ****************/ - -/* Some operations (i.e., add and subtract) with mixed mpz/mpq arguments - can be done directly without first converting the mpz to mpq. - Appropriate specializations of __gmp_expr are required. */ - - -#define __GMPZQ_DEFINE_EXPR(eval_fun) \ - \ -template <> \ -class __gmp_expr > \ -{ \ -private: \ - typedef mpz_class val1_type; \ - typedef mpq_class val2_type; \ - \ - __gmp_binary_expr expr; \ -public: \ - __gmp_expr(const val1_type &val1, const val2_type &val2) \ - : expr(val1, val2) { } \ - void eval(mpq_ptr q) const \ - { eval_fun::eval(q, expr.val1.get_mpz_t(), expr.val2.get_mpq_t()); } \ - const val1_type & get_val1() const { return expr.val1; } \ - const val2_type & get_val2() const { return expr.val2; } \ - unsigned long int get_prec() const { return mpf_get_default_prec(); } \ -}; \ - \ -template <> \ -class __gmp_expr > \ -{ \ -private: \ - typedef mpq_class val1_type; \ - typedef mpz_class val2_type; \ - \ - __gmp_binary_expr expr; \ -public: \ - __gmp_expr(const val1_type &val1, const val2_type &val2) \ - : expr(val1, val2) { } \ - void eval(mpq_ptr q) const \ - { eval_fun::eval(q, expr.val1.get_mpq_t(), expr.val2.get_mpz_t()); } \ - const val1_type & get_val1() const { return expr.val1; } \ - const val2_type & get_val2() const { return expr.val2; } \ - unsigned long int get_prec() const { return mpf_get_default_prec(); } \ -}; \ - \ -template \ -class __gmp_expr \ -, eval_fun> > \ -{ \ -private: \ - typedef mpz_class val1_type; \ - typedef __gmp_expr val2_type; \ - \ - __gmp_binary_expr expr; \ -public: \ - __gmp_expr(const val1_type &val1, const val2_type &val2) \ - : expr(val1, val2) { } \ - void eval(mpq_ptr q) const \ - { \ - mpq_class temp(expr.val2); \ - eval_fun::eval(q, expr.val1.get_mpz_t(), temp.get_mpq_t()); \ - } \ - const val1_type & get_val1() const { return expr.val1; } \ - const val2_type & get_val2() const { return expr.val2; } \ - unsigned long int get_prec() const { return mpf_get_default_prec(); } \ -}; \ - \ -template \ -class __gmp_expr \ -, eval_fun> > \ -{ \ -private: \ - typedef mpq_class val1_type; \ - typedef __gmp_expr val2_type; \ - \ - __gmp_binary_expr expr; \ -public: \ - __gmp_expr(const val1_type &val1, const val2_type &val2) \ - : expr(val1, val2) { } \ - void eval(mpq_ptr q) const \ - { \ - mpz_class temp(expr.val2); \ - eval_fun::eval(q, expr.val1.get_mpq_t(), temp.get_mpz_t()); \ - } \ - const val1_type & get_val1() const { return expr.val1; } \ - const val2_type & get_val2() const { return expr.val2; } \ - unsigned long int get_prec() const { return mpf_get_default_prec(); } \ -}; \ - \ -template \ -class __gmp_expr \ -, mpq_class, eval_fun> > \ -{ \ -private: \ - typedef __gmp_expr val1_type; \ - typedef mpq_class val2_type; \ - \ - __gmp_binary_expr expr; \ -public: \ - __gmp_expr(const val1_type &val1, const val2_type &val2) \ - : expr(val1, val2) { } \ - void eval(mpq_ptr q) const \ - { \ - mpz_class temp(expr.val1); \ - eval_fun::eval(q, temp.get_mpz_t(), expr.val2.get_mpq_t()); \ - } \ - const val1_type & get_val1() const { return expr.val1; } \ - const val2_type & get_val2() const { return expr.val2; } \ - unsigned long int get_prec() const { return mpf_get_default_prec(); } \ -}; \ - \ -template \ -class __gmp_expr \ -, mpz_class, eval_fun> > \ -{ \ -private: \ - typedef __gmp_expr val1_type; \ - typedef mpz_class val2_type; \ - \ - __gmp_binary_expr expr; \ -public: \ - __gmp_expr(const val1_type &val1, const val2_type &val2) \ - : expr(val1, val2) { } \ - void eval(mpq_ptr q) const \ - { \ - mpq_class temp(expr.val1); \ - eval_fun::eval(q, temp.get_mpq_t(), expr.val2.get_mpz_t()); \ - } \ - const val1_type & get_val1() const { return expr.val1; } \ - const val2_type & get_val2() const { return expr.val2; } \ - unsigned long int get_prec() const { return mpf_get_default_prec(); } \ -}; \ - \ -template \ -class __gmp_expr, __gmp_expr, eval_fun> > \ -{ \ -private: \ - typedef __gmp_expr val1_type; \ - typedef __gmp_expr val2_type; \ - \ - __gmp_binary_expr expr; \ -public: \ - __gmp_expr(const val1_type &val1, const val2_type &val2) \ - : expr(val1, val2) { } \ - void eval(mpq_ptr q) const \ - { \ - mpz_class temp1(expr.val1); \ - mpq_class temp2(expr.val2); \ - eval_fun::eval(q, temp1.get_mpz_t(), temp2.get_mpq_t()); \ - } \ - const val1_type & get_val1() const { return expr.val1; } \ - const val2_type & get_val2() const { return expr.val2; } \ - unsigned long int get_prec() const { return mpf_get_default_prec(); } \ -}; \ - \ -template \ -class __gmp_expr, __gmp_expr, eval_fun> > \ -{ \ -private: \ - typedef __gmp_expr val1_type; \ - typedef __gmp_expr val2_type; \ - \ - __gmp_binary_expr expr; \ -public: \ - __gmp_expr(const val1_type &val1, const val2_type &val2) \ - : expr(val1, val2) { } \ - void eval(mpq_ptr q) const \ - { \ - mpq_class temp1(expr.val1); \ - mpz_class temp2(expr.val2); \ - eval_fun::eval(q, temp1.get_mpq_t(), temp2.get_mpz_t()); \ - } \ - const val1_type & get_val1() const { return expr.val1; } \ - const val2_type & get_val2() const { return expr.val2; } \ - unsigned long int get_prec() const { return mpf_get_default_prec(); } \ -}; - - -__GMPZQ_DEFINE_EXPR(__gmp_binary_plus) -__GMPZQ_DEFINE_EXPR(__gmp_binary_minus) - -/**************** Macros for defining functions ****************/ -/* Results of operators and functions are instances of __gmp_expr. - T determines the numerical type of the expression: it can be either - mpz_t, mpq_t, or mpf_t. When the arguments of a binary - expression have different numerical types, __gmp_resolve_expr is used - to determine the "larger" type. - U is either __gmp_unary_expr or __gmp_binary_expr, - where V and W are the arguments' types -- they can in turn be - expressions, thus allowing to build compound expressions to any - degree of complexity. - Op is a function object that must have an eval() method accepting - appropriate arguments. - Actual evaluation of a __gmp_expr object is done when it gets - assigned to an mp*_class ("lazy" evaluation): this is done by calling - its eval() method. */ - - -// non-member unary operators and functions - -#define __GMP_DEFINE_UNARY_FUNCTION(fun, eval_fun) \ - \ -template \ -inline __gmp_expr, eval_fun> > \ -fun(const __gmp_expr &expr) \ -{ \ - return __gmp_expr, eval_fun> >(expr); \ -} - -#define __GMP_DEFINE_UNARY_TYPE_FUNCTION(type, fun, eval_fun) \ - \ -template \ -inline type fun(const __gmp_expr &expr) \ -{ \ - typename __gmp_resolve_temp::temp_type temp(expr); \ - return eval_fun::eval(temp.__get_mp()); \ -} - - -// non-member binary operators and functions - -#define __GMPP_DEFINE_BINARY_FUNCTION(fun, eval_fun) \ - \ -template \ -inline __gmp_expr::value_type, \ -__gmp_binary_expr<__gmp_expr, __gmp_expr, eval_fun> > \ -fun(const __gmp_expr &expr1, const __gmp_expr &expr2) \ -{ \ - return __gmp_expr::value_type, \ - __gmp_binary_expr<__gmp_expr, __gmp_expr, eval_fun> > \ - (expr1, expr2); \ -} - -#define __GMPNN_DEFINE_BINARY_FUNCTION(fun, eval_fun, type, bigtype) \ - \ -template \ -inline __gmp_expr \ -, bigtype, eval_fun> > \ -fun(const __gmp_expr &expr, type t) \ -{ \ - return __gmp_expr \ - , bigtype, eval_fun> >(expr, t); \ -} \ - \ -template \ -inline __gmp_expr \ -, eval_fun> > \ -fun(type t, const __gmp_expr &expr) \ -{ \ - return __gmp_expr \ - , eval_fun> >(t, expr); \ -} - -#define __GMPNS_DEFINE_BINARY_FUNCTION(fun, eval_fun, type) \ -__GMPNN_DEFINE_BINARY_FUNCTION(fun, eval_fun, type, signed long int) - -#define __GMPNU_DEFINE_BINARY_FUNCTION(fun, eval_fun, type) \ -__GMPNN_DEFINE_BINARY_FUNCTION(fun, eval_fun, type, unsigned long int) - -#define __GMPND_DEFINE_BINARY_FUNCTION(fun, eval_fun, type) \ -__GMPNN_DEFINE_BINARY_FUNCTION(fun, eval_fun, type, double) - -#define __GMPNLD_DEFINE_BINARY_FUNCTION(fun, eval_fun, type) \ -__GMPNN_DEFINE_BINARY_FUNCTION(fun, eval_fun, type, long double) - -#define __GMPN_DEFINE_BINARY_FUNCTION(fun, eval_fun) \ -__GMPNS_DEFINE_BINARY_FUNCTION(fun, eval_fun, signed char) \ -__GMPNU_DEFINE_BINARY_FUNCTION(fun, eval_fun, unsigned char) \ -__GMPNS_DEFINE_BINARY_FUNCTION(fun, eval_fun, signed int) \ -__GMPNU_DEFINE_BINARY_FUNCTION(fun, eval_fun, unsigned int) \ -__GMPNS_DEFINE_BINARY_FUNCTION(fun, eval_fun, signed short int) \ -__GMPNU_DEFINE_BINARY_FUNCTION(fun, eval_fun, unsigned short int) \ -__GMPNS_DEFINE_BINARY_FUNCTION(fun, eval_fun, signed long int) \ -__GMPNU_DEFINE_BINARY_FUNCTION(fun, eval_fun, unsigned long int) \ -__GMPND_DEFINE_BINARY_FUNCTION(fun, eval_fun, float) \ -__GMPND_DEFINE_BINARY_FUNCTION(fun, eval_fun, double) \ -__GMPNLD_DEFINE_BINARY_FUNCTION(fun, eval_fun, long double) - -#define __GMP_DEFINE_BINARY_FUNCTION(fun, eval_fun) \ -__GMPP_DEFINE_BINARY_FUNCTION(fun, eval_fun) \ -__GMPN_DEFINE_BINARY_FUNCTION(fun, eval_fun) - - -#define __GMP_DEFINE_BINARY_FUNCTION_UI(fun, eval_fun) \ - \ -template \ -inline __gmp_expr \ -, unsigned long int, eval_fun> > \ -fun(const __gmp_expr &expr, unsigned long int l) \ -{ \ - return __gmp_expr, unsigned long int, eval_fun> >(expr, l); \ -} - - -#define __GMPP_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun) \ - \ -template \ -inline type fun(const __gmp_expr &expr1, \ - const __gmp_expr &expr2) \ -{ \ - typedef typename __gmp_resolve_expr::value_type eval_type; \ - typename __gmp_resolve_temp::temp_type temp1(expr1); \ - typename __gmp_resolve_temp::temp_type temp2(expr2); \ - return eval_fun::eval(temp1.__get_mp(), temp2.__get_mp()); \ -} - -#define __GMPNN_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, \ - type2, bigtype) \ - \ -template \ -inline type fun(const __gmp_expr &expr, type2 t) \ -{ \ - typename __gmp_resolve_temp::temp_type temp(expr); \ - return eval_fun::eval(temp.__get_mp(), static_cast(t)); \ -} \ - \ -template \ -inline type fun(type2 t, const __gmp_expr &expr) \ -{ \ - typename __gmp_resolve_temp::temp_type temp(expr); \ - return eval_fun::eval(static_cast(t), temp.__get_mp()); \ -} - -#define __GMPNS_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, type2) \ -__GMPNN_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, \ - type2, signed long int) - -#define __GMPNU_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, type2) \ -__GMPNN_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, \ - type2, unsigned long int) - -#define __GMPND_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, type2) \ -__GMPNN_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, type2, double) - -#define __GMPNLD_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, type2) \ -__GMPNN_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, type2, long double) - -#define __GMPN_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun) \ -__GMPNS_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, signed char) \ -__GMPNU_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, unsigned char) \ -__GMPNS_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, signed int) \ -__GMPNU_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, unsigned int) \ -__GMPNS_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, signed short int) \ -__GMPNU_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, unsigned short int) \ -__GMPNS_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, signed long int) \ -__GMPNU_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, unsigned long int) \ -__GMPND_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, float) \ -__GMPND_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, double) \ -__GMPNLD_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, long double) - -#define __GMP_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun) \ -__GMPP_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun) \ -__GMPN_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun) - - -// member operators - -#define __GMPP_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun) \ - \ -template \ -inline type##_class & type##_class::fun(const __gmp_expr &expr) \ -{ \ - __gmp_set_expr(mp, __gmp_expr, eval_fun> >(*this, expr)); \ - return *this; \ -} - -#define __GMPNN_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, \ - type2, bigtype) \ - \ -inline type##_class & type##_class::fun(type2 t) \ -{ \ - __gmp_set_expr(mp, __gmp_expr >(*this, t)); \ - return *this; \ -} - -#define __GMPNS_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, type2) \ -__GMPNN_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, \ - type2, signed long int) - -#define __GMPNU_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, type2) \ -__GMPNN_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, \ - type2, unsigned long int) - -#define __GMPND_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, type2) \ -__GMPNN_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, type2, double) - -#define __GMPNLD_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, type2) \ -__GMPNN_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, type2, long double) - -#define __GMPN_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun) \ -__GMPNS_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, signed char) \ -__GMPNU_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, unsigned char) \ -__GMPNS_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, signed int) \ -__GMPNU_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, unsigned int) \ -__GMPNS_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, signed short int) \ -__GMPNU_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, unsigned short int) \ -__GMPNS_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, signed long int) \ -__GMPNU_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, unsigned long int) \ -__GMPND_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, float) \ -__GMPND_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, double) \ -/* __GMPNLD_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, long double) */ - -#define __GMP_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun) \ -__GMPP_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun) \ -__GMPN_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun) - -#define __GMPZ_DEFINE_COMPOUND_OPERATOR(fun, eval_fun) \ -__GMP_DEFINE_COMPOUND_OPERATOR(mpz, fun, eval_fun) - -#define __GMPZZ_DEFINE_COMPOUND_OPERATOR(fun, eval_fun) \ -__GMPP_DEFINE_COMPOUND_OPERATOR(mpz, fun, eval_fun) - -#define __GMPQ_DEFINE_COMPOUND_OPERATOR(fun, eval_fun) \ -__GMP_DEFINE_COMPOUND_OPERATOR(mpq, fun, eval_fun) - -#define __GMPF_DEFINE_COMPOUND_OPERATOR(fun, eval_fun) \ -__GMP_DEFINE_COMPOUND_OPERATOR(mpf, fun, eval_fun) - - - -#define __GMP_DEFINE_COMPOUND_OPERATOR_UI(type, fun, eval_fun) \ - \ -inline type##_class & type##_class::fun(unsigned long int l) \ -{ \ - __gmp_set_expr(mp, __gmp_expr >(*this, l)); \ - return *this; \ -} - -#define __GMPZ_DEFINE_COMPOUND_OPERATOR_UI(fun, eval_fun) \ -__GMP_DEFINE_COMPOUND_OPERATOR_UI(mpz, fun, eval_fun) - -#define __GMPQ_DEFINE_COMPOUND_OPERATOR_UI(fun, eval_fun) \ -__GMP_DEFINE_COMPOUND_OPERATOR_UI(mpq, fun, eval_fun) - -#define __GMPF_DEFINE_COMPOUND_OPERATOR_UI(fun, eval_fun) \ -__GMP_DEFINE_COMPOUND_OPERATOR_UI(mpf, fun, eval_fun) - - - -#define __GMP_DEFINE_INCREMENT_OPERATOR(type, fun, eval_fun) \ - \ -inline type##_class & type##_class::fun() \ -{ \ - eval_fun::eval(mp); \ - return *this; \ -} \ - \ -inline type##_class type##_class::fun(int) \ -{ \ - type##_class temp(*this); \ - eval_fun::eval(mp); \ - return temp; \ -} - -#define __GMPZ_DEFINE_INCREMENT_OPERATOR(fun, eval_fun) \ -__GMP_DEFINE_INCREMENT_OPERATOR(mpz, fun, eval_fun) - -#define __GMPQ_DEFINE_INCREMENT_OPERATOR(fun, eval_fun) \ -__GMP_DEFINE_INCREMENT_OPERATOR(mpq, fun, eval_fun) - -#define __GMPF_DEFINE_INCREMENT_OPERATOR(fun, eval_fun) \ -__GMP_DEFINE_INCREMENT_OPERATOR(mpf, fun, eval_fun) - - - -/**************** Arithmetic operators and functions ****************/ - -// non-member operators and functions - -__GMP_DEFINE_UNARY_FUNCTION(operator+, __gmp_unary_plus) -__GMP_DEFINE_UNARY_FUNCTION(operator-, __gmp_unary_minus) -__GMP_DEFINE_UNARY_FUNCTION(operator~, __gmp_unary_com) - -__GMP_DEFINE_BINARY_FUNCTION(operator+, __gmp_binary_plus) -__GMP_DEFINE_BINARY_FUNCTION(operator-, __gmp_binary_minus) -__GMP_DEFINE_BINARY_FUNCTION(operator*, __gmp_binary_multiplies) -__GMP_DEFINE_BINARY_FUNCTION(operator/, __gmp_binary_divides) -__GMP_DEFINE_BINARY_FUNCTION(operator%, __gmp_binary_modulus) -__GMP_DEFINE_BINARY_FUNCTION(operator&, __gmp_binary_and) -__GMP_DEFINE_BINARY_FUNCTION(operator|, __gmp_binary_ior) -__GMP_DEFINE_BINARY_FUNCTION(operator^, __gmp_binary_xor) - -__GMP_DEFINE_BINARY_FUNCTION_UI(operator<<, __gmp_binary_lshift) -__GMP_DEFINE_BINARY_FUNCTION_UI(operator>>, __gmp_binary_rshift) - -__GMP_DEFINE_BINARY_TYPE_FUNCTION(bool, operator==, __gmp_binary_equal) -__GMP_DEFINE_BINARY_TYPE_FUNCTION(bool, operator!=, __gmp_binary_not_equal) -__GMP_DEFINE_BINARY_TYPE_FUNCTION(bool, operator<, __gmp_binary_less) -__GMP_DEFINE_BINARY_TYPE_FUNCTION(bool, operator<=, __gmp_binary_less_equal) -__GMP_DEFINE_BINARY_TYPE_FUNCTION(bool, operator>, __gmp_binary_greater) -__GMP_DEFINE_BINARY_TYPE_FUNCTION(bool, operator>=, \ - __gmp_binary_greater_equal) - -__GMP_DEFINE_UNARY_FUNCTION(abs, __gmp_abs_function) -__GMP_DEFINE_UNARY_FUNCTION(trunc, __gmp_trunc_function) -__GMP_DEFINE_UNARY_FUNCTION(floor, __gmp_floor_function) -__GMP_DEFINE_UNARY_FUNCTION(ceil, __gmp_ceil_function) -__GMP_DEFINE_UNARY_FUNCTION(sqrt, __gmp_sqrt_function) -__GMP_DEFINE_BINARY_FUNCTION(hypot, __gmp_hypot_function) - -__GMP_DEFINE_UNARY_TYPE_FUNCTION(int, sgn, __gmp_sgn_function) -__GMP_DEFINE_BINARY_TYPE_FUNCTION(int, cmp, __gmp_cmp_function) - -// member operators for mpz_class - -__GMPZ_DEFINE_COMPOUND_OPERATOR(operator+=, __gmp_binary_plus) -__GMPZ_DEFINE_COMPOUND_OPERATOR(operator-=, __gmp_binary_minus) -__GMPZ_DEFINE_COMPOUND_OPERATOR(operator*=, __gmp_binary_multiplies) -__GMPZ_DEFINE_COMPOUND_OPERATOR(operator/=, __gmp_binary_divides) -__GMPZ_DEFINE_COMPOUND_OPERATOR(operator%=, __gmp_binary_modulus) - -__GMPZZ_DEFINE_COMPOUND_OPERATOR(operator&=, __gmp_binary_and) -__GMPZZ_DEFINE_COMPOUND_OPERATOR(operator|=, __gmp_binary_ior) -__GMPZZ_DEFINE_COMPOUND_OPERATOR(operator^=, __gmp_binary_xor) - -__GMPZ_DEFINE_COMPOUND_OPERATOR_UI(operator<<=, __gmp_binary_lshift) -__GMPZ_DEFINE_COMPOUND_OPERATOR_UI(operator>>=, __gmp_binary_rshift) - -__GMPZ_DEFINE_INCREMENT_OPERATOR(operator++, __gmp_unary_increment) -__GMPZ_DEFINE_INCREMENT_OPERATOR(operator--, __gmp_unary_decrement) - -// member operators for mpq_class - -__GMPQ_DEFINE_COMPOUND_OPERATOR(operator+=, __gmp_binary_plus) -__GMPQ_DEFINE_COMPOUND_OPERATOR(operator-=, __gmp_binary_minus) -__GMPQ_DEFINE_COMPOUND_OPERATOR(operator*=, __gmp_binary_multiplies) -__GMPQ_DEFINE_COMPOUND_OPERATOR(operator/=, __gmp_binary_divides) - -__GMPQ_DEFINE_COMPOUND_OPERATOR_UI(operator<<=, __gmp_binary_lshift) -__GMPQ_DEFINE_COMPOUND_OPERATOR_UI(operator>>=, __gmp_binary_rshift) - -__GMPQ_DEFINE_INCREMENT_OPERATOR(operator++, __gmp_unary_increment) -__GMPQ_DEFINE_INCREMENT_OPERATOR(operator--, __gmp_unary_decrement) - -// member operators for mpf_class - -__GMPF_DEFINE_COMPOUND_OPERATOR(operator+=, __gmp_binary_plus) -__GMPF_DEFINE_COMPOUND_OPERATOR(operator-=, __gmp_binary_minus) -__GMPF_DEFINE_COMPOUND_OPERATOR(operator*=, __gmp_binary_multiplies) -__GMPF_DEFINE_COMPOUND_OPERATOR(operator/=, __gmp_binary_divides) - -__GMPF_DEFINE_COMPOUND_OPERATOR_UI(operator<<=, __gmp_binary_lshift) -__GMPF_DEFINE_COMPOUND_OPERATOR_UI(operator>>=, __gmp_binary_rshift) - -__GMPF_DEFINE_INCREMENT_OPERATOR(operator++, __gmp_unary_increment) -__GMPF_DEFINE_INCREMENT_OPERATOR(operator--, __gmp_unary_decrement) - - - -/**************** Class wrapper for gmp_randstate_t ****************/ - -class __gmp_urandomb_value { }; -class __gmp_urandomm_value { }; - -template <> -class __gmp_expr -{ -private: - __gmp_randstate_struct *state; - unsigned long int bits; -public: - __gmp_expr(gmp_randstate_t s, unsigned long int l) : state(s), bits(l) { } - void eval(mpz_ptr z) const { __gmp_rand_function::eval(z, state, bits); } - unsigned long int get_prec() const { return mpf_get_default_prec(); } -}; - -template <> -class __gmp_expr -{ -private: - __gmp_randstate_struct *state; - mpz_class range; -public: - __gmp_expr(gmp_randstate_t s, const mpz_class &z) : state(s), range(z) { } - void eval(mpz_ptr z) const - { __gmp_rand_function::eval(z, state, range.get_mpz_t()); } - unsigned long int get_prec() const { return mpf_get_default_prec(); } -}; - -template <> -class __gmp_expr -{ -private: - __gmp_randstate_struct *state; - unsigned long int bits; -public: - __gmp_expr(gmp_randstate_t s, unsigned long int l) : state(s), bits(l) { } - void eval(mpf_ptr f, mp_bitcnt_t prec) const - { __gmp_rand_function::eval(f, state, (bits>0) ? get_prec() : prec); } - unsigned long int get_prec() const - { - if (bits == 0) - return mpf_get_default_prec(); - else - return bits; - } -}; - -extern "C" { - typedef void __gmp_randinit_default_t (gmp_randstate_t); - typedef void __gmp_randinit_lc_2exp_t (gmp_randstate_t, mpz_srcptr, unsigned long int, mp_bitcnt_t); - typedef int __gmp_randinit_lc_2exp_size_t (gmp_randstate_t, mp_bitcnt_t); -} - -class gmp_randclass -{ -private: - gmp_randstate_t state; - - // copy construction and assignment not allowed - gmp_randclass(const gmp_randclass &); - void operator=(const gmp_randclass &); -public: - // constructors and destructor - gmp_randclass(gmp_randalg_t alg, unsigned long int size) - { - switch (alg) - { - case GMP_RAND_ALG_LC: // no other cases for now - default: - gmp_randinit_lc_2exp_size(state, size); - break; - } - } - - // gmp_randinit_default - gmp_randclass(__gmp_randinit_default_t* f) { f(state); } - - // gmp_randinit_lc_2exp - gmp_randclass(__gmp_randinit_lc_2exp_t* f, - mpz_class z, unsigned long int l1, unsigned long int l2) - { f(state, z.get_mpz_t(), l1, l2); } - - // gmp_randinit_lc_2exp_size - gmp_randclass(__gmp_randinit_lc_2exp_size_t* f, - unsigned long int size) - { - if (f (state, size) == 0) - throw std::length_error ("gmp_randinit_lc_2exp_size"); - } - - ~gmp_randclass() { gmp_randclear(state); } - - // initialize - void seed(); // choose a random seed some way (?) - void seed(unsigned long int s) { gmp_randseed_ui(state, s); } - void seed(const mpz_class &z) { gmp_randseed(state, z.get_mpz_t()); } - - // get random number - __gmp_expr get_z_bits(unsigned long int l) - { return __gmp_expr(state, l); } - __gmp_expr get_z_bits(const mpz_class &z) - { return get_z_bits(z.get_ui()); } - - __gmp_expr get_z_range(const mpz_class &z) - { return __gmp_expr(state, z); } - - __gmp_expr get_f(unsigned long int prec = 0) - { return __gmp_expr(state, prec); } -}; - - -/**************** #undef all private macros ****************/ - -#undef __GMPP_DECLARE_COMPOUND_OPERATOR -#undef __GMPN_DECLARE_COMPOUND_OPERATOR -#undef __GMP_DECLARE_COMPOUND_OPERATOR -#undef __GMP_DECLARE_COMPOUND_OPERATOR_UI -#undef __GMP_DECLARE_INCREMENT_OPERATOR - -#undef __GMPZQ_DEFINE_EXPR -#undef __GMP_DEFINE_TERNARY_EXPR - -#undef __GMP_DEFINE_UNARY_FUNCTION -#undef __GMP_DEFINE_UNARY_TYPE_FUNCTION - -#undef __GMPP_DEFINE_BINARY_FUNCTION -#undef __GMPNN_DEFINE_BINARY_FUNCTION -#undef __GMPNS_DEFINE_BINARY_FUNCTION -#undef __GMPNU_DEFINE_BINARY_FUNCTION -#undef __GMPND_DEFINE_BINARY_FUNCTION -#undef __GMPNLD_DEFINE_BINARY_FUNCTION -#undef __GMPN_DEFINE_BINARY_FUNCTION -#undef __GMP_DEFINE_BINARY_FUNCTION - -#undef __GMP_DEFINE_BINARY_FUNCTION_UI - -#undef __GMPP_DEFINE_BINARY_TYPE_FUNCTION -#undef __GMPNN_DEFINE_BINARY_TYPE_FUNCTION -#undef __GMPNS_DEFINE_BINARY_TYPE_FUNCTION -#undef __GMPNU_DEFINE_BINARY_TYPE_FUNCTION -#undef __GMPND_DEFINE_BINARY_TYPE_FUNCTION -#undef __GMPNLD_DEFINE_BINARY_TYPE_FUNCTION -#undef __GMPN_DEFINE_BINARY_TYPE_FUNCTION -#undef __GMP_DEFINE_BINARY_TYPE_FUNCTION - -#undef __GMPP_DECLARE_COMPOUND_OPERATOR -#undef __GMPN_DECLARE_COMPOUND_OPERATOR -#undef __GMP_DECLARE_COMPOUND_OPERATOR - -#undef __GMP_DECLARE_COMPOUND_OPERATOR_UI -#undef __GMP_DECLARE_INCREMENT_OPERATOR - -#undef __GMPZ_DEFINE_COMPOUND_OPERATOR -#undef __GMPZZ_DEFINE_COMPOUND_OPERATOR -#undef __GMPZN_DEFINE_COMPOUND_OPERATOR -#undef __GMPZNN_DEFINE_COMPOUND_OPERATOR -#undef __GMPZNS_DEFINE_COMPOUND_OPERATOR -#undef __GMPZNU_DEFINE_COMPOUND_OPERATOR -#undef __GMPZND_DEFINE_COMPOUND_OPERATOR -#undef __GMPZNLD_DEFINE_COMPOUND_OPERATOR - -#undef __GMPP_DEFINE_COMPOUND_OPERATOR -#undef __GMPNN_DEFINE_COMPOUND_OPERATOR -#undef __GMPNS_DEFINE_COMPOUND_OPERATOR -#undef __GMPNU_DEFINE_COMPOUND_OPERATOR -#undef __GMPND_DEFINE_COMPOUND_OPERATOR -#undef __GMPNLD_DEFINE_COMPOUND_OPERATOR -#undef __GMPN_DEFINE_COMPOUND_OPERATOR -#undef __GMP_DEFINE_COMPOUND_OPERATOR - -#undef __GMPZ_DEFINE_COMPOUND_OPERATOR -#undef __GMPZZ_DEFINE_COMPOUND_OPERATOR -#undef __GMPQ_DEFINE_COMPOUND_OPERATOR -#undef __GMPF_DEFINE_COMPOUND_OPERATOR - -#undef __GMP_DEFINE_COMPOUND_OPERATOR_UI -#undef __GMPZ_DEFINE_COMPOUND_OPERATOR_UI -#undef __GMPQ_DEFINE_COMPOUND_OPERATOR_UI -#undef __GMPF_DEFINE_COMPOUND_OPERATOR_UI - -#undef __GMP_DEFINE_INCREMENT_OPERATOR -#undef __GMPZ_DEFINE_INCREMENT_OPERATOR -#undef __GMPQ_DEFINE_INCREMENT_OPERATOR -#undef __GMPF_DEFINE_INCREMENT_OPERATOR - -#endif /* __GMP_PLUSPLUS__ */ diff --git a/src/external/levmar.cmake b/src/external/levmar.cmake index 1256f5fe2..63ed77e46 100644 --- a/src/external/levmar.cmake +++ b/src/external/levmar.cmake @@ -4,7 +4,7 @@ option(ALLOW_BUNDLED_LEVMAR "Allow use of bundled levmar source" ON) -set(LEVMAR_DIR ${EXTERNAL_DIR}/levmar-2.3) +set(LEVMAR_DIR ${CMAKE_CURRENT_LIST_DIR}/levmar-2.3) if(ALLOW_BUNDLED_LEVMAR AND EXISTS "${LEVMAR_DIR}/lm.h") message(STATUS "- levmar - using bundled source") diff --git a/src/external/lib3ds.cmake b/src/external/lib3ds.cmake index d526d3d4e..2c630c4df 100644 --- a/src/external/lib3ds.cmake +++ b/src/external/lib3ds.cmake @@ -7,7 +7,7 @@ option(ALLOW_BUNDLED_LIB3DS "Allow use of bundled lib3ds source" ON) option(ALLOW_SYSTEM_LIB3DS "Allow use of system-provided lib3ds" ON) find_package(Lib3ds) -set(LIB3DS_DIR ${EXTERNAL_DIR}/lib3ds-1.3.0) +set(LIB3DS_DIR ${CMAKE_CURRENT_LIST_DIR}/lib3ds-1.3.0) if(ALLOW_SYSTEM_LIB3DS AND TARGET Lib3ds::Lib3ds) message(STATUS "- lib3ds - using system-provided library") diff --git a/src/external/libigl-2.3.0/.github/ISSUE_TEMPLATE/bug_report.md b/src/external/libigl-2.3.0/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 000000000..66bc3d370 --- /dev/null +++ b/src/external/libigl-2.3.0/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,18 @@ +--- +name: 🐛 Bug Report +about: If something isn't working as expected +title: '' +labels: bug, pending verification +assignees: '' + +--- + +#### Describe the bug + + +#### Platform + + +- [ ] Windows +- [ ] macOS +- [ ] Linux diff --git a/src/external/libigl-2.3.0/.github/ISSUE_TEMPLATE/compilation.md b/src/external/libigl-2.3.0/.github/ISSUE_TEMPLATE/compilation.md new file mode 100644 index 000000000..79c95d3b1 --- /dev/null +++ b/src/external/libigl-2.3.0/.github/ISSUE_TEMPLATE/compilation.md @@ -0,0 +1,25 @@ +--- +name: 😱 Compilation issue +about: Report a problem when compiling the code +title: '' +labels: 'compilation' +assignees: '' + +--- + +#### Describe your issue + + + +#### Checklist + + +- [ ] I have read the [bug report](https://libigl.github.io/bug-report/) +- [ ] CMake issue: I have tried with a fresh clone/empty build directory + +#### Platform + + +- [ ] Windows +- [ ] macOS +- [ ] Linux diff --git a/src/external/libigl-2.3.0/.github/ISSUE_TEMPLATE/config.yml b/src/external/libigl-2.3.0/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 000000000..9bc6424af --- /dev/null +++ b/src/external/libigl-2.3.0/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,8 @@ +blank_issues_enabled: false +contact_links: + - name: 🚀 Feature Request + url: https://github.com/libigl/libigl/discussions/new?category_id=32617689 + about: Share ideas for new features + - name: ❓ Ask a Question + url: https://github.com/libigl/libigl/discussions/new?category_id=32617688 + about: Ask the community for help diff --git a/src/external/libigl-2.3.0/.github/pull_request_template.md b/src/external/libigl-2.3.0/.github/pull_request_template.md new file mode 100644 index 000000000..5f03fb757 --- /dev/null +++ b/src/external/libigl-2.3.0/.github/pull_request_template.md @@ -0,0 +1,12 @@ +Fixes # . + + + + +#### Checklist + + +- [ ] All changes meet [libigl style-guidelines](https://libigl.github.io/style-guidelines/). +- [ ] Adds new .cpp file. +- [ ] Adds corresponding unit test. +- [ ] This is a minor change. diff --git a/src/external/libigl-2.3.0/.github/workflows/continuous.yml b/src/external/libigl-2.3.0/.github/workflows/continuous.yml new file mode 100644 index 000000000..4d7428e2d --- /dev/null +++ b/src/external/libigl-2.3.0/.github/workflows/continuous.yml @@ -0,0 +1,153 @@ +name: Build + +on: + push: + branches: + - master + - stable + pull_request: + branches: + - master + - stable + +env: + CTEST_OUTPUT_ON_FAILURE: ON + CTEST_PARALLEL_LEVEL: 2 + +jobs: + #################### + # Linux / macOS + #################### + + Unix: + name: ${{ matrix.name }} (${{ matrix.config }}, ${{ fromJSON('["Static", "HeaderOnly"]')[matrix.static == 'ON'] }}) + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ubuntu-20.04, macos-latest] + config: [Release] + static: [ON, OFF] + include: + - os: macos-latest + name: macOS + - os: ubuntu-20.04 + name: Linux + env: + LIBIGL_NUM_THREADS: 1 # See https://github.com/libigl/libigl/pull/996 + steps: + - name: Checkout repository + uses: actions/checkout@v1 + with: + fetch-depth: 10 + + - name: Dependencies (Linux) + if: runner.os == 'Linux' + run: | + sudo apt-get update + sudo apt-get install \ + libblas-dev \ + libboost-filesystem-dev \ + libboost-system-dev \ + libboost-thread-dev \ + libglu1-mesa-dev \ + liblapack-dev \ + libmpfr-dev \ + xorg-dev \ + ccache + + - name: Dependencies (macOS) + if: runner.os == 'macOS' + run: brew install boost gmp mpfr ccache + + - name: Cache Build + id: cache-build + uses: actions/cache@v1 + with: + path: ~/.ccache + key: ${{ runner.os }}-${{ matrix.config }}-${{ matrix.static }}-cache + + - name: Prepare ccache + run: | + ccache --max-size=1.0G + ccache -V && ccache --show-stats && ccache --zero-stats + + - name: Configure + run: | + mkdir -p build + cd build + cmake .. \ + -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \ + -DCMAKE_BUILD_TYPE=${{ matrix.config }} \ + -DLIBIGL_USE_STATIC_LIBRARY=${{ matrix.static }} \ + -DLIBIGL_WITH_CGAL=ON \ + -DLIBIGL_WITH_COMISO=ON + + - name: Build + run: cd build; make -j2; ccache --show-stats + + - name: Tests + run: cd build; ctest --verbose + + #################### + # Windows + #################### + + Windows: + name: Windows (${{ matrix.config }}, ${{ fromJSON('["Static", "HeaderOnly"]')[matrix.static == 'ON'] }}) + runs-on: windows-2019 + env: + CC: cl.exe + CXX: cl.exe + strategy: + fail-fast: false + matrix: + config: [Release] + static: [ON, OFF] + steps: + - name: Checkout repository + uses: actions/checkout@v1 + with: + fetch-depth: 10 + - uses: seanmiddleditch/gha-setup-ninja@master + + - name: Set env + run: | + echo "BOOST_ROOT=$env:BOOST_ROOT_1_72_0" >> ${env:GITHUB_ENV} + echo "appdata=$env:LOCALAPPDATA" >> ${env:GITHUB_ENV} + + - name: Cache build + id: cache-build + uses: actions/cache@v1 + with: + path: ${{ env.appdata }}\Mozilla\sccache + key: ${{ runner.os }}-${{ matrix.config }}-${{ matrix.static }}-cache + + - name: Prepare sccache + run: | + Invoke-Expression (New-Object System.Net.WebClient).DownloadString('https://get.scoop.sh') + scoop install sccache --global + # Scoop modifies the PATH so we make it available for the next steps of the job + echo "${env:PATH}" >> ${env:GITHUB_PATH} + + # We run configure + build in the same step, since they both need to call VsDevCmd + # Also, cmd uses ^ to break commands into multiple lines (in powershell this is `) + - name: Configure and build + shell: cmd + run: | + call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\Tools\VsDevCmd.bat" -arch=x64 + cmake -G Ninja ^ + -DCMAKE_CXX_COMPILER_LAUNCHER=sccache ^ + -DCMAKE_BUILD_TYPE=${{ matrix.config }} ^ + -DLIBIGL_USE_STATIC_LIBRARY=${{ matrix.static }} ^ + -DLIBIGL_WITH_CGAL=ON ^ + -DLIBIGL_WITH_COMISO=OFF ^ + -DCMAKE_JOB_POOLS=pool-linking=1;pool-compilation=2 ^ + -DCMAKE_JOB_POOL_COMPILE:STRING=pool-compilation ^ + -DCMAKE_JOB_POOL_LINK:STRING=pool-linking ^ + -B build ^ + -S . + cmake --build build + + - name: Tests + run: cd build; ctest --verbose diff --git a/src/external/libigl-2.3.0/.github/workflows/nightly.yml b/src/external/libigl-2.3.0/.github/workflows/nightly.yml new file mode 100644 index 000000000..190adf118 --- /dev/null +++ b/src/external/libigl-2.3.0/.github/workflows/nightly.yml @@ -0,0 +1,190 @@ +name: Nightly + +on: + schedule: + - cron: '0 4 * * *' + +env: + CTEST_OUTPUT_ON_FAILURE: ON + CTEST_PARALLEL_LEVEL: 2 + +jobs: + #################### + # Linux / macOS + #################### + + # Part of this file is inspired from + # https://github.com/onqtam/doctest/blob/dev/.github/workflows/main.yml + + Unix: + name: ${{ matrix.name }} (${{ matrix.config }}, ${{ fromJSON('["Static", "HeaderOnly"]')[matrix.static == 'ON'] }}) + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + name: [ + ubuntu-20.04-gcc-8, + ubuntu-20.04-gcc-9, + ubuntu-20.04-gcc-10, + ubuntu-20.04-clang-8, + ubuntu-20.04-clang-9, + ubuntu-20.04-clang-10, + macOS-latest, + ] + config: [Debug, Release] + static: [ON, OFF] + include: + - name: ubuntu-20.04-gcc-8 + os: ubuntu-20.04 + compiler: gcc + version: "8" + + - name: ubuntu-20.04-gcc-9 + os: ubuntu-20.04 + compiler: gcc + version: "9" + + - name: ubuntu-20.04-gcc-10 + os: ubuntu-20.04 + compiler: gcc + version: "10" + + - name: ubuntu-20.04-clang-8 + os: ubuntu-20.04 + compiler: clang + version: "8" + + - name: ubuntu-20.04-clang-9 + os: ubuntu-20.04 + compiler: clang + version: "9" + + - name: ubuntu-20.04-clang-10 + os: ubuntu-20.04 + compiler: clang + version: "10" + + - name: macOS-latest + os: macOS-latest + + # Build tutorials for most configurations + - tutorials: ON + + # Except with Debug mode + - config: Debug + tutorials: OFF + env: + LIBIGL_NUM_THREADS: 1 # See https://github.com/libigl/libigl/pull/996 + steps: + - name: Checkout repository + uses: actions/checkout@v1 + with: + fetch-depth: 10 + + - name: Dependencies (Linux) + if: runner.os == 'Linux' + run: | + sudo apt-get update + + if [ "${{ matrix.compiler }}" = "gcc" ]; then + sudo apt-get install -y g++-${{ matrix.version }} + echo "CC=gcc-${{ matrix.version }}" >> $GITHUB_ENV + echo "CXX=g++-${{ matrix.version }}" >> $GITHUB_ENV + else + sudo apt-get install -y clang-${{ matrix.version }} + echo "CC=clang-${{ matrix.version }}" >> $GITHUB_ENV + echo "CXX=clang++-${{ matrix.version }}" >> $GITHUB_ENV + fi + + sudo apt-get install \ + libblas-dev \ + libboost-filesystem-dev \ + libboost-system-dev \ + libboost-thread-dev \ + libglu1-mesa-dev \ + liblapack-dev \ + libmpfr-dev \ + xorg-dev + + - name: Dependencies (macOS) + if: runner.os == 'macOS' + run: brew install boost gmp mpfr + + - name: Configure + run: | + mkdir -p build + cd build + cmake .. \ + -DCMAKE_BUILD_TYPE=${{ matrix.config }} \ + -DLIBIGL_USE_STATIC_LIBRARY=${{ matrix.static }} \ + -DLIBIGL_BUILD_TUTORIALS=${{ matrix.tutorials }} \ + -DLIBIGL_WITH_CGAL=ON \ + -DLIBIGL_WITH_COMISO=ON + + - name: Free Disk Space + if: runner.os == 'Linux' + run: | + sudo swapoff -a + sudo apt clean + sudo rm -rf /swapfile /usr/share/dotnet /usr/local/lib/android /opt/ghc + df -h + + - name: Build + run: cd build; make -j1 + + - name: Tests + run: cd build; ctest --verbose + + #################### + # Windows + #################### + + Windows: + name: Windows (${{ matrix.config }}, ${{ fromJSON('["Static", "HeaderOnly"]')[matrix.static == 'ON'] }}) + runs-on: windows-2019 + env: + CC: cl.exe + CXX: cl.exe + strategy: + fail-fast: false + matrix: + config: [Debug, Release] + static: [ON, OFF] + include: + - config: Debug + tutorials: OFF + - config: Release + tutorials: ON + steps: + - name: Checkout repository + uses: actions/checkout@v1 + with: + fetch-depth: 10 + - uses: seanmiddleditch/gha-setup-ninja@master + + - name: Set env + run: | + echo "BOOST_ROOT=$env:BOOST_ROOT_1_72_0" >> ${env:GITHUB_ENV} + + # We run configure + build in the same step, since they both need to call VsDevCmd + # Also, cmd uses ^ to break commands into multiple lines (in powershell this is `) + - name: Configure and build + shell: cmd + run: | + call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\Tools\VsDevCmd.bat" -arch=x64 + cmake -G Ninja ^ + -DCMAKE_BUILD_TYPE=${{ matrix.config }} ^ + -DLIBIGL_USE_STATIC_LIBRARY=${{ matrix.static }} ^ + -DLIBIGL_BUILD_TUTORIALS=${{ matrix.tutorials }} ^ + -DLIBIGL_WITH_CGAL=ON ^ + -DLIBIGL_WITH_COMISO=OFF ^ + -DCMAKE_JOB_POOLS=job-pool=1 ^ + -DCMAKE_JOB_POOL_COMPILE:STRING=job-pool ^ + -DCMAKE_JOB_POOL_LINK:STRING=job-pool ^ + -B build ^ + -S . + cd build + ninja -j 1 -k 10 + + - name: Tests + run: cd build; ctest --verbose diff --git a/src/external/libigl-2.3.0/.gitignore b/src/external/libigl-2.3.0/.gitignore new file mode 100644 index 000000000..3c61a0cbf --- /dev/null +++ b/src/external/libigl-2.3.0/.gitignore @@ -0,0 +1,100 @@ +# use glob syntax. +*.a +*.dylib +*.egg-info/ +*.exe +*.ilk +*.log +*.o +*.opensdf +*.orig +*.pdb +*.psess +*.pyc +*.sdf +*.so +*.so.[0123456789] +*.so.[0123456789].[0123456789] +*.suo +*.swo +*.swp +*.tlog +*.user +*.vsp +*CMakeFiles* +*buildXcode* +*tags +*~ +.DS_Store +.idea/ +.vs/ +.vscode/ +/external +Debug/ +README.html +Release/ +Untitled.ipynb +build +doc.html +documentation/*.aux +documentation/*.log +documentation/*.out +example +example1 +example_header_only +example_static +examples/*/*.mexmaci64 +examples/*/*.rbr +examples/bbw/bbw_demo +examples/bbw/bbw_demo_selfcontained.zip +examples/bbw/bbw_demo_selfcontained/* +examples/bbw/examples/*-volume.dmat +examples/bbw/examples/*-volume.mesh +examples/principal_curvature/curvature +examples/quicklook-mesh/Mesh.qlgenerator/* +examples/upright/upright +external/MeshFix/meshfix +external/embree/build/* +external/glew/build +external/glfw/build +external/libpng/build +external/medit/rebar.rbr +external/tetgen/tetgen +external/tinyxml2/build +external/tinyxml2/test +external/tinyxml2/tinyxml2.pc +external/yimg/showpng +iglhelpers.pyc +lib +libigl.zip +optional/build +python/.idea +python/.ipynb_checkpoints +python/__pycache__ +python/build +python/build2 +python/build3 +python/build4 +python/builddebug +python/buildstatic +python/py_igl/todo +python/py_igl/todo +python/scripts/generated +scripts/change_name.sh +site/ +syntax: glob +tests/bin +tests/build +tests/data +tutorial/*/*.mexmaci64 +tutorial/*/Makefile +tutorial/*/build/* +tutorial/.idea +tutorial/XXX_test/CMakeLists.txt +tutorial/XXX_test/main.cpp +tutorial/build +tutorial/cmake-build-debug +tutorial/data +tutorial/readme.html +untitled +scripts diff --git a/src/external/libigl-2.3.0/.mailmap b/src/external/libigl-2.3.0/.mailmap new file mode 100644 index 000000000..f3950cf16 --- /dev/null +++ b/src/external/libigl-2.3.0/.mailmap @@ -0,0 +1,19 @@ +# +# This list is used by git-shortlog to fix a few botched name translations +# in the libigl archive, either because the author's full name was messed up +# and/or not always written the same way, making contributions from the +# same person appearing not to be so. +# +Alec Jacobson Alec Jacobson (jalec +Alec Jacobson jalec +Alec Jacobson Alec Jacobson +Alec Jacobson ajx +Alec Jacobson mangledorf +Daniele Panozzo Daniele Panozzo +Daniele Panozzo dpanozzo +Wenzel Jakob Wenzel Jakob +Olga Diamanti dolga +schuellc schuellc +Kenshi Takayama Kenshi Takayama (kenshi +Kenshi Takayama kenshi +Kenshi Takayama kenshi84 diff --git a/src/external/libigl-2.3.0/CMakeLists.txt b/src/external/libigl-2.3.0/CMakeLists.txt new file mode 100644 index 000000000..26583b97b --- /dev/null +++ b/src/external/libigl-2.3.0/CMakeLists.txt @@ -0,0 +1,74 @@ +cmake_minimum_required(VERSION 3.1) + +# Toggles the use of the hunter package manager +option(HUNTER_ENABLED "Enable Hunter package manager support" OFF) + +include("cmake/HunterGate.cmake") +HunterGate( + URL "https://github.com/ruslo/hunter/archive/v0.23.171.tar.gz" + SHA1 "5d68bcca78eee347239ca5f4d34f4b6c12683154" +) + +project(libigl) + +# Detects whether this is a top-level project +get_directory_property(LIBIGL_PARENT_DIR PARENT_DIRECTORY) +if(NOT LIBIGL_PARENT_DIR) + set(LIBIGL_TOPLEVEL_PROJECT ON) +else() + set(LIBIGL_TOPLEVEL_PROJECT OFF) +endif() + +# Build tests and tutorials +option(LIBIGL_BUILD_TESTS "Build libigl unit test" ${LIBIGL_TOPLEVEL_PROJECT}) +option(LIBIGL_BUILD_TUTORIALS "Build libigl tutorial" ${LIBIGL_TOPLEVEL_PROJECT}) +option(LIBIGL_EXPORT_TARGETS "Export libigl CMake targets" ${LIBIGL_TOPLEVEL_PROJECT}) + +# USE_STATIC_LIBRARY speeds up the generation of multiple binaries, +# at the cost of a longer initial compilation time +# (by default, static build is off since libigl is a header-only library) +option(LIBIGL_USE_STATIC_LIBRARY "Use libigl as static library" ON) + +# All dependencies that are downloaded as cmake projects and tested on the auto-builds are ON +# (by default, all build options are off) +option(LIBIGL_WITH_COMISO "Use CoMiso" ON) +option(LIBIGL_WITH_EMBREE "Use Embree" ON) +option(LIBIGL_WITH_OPENGL "Use OpenGL" ON) +option(LIBIGL_WITH_OPENGL_GLFW "Use GLFW" ON) +option(LIBIGL_WITH_OPENGL_GLFW_IMGUI "Use ImGui" ON) +option(LIBIGL_WITH_PNG "Use PNG" ON) +option(LIBIGL_WITH_TETGEN "Use Tetgen" ON) +option(LIBIGL_WITH_TRIANGLE "Use Triangle" ON) +option(LIBIGL_WITH_PREDICATES "Use exact predicates" ON) +option(LIBIGL_WITH_XML "Use XML" ON) +option(LIBIGL_WITH_PYTHON "Use Python" OFF) +### End + +if(${LIBIGL_WITH_PYTHON}) + message(FATAL_ERROR "Python binding are in the process of being redone. Please use the master branch or refer to https://github.com/geometryprocessing/libigl-python-bindings for the developement version or https://anaconda.org/conda-forge/igl for the stable version.") +endif() + +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) + +### conditionally compile certain modules depending on libraries found on the system +list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/cmake) + +### Adding libIGL: choose the path to your local copy libIGL +include(libigl) + +if(LIBIGL_BUILD_TUTORIALS) + add_subdirectory(tutorial) +endif() + +if(LIBIGL_BUILD_TESTS) + include(CTest) + enable_testing() + add_subdirectory(tests) +endif() + +if(LIBIGL_TOPLEVEL_PROJECT) + # Set folders for Visual Studio/Xcode + igl_set_folders() +endif() diff --git a/src/external/libigl-2.3.0/LICENSE.GPL b/src/external/libigl-2.3.0/LICENSE.GPL new file mode 100644 index 000000000..94a9ed024 --- /dev/null +++ b/src/external/libigl-2.3.0/LICENSE.GPL @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/src/external/libigl-2.3.0/LICENSE.MPL2 b/src/external/libigl-2.3.0/LICENSE.MPL2 new file mode 100644 index 000000000..14e2f777f --- /dev/null +++ b/src/external/libigl-2.3.0/LICENSE.MPL2 @@ -0,0 +1,373 @@ +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. diff --git a/src/external/libigl-2.3.0/README.md b/src/external/libigl-2.3.0/README.md new file mode 100644 index 000000000..7f4188c9c --- /dev/null +++ b/src/external/libigl-2.3.0/README.md @@ -0,0 +1,8 @@ +# libigl - A simple C++ geometry processing library +[![](https://github.com/libigl/libigl/workflows/Build/badge.svg?event=push)](https://github.com/libigl/libigl/actions?query=workflow%3ABuild+branch%3Amaster+event%3Apush) +[![](https://github.com/libigl/libigl/workflows/Nightly/badge.svg)](https://github.com/libigl/libigl/actions?query=workflow%3ANightly+branch%3Amaster+event%3Aschedule) +[![](https://anaconda.org/conda-forge/igl/badges/installer/conda.svg)](https://anaconda.org/conda-forge/igl) + +![](https://libigl.github.io/libigl-teaser.png) + +Documentation, tutorial, and instructions at . diff --git a/src/external/libigl-2.3.0/cmake/CXXFeatures.cmake b/src/external/libigl-2.3.0/cmake/CXXFeatures.cmake new file mode 100644 index 000000000..8689d0ae0 --- /dev/null +++ b/src/external/libigl-2.3.0/cmake/CXXFeatures.cmake @@ -0,0 +1,85 @@ +################################################################################ + +if(NOT (${CMAKE_VERSION} VERSION_LESS "3.8.0")) + # For CMake 3.8 and above, we can use meta features directly provided by CMake itself + set(CXX11_FEATURES cxx_std_11) + set(CXX14_FEATURES cxx_std_14) + set(CXX17_FEATURES cxx_std_17) + return() +endif() + +################################################################################ + +set(CXX11_FEATURES + cxx_auto_type + cxx_constexpr +) + +set(CXX14_FEATURES + cxx_generic_lambdas +) + +set(CXX17_FEATURES + +) + +################################################################################ + +# https://cmake.org/cmake/help/v3.1/prop_gbl/CMAKE_CXX_KNOWN_FEATURES.html +# cxx_aggregate_default_initializers Aggregate default initializers, as defined in N3605. +# cxx_alias_templates Template aliases, as defined in N2258. +# cxx_alignas Alignment control alignas, as defined in N2341. +# cxx_alignof Alignment control alignof, as defined in N2341. +# cxx_attributes Generic attributes, as defined in N2761. +# cxx_attribute_deprecated deprecated]] attribute, as defined in N3760. +# cxx_auto_type Automatic type deduction, as defined in N1984. +# cxx_binary_literals Binary literals, as defined in N3472. +# cxx_constexpr Constant expressions, as defined in N2235. +# cxx_contextual_conversions Contextual conversions, as defined in N3323. +# cxx_decltype_incomplete_return_types Decltype on incomplete return types, as defined in N3276. +# cxx_decltype Decltype, as defined in N2343. +# cxx_decltype_auto decltype(auto) semantics, as defined in N3638. +# cxx_default_function_template_args Default template arguments for function templates, as defined in DR226 +# cxx_defaulted_functions Defaulted functions, as defined in N2346. +# cxx_defaulted_move_initializers Defaulted move initializers, as defined in N3053. +# cxx_delegating_constructors Delegating constructors, as defined in N1986. +# cxx_deleted_functions Deleted functions, as defined in N2346. +# cxx_digit_separators Digit separators, as defined in N3781. +# cxx_enum_forward_declarations Enum forward declarations, as defined in N2764. +# cxx_explicit_conversions Explicit conversion operators, as defined in N2437. +# cxx_extended_friend_declarations Extended friend declarations, as defined in N1791. +# cxx_extern_templates Extern templates, as defined in N1987. +# cxx_final Override control final keyword, as defined in N2928, N3206 and N3272. +# cxx_func_identifier Predefined __func__ identifier, as defined in N2340. +# cxx_generalized_initializers Initializer lists, as defined in N2672. +# cxx_generic_lambdas Generic lambdas, as defined in N3649. +# cxx_inheriting_constructors Inheriting constructors, as defined in N2540. +# cxx_inline_namespaces Inline namespaces, as defined in N2535. +# cxx_lambdas Lambda functions, as defined in N2927. +# cxx_lambda_init_captures Initialized lambda captures, as defined in N3648. +# cxx_local_type_template_args Local and unnamed types as template arguments, as defined in N2657. +# cxx_long_long_type long long type, as defined in N1811. +# cxx_noexcept Exception specifications, as defined in N3050. +# cxx_nonstatic_member_init Non-static data member initialization, as defined in N2756. +# cxx_nullptr Null pointer, as defined in N2431. +# cxx_override Override control override keyword, as defined in N2928, N3206 and N3272. +# cxx_range_for Range-based for, as defined in N2930. +# cxx_raw_string_literals Raw string literals, as defined in N2442. +# cxx_reference_qualified_functions Reference qualified functions, as defined in N2439. +# cxx_relaxed_constexpr Relaxed constexpr, as defined in N3652. +# cxx_return_type_deduction Return type deduction on normal functions, as defined in N3386. +# cxx_right_angle_brackets Right angle bracket parsing, as defined in N1757. +# cxx_rvalue_references R-value references, as defined in N2118. +# cxx_sizeof_member Size of non-static data members, as defined in N2253. +# cxx_static_assert Static assert, as defined in N1720. +# cxx_strong_enums Strongly typed enums, as defined in N2347. +# cxx_thread_local Thread-local variables, as defined in N2659. +# cxx_trailing_return_types Automatic function return type, as defined in N2541. +# cxx_unicode_literals Unicode string literals, as defined in N2442. +# cxx_uniform_initialization Uniform initialization, as defined in N2640. +# cxx_unrestricted_unions Unrestricted unions, as defined in N2544. +# cxx_user_literals User-defined literals, as defined in N2765. +# cxx_variable_templates Variable templates, as defined in N3651. +# cxx_variadic_macros Variadic macros, as defined in N1653. +# cxx_variadic_templates Variadic templates, as defined in N2242. +# cxx_template_template_parameters Template template parameters, as defined in ISO/IEC 14882:1998. diff --git a/src/external/libigl-2.3.0/cmake/DownloadProject.CMakeLists.cmake.in b/src/external/libigl-2.3.0/cmake/DownloadProject.CMakeLists.cmake.in new file mode 100644 index 000000000..6ab486145 --- /dev/null +++ b/src/external/libigl-2.3.0/cmake/DownloadProject.CMakeLists.cmake.in @@ -0,0 +1,17 @@ +# Distributed under the OSI-approved MIT License. See accompanying +# file LICENSE or https://github.com/Crascit/DownloadProject for details. + +cmake_minimum_required(VERSION 3.1) + +project(${DL_ARGS_PROJ}-download NONE) + +include(ExternalProject) +ExternalProject_Add(${DL_ARGS_PROJ}-download + ${DL_ARGS_UNPARSED_ARGUMENTS} + SOURCE_DIR "${DL_ARGS_SOURCE_DIR}" + BINARY_DIR "${DL_ARGS_BINARY_DIR}" + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + INSTALL_COMMAND "" + TEST_COMMAND "" +) diff --git a/src/external/libigl-2.3.0/cmake/DownloadProject.cmake b/src/external/libigl-2.3.0/cmake/DownloadProject.cmake new file mode 100644 index 000000000..e300f4265 --- /dev/null +++ b/src/external/libigl-2.3.0/cmake/DownloadProject.cmake @@ -0,0 +1,182 @@ +# Distributed under the OSI-approved MIT License. See accompanying +# file LICENSE or https://github.com/Crascit/DownloadProject for details. +# +# MODULE: DownloadProject +# +# PROVIDES: +# download_project( PROJ projectName +# [PREFIX prefixDir] +# [DOWNLOAD_DIR downloadDir] +# [SOURCE_DIR srcDir] +# [BINARY_DIR binDir] +# [QUIET] +# ... +# ) +# +# Provides the ability to download and unpack a tarball, zip file, git repository, +# etc. at configure time (i.e. when the cmake command is run). How the downloaded +# and unpacked contents are used is up to the caller, but the motivating case is +# to download source code which can then be included directly in the build with +# add_subdirectory() after the call to download_project(). Source and build +# directories are set up with this in mind. +# +# The PROJ argument is required. The projectName value will be used to construct +# the following variables upon exit (obviously replace projectName with its actual +# value): +# +# projectName_SOURCE_DIR +# projectName_BINARY_DIR +# +# The SOURCE_DIR and BINARY_DIR arguments are optional and would not typically +# need to be provided. They can be specified if you want the downloaded source +# and build directories to be located in a specific place. The contents of +# projectName_SOURCE_DIR and projectName_BINARY_DIR will be populated with the +# locations used whether you provide SOURCE_DIR/BINARY_DIR or not. +# +# The DOWNLOAD_DIR argument does not normally need to be set. It controls the +# location of the temporary CMake build used to perform the download. +# +# The PREFIX argument can be provided to change the base location of the default +# values of DOWNLOAD_DIR, SOURCE_DIR and BINARY_DIR. If all of those three arguments +# are provided, then PREFIX will have no effect. The default value for PREFIX is +# CMAKE_BINARY_DIR. +# +# The QUIET option can be given if you do not want to show the output associated +# with downloading the specified project. +# +# In addition to the above, any other options are passed through unmodified to +# ExternalProject_Add() to perform the actual download, patch and update steps. +# The following ExternalProject_Add() options are explicitly prohibited (they +# are reserved for use by the download_project() command): +# +# CONFIGURE_COMMAND +# BUILD_COMMAND +# INSTALL_COMMAND +# TEST_COMMAND +# +# Only those ExternalProject_Add() arguments which relate to downloading, patching +# and updating of the project sources are intended to be used. Also note that at +# least one set of download-related arguments are required. +# +# If using CMake 3.2 or later, the UPDATE_DISCONNECTED option can be used to +# prevent a check at the remote end for changes every time CMake is run +# after the first successful download. See the documentation of the ExternalProject +# module for more information. It is likely you will want to use this option if it +# is available to you. Note, however, that the ExternalProject implementation contains +# bugs which result in incorrect handling of the UPDATE_DISCONNECTED option when +# using the URL download method or when specifying a SOURCE_DIR with no download +# method. Fixes for these have been created, the last of which is scheduled for +# inclusion in CMake 3.8.0. Details can be found here: +# +# https://gitlab.kitware.com/cmake/cmake/commit/bdca68388bd57f8302d3c1d83d691034b7ffa70c +# https://gitlab.kitware.com/cmake/cmake/issues/16428 +# +# If you experience build errors related to the update step, consider avoiding +# the use of UPDATE_DISCONNECTED. +# +# EXAMPLE USAGE: +# +# include(DownloadProject) +# download_project(PROJ googletest +# GIT_REPOSITORY https://github.com/google/googletest.git +# GIT_TAG master +# UPDATE_DISCONNECTED 1 +# QUIET +# ) +# +# add_subdirectory(${googletest_SOURCE_DIR} ${googletest_BINARY_DIR}) +# +#======================================================================================== + + +set(_DownloadProjectDir "${CMAKE_CURRENT_LIST_DIR}") + +include(CMakeParseArguments) + +function(download_project) + + set(options QUIET) + set(oneValueArgs + PROJ + PREFIX + DOWNLOAD_DIR + SOURCE_DIR + BINARY_DIR + # Prevent the following from being passed through + CONFIGURE_COMMAND + BUILD_COMMAND + INSTALL_COMMAND + TEST_COMMAND + ) + set(multiValueArgs "") + + cmake_parse_arguments(DL_ARGS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + # Hide output if requested + if (DL_ARGS_QUIET) + set(OUTPUT_QUIET "OUTPUT_QUIET") + else() + unset(OUTPUT_QUIET) + message(STATUS "Downloading/updating ${DL_ARGS_PROJ}") + endif() + + # Set up where we will put our temporary CMakeLists.txt file and also + # the base point below which the default source and binary dirs will be. + # The prefix must always be an absolute path. + if (NOT DL_ARGS_PREFIX) + set(DL_ARGS_PREFIX "${CMAKE_BINARY_DIR}") + else() + get_filename_component(DL_ARGS_PREFIX "${DL_ARGS_PREFIX}" ABSOLUTE + BASE_DIR "${CMAKE_CURRENT_BINARY_DIR}") + endif() + if (NOT DL_ARGS_DOWNLOAD_DIR) + set(DL_ARGS_DOWNLOAD_DIR "${DL_ARGS_PREFIX}/${DL_ARGS_PROJ}-download") + endif() + + # Ensure the caller can know where to find the source and build directories + if (NOT DL_ARGS_SOURCE_DIR) + set(DL_ARGS_SOURCE_DIR "${DL_ARGS_PREFIX}/${DL_ARGS_PROJ}-src") + endif() + if (NOT DL_ARGS_BINARY_DIR) + set(DL_ARGS_BINARY_DIR "${DL_ARGS_PREFIX}/${DL_ARGS_PROJ}-build") + endif() + set(${DL_ARGS_PROJ}_SOURCE_DIR "${DL_ARGS_SOURCE_DIR}" PARENT_SCOPE) + set(${DL_ARGS_PROJ}_BINARY_DIR "${DL_ARGS_BINARY_DIR}" PARENT_SCOPE) + + # The way that CLion manages multiple configurations, it causes a copy of + # the CMakeCache.txt to be copied across due to it not expecting there to + # be a project within a project. This causes the hard-coded paths in the + # cache to be copied and builds to fail. To mitigate this, we simply + # remove the cache if it exists before we configure the new project. It + # is safe to do so because it will be re-generated. Since this is only + # executed at the configure step, it should not cause additional builds or + # downloads. + file(REMOVE "${DL_ARGS_DOWNLOAD_DIR}/CMakeCache.txt") + + # Create and build a separate CMake project to carry out the download. + # If we've already previously done these steps, they will not cause + # anything to be updated, so extra rebuilds of the project won't occur. + # Make sure to pass through CMAKE_MAKE_PROGRAM in case the main project + # has this set to something not findable on the PATH. + configure_file("${_DownloadProjectDir}/DownloadProject.CMakeLists.cmake.in" + "${DL_ARGS_DOWNLOAD_DIR}/CMakeLists.txt") + execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" + -D "CMAKE_MAKE_PROGRAM:FILE=${CMAKE_MAKE_PROGRAM}" + . + RESULT_VARIABLE result + ${OUTPUT_QUIET} + WORKING_DIRECTORY "${DL_ARGS_DOWNLOAD_DIR}" + ) + if(result) + message(FATAL_ERROR "CMake step for ${DL_ARGS_PROJ} failed: ${result}") + endif() + execute_process(COMMAND ${CMAKE_COMMAND} --build . + RESULT_VARIABLE result + ${OUTPUT_QUIET} + WORKING_DIRECTORY "${DL_ARGS_DOWNLOAD_DIR}" + ) + if(result) + message(FATAL_ERROR "Build step for ${DL_ARGS_PROJ} failed: ${result}") + endif() + +endfunction() diff --git a/src/external/libigl-2.3.0/cmake/FindCORK.cmake b/src/external/libigl-2.3.0/cmake/FindCORK.cmake new file mode 100644 index 000000000..5faee49df --- /dev/null +++ b/src/external/libigl-2.3.0/cmake/FindCORK.cmake @@ -0,0 +1,52 @@ +# +# Try to find CORK library and include path. +# Once done this will define +# +# CORK_FOUND +# CORK_INCLUDE_DIR +# CORK_LIBRARIES +# + +if(NOT CORK_FOUND) + +FIND_PATH(CORK_INCLUDE_DIR cork.h + PATHS + ${PROJECT_SOURCE_DIR}/../../external/cork/include + ${PROJECT_SOURCE_DIR}/../external/cork/include + ${PROJECT_SOURCE_DIR}/external/cork/include + /usr/local/include + /usr/X11/include + /usr/include + /opt/local/include + NO_DEFAULT_PATH + ) + +FIND_LIBRARY( CORK_LIBRARIES NAMES cork + PATHS + ${PROJECT_SOURCE_DIR}/../../external/cork/lib/ + ${PROJECT_SOURCE_DIR}/../external/cork/lib/ + ${PROJECT_SOURCE_DIR}/external/cork/lib/ + /usr/local + /usr/X11 + /usr + PATH_SUFFIXES + a + lib64 + lib + NO_DEFAULT_PATH +) + +SET(CORK_FOUND "NO") +IF (CORK_INCLUDE_DIR AND CORK_LIBRARIES) + SET(CORK_FOUND "YES") +ENDIF (CORK_INCLUDE_DIR AND CORK_LIBRARIES) + +if(CORK_FOUND) + message(STATUS "Found CORK: ${CORK_INCLUDE_DIR}") +else(CORK_FOUND) + if (NOT CORK_FIND_QUIETLY) + message(FATAL_ERROR "could NOT find CORK") + endif (NOT CORK_FIND_QUIETLY) +endif(CORK_FOUND) + +endif(NOT CORK_FOUND) diff --git a/src/external/libigl-2.3.0/cmake/FindMATLAB.cmake b/src/external/libigl-2.3.0/cmake/FindMATLAB.cmake new file mode 100644 index 000000000..7ba98b3c3 --- /dev/null +++ b/src/external/libigl-2.3.0/cmake/FindMATLAB.cmake @@ -0,0 +1,1547 @@ +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file Copyright.txt or https://cmake.org/licensing for details. + +#.rst: +# FindMatlab +# ---------- +# +# Finds Matlab installations and provides Matlab tools and libraries to cmake. +# +# This package first intention is to find the libraries associated with Matlab +# in order to be able to build Matlab extensions (mex files). It can also be +# used: +# +# * run specific commands in Matlab +# * declare Matlab unit test +# * retrieve various information from Matlab (mex extensions, versions and +# release queries, ...) +# +# The module supports the following components: +# +# * ``MX_LIBRARY``, ``ENG_LIBRARY`` and ``MAT_LIBRARY``: respectively the MX, +# ENG and MAT libraries of Matlab +# * ``MAIN_PROGRAM`` the Matlab binary program. +# * ``MEX_COMPILER`` the MEX compiler. +# * ``SIMULINK`` the Simulink environment. +# +# .. note:: +# +# The version given to the :command:`find_package` directive is the Matlab +# **version**, which should not be confused with the Matlab *release* name +# (eg. `R2014`). +# The :command:`matlab_get_version_from_release_name` and +# :command:`matlab_get_release_name_from_version` allow a mapping +# from the release name to the version. +# +# The variable :variable:`Matlab_ROOT_DIR` may be specified in order to give +# the path of the desired Matlab version. Otherwise, the behaviour is platform +# specific: +# +# * Windows: The installed versions of Matlab are retrieved from the +# Windows registry +# * OS X: The installed versions of Matlab are given by the MATLAB +# paths in ``/Application``. If no such application is found, it falls back +# to the one that might be accessible from the PATH. +# * Unix: The desired Matlab should be accessible from the PATH. +# +# Additional information is provided when :variable:`MATLAB_FIND_DEBUG` is set. +# When a Matlab binary is found automatically and the ``MATLAB_VERSION`` +# is not given, the version is queried from Matlab directly. +# On Windows, it can make a window running Matlab appear. +# +# The mapping of the release names and the version of Matlab is performed by +# defining pairs (name, version). The variable +# :variable:`MATLAB_ADDITIONAL_VERSIONS` may be provided before the call to +# the :command:`find_package` in order to handle additional versions. +# +# A Matlab scripts can be added to the set of tests using the +# :command:`matlab_add_unit_test`. By default, the Matlab unit test framework +# will be used (>= 2013a) to run this script, but regular ``.m`` files +# returning an exit code can be used as well (0 indicating a success). +# +# Module Input Variables +# ^^^^^^^^^^^^^^^^^^^^^^ +# +# Users or projects may set the following variables to configure the module +# behaviour: +# +# :variable:`Matlab_ROOT_DIR` +# the root of the Matlab installation. +# :variable:`MATLAB_FIND_DEBUG` +# outputs debug information +# :variable:`MATLAB_ADDITIONAL_VERSIONS` +# additional versions of Matlab for the automatic retrieval of the installed +# versions. +# +# Variables defined by the module +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# +# Result variables +# """""""""""""""" +# +# ``Matlab_FOUND`` +# ``TRUE`` if the Matlab installation is found, ``FALSE`` +# otherwise. All variable below are defined if Matlab is found. +# ``Matlab_ROOT_DIR`` +# the final root of the Matlab installation determined by the FindMatlab +# module. +# ``Matlab_MAIN_PROGRAM`` +# the Matlab binary program. Available only if the component ``MAIN_PROGRAM`` +# is given in the :command:`find_package` directive. +# ``Matlab_INCLUDE_DIRS`` +# the path of the Matlab libraries headers +# ``Matlab_MEX_LIBRARY`` +# library for mex, always available. +# ``Matlab_MX_LIBRARY`` +# mx library of Matlab (arrays). Available only if the component +# ``MX_LIBRARY`` has been requested. +# ``Matlab_ENG_LIBRARY`` +# Matlab engine library. Available only if the component ``ENG_LIBRARY`` +# is requested. +# ``Matlab_MAT_LIBRARY`` +# Matlab matrix library. Available only if the component ``MAT_LIBRARY`` +# is requested. +# ``Matlab_LIBRARIES`` +# the whole set of libraries of Matlab +# ``Matlab_MEX_COMPILER`` +# the mex compiler of Matlab. Currently not used. +# Available only if the component ``MEX_COMPILER`` is asked +# +# Cached variables +# """""""""""""""" +# +# ``Matlab_MEX_EXTENSION`` +# the extension of the mex files for the current platform (given by Matlab). +# ``Matlab_ROOT_DIR`` +# the location of the root of the Matlab installation found. If this value +# is changed by the user, the result variables are recomputed. +# +# Provided macros +# ^^^^^^^^^^^^^^^ +# +# :command:`matlab_get_version_from_release_name` +# returns the version from the release name +# :command:`matlab_get_release_name_from_version` +# returns the release name from the Matlab version +# +# Provided functions +# ^^^^^^^^^^^^^^^^^^ +# +# :command:`matlab_add_mex` +# adds a target compiling a MEX file. +# :command:`matlab_add_unit_test` +# adds a Matlab unit test file as a test to the project. +# :command:`matlab_extract_all_installed_versions_from_registry` +# parses the registry for all Matlab versions. Available on Windows only. +# The part of the registry parsed is dependent on the host processor +# :command:`matlab_get_all_valid_matlab_roots_from_registry` +# returns all the possible Matlab paths, according to a previously +# given list. Only the existing/accessible paths are kept. This is mainly +# useful for the searching all possible Matlab installation. +# :command:`matlab_get_mex_suffix` +# returns the suffix to be used for the mex files +# (platform/architecture dependent) +# :command:`matlab_get_version_from_matlab_run` +# returns the version of Matlab, given the full directory of the Matlab +# program. +# +# +# Known issues +# ^^^^^^^^^^^^ +# +# **Symbol clash in a MEX target** +# By default, every symbols inside a MEX +# file defined with the command :command:`matlab_add_mex` have hidden +# visibility, except for the entry point. This is the default behaviour of +# the MEX compiler, which lowers the risk of symbol collision between the +# libraries shipped with Matlab, and the libraries to which the MEX file is +# linking to. This is also the default on Windows platforms. +# +# However, this is not sufficient in certain case, where for instance your +# MEX file is linking against libraries that are already loaded by Matlab, +# even if those libraries have different SONAMES. +# A possible solution is to hide the symbols of the libraries to which the +# MEX target is linking to. This can be achieved in GNU GCC compilers with +# the linker option ``-Wl,--exclude-libs,ALL``. +# +# **Tests using GPU resources** +# in case your MEX file is using the GPU and +# in order to be able to run unit tests on this MEX file, the GPU resources +# should be properly released by Matlab. A possible solution is to make +# Matlab aware of the use of the GPU resources in the session, which can be +# performed by a command such as ``D = gpuDevice()`` at the beginning of +# the test script (or via a fixture). +# +# +# Reference +# ^^^^^^^^^ +# +# .. variable:: Matlab_ROOT_DIR +# +# The root folder of the Matlab installation. If set before the call to +# :command:`find_package`, the module will look for the components in that +# path. If not set, then an automatic search of Matlab +# will be performed. If set, it should point to a valid version of Matlab. +# +# .. variable:: MATLAB_FIND_DEBUG +# +# If set, the lookup of Matlab and the intermediate configuration steps are +# outputted to the console. +# +# .. variable:: MATLAB_ADDITIONAL_VERSIONS +# +# If set, specifies additional versions of Matlab that may be looked for. +# The variable should be a list of strings, organised by pairs of release +# name and versions, such as follows:: +# +# set(MATLAB_ADDITIONAL_VERSIONS +# "release_name1=corresponding_version1" +# "release_name2=corresponding_version2" +# ... +# ) +# +# Example:: +# +# set(MATLAB_ADDITIONAL_VERSIONS +# "R2013b=8.2" +# "R2013a=8.1" +# "R2012b=8.0") +# +# The order of entries in this list matters when several versions of +# Matlab are installed. The priority is set according to the ordering in +# this list. + +set(_FindMatlab_SELF_DIR "${CMAKE_CURRENT_LIST_DIR}") + +include(FindPackageHandleStandardArgs) +include(CheckCXXCompilerFlag) +include(CheckCCompilerFlag) + + +# The currently supported versions. Other version can be added by the user by +# providing MATLAB_ADDITIONAL_VERSIONS +if(NOT MATLAB_ADDITIONAL_VERSIONS) + set(MATLAB_ADDITIONAL_VERSIONS) +endif() + +# Is this mapping necessary? It's always causing trouble to need to bump these +# for each new version. +set(MATLAB_VERSIONS_MAPPING + "R2020b=9.9" + "R2020a=9.8" + "R2019b=9.7" + "R2019a=9.6" + "R2018b=9.5" + "R2018a=9.4" + "R2017b=9.3" + "R2017a=9.2" + "R2016b=9.1" + "R2016a=9.0" + "R2015b=8.6" + "R2015a=8.5" + "R2014b=8.4" + "R2014a=8.3" + "R2013b=8.2" + "R2013a=8.1" + "R2012b=8.0" + "R2012a=7.14" + "R2011b=7.13" + "R2011a=7.12" + "R2010b=7.11" + + ${MATLAB_ADDITIONAL_VERSIONS} + ) + + +# temporary folder for all Matlab runs +set(_matlab_temporary_folder ${CMAKE_BINARY_DIR}/Matlab) + +if(NOT EXISTS "${_matlab_temporary_folder}") + file(MAKE_DIRECTORY "${_matlab_temporary_folder}") +endif() + +#.rst: +# .. command:: matlab_get_version_from_release_name +# +# Returns the version of Matlab (17.58) from a release name (R2017k) +macro (matlab_get_version_from_release_name release_name version_name) + + string(REGEX MATCHALL "${release_name}=([0-9]+\\.?[0-9]*)" _matched ${MATLAB_VERSIONS_MAPPING}) + + set(${version_name} "") + if(NOT _matched STREQUAL "") + set(${version_name} ${CMAKE_MATCH_1}) + else() + message(WARNING "The release name ${release_name} is not registered") + endif() + unset(_matched) + +endmacro() + + + + + +#.rst: +# .. command:: matlab_get_release_name_from_version +# +# Returns the release name (R2017k) from the version of Matlab (17.58) +macro (matlab_get_release_name_from_version version release_name) + + set(${release_name} "") + foreach(_var IN LISTS MATLAB_VERSIONS_MAPPING) + string(REGEX MATCHALL "(.+)=${version}" _matched ${_var}) + if(NOT _matched STREQUAL "") + set(${release_name} ${CMAKE_MATCH_1}) + break() + endif() + endforeach(_var) + + unset(_var) + unset(_matched) + if(${release_name} STREQUAL "") + message(WARNING "The version ${version} is not registered") + endif() + +endmacro() + + + + + +# extracts all the supported release names (R2017k...) of Matlab +# internal use +macro(matlab_get_supported_releases list_releases) + set(${list_releases}) + foreach(_var IN LISTS MATLAB_VERSIONS_MAPPING) + string(REGEX MATCHALL "(.+)=([0-9]+\\.?[0-9]*)" _matched ${_var}) + if(NOT _matched STREQUAL "") + list(APPEND ${list_releases} ${CMAKE_MATCH_1}) + endif() + unset(_matched) + unset(CMAKE_MATCH_1) + endforeach(_var) + unset(_var) +endmacro() + + + +# extracts all the supported versions of Matlab +# internal use +macro(matlab_get_supported_versions list_versions) + set(${list_versions}) + foreach(_var IN LISTS MATLAB_VERSIONS_MAPPING) + string(REGEX MATCHALL "(.+)=([0-9]+\\.?[0-9]*)" _matched ${_var}) + if(NOT _matched STREQUAL "") + list(APPEND ${list_versions} ${CMAKE_MATCH_2}) + endif() + unset(_matched) + unset(CMAKE_MATCH_1) + endforeach(_var) + unset(_var) +endmacro() + + +#.rst: +# .. command:: matlab_extract_all_installed_versions_from_registry +# +# This function parses the registry and founds the Matlab versions that are +# installed. The found versions are returned in `matlab_versions`. +# Set `win64` to `TRUE` if the 64 bit version of Matlab should be looked for +# The returned list contains all versions under +# ``HKLM\\SOFTWARE\\Mathworks\\MATLAB`` or an empty list in case an error +# occurred (or nothing found). +# +# .. note:: +# +# Only the versions are provided. No check is made over the existence of the +# installation referenced in the registry, +# +function(matlab_extract_all_installed_versions_from_registry win64 matlab_versions) + + if(NOT CMAKE_HOST_WIN32) + message(FATAL_ERROR "This macro can only be called by a windows host (call to reg.exe") + endif() + + + if(${win64} AND ${CMAKE_HOST_SYSTEM_PROCESSOR} MATCHES "64") + set(APPEND_REG "/reg:64") + else() + set(APPEND_REG "/reg:32") + endif() + + # /reg:64 should be added on 64 bits capable OSs in order to enable the + # redirection of 64 bits applications + execute_process( + COMMAND reg query HKEY_LOCAL_MACHINE\\SOFTWARE\\Mathworks\\MATLAB /f * /k ${APPEND_REG} + RESULT_VARIABLE resultMatlab + OUTPUT_VARIABLE varMatlab + ERROR_VARIABLE errMatlab + INPUT_FILE NUL + ) + + + set(matlabs_from_registry) + if(${resultMatlab} EQUAL 0) + + string( + REGEX MATCHALL "MATLAB\\\\([0-9]+(\\.[0-9]+)?)" + matlab_versions_regex ${varMatlab}) + + foreach(match IN LISTS matlab_versions_regex) + string( + REGEX MATCH "MATLAB\\\\(([0-9]+)(\\.([0-9]+))?)" + current_match ${match}) + + set(_matlab_current_version ${CMAKE_MATCH_1}) + set(current_matlab_version_major ${CMAKE_MATCH_2}) + set(current_matlab_version_minor ${CMAKE_MATCH_4}) + if(NOT current_matlab_version_minor) + set(current_matlab_version_minor "0") + endif() + + list(APPEND matlabs_from_registry ${_matlab_current_version}) + unset(_matlab_current_version) + endforeach(match) + + endif() + + if(matlabs_from_registry) + list(REMOVE_DUPLICATES matlabs_from_registry) + list(SORT matlabs_from_registry) + list(REVERSE matlabs_from_registry) + endif() + + set(${matlab_versions} ${matlabs_from_registry} PARENT_SCOPE) + +endfunction() + + + +# (internal) +macro(extract_matlab_versions_from_registry_brute_force matlab_versions) + # get the supported versions + set(matlab_supported_versions) + matlab_get_supported_versions(matlab_supported_versions) + + + # this is a manual population of the versions we want to look for + # this can be done as is, but preferably with the call to + # matlab_get_supported_versions and variable + + # populating the versions we want to look for + # set(matlab_supported_versions) + + # # Matlab 7 + # set(matlab_major 7) + # foreach(current_matlab_minor RANGE 4 20) + # list(APPEND matlab_supported_versions "${matlab_major}.${current_matlab_minor}") + # endforeach(current_matlab_minor) + + # # Matlab 8 + # set(matlab_major 8) + # foreach(current_matlab_minor RANGE 0 5) + # list(APPEND matlab_supported_versions "${matlab_major}.${current_matlab_minor}") + # endforeach(current_matlab_minor) + + # # taking into account the possible additional versions provided by the user + # if(DEFINED MATLAB_ADDITIONAL_VERSIONS) + # list(APPEND matlab_supported_versions MATLAB_ADDITIONAL_VERSIONS) + # endif() + + + # we order from more recent to older + if(matlab_supported_versions) + list(REMOVE_DUPLICATES matlab_supported_versions) + list(SORT matlab_supported_versions) + list(REVERSE matlab_supported_versions) + endif() + + + set(${matlab_versions} ${matlab_supported_versions}) + + +endmacro() + + + + +#.rst: +# .. command:: matlab_get_all_valid_matlab_roots_from_registry +# +# Populates the Matlab root with valid versions of Matlab. +# The returned matlab_roots is organized in pairs +# ``(version_number,matlab_root_path)``. +# +# :: +# +# matlab_get_all_valid_matlab_roots_from_registry( +# matlab_versions +# matlab_roots) +# +# ``matlab_versions`` +# the versions of each of the Matlab installations +# ``matlab_roots`` +# the location of each of the Matlab installations +function(matlab_get_all_valid_matlab_roots_from_registry matlab_versions matlab_roots) + + # The matlab_versions comes either from + # extract_matlab_versions_from_registry_brute_force or + # matlab_extract_all_installed_versions_from_registry. + + + set(_matlab_roots_list ) + foreach(_matlab_current_version ${matlab_versions}) + get_filename_component( + current_MATLAB_ROOT + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MathWorks\\MATLAB\\${_matlab_current_version};MATLABROOT]" + ABSOLUTE) + + if(EXISTS ${current_MATLAB_ROOT}) + list(APPEND _matlab_roots_list ${_matlab_current_version} ${current_MATLAB_ROOT}) + endif() + + endforeach(_matlab_current_version) + unset(_matlab_current_version) + set(${matlab_roots} ${_matlab_roots_list} PARENT_SCOPE) + unset(_matlab_roots_list) +endfunction() + +#.rst: +# .. command:: matlab_get_mex_suffix +# +# Returns the extension of the mex files (the suffixes). +# This function should not be called before the appropriate Matlab root has +# been found. +# +# :: +# +# matlab_get_mex_suffix( +# matlab_root +# mex_suffix) +# +# ``matlab_root`` +# the root of the Matlab installation +# ``mex_suffix`` +# the variable name in which the suffix will be returned. +function(matlab_get_mex_suffix matlab_root mex_suffix) + + # todo setup the extension properly. Currently I do not know if this is + # sufficient for all win32 distributions. + # there is also CMAKE_EXECUTABLE_SUFFIX that could be tweaked + set(mexext_suffix "") + if(WIN32) + list(APPEND mexext_suffix ".bat") + endif() + + # we first try without suffix, since cmake does not understand a list with + # one empty string element + find_program( + Matlab_MEXEXTENSIONS_PROG + NAMES mexext + PATHS ${matlab_root}/bin + DOC "Matlab MEX extension provider" + NO_DEFAULT_PATH + ) + + foreach(current_mexext_suffix IN LISTS mexext_suffix) + if(NOT DEFINED Matlab_MEXEXTENSIONS_PROG OR NOT Matlab_MEXEXTENSIONS_PROG) + # this call should populate the cache automatically + find_program( + Matlab_MEXEXTENSIONS_PROG + "mexext${current_mexext_suffix}" + PATHS ${matlab_root}/bin + DOC "Matlab MEX extension provider" + NO_DEFAULT_PATH + ) + endif() + endforeach(current_mexext_suffix) + + + # the program has been found? + if((NOT Matlab_MEXEXTENSIONS_PROG) OR (NOT EXISTS ${Matlab_MEXEXTENSIONS_PROG})) + if(MATLAB_FIND_DEBUG) + message(WARNING "[MATLAB] Cannot found mexext program. Matlab root is ${matlab_root}") + endif() + unset(Matlab_MEXEXTENSIONS_PROG CACHE) + return() + endif() + + set(_matlab_mex_extension) + + set(devnull) + if(UNIX) + set(devnull INPUT_FILE /dev/null) + elseif(WIN32) + set(devnull INPUT_FILE NUL) + endif() + + execute_process( + COMMAND ${Matlab_MEXEXTENSIONS_PROG} + OUTPUT_VARIABLE _matlab_mex_extension + ERROR_VARIABLE _matlab_mex_extension_error + ${devnull}) + string(STRIP ${_matlab_mex_extension} _matlab_mex_extension) + + unset(Matlab_MEXEXTENSIONS_PROG CACHE) + set(${mex_suffix} ${_matlab_mex_extension} PARENT_SCOPE) +endfunction() + + + + +#.rst: +# .. command:: matlab_get_version_from_matlab_run +# +# This function runs Matlab program specified on arguments and extracts its +# version. +# +# :: +# +# matlab_get_version_from_matlab_run( +# matlab_binary_path +# matlab_list_versions) +# +# ``matlab_binary_path`` +# the location of the `matlab` binary executable +# ``matlab_list_versions`` +# the version extracted from Matlab +function(matlab_get_version_from_matlab_run matlab_binary_program matlab_list_versions) + + set(${matlab_list_versions} "" PARENT_SCOPE) + + + if(MATLAB_FIND_DEBUG) + message(STATUS "[MATLAB] Determining the version of Matlab from ${matlab_binary_program}") + endif() + + if(EXISTS "${_matlab_temporary_folder}/matlabVersionLog.cmaketmp") + if(MATLAB_FIND_DEBUG) + message(STATUS "[MATLAB] Removing previous ${_matlab_temporary_folder}/matlabVersionLog.cmaketmp file") + endif() + file(REMOVE "${_matlab_temporary_folder}/matlabVersionLog.cmaketmp") + endif() + + + # the log file is needed since on windows the command executes in a new + # window and it is not possible to get back the answer of Matlab + # the -wait command is needed on windows, otherwise the call returns + # immediately after the program launches itself. + if(WIN32) + set(_matlab_additional_commands "-wait") + endif() + + set(devnull) + if(UNIX) + set(devnull INPUT_FILE /dev/null) + elseif(WIN32) + set(devnull INPUT_FILE NUL) + endif() + + # timeout set to 120 seconds, in case it does not start + # note as said before OUTPUT_VARIABLE cannot be used in a platform + # independent manner however, not setting it would flush the output of Matlab + # in the current console (unix variant) + execute_process( + COMMAND "${matlab_binary_program}" -nosplash -nojvm ${_matlab_additional_commands} -logfile "matlabVersionLog.cmaketmp" -nodesktop -nodisplay -r "version, exit" + OUTPUT_VARIABLE _matlab_version_from_cmd_dummy + RESULT_VARIABLE _matlab_result_version_call + ERROR_VARIABLE _matlab_result_version_call_error + TIMEOUT 120 + WORKING_DIRECTORY "${_matlab_temporary_folder}" + ${devnull} + ) + + if("${_matlab_result_version_call}" MATCHES "timeout") + if(MATLAB_FIND_DEBUG) + message(WARNING "[MATLAB] Unable to determine the version of Matlab." + " Matlab call timed out after 120 seconds.") + endif() + return() + endif() + + if(${_matlab_result_version_call}) + if(MATLAB_FIND_DEBUG) + message(WARNING "[MATLAB] Unable to determine the version of Matlab. Matlab call returned with error ${_matlab_result_version_call}.") + endif() + return() + elseif(NOT EXISTS "${_matlab_temporary_folder}/matlabVersionLog.cmaketmp") + if(MATLAB_FIND_DEBUG) + message(WARNING "[MATLAB] Unable to determine the version of Matlab. The log file does not exist.") + endif() + return() + endif() + + # if successful, read back the log + file(READ "${_matlab_temporary_folder}/matlabVersionLog.cmaketmp" _matlab_version_from_cmd) + file(REMOVE "${_matlab_temporary_folder}/matlabVersionLog.cmaketmp") + + set(index -1) + string(FIND ${_matlab_version_from_cmd} "ans" index) + if(index EQUAL -1) + + if(MATLAB_FIND_DEBUG) + message(WARNING "[MATLAB] Cannot find the version of Matlab returned by the run.") + endif() + + else() + set(matlab_list_of_all_versions_tmp) + + string(SUBSTRING ${_matlab_version_from_cmd} ${index} -1 substring_ans) + string( + REGEX MATCHALL "ans[\r\n\t ]*=[\r\n\t ]*'?([0-9]+(\\.[0-9]+)?)" + matlab_versions_regex + ${substring_ans}) + foreach(match IN LISTS matlab_versions_regex) + string( + REGEX MATCH "ans[\r\n\t ]*=[\r\n\t ]*'?(([0-9]+)(\\.([0-9]+))?)" + current_match ${match}) + + list(APPEND matlab_list_of_all_versions_tmp ${CMAKE_MATCH_1}) + endforeach() + if(matlab_list_of_all_versions_tmp) + list(REMOVE_DUPLICATES matlab_list_of_all_versions_tmp) + endif() + set(${matlab_list_versions} ${matlab_list_of_all_versions_tmp} PARENT_SCOPE) + + endif() + +endfunction() + +#.rst: +# .. command:: matlab_add_unit_test +# +# Adds a Matlab unit test to the test set of cmake/ctest. +# This command requires the component ``MAIN_PROGRAM``. +# The unit test uses the Matlab unittest framework (default, available +# starting Matlab 2013b+) except if the option ``NO_UNITTEST_FRAMEWORK`` +# is given. +# +# The function expects one Matlab test script file to be given. +# In the case ``NO_UNITTEST_FRAMEWORK`` is given, the unittest script file +# should contain the script to be run, plus an exit command with the exit +# value. This exit value will be passed to the ctest framework (0 success, +# non 0 failure). Additional arguments accepted by :command:`add_test` can be +# passed through ``TEST_ARGS`` (eg. ``CONFIGURATION ...``). +# +# :: +# +# matlab_add_unit_test( +# NAME +# UNITTEST_FILE matlab_file_containing_unittest.m +# [CUSTOM_TEST_COMMAND matlab_command_to_run_as_test] +# [UNITTEST_PRECOMMAND matlab_command_to_run] +# [TIMEOUT timeout] +# [ADDITIONAL_PATH path1 [path2 ...]] +# [MATLAB_ADDITIONAL_STARTUP_OPTIONS option1 [option2 ...]] +# [TEST_ARGS arg1 [arg2 ...]] +# [NO_UNITTEST_FRAMEWORK] +# ) +# +# The function arguments are: +# +# ``NAME`` +# name of the unittest in ctest. +# ``UNITTEST_FILE`` +# the matlab unittest file. Its path will be automatically +# added to the Matlab path. +# ``CUSTOM_TEST_COMMAND`` +# Matlab script command to run as the test. +# If this is not set, then the following is run: +# ``runtests('matlab_file_name'), exit(max([ans(1,:).Failed]))`` +# where ``matlab_file_name`` is the ``UNITTEST_FILE`` without the extension. +# ``UNITTEST_PRECOMMAND`` +# Matlab script command to be ran before the file +# containing the test (eg. GPU device initialisation based on CMake +# variables). +# ``TIMEOUT`` +# the test timeout in seconds. Defaults to 180 seconds as the +# Matlab unit test may hang. +# ``ADDITIONAL_PATH`` +# a list of paths to add to the Matlab path prior to +# running the unit test. +# ``MATLAB_ADDITIONAL_STARTUP_OPTIONS`` +# a list of additional option in order +# to run Matlab from the command line. +# ``-nosplash -nodesktop -nodisplay`` are always added. +# ``TEST_ARGS`` +# Additional options provided to the add_test command. These +# options are added to the default options (eg. "CONFIGURATIONS Release") +# ``NO_UNITTEST_FRAMEWORK`` +# when set, indicates that the test should not +# use the unittest framework of Matlab (available for versions >= R2013a). +# ``WORKING_DIRECTORY`` +# This will be the working directory for the test. If specified it will +# also be the output directory used for the log file of the test run. +# If not specifed the temporary directory ``${CMAKE_BINARY_DIR}/Matlab`` will +# be used as the working directory and the log location. +# +function(matlab_add_unit_test) + + if(NOT Matlab_MAIN_PROGRAM) + message(FATAL_ERROR "[MATLAB] This functionality needs the MAIN_PROGRAM component (not default)") + endif() + + set(options NO_UNITTEST_FRAMEWORK) + set(oneValueArgs NAME UNITTEST_FILE TIMEOUT WORKING_DIRECTORY + UNITTEST_PRECOMMAND CUSTOM_TEST_COMMAND) + set(multiValueArgs ADDITIONAL_PATH MATLAB_ADDITIONAL_STARTUP_OPTIONS TEST_ARGS) + + set(prefix _matlab_unittest_prefix) + cmake_parse_arguments(PARSE_ARGV 0 ${prefix} "${options}" "${oneValueArgs}" "${multiValueArgs}" ) + + if(NOT ${prefix}_NAME) + message(FATAL_ERROR "[MATLAB] The Matlab test name cannot be empty") + endif() + + add_test(NAME ${${prefix}_NAME} + COMMAND ${CMAKE_COMMAND} + "-Dtest_name=${${prefix}_NAME}" + "-Dadditional_paths=${${prefix}_ADDITIONAL_PATH}" + "-Dtest_timeout=${${prefix}_TIMEOUT}" + "-Doutput_directory=${_matlab_temporary_folder}" + "-Dworking_directory=${${prefix}_WORKING_DIRECTORY}" + "-DMatlab_PROGRAM=${Matlab_MAIN_PROGRAM}" + "-Dno_unittest_framework=${${prefix}_NO_UNITTEST_FRAMEWORK}" + "-DMatlab_ADDITIONAL_STARTUP_OPTIONS=${${prefix}_MATLAB_ADDITIONAL_STARTUP_OPTIONS}" + "-Dunittest_file_to_run=${${prefix}_UNITTEST_FILE}" + "-Dcustom_Matlab_test_command=${${prefix}_CUSTOM_TEST_COMMAND}" + "-Dcmd_to_run_before_test=${${prefix}_UNITTEST_PRECOMMAND}" + -P ${_FindMatlab_SELF_DIR}/MatlabTestsRedirect.cmake + ${${prefix}_TEST_ARGS} + ${${prefix}_UNPARSED_ARGUMENTS} + ) +endfunction() + + +#.rst: +# .. command:: matlab_add_mex +# +# Adds a Matlab MEX target. +# This commands compiles the given sources with the current tool-chain in +# order to produce a MEX file. The final name of the produced output may be +# specified, as well as additional link libraries, and a documentation entry +# for the MEX file. Remaining arguments of the call are passed to the +# :command:`add_library` or :command:`add_executable` command. +# +# :: +# +# matlab_add_mex( +# NAME +# [EXECUTABLE | MODULE | SHARED] +# SRC src1 [src2 ...] +# [OUTPUT_NAME output_name] +# [DOCUMENTATION file.txt] +# [LINK_TO target1 target2 ...] +# [...] +# ) +# +# ``NAME`` +# name of the target. +# ``SRC`` +# list of source files. +# ``LINK_TO`` +# a list of additional link dependencies. The target links to ``libmex`` +# by default. If ``Matlab_MX_LIBRARY`` is defined, it also +# links to ``libmx``. +# ``OUTPUT_NAME`` +# if given, overrides the default name. The default name is +# the name of the target without any prefix and +# with ``Matlab_MEX_EXTENSION`` suffix. +# ``DOCUMENTATION`` +# if given, the file ``file.txt`` will be considered as +# being the documentation file for the MEX file. This file is copied into +# the same folder without any processing, with the same name as the final +# mex file, and with extension `.m`. In that case, typing ``help `` +# in Matlab prints the documentation contained in this file. +# ``MODULE`` or ``SHARED`` may be given to specify the type of library to be +# created. ``EXECUTABLE`` may be given to create an executable instead of +# a library. If no type is given explicitly, the type is ``SHARED``. +# +# The documentation file is not processed and should be in the following +# format: +# +# :: +# +# % This is the documentation +# function ret = mex_target_output_name(input1) +# +function(matlab_add_mex) + + if(NOT WIN32) + # we do not need all this on Windows + # pthread options + if(CMAKE_CXX_COMPILER_LOADED) + check_cxx_compiler_flag(-pthread HAS_MINUS_PTHREAD) + elseif(CMAKE_C_COMPILER_LOADED) + check_c_compiler_flag(-pthread HAS_MINUS_PTHREAD) + endif() + # we should use try_compile instead, the link flags are discarded from + # this compiler_flag function. + #check_cxx_compiler_flag(-Wl,--exclude-libs,ALL HAS_SYMBOL_HIDING_CAPABILITY) + + endif() + + set(options EXECUTABLE MODULE SHARED) + set(oneValueArgs NAME DOCUMENTATION OUTPUT_NAME) + set(multiValueArgs LINK_TO SRC) + + set(prefix _matlab_addmex_prefix) + cmake_parse_arguments(${prefix} "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} ) + + if(NOT ${prefix}_NAME) + message(FATAL_ERROR "[MATLAB] The MEX target name cannot be empty") + endif() + + if(NOT ${prefix}_OUTPUT_NAME) + set(${prefix}_OUTPUT_NAME ${${prefix}_NAME}) + endif() + + if(${prefix}_EXECUTABLE) + add_executable(${${prefix}_NAME} + ${${prefix}_SRC} + ${${prefix}_DOCUMENTATION} + ${${prefix}_UNPARSED_ARGUMENTS}) + else() + if(${prefix}_MODULE) + set(type MODULE) + else() + set(type SHARED) + endif() + + add_library(${${prefix}_NAME} + ${type} + ${${prefix}_SRC} + ${${prefix}_DOCUMENTATION} + ${${prefix}_UNPARSED_ARGUMENTS}) + endif() + + target_include_directories(${${prefix}_NAME} PRIVATE ${Matlab_INCLUDE_DIRS}) + + if(DEFINED Matlab_MX_LIBRARY) + target_link_libraries(${${prefix}_NAME} ${Matlab_MX_LIBRARY}) + endif() + + target_link_libraries(${${prefix}_NAME} ${Matlab_MEX_LIBRARY} ${${prefix}_LINK_TO}) + set_target_properties(${${prefix}_NAME} + PROPERTIES + PREFIX "" + OUTPUT_NAME ${${prefix}_OUTPUT_NAME} + SUFFIX ".${Matlab_MEX_EXTENSION}") + + + # documentation + if(NOT ${${prefix}_DOCUMENTATION} STREQUAL "") + get_target_property(output_name ${${prefix}_NAME} OUTPUT_NAME) + add_custom_command( + TARGET ${${prefix}_NAME} + PRE_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different ${${prefix}_DOCUMENTATION} $/${output_name}.m + COMMENT "Copy ${${prefix}_NAME} documentation file into the output folder" + ) + endif() # documentation + + # entry point in the mex file + taking care of visibility and symbol clashes. + if(WIN32) + set_target_properties(${${prefix}_NAME} + PROPERTIES + DEFINE_SYMBOL "DLL_EXPORT_SYM=__declspec(dllexport)") + else() + + if(HAS_MINUS_PTHREAD AND NOT APPLE) + # Apparently, compiling with -pthread generated the proper link flags + # and some defines at compilation + target_compile_options(${${prefix}_NAME} PRIVATE "-pthread") + endif() + + + # if we do not do that, the symbols linked from eg. boost remain weak and + # then clash with the ones defined in the matlab process. So by default + # the symbols are hidden. + # This also means that for shared libraries (like MEX), the entry point + # should be explicitly declared with default visibility, otherwise Matlab + # cannot find the entry point. + # Note that this is particularly meaningful if the MEX wrapper itself + # contains symbols that are clashing with Matlab (that are compiled in the + # MEX file). In order to propagate the visibility options to the libraries + # to which the MEX file is linked against, the -Wl,--exclude-libs,ALL + # option should also be specified. + + set_target_properties(${${prefix}_NAME} + PROPERTIES + CXX_VISIBILITY_PRESET "hidden" + C_VISIBILITY_PRESET "hidden" + VISIBILITY_INLINES_HIDDEN ON + ) + + # get_target_property( + # _previous_link_flags + # ${${prefix}_NAME} + # LINK_FLAGS) + # if(NOT _previous_link_flags) + # set(_previous_link_flags) + # endif() + + # if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") + # set_target_properties(${${prefix}_NAME} + # PROPERTIES + # LINK_FLAGS "${_previous_link_flags} -Wl,--exclude-libs,ALL" + # # -Wl,--version-script=${_FindMatlab_SELF_DIR}/MatlabLinuxVisibility.map" + # ) + # elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") + # # in this case, all other symbols become hidden. + # set_target_properties(${${prefix}_NAME} + # PROPERTIES + # LINK_FLAGS "${_previous_link_flags} -Wl,-exported_symbol,_mexFunction" + # #-Wl,-exported_symbols_list,${_FindMatlab_SELF_DIR}/MatlabOSXVisilibity.map" + # ) + # endif() + + + + set_target_properties(${${prefix}_NAME} + PROPERTIES + DEFINE_SYMBOL "DLL_EXPORT_SYM=__attribute__ ((visibility (\"default\")))" + ) + + + endif() + +endfunction() + + +# (internal) +# Used to get the version of matlab, using caching. This basically transforms the +# output of the root list, with possible unknown version, to a version +# +function(_Matlab_get_version_from_root matlab_root matlab_known_version matlab_final_version) + + # if the version is not trivial, we query matlab for that + # we keep track of the location of matlab that induced this version + #if(NOT DEFINED Matlab_PROG_VERSION_STRING_AUTO_DETECT) + # set(Matlab_PROG_VERSION_STRING_AUTO_DETECT "" CACHE INTERNAL "internal matlab location for the discovered version") + #endif() + + if(NOT ${matlab_known_version} STREQUAL "NOTFOUND") + # the version is known, we just return it + set(${matlab_final_version} ${matlab_known_version} PARENT_SCOPE) + set(Matlab_VERSION_STRING_INTERNAL ${matlab_known_version} CACHE INTERNAL "Matlab version (automatically determined)" FORCE) + return() + endif() + + # + set(_matlab_current_program ${Matlab_MAIN_PROGRAM}) + + # do we already have a matlab program? + if(NOT _matlab_current_program) + + set(_find_matlab_options) + if(matlab_root AND EXISTS ${matlab_root}) + set(_find_matlab_options PATHS ${matlab_root} ${matlab_root}/bin NO_DEFAULT_PATH) + endif() + + find_program( + _matlab_current_program + matlab + ${_find_matlab_options} + DOC "Matlab main program" + ) + endif() + + if(NOT _matlab_current_program OR NOT EXISTS ${_matlab_current_program}) + # if not found, clear the dependent variables + if(MATLAB_FIND_DEBUG) + message(WARNING "[MATLAB] Cannot find the main matlab program under ${matlab_root}") + endif() + set(Matlab_PROG_VERSION_STRING_AUTO_DETECT "" CACHE INTERNAL "internal matlab location for the discovered version" FORCE) + set(Matlab_VERSION_STRING_INTERNAL "" CACHE INTERNAL "internal matlab location for the discovered version" FORCE) + unset(_matlab_current_program) + unset(_matlab_current_program CACHE) + return() + endif() + + # full real path for path comparison + get_filename_component(_matlab_main_real_path_tmp "${_matlab_current_program}" REALPATH) + unset(_matlab_current_program) + unset(_matlab_current_program CACHE) + + # is it the same as the previous one? + if(_matlab_main_real_path_tmp STREQUAL Matlab_PROG_VERSION_STRING_AUTO_DETECT) + set(${matlab_final_version} ${Matlab_VERSION_STRING_INTERNAL} PARENT_SCOPE) + return() + endif() + + # update the location of the program + set(Matlab_PROG_VERSION_STRING_AUTO_DETECT ${_matlab_main_real_path_tmp} CACHE INTERNAL "internal matlab location for the discovered version" FORCE) + + set(matlab_list_of_all_versions) + matlab_get_version_from_matlab_run("${Matlab_PROG_VERSION_STRING_AUTO_DETECT}" matlab_list_of_all_versions) + + list(LENGTH matlab_list_of_all_versions list_of_all_versions_length) + if(${list_of_all_versions_length} GREATER 0) + list(GET matlab_list_of_all_versions 0 _matlab_version_tmp) + else() + set(_matlab_version_tmp "unknown") + endif() + + # set the version into the cache + set(Matlab_VERSION_STRING_INTERNAL ${_matlab_version_tmp} CACHE INTERNAL "Matlab version (automatically determined)" FORCE) + + # warning, just in case several versions found (should not happen) + if((${list_of_all_versions_length} GREATER 1) AND MATLAB_FIND_DEBUG) + message(WARNING "[MATLAB] Found several versions, taking the first one (versions found ${matlab_list_of_all_versions})") + endif() + + # return the updated value + set(${matlab_final_version} ${Matlab_VERSION_STRING_INTERNAL} PARENT_SCOPE) + +endfunction() + + + + + + + +# ################################### +# Exploring the possible Matlab_ROOTS + +# this variable will get all Matlab installations found in the current system. +set(_matlab_possible_roots) + + + +if(Matlab_ROOT_DIR) + # if the user specifies a possible root, we keep this one + + if(NOT EXISTS ${Matlab_ROOT_DIR}) + # if Matlab_ROOT_DIR specified but erroneous + if(MATLAB_FIND_DEBUG) + message(WARNING "[MATLAB] the specified path for Matlab_ROOT_DIR does not exist (${Matlab_ROOT_DIR})") + endif() + else() + # NOTFOUND indicates the code below to search for the version automatically + if("${Matlab_VERSION_STRING_INTERNAL}" STREQUAL "") + list(APPEND _matlab_possible_roots "NOTFOUND" ${Matlab_ROOT_DIR}) # empty version + else() + list(APPEND _matlab_possible_roots ${Matlab_VERSION_STRING_INTERNAL} ${Matlab_ROOT_DIR}) # cached version + endif() + endif() + + +else() + + # if the user does not specify the possible installation root, we look for + # one installation using the appropriate heuristics + + if(WIN32) + + # On WIN32, we look for Matlab installation in the registry + # if unsuccessful, we look for all known revision and filter the existing + # ones. + + # testing if we are able to extract the needed information from the registry + set(_matlab_versions_from_registry) + + if(CMAKE_SIZEOF_VOID_P EQUAL 8) + set(_matlab_win64 ON) + else() + set(_matlab_win64 OFF) + endif() + + matlab_extract_all_installed_versions_from_registry(_matlab_win64 _matlab_versions_from_registry) + + # the returned list is empty, doing the search on all known versions + if(NOT _matlab_versions_from_registry) + + if(MATLAB_FIND_DEBUG) + message(STATUS "[MATLAB] Search for Matlab from the registry unsuccessful, testing all supported versions") + endif() + + extract_matlab_versions_from_registry_brute_force(_matlab_versions_from_registry) + endif() + + # filtering the results with the registry keys + matlab_get_all_valid_matlab_roots_from_registry("${_matlab_versions_from_registry}" _matlab_possible_roots) + unset(_matlab_versions_from_registry) + + elseif(APPLE) + + # on mac, we look for the /Application paths + # this corresponds to the behaviour on Windows. On Linux, we do not have + # any other guess. + matlab_get_supported_releases(_matlab_releases) + if(MATLAB_FIND_DEBUG) + message(STATUS "[MATLAB] Matlab supported versions ${_matlab_releases}. If more version should be supported " + "the variable MATLAB_ADDITIONAL_VERSIONS can be set according to the documentation") + endif() + + foreach(_matlab_current_release IN LISTS _matlab_releases) + set(_matlab_full_string "/Applications/MATLAB_${_matlab_current_release}.app") + if(EXISTS ${_matlab_full_string}) + set(_matlab_current_version) + matlab_get_version_from_release_name("${_matlab_current_release}" _matlab_current_version) + if(MATLAB_FIND_DEBUG) + message(STATUS "[MATLAB] Found version ${_matlab_current_release} (${_matlab_current_version}) in ${_matlab_full_string}") + endif() + list(APPEND _matlab_possible_roots ${_matlab_current_version} ${_matlab_full_string}) + unset(_matlab_current_version) + endif() + + unset(_matlab_full_string) + endforeach(_matlab_current_release) + + unset(_matlab_current_release) + unset(_matlab_releases) + + endif() + +endif() + + + +list(LENGTH _matlab_possible_roots _numbers_of_matlab_roots) +if(_numbers_of_matlab_roots EQUAL 0) + # if we have not found anything, we fall back on the PATH + + + # At this point, we have no other choice than trying to find it from PATH. + # If set by the user, this wont change + find_program( + _matlab_main_tmp + NAMES matlab) + + + if(_matlab_main_tmp) + # we then populate the list of roots, with empty version + if(MATLAB_FIND_DEBUG) + message(STATUS "[MATLAB] matlab found from PATH: ${_matlab_main_tmp}") + endif() + + # resolve symlinks + get_filename_component(_matlab_current_location "${_matlab_main_tmp}" REALPATH) + + # get the directory (the command below has to be run twice) + # this will be the matlab root + get_filename_component(_matlab_current_location "${_matlab_current_location}" DIRECTORY) + get_filename_component(_matlab_current_location "${_matlab_current_location}" DIRECTORY) # Matlab should be in bin + + list(APPEND _matlab_possible_roots "NOTFOUND" ${_matlab_current_location}) + + unset(_matlab_current_location) + + endif() + unset(_matlab_main_tmp CACHE) + +endif() + + + + + +if(MATLAB_FIND_DEBUG) + message(STATUS "[MATLAB] Matlab root folders are ${_matlab_possible_roots}") +endif() + + + + + +# take the first possible Matlab root +list(LENGTH _matlab_possible_roots _numbers_of_matlab_roots) +set(Matlab_VERSION_STRING "NOTFOUND") +if(_numbers_of_matlab_roots GREATER 0) + list(GET _matlab_possible_roots 0 Matlab_VERSION_STRING) + list(GET _matlab_possible_roots 1 Matlab_ROOT_DIR) + + # adding a warning in case of ambiguity + if(_numbers_of_matlab_roots GREATER 2 AND MATLAB_FIND_DEBUG) + message(WARNING "[MATLAB] Found several distributions of Matlab. Setting the current version to ${Matlab_VERSION_STRING} (located ${Matlab_ROOT_DIR})." + " If this is not the desired behaviour, provide the -DMatlab_ROOT_DIR=... on the command line") + endif() +endif() + + +# check if the root changed wrt. the previous defined one, if so +# clear all the cached variables for being able to reconfigure properly +if(DEFINED Matlab_ROOT_DIR_LAST_CACHED) + + if(NOT Matlab_ROOT_DIR_LAST_CACHED STREQUAL Matlab_ROOT_DIR) + set(_Matlab_cached_vars + Matlab_INCLUDE_DIRS + Matlab_MEX_LIBRARY + Matlab_MEX_COMPILER + Matlab_MAIN_PROGRAM + Matlab_MX_LIBRARY + Matlab_ENG_LIBRARY + Matlab_MAT_LIBRARY + Matlab_MEX_EXTENSION + Matlab_SIMULINK_INCLUDE_DIR + + # internal + Matlab_MEXEXTENSIONS_PROG + Matlab_ROOT_DIR_LAST_CACHED + #Matlab_PROG_VERSION_STRING_AUTO_DETECT + Matlab_VERSION_STRING_INTERNAL + ) + foreach(_var IN LISTS _Matlab_cached_vars) + if(DEFINED ${_var}) + unset(${_var} CACHE) + endif() + endforeach() + endif() +endif() + +set(Matlab_ROOT_DIR_LAST_CACHED ${Matlab_ROOT_DIR} CACHE INTERNAL "last Matlab root dir location") +set(Matlab_ROOT_DIR ${Matlab_ROOT_DIR} CACHE PATH "Matlab installation root path" FORCE) + +# Fix the version, in case this one is NOTFOUND +_Matlab_get_version_from_root( + "${Matlab_ROOT_DIR}" + ${Matlab_VERSION_STRING} + Matlab_VERSION_STRING +) + + + + +if(MATLAB_FIND_DEBUG) + message(STATUS "[MATLAB] Current version is ${Matlab_VERSION_STRING} located ${Matlab_ROOT_DIR}") +endif() + + + +if(Matlab_ROOT_DIR) + file(TO_CMAKE_PATH ${Matlab_ROOT_DIR} Matlab_ROOT_DIR) +endif() + +if(CMAKE_SIZEOF_VOID_P EQUAL 4) + set(_matlab_64Build FALSE) +else() + set(_matlab_64Build TRUE) +endif() + +if(APPLE) + set(_matlab_bin_prefix "mac") # i should be for intel + set(_matlab_bin_suffix_32bits "i") + set(_matlab_bin_suffix_64bits "i64") +elseif(UNIX) + set(_matlab_bin_prefix "gln") + set(_matlab_bin_suffix_32bits "x86") + set(_matlab_bin_suffix_64bits "xa64") +else() + set(_matlab_bin_prefix "win") + set(_matlab_bin_suffix_32bits "32") + set(_matlab_bin_suffix_64bits "64") +endif() + + + +set(MATLAB_INCLUDE_DIR_TO_LOOK ${Matlab_ROOT_DIR}/extern/include) +if(_matlab_64Build) + set(_matlab_current_suffix ${_matlab_bin_suffix_64bits}) +else() + set(_matlab_current_suffix ${_matlab_bin_suffix_32bits}) +endif() + +set(Matlab_BINARIES_DIR + ${Matlab_ROOT_DIR}/bin/${_matlab_bin_prefix}${_matlab_current_suffix}) +set(Matlab_EXTERN_LIBRARY_DIR + ${Matlab_ROOT_DIR}/extern/lib/${_matlab_bin_prefix}${_matlab_current_suffix}) + +if(WIN32) + if(MINGW) + set(_matlab_lib_dir_for_search ${Matlab_EXTERN_LIBRARY_DIR}/mingw64) + else() + set(_matlab_lib_dir_for_search ${Matlab_EXTERN_LIBRARY_DIR}/microsoft) + endif() + set(_matlab_lib_prefix_for_search "lib") +else() + set(_matlab_lib_dir_for_search ${Matlab_BINARIES_DIR}) + set(_matlab_lib_prefix_for_search "lib") +endif() + +unset(_matlab_64Build) + + +if(NOT DEFINED Matlab_MEX_EXTENSION) + set(_matlab_mex_extension "") + matlab_get_mex_suffix("${Matlab_ROOT_DIR}" _matlab_mex_extension) + + # This variable goes to the cache. + set(Matlab_MEX_EXTENSION ${_matlab_mex_extension} CACHE STRING "Extensions for the mex targets (automatically given by Matlab)") + unset(_matlab_mex_extension) +endif() + + +if(MATLAB_FIND_DEBUG) + message(STATUS "[MATLAB] [DEBUG]_matlab_lib_prefix_for_search = ${_matlab_lib_prefix_for_search} | _matlab_lib_dir_for_search = ${_matlab_lib_dir_for_search}") +endif() + + + +# internal +# This small stub around find_library is to prevent any pollution of CMAKE_FIND_LIBRARY_PREFIXES in the global scope. +# This is the function to be used below instead of the find_library directives. +function(_Matlab_find_library _matlab_library_prefix) + set(CMAKE_FIND_LIBRARY_PREFIXES ${CMAKE_FIND_LIBRARY_PREFIXES} ${_matlab_library_prefix}) + find_library(${ARGN}) +endfunction() + + +set(_matlab_required_variables) + + +# the MEX library/header are required +find_path( + Matlab_INCLUDE_DIRS + mex.h + PATHS ${MATLAB_INCLUDE_DIR_TO_LOOK} + NO_DEFAULT_PATH + ) +list(APPEND _matlab_required_variables Matlab_INCLUDE_DIRS) + +_Matlab_find_library( + ${_matlab_lib_prefix_for_search} + Matlab_MEX_LIBRARY + mex + PATHS ${_matlab_lib_dir_for_search} + NO_DEFAULT_PATH +) + +list(APPEND _matlab_required_variables Matlab_MEX_LIBRARY) + +# the MEX extension is required +list(APPEND _matlab_required_variables Matlab_MEX_EXTENSION) + +# the matlab root is required +list(APPEND _matlab_required_variables Matlab_ROOT_DIR) + +# component Mex Compiler +list(FIND Matlab_FIND_COMPONENTS MEX_COMPILER _matlab_find_mex_compiler) +if(_matlab_find_mex_compiler GREATER -1) + find_program( + Matlab_MEX_COMPILER + "mex" + PATHS ${Matlab_BINARIES_DIR} + DOC "Matlab MEX compiler" + NO_DEFAULT_PATH + ) + if(Matlab_MEX_COMPILER) + set(Matlab_MEX_COMPILER_FOUND TRUE) + endif() +endif() +unset(_matlab_find_mex_compiler) + +# component Matlab program +list(FIND Matlab_FIND_COMPONENTS MAIN_PROGRAM _matlab_find_matlab_program) +if(_matlab_find_matlab_program GREATER -1) + find_program( + Matlab_MAIN_PROGRAM + matlab + PATHS ${Matlab_ROOT_DIR} ${Matlab_ROOT_DIR}/bin + DOC "Matlab main program" + NO_DEFAULT_PATH + ) + if(Matlab_MAIN_PROGRAM) + set(Matlab_MAIN_PROGRAM_FOUND TRUE) + endif() +endif() +unset(_matlab_find_matlab_program) + +# Component MX library +list(FIND Matlab_FIND_COMPONENTS MX_LIBRARY _matlab_find_mx) +if(_matlab_find_mx GREATER -1) + _Matlab_find_library( + ${_matlab_lib_prefix_for_search} + Matlab_MX_LIBRARY + mx + PATHS ${_matlab_lib_dir_for_search} + NO_DEFAULT_PATH + ) + if(Matlab_MX_LIBRARY) + set(Matlab_MX_LIBRARY_FOUND TRUE) + endif() +endif() +unset(_matlab_find_mx) + +# Component ENG library +list(FIND Matlab_FIND_COMPONENTS ENG_LIBRARY _matlab_find_eng) +if(_matlab_find_eng GREATER -1) + _Matlab_find_library( + ${_matlab_lib_prefix_for_search} + Matlab_ENG_LIBRARY + eng + PATHS ${_matlab_lib_dir_for_search} + NO_DEFAULT_PATH + ) + if(Matlab_ENG_LIBRARY) + set(Matlab_ENG_LIBRARY_FOUND TRUE) + endif() +endif() +unset(_matlab_find_eng) + +# Component MAT library +list(FIND Matlab_FIND_COMPONENTS MAT_LIBRARY _matlab_find_mat) +if(_matlab_find_mat GREATER -1) + _Matlab_find_library( + ${_matlab_lib_prefix_for_search} + Matlab_MAT_LIBRARY + mat + PATHS ${_matlab_lib_dir_for_search} + NO_DEFAULT_PATH + ) + if(Matlab_MAT_LIBRARY) + set(Matlab_MAT_LIBRARY_FOUND TRUE) + endif() +endif() +unset(_matlab_find_mat) + +# Component Simulink +list(FIND Matlab_FIND_COMPONENTS SIMULINK _matlab_find_simulink) +if(_matlab_find_simulink GREATER -1) + find_path( + Matlab_SIMULINK_INCLUDE_DIR + simstruc.h + PATHS "${Matlab_ROOT_DIR}/simulink/include" + NO_DEFAULT_PATH + ) + if(Matlab_SIMULINK_INCLUDE_DIR) + set(Matlab_SIMULINK_FOUND TRUE) + list(APPEND Matlab_INCLUDE_DIRS "${Matlab_SIMULINK_INCLUDE_DIR}") + endif() +endif() +unset(_matlab_find_simulink) + +unset(_matlab_lib_dir_for_search) + +set(Matlab_LIBRARIES ${Matlab_MEX_LIBRARY} ${Matlab_MX_LIBRARY} ${Matlab_ENG_LIBRARY} ${Matlab_MAT_LIBRARY}) + +find_package_handle_standard_args( + Matlab + FOUND_VAR Matlab_FOUND + REQUIRED_VARS ${_matlab_required_variables} + VERSION_VAR Matlab_VERSION_STRING + HANDLE_COMPONENTS) + +unset(_matlab_required_variables) +unset(_matlab_bin_prefix) +unset(_matlab_bin_suffix_32bits) +unset(_matlab_bin_suffix_64bits) +unset(_matlab_current_suffix) +unset(_matlab_lib_dir_for_search) +unset(_matlab_lib_prefix_for_search) + +if(Matlab_INCLUDE_DIRS AND Matlab_LIBRARIES) + mark_as_advanced( + Matlab_MEX_LIBRARY + Matlab_MX_LIBRARY + Matlab_ENG_LIBRARY + Matlab_MAT_LIBRARY + Matlab_INCLUDE_DIRS + Matlab_FOUND + Matlab_MAIN_PROGRAM + Matlab_MEXEXTENSIONS_PROG + Matlab_MEX_EXTENSION + ) +endif() diff --git a/src/external/libigl-2.3.0/cmake/FindMOSEK.cmake b/src/external/libigl-2.3.0/cmake/FindMOSEK.cmake new file mode 100644 index 000000000..72dd05ac7 --- /dev/null +++ b/src/external/libigl-2.3.0/cmake/FindMOSEK.cmake @@ -0,0 +1,43 @@ +# +# Try to find MOSEK +# Once done this will define +# +# MOSEK_FOUND - system has MOSEK +# MOSEK_INCLUDE_DIRS - the MOSEK include directories +# MOSEK_LIBRARIES - Link these to use MOSEK +# + +# Hardcoded search paths +set(SEARCH_PATHS + ${CMAKE_SOURCE_DIR}/mosek/9.2/tools/platform/osx64x86/ + /usr/local/mosek/7/tools/platform/osx64x86/ + /usr/local/mosek/8/tools/platform/osx64x86/ + /usr/local/mosek/9.2/tools/platform/osx64x86/ + /opt/mosek/7/tools/platform/linux64x86/ +) + +find_path(MOSEK_INCLUDE_DIR mosek.h + PATHS ${SEARCH_PATHS} + PATH_SUFFIXES h +) + +set(MOSEK_LIBRARIES) +find_library(MOSEK_LIBRARIES NAMES mosek64 + HINT + "${MOSEK_INCLUDE_DIR}" + "${MOSEK_INCLUDE_DIR}/../bin" + "${MOSEK_INCLUDE_DIR}/lib" + PATHS + ${SEARCH_PATHS} + NO_DEFAULT_PATH + PATH_SUFFIXES a bin lib dylib) + +# Check that Mosek was successfully found +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args( + MOSEK DEFAULT_MSG MOSEK_LIBRARIES MOSEK_INCLUDE_DIR +) +set(MOSEK_INCLUDE_DIRS ${MOSEK_INCLUDE_DIR}) + +# Hide variables from CMake-Gui options +mark_as_advanced(MOSEK_LIBRARIES MOSEK_INCLUDE_DIRS MOSEK_INCLUDE_DIR) diff --git a/src/external/libigl-2.3.0/cmake/HunterGate.cmake b/src/external/libigl-2.3.0/cmake/HunterGate.cmake new file mode 100644 index 000000000..887557a58 --- /dev/null +++ b/src/external/libigl-2.3.0/cmake/HunterGate.cmake @@ -0,0 +1,540 @@ +# Copyright (c) 2013-2018, Ruslan Baratov +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# This is a gate file to Hunter package manager. +# Include this file using `include` command and add package you need, example: +# +# cmake_minimum_required(VERSION 3.2) +# +# include("cmake/HunterGate.cmake") +# HunterGate( +# URL "https://github.com/path/to/hunter/archive.tar.gz" +# SHA1 "798501e983f14b28b10cda16afa4de69eee1da1d" +# ) +# +# project(MyProject) +# +# hunter_add_package(Foo) +# hunter_add_package(Boo COMPONENTS Bar Baz) +# +# Projects: +# * https://github.com/hunter-packages/gate/ +# * https://github.com/ruslo/hunter + +option(HUNTER_ENABLED "Enable Hunter package manager support" ON) + +if(HUNTER_ENABLED) + if(CMAKE_VERSION VERSION_LESS "3.2") + message( + FATAL_ERROR + "At least CMake version 3.2 required for Hunter dependency management." + " Update CMake or set HUNTER_ENABLED to OFF." + ) + endif() +endif() + +include(CMakeParseArguments) # cmake_parse_arguments + +option(HUNTER_STATUS_PRINT "Print working status" ON) +option(HUNTER_STATUS_DEBUG "Print a lot info" OFF) +option(HUNTER_TLS_VERIFY "Enable/disable TLS certificate checking on downloads" ON) + +set(HUNTER_WIKI "https://github.com/ruslo/hunter/wiki") + +function(hunter_gate_status_print) + if(HUNTER_STATUS_PRINT OR HUNTER_STATUS_DEBUG) + foreach(print_message ${ARGV}) + message(STATUS "[hunter] ${print_message}") + endforeach() + endif() +endfunction() + +function(hunter_gate_status_debug) + if(HUNTER_STATUS_DEBUG) + foreach(print_message ${ARGV}) + string(TIMESTAMP timestamp) + message(STATUS "[hunter *** DEBUG *** ${timestamp}] ${print_message}") + endforeach() + endif() +endfunction() + +function(hunter_gate_wiki wiki_page) + message("------------------------------ WIKI -------------------------------") + message(" ${HUNTER_WIKI}/${wiki_page}") + message("-------------------------------------------------------------------") + message("") + message(FATAL_ERROR "") +endfunction() + +function(hunter_gate_internal_error) + message("") + foreach(print_message ${ARGV}) + message("[hunter ** INTERNAL **] ${print_message}") + endforeach() + message("[hunter ** INTERNAL **] [Directory:${CMAKE_CURRENT_LIST_DIR}]") + message("") + hunter_gate_wiki("error.internal") +endfunction() + +function(hunter_gate_fatal_error) + cmake_parse_arguments(hunter "" "WIKI" "" "${ARGV}") + string(COMPARE EQUAL "${hunter_WIKI}" "" have_no_wiki) + if(have_no_wiki) + hunter_gate_internal_error("Expected wiki") + endif() + message("") + foreach(x ${hunter_UNPARSED_ARGUMENTS}) + message("[hunter ** FATAL ERROR **] ${x}") + endforeach() + message("[hunter ** FATAL ERROR **] [Directory:${CMAKE_CURRENT_LIST_DIR}]") + message("") + hunter_gate_wiki("${hunter_WIKI}") +endfunction() + +function(hunter_gate_user_error) + hunter_gate_fatal_error(${ARGV} WIKI "error.incorrect.input.data") +endfunction() + +function(hunter_gate_self root version sha1 result) + string(COMPARE EQUAL "${root}" "" is_bad) + if(is_bad) + hunter_gate_internal_error("root is empty") + endif() + + string(COMPARE EQUAL "${version}" "" is_bad) + if(is_bad) + hunter_gate_internal_error("version is empty") + endif() + + string(COMPARE EQUAL "${sha1}" "" is_bad) + if(is_bad) + hunter_gate_internal_error("sha1 is empty") + endif() + + string(SUBSTRING "${sha1}" 0 7 archive_id) + + if(EXISTS "${root}/cmake/Hunter") + set(hunter_self "${root}") + else() + set( + hunter_self + "${root}/_Base/Download/Hunter/${version}/${archive_id}/Unpacked" + ) + endif() + + set("${result}" "${hunter_self}" PARENT_SCOPE) +endfunction() + +# Set HUNTER_GATE_ROOT cmake variable to suitable value. +function(hunter_gate_detect_root) + # Check CMake variable + string(COMPARE NOTEQUAL "${HUNTER_ROOT}" "" not_empty) + if(not_empty) + set(HUNTER_GATE_ROOT "${HUNTER_ROOT}" PARENT_SCOPE) + hunter_gate_status_debug("HUNTER_ROOT detected by cmake variable") + return() + endif() + + # Check environment variable + string(COMPARE NOTEQUAL "$ENV{HUNTER_ROOT}" "" not_empty) + if(not_empty) + set(HUNTER_GATE_ROOT "$ENV{HUNTER_ROOT}" PARENT_SCOPE) + hunter_gate_status_debug("HUNTER_ROOT detected by environment variable") + return() + endif() + + # Check HOME environment variable + string(COMPARE NOTEQUAL "$ENV{HOME}" "" result) + if(result) + set(HUNTER_GATE_ROOT "$ENV{HOME}/.hunter" PARENT_SCOPE) + hunter_gate_status_debug("HUNTER_ROOT set using HOME environment variable") + return() + endif() + + # Check SYSTEMDRIVE and USERPROFILE environment variable (windows only) + if(WIN32) + string(COMPARE NOTEQUAL "$ENV{SYSTEMDRIVE}" "" result) + if(result) + set(HUNTER_GATE_ROOT "$ENV{SYSTEMDRIVE}/.hunter" PARENT_SCOPE) + hunter_gate_status_debug( + "HUNTER_ROOT set using SYSTEMDRIVE environment variable" + ) + return() + endif() + + string(COMPARE NOTEQUAL "$ENV{USERPROFILE}" "" result) + if(result) + set(HUNTER_GATE_ROOT "$ENV{USERPROFILE}/.hunter" PARENT_SCOPE) + hunter_gate_status_debug( + "HUNTER_ROOT set using USERPROFILE environment variable" + ) + return() + endif() + endif() + + hunter_gate_fatal_error( + "Can't detect HUNTER_ROOT" + WIKI "error.detect.hunter.root" + ) +endfunction() + +function(hunter_gate_download dir) + string( + COMPARE + NOTEQUAL + "$ENV{HUNTER_DISABLE_AUTOINSTALL}" + "" + disable_autoinstall + ) + if(disable_autoinstall AND NOT HUNTER_RUN_INSTALL) + hunter_gate_fatal_error( + "Hunter not found in '${dir}'" + "Set HUNTER_RUN_INSTALL=ON to auto-install it from '${HUNTER_GATE_URL}'" + "Settings:" + " HUNTER_ROOT: ${HUNTER_GATE_ROOT}" + " HUNTER_SHA1: ${HUNTER_GATE_SHA1}" + WIKI "error.run.install" + ) + endif() + string(COMPARE EQUAL "${dir}" "" is_bad) + if(is_bad) + hunter_gate_internal_error("Empty 'dir' argument") + endif() + + string(COMPARE EQUAL "${HUNTER_GATE_SHA1}" "" is_bad) + if(is_bad) + hunter_gate_internal_error("HUNTER_GATE_SHA1 empty") + endif() + + string(COMPARE EQUAL "${HUNTER_GATE_URL}" "" is_bad) + if(is_bad) + hunter_gate_internal_error("HUNTER_GATE_URL empty") + endif() + + set(done_location "${dir}/DONE") + set(sha1_location "${dir}/SHA1") + + set(build_dir "${dir}/Build") + set(cmakelists "${dir}/CMakeLists.txt") + + hunter_gate_status_debug("Locking directory: ${dir}") + file(LOCK "${dir}" DIRECTORY GUARD FUNCTION) + hunter_gate_status_debug("Lock done") + + if(EXISTS "${done_location}") + # while waiting for lock other instance can do all the job + hunter_gate_status_debug("File '${done_location}' found, skip install") + return() + endif() + + file(REMOVE_RECURSE "${build_dir}") + file(REMOVE_RECURSE "${cmakelists}") + + file(MAKE_DIRECTORY "${build_dir}") # check directory permissions + + # Disabling languages speeds up a little bit, reduces noise in the output + # and avoids path too long windows error + file( + WRITE + "${cmakelists}" + "cmake_minimum_required(VERSION 3.2)\n" + "project(HunterDownload LANGUAGES NONE)\n" + "include(ExternalProject)\n" + "ExternalProject_Add(\n" + " Hunter\n" + " URL\n" + " \"${HUNTER_GATE_URL}\"\n" + " URL_HASH\n" + " SHA1=${HUNTER_GATE_SHA1}\n" + " DOWNLOAD_DIR\n" + " \"${dir}\"\n" + " TLS_VERIFY\n" + " ${HUNTER_TLS_VERIFY}\n" + " SOURCE_DIR\n" + " \"${dir}/Unpacked\"\n" + " CONFIGURE_COMMAND\n" + " \"\"\n" + " BUILD_COMMAND\n" + " \"\"\n" + " INSTALL_COMMAND\n" + " \"\"\n" + ")\n" + ) + + if(HUNTER_STATUS_DEBUG) + set(logging_params "") + else() + set(logging_params OUTPUT_QUIET) + endif() + + hunter_gate_status_debug("Run generate") + + # Need to add toolchain file too. + # Otherwise on Visual Studio + MDD this will fail with error: + # "Could not find an appropriate version of the Windows 10 SDK installed on this machine" + if(EXISTS "${CMAKE_TOOLCHAIN_FILE}") + get_filename_component(absolute_CMAKE_TOOLCHAIN_FILE "${CMAKE_TOOLCHAIN_FILE}" ABSOLUTE) + set(toolchain_arg "-DCMAKE_TOOLCHAIN_FILE=${absolute_CMAKE_TOOLCHAIN_FILE}") + else() + # 'toolchain_arg' can't be empty + set(toolchain_arg "-DCMAKE_TOOLCHAIN_FILE=") + endif() + + string(COMPARE EQUAL "${CMAKE_MAKE_PROGRAM}" "" no_make) + if(no_make) + set(make_arg "") + else() + # Test case: remove Ninja from PATH but set it via CMAKE_MAKE_PROGRAM + set(make_arg "-DCMAKE_MAKE_PROGRAM=${CMAKE_MAKE_PROGRAM}") + endif() + + execute_process( + COMMAND + "${CMAKE_COMMAND}" + "-H${dir}" + "-B${build_dir}" + "-G${CMAKE_GENERATOR}" + "${toolchain_arg}" + ${make_arg} + WORKING_DIRECTORY "${dir}" + RESULT_VARIABLE download_result + ${logging_params} + ) + + if(NOT download_result EQUAL 0) + hunter_gate_internal_error( + "Configure project failed." + "To reproduce the error run: ${CMAKE_COMMAND} -H${dir} -B${build_dir} -G${CMAKE_GENERATOR} ${toolchain_arg} ${make_arg}" + "In directory ${dir}" + ) + endif() + + hunter_gate_status_print( + "Initializing Hunter workspace (${HUNTER_GATE_SHA1})" + " ${HUNTER_GATE_URL}" + " -> ${dir}" + ) + execute_process( + COMMAND "${CMAKE_COMMAND}" --build "${build_dir}" + WORKING_DIRECTORY "${dir}" + RESULT_VARIABLE download_result + ${logging_params} + ) + + if(NOT download_result EQUAL 0) + hunter_gate_internal_error("Build project failed") + endif() + + file(REMOVE_RECURSE "${build_dir}") + file(REMOVE_RECURSE "${cmakelists}") + + file(WRITE "${sha1_location}" "${HUNTER_GATE_SHA1}") + file(WRITE "${done_location}" "DONE") + + hunter_gate_status_debug("Finished") +endfunction() + +# Must be a macro so master file 'cmake/Hunter' can +# apply all variables easily just by 'include' command +# (otherwise PARENT_SCOPE magic needed) +macro(HunterGate) + if(HUNTER_GATE_DONE) + # variable HUNTER_GATE_DONE set explicitly for external project + # (see `hunter_download`) + set_property(GLOBAL PROPERTY HUNTER_GATE_DONE YES) + endif() + + # First HunterGate command will init Hunter, others will be ignored + get_property(_hunter_gate_done GLOBAL PROPERTY HUNTER_GATE_DONE SET) + + if(NOT HUNTER_ENABLED) + # Empty function to avoid error "unknown function" + function(hunter_add_package) + endfunction() + + set( + _hunter_gate_disabled_mode_dir + "${CMAKE_CURRENT_LIST_DIR}/cmake/Hunter/disabled-mode" + ) + if(EXISTS "${_hunter_gate_disabled_mode_dir}") + hunter_gate_status_debug( + "Adding \"disabled-mode\" modules: ${_hunter_gate_disabled_mode_dir}" + ) + list(APPEND CMAKE_PREFIX_PATH "${_hunter_gate_disabled_mode_dir}") + endif() + elseif(_hunter_gate_done) + hunter_gate_status_debug("Secondary HunterGate (use old settings)") + hunter_gate_self( + "${HUNTER_CACHED_ROOT}" + "${HUNTER_VERSION}" + "${HUNTER_SHA1}" + _hunter_self + ) + include("${_hunter_self}/cmake/Hunter") + else() + set(HUNTER_GATE_LOCATION "${CMAKE_CURRENT_SOURCE_DIR}") + + string(COMPARE NOTEQUAL "${PROJECT_NAME}" "" _have_project_name) + if(_have_project_name) + hunter_gate_fatal_error( + "Please set HunterGate *before* 'project' command. " + "Detected project: ${PROJECT_NAME}" + WIKI "error.huntergate.before.project" + ) + endif() + + cmake_parse_arguments( + HUNTER_GATE "LOCAL" "URL;SHA1;GLOBAL;FILEPATH" "" ${ARGV} + ) + + string(COMPARE EQUAL "${HUNTER_GATE_SHA1}" "" _empty_sha1) + string(COMPARE EQUAL "${HUNTER_GATE_URL}" "" _empty_url) + string( + COMPARE + NOTEQUAL + "${HUNTER_GATE_UNPARSED_ARGUMENTS}" + "" + _have_unparsed + ) + string(COMPARE NOTEQUAL "${HUNTER_GATE_GLOBAL}" "" _have_global) + string(COMPARE NOTEQUAL "${HUNTER_GATE_FILEPATH}" "" _have_filepath) + + if(_have_unparsed) + hunter_gate_user_error( + "HunterGate unparsed arguments: ${HUNTER_GATE_UNPARSED_ARGUMENTS}" + ) + endif() + if(_empty_sha1) + hunter_gate_user_error("SHA1 suboption of HunterGate is mandatory") + endif() + if(_empty_url) + hunter_gate_user_error("URL suboption of HunterGate is mandatory") + endif() + if(_have_global) + if(HUNTER_GATE_LOCAL) + hunter_gate_user_error("Unexpected LOCAL (already has GLOBAL)") + endif() + if(_have_filepath) + hunter_gate_user_error("Unexpected FILEPATH (already has GLOBAL)") + endif() + endif() + if(HUNTER_GATE_LOCAL) + if(_have_global) + hunter_gate_user_error("Unexpected GLOBAL (already has LOCAL)") + endif() + if(_have_filepath) + hunter_gate_user_error("Unexpected FILEPATH (already has LOCAL)") + endif() + endif() + if(_have_filepath) + if(_have_global) + hunter_gate_user_error("Unexpected GLOBAL (already has FILEPATH)") + endif() + if(HUNTER_GATE_LOCAL) + hunter_gate_user_error("Unexpected LOCAL (already has FILEPATH)") + endif() + endif() + + hunter_gate_detect_root() # set HUNTER_GATE_ROOT + + # Beautify path, fix probable problems with windows path slashes + get_filename_component( + HUNTER_GATE_ROOT "${HUNTER_GATE_ROOT}" ABSOLUTE + ) + hunter_gate_status_debug("HUNTER_ROOT: ${HUNTER_GATE_ROOT}") + if(NOT HUNTER_ALLOW_SPACES_IN_PATH) + string(FIND "${HUNTER_GATE_ROOT}" " " _contain_spaces) + if(NOT _contain_spaces EQUAL -1) + hunter_gate_fatal_error( + "HUNTER_ROOT (${HUNTER_GATE_ROOT}) contains spaces." + "Set HUNTER_ALLOW_SPACES_IN_PATH=ON to skip this error" + "(Use at your own risk!)" + WIKI "error.spaces.in.hunter.root" + ) + endif() + endif() + + string( + REGEX + MATCH + "[0-9]+\\.[0-9]+\\.[0-9]+[-_a-z0-9]*" + HUNTER_GATE_VERSION + "${HUNTER_GATE_URL}" + ) + string(COMPARE EQUAL "${HUNTER_GATE_VERSION}" "" _is_empty) + if(_is_empty) + set(HUNTER_GATE_VERSION "unknown") + endif() + + hunter_gate_self( + "${HUNTER_GATE_ROOT}" + "${HUNTER_GATE_VERSION}" + "${HUNTER_GATE_SHA1}" + _hunter_self + ) + + set(_master_location "${_hunter_self}/cmake/Hunter") + if(EXISTS "${HUNTER_GATE_ROOT}/cmake/Hunter") + # Hunter downloaded manually (e.g. by 'git clone') + set(_unused "xxxxxxxxxx") + set(HUNTER_GATE_SHA1 "${_unused}") + set(HUNTER_GATE_VERSION "${_unused}") + else() + get_filename_component(_archive_id_location "${_hunter_self}/.." ABSOLUTE) + set(_done_location "${_archive_id_location}/DONE") + set(_sha1_location "${_archive_id_location}/SHA1") + + # Check Hunter already downloaded by HunterGate + if(NOT EXISTS "${_done_location}") + hunter_gate_download("${_archive_id_location}") + endif() + + if(NOT EXISTS "${_done_location}") + hunter_gate_internal_error("hunter_gate_download failed") + endif() + + if(NOT EXISTS "${_sha1_location}") + hunter_gate_internal_error("${_sha1_location} not found") + endif() + file(READ "${_sha1_location}" _sha1_value) + string(COMPARE EQUAL "${_sha1_value}" "${HUNTER_GATE_SHA1}" _is_equal) + if(NOT _is_equal) + hunter_gate_internal_error( + "Short SHA1 collision:" + " ${_sha1_value} (from ${_sha1_location})" + " ${HUNTER_GATE_SHA1} (HunterGate)" + ) + endif() + if(NOT EXISTS "${_master_location}") + hunter_gate_user_error( + "Master file not found:" + " ${_master_location}" + "try to update Hunter/HunterGate" + ) + endif() + endif() + include("${_master_location}") + set_property(GLOBAL PROPERTY HUNTER_GATE_DONE YES) + endif() +endmacro() diff --git a/src/external/libigl-2.3.0/cmake/LibiglDownloadExternal.cmake b/src/external/libigl-2.3.0/cmake/LibiglDownloadExternal.cmake new file mode 100644 index 000000000..442c985e3 --- /dev/null +++ b/src/external/libigl-2.3.0/cmake/LibiglDownloadExternal.cmake @@ -0,0 +1,198 @@ +################################################################################ +include(DownloadProject) + +# With CMake 3.8 and above, we can hide warnings about git being in a +# detached head by passing an extra GIT_CONFIG option. +set(LIBIGL_EXTRA_OPTIONS TLS_VERIFY OFF) +if(NOT (${CMAKE_VERSION} VERSION_LESS "3.8.0")) + list(APPEND LIBIGL_EXTRA_OPTIONS GIT_CONFIG advice.detachedHead=false) +endif() + +# On CMake 3.6.3 and above, there is an option to use shallow clones of git repositories. +# The shallow clone option only works with real tags, not SHA1, so we use a separate option. +set(LIBIGL_BRANCH_OPTIONS) +if(NOT (${CMAKE_VERSION} VERSION_LESS "3.6.3")) + # Disabled for now until we can make sure that it has no adverse effects + # (Downside is that the eigen mirror is huge again) + # list(APPEND LIBIGL_BRANCH_OPTIONS GIT_SHALLOW 1) +endif() + +option(LIBIGL_SKIP_DOWNLOAD "Skip downloading external libraries" OFF) + +# Shortcut functions +function(igl_download_project_aux name source) + if(NOT LIBIGL_SKIP_DOWNLOAD) + download_project( + PROJ ${name} + SOURCE_DIR "${source}" + DOWNLOAD_DIR "${LIBIGL_EXTERNAL}/.cache/${name}" + QUIET + ${LIBIGL_EXTRA_OPTIONS} + ${ARGN} + ) + endif() +endfunction() + +function(igl_download_project name) + igl_download_project_aux(${name} "${LIBIGL_EXTERNAL}/${name}" ${ARGN}) +endfunction() + +################################################################################ + +## CGAL +function(igl_download_cgal) + igl_download_project(cgal + GIT_REPOSITORY https://github.com/CGAL/cgal.git + GIT_TAG f7c3c8212b56c0d6dae63787efc99093f4383415 + ) +endfunction() + +## CoMISo +function(igl_download_comiso) + igl_download_project(CoMISo + GIT_REPOSITORY https://github.com/libigl/CoMISo.git + GIT_TAG d60aa4759fba76b0b793b1efb090b7a771dd7c56 + ) +endfunction() + +## Cork +function(igl_download_cork) + igl_download_project(cork + GIT_REPOSITORY https://github.com/libigl/cork.git + GIT_TAG 27ad8a285838f5a480d856429e39d3d56d4338f9 + ) +endfunction() + +## Eigen +set(LIBIGL_EIGEN_VERSION 3.3.7 CACHE STRING "Default version of Eigen used by libigl.") +function(igl_download_eigen) + igl_download_project(eigen + GIT_REPOSITORY https://gitlab.com/libeigen/eigen.git + GIT_TAG ${LIBIGL_EIGEN_VERSION} + ${LIBIGL_BRANCH_OPTIONS} + ) +endfunction() + +## Embree +function(igl_download_embree) + igl_download_project(embree + GIT_REPOSITORY https://github.com/embree/embree.git + GIT_TAG v3.12.1 + ${LIBIGL_BRANCH_OPTIONS} + ) +endfunction() + +## glad +function(igl_download_glad) + igl_download_project(glad + GIT_REPOSITORY https://github.com/libigl/libigl-glad.git + GIT_TAG 09b4969c56779f7ddf8e6176ec1873184aec890f + ) +endfunction() + +## GLFW +function(igl_download_glfw) + igl_download_project(glfw + GIT_REPOSITORY https://github.com/glfw/glfw.git + GIT_TAG 3327050ca66ad34426a82c217c2d60ced61526b7 + ${LIBIGL_BRANCH_OPTIONS} + ) +endfunction() + +## ImGui +function(igl_download_imgui) + igl_download_project(imgui + GIT_REPOSITORY https://github.com/ocornut/imgui.git + GIT_TAG 61b19489f1ba35934d9114c034b24eb5bff149e7 # 1.81 + patch for #1669 + ${LIBIGL_BRANCH_OPTIONS} + ) + igl_download_project(libigl-imgui + GIT_REPOSITORY https://github.com/libigl/libigl-imgui.git + GIT_TAG 7e1053e750b0f4c129b046f4e455243cb7f804f3 + ) +endfunction() + +## ImGuizmo +function(igl_download_imguizmo) + igl_download_project(imguizmo + GIT_REPOSITORY https://github.com/CedricGuillemet/ImGuizmo.git + GIT_TAG a23567269f6617342bcc112394bdad937b54b2d7 + ${LIBIGL_BRANCH_OPTIONS} + ) +endfunction() + +## pybind11 +function(igl_download_pybind11) + igl_download_project(pybind11 + GIT_REPOSITORY https://github.com/pybind/pybind11.git + GIT_TAG 2d0507db43cd5a117f7843e053b17dffca114107 + ) +endfunction() + +## stb_image +function(igl_download_stb) + igl_download_project(stb + GIT_REPOSITORY https://github.com/libigl/libigl-stb.git + GIT_TAG cd0fa3fcd90325c83be4d697b00214e029f94ca3 + ) +endfunction() + +## TetGen +function(igl_download_tetgen) + igl_download_project(tetgen + GIT_REPOSITORY https://github.com/jdumas/tetgen.git + GIT_TAG c63e7a6434652b8a2065c835bd9d6d298db1a0bc + ) +endfunction() + +## TinyXML +function(igl_download_tinyxml2) + igl_download_project(tinyxml2 + GIT_REPOSITORY https://github.com/leethomason/tinyxml2.git + GIT_TAG d175e9de0be0d4db75d0a8cf065599a435a87eb6 + ) +endfunction() + +## Triangle +function(igl_download_triangle) + igl_download_project(triangle + GIT_REPOSITORY https://github.com/libigl/triangle.git + GIT_TAG 5a70326574b34d6a51d9eaf6a9f78813657ee108 + ) +endfunction() + +## Catch2 +function(igl_download_catch2) + igl_download_project(catch2 + GIT_REPOSITORY https://github.com/catchorg/Catch2.git + GIT_TAG v2.11.0 + ) +endfunction() + +## Predicates +function(igl_download_predicates) + igl_download_project(predicates + GIT_REPOSITORY https://github.com/libigl/libigl-predicates.git + GIT_TAG 488242fa2b1f98a9c5bd1441297fb4a99a6a9ae4 + ) +endfunction() + +################################################################################ + +## Test data +function(igl_download_test_data) + igl_download_project_aux(test_data + "${LIBIGL_EXTERNAL}/../tests/data" + GIT_REPOSITORY https://github.com/libigl/libigl-tests-data + GIT_TAG 19cedf96d70702d8b3a83eb27934780c542356fe + ) +endfunction() + +## Tutorial data +function(igl_download_tutorial_data) + igl_download_project_aux(tutorial_data + "${LIBIGL_EXTERNAL}/../tutorial/data" + GIT_REPOSITORY https://github.com/libigl/libigl-tutorial-data + GIT_TAG c1f9ede366d02e3531ecbaec5e3769312f31cccd + ) +endfunction() diff --git a/src/external/libigl-2.3.0/cmake/LibiglFolders.cmake b/src/external/libigl-2.3.0/cmake/LibiglFolders.cmake new file mode 100644 index 000000000..92418a2d5 --- /dev/null +++ b/src/external/libigl-2.3.0/cmake/LibiglFolders.cmake @@ -0,0 +1,118 @@ +# Sort projects inside the solution +set_property(GLOBAL PROPERTY USE_FOLDERS ON) + +function(igl_folder_targets FOLDER_NAME) + foreach(target IN ITEMS ${ARGN}) + if(TARGET ${target}) + get_target_property(TYPE ${target} TYPE) + if(NOT (TYPE STREQUAL "INTERFACE_LIBRARY")) + set_target_properties(${target} PROPERTIES FOLDER "${FOLDER_NAME}") + endif() + endif() + endforeach() +endfunction() + +function(igl_set_folders) + +igl_folder_targets("ThirdParty/Embree" + algorithms + embree + lexers + math + simd + sys + tasking +) + +igl_folder_targets("ThirdParty" + CoMISo + glad + glfw + imgui + predicates + tetgen + tinyxml2 + triangle +) + +igl_folder_targets("Libigl" + igl + igl_comiso + igl_embree + igl_opengl + igl_opengl_glfw + igl_opengl_glfw_imgui + igl_png + igl_predicates + igl_stb_image + igl_tetgen + igl_triangle + igl_xml +) + +igl_folder_targets("Unit Tests" + libigl_tests +) + +igl_folder_targets("Tutorials" + 101_FileIO_bin + 102_DrawMesh_bin + 103_Events_bin + 104_Colors_bin + 105_Overlays_bin + 106_ViewerMenu_bin + 107_MultipleMeshes_bin + 108_MultipleViews_bin + 201_Normals_bin + 202_GaussianCurvature_bin + 203_CurvatureDirections_bin + 204_Gradient_bin + 205_Laplacian_bin + 206_GeodesicDistance_bin + 301_Slice_bin + 302_Sort_bin + 303_LaplaceEquation_bin + 304_LinearEqualityConstraints_bin + 305_QuadraticProgramming_bin + 306_EigenDecomposition_bin + 401_BiharmonicDeformation_bin + 402_PolyharmonicDeformation_bin + 403_BoundedBiharmonicWeights_bin + 404_DualQuaternionSkinning_bin + 405_AsRigidAsPossible_bin + 406_FastAutomaticSkinningTransformations_bin + 407_BiharmonicCoordinates_bin + 408_DirectDeltaMush_bin + 501_HarmonicParam_bin + 502_LSCMParam_bin + 503_ARAPParam_bin + 504_NRosyDesign_bin + 505_MIQ_bin + 506_FrameField_bin + 507_Planarization_bin + 601_Serialization_bin + 604_Triangle_bin + 605_Tetgen_bin + 606_AmbientOcclusion_bin + 607_ScreenCapture_bin + 701_Statistics_bin + 702_WindingNumber_bin + 703_Decimation_bin + 704_SignedDistance_bin + 705_MarchingCubes_bin + 706_FacetOrientation_bin + 707_SweptVolume_bin + 708_Picking_bin + 709_SLIM_bin + 710_SCAF_bin + 711_Subdivision_bin + 712_DataSmoothing_bin + 713_ShapeUp_bin + 714_MarchingTets_bin + 715_MeshImplicitFunction_bin + 716_HeatGeodesics_bin + 718_IterativeClosestPoint_bin + 719_ExplodedView_bin +) + +endfunction() diff --git a/src/external/libigl-2.3.0/cmake/LibiglWindows.cmake b/src/external/libigl-2.3.0/cmake/LibiglWindows.cmake new file mode 100644 index 000000000..b98aa5580 --- /dev/null +++ b/src/external/libigl-2.3.0/cmake/LibiglWindows.cmake @@ -0,0 +1,26 @@ +if(MSVC) + option(IGL_STATIC_RUNTIME "Use libigl with the static MSVC runtime." OFF) + if(IGL_STATIC_RUNTIME) + message(STATUS "MSVC -> forcing use of statically-linked runtime.") + foreach(config ${CMAKE_CONFIGURATION_TYPES}) + string(TOUPPER ${config} config) + string(REPLACE /MD /MT CMAKE_C_FLAGS_${config} "${CMAKE_C_FLAGS_${config}}") + string(REPLACE /MD /MT CMAKE_CXX_FLAGS_${config} "${CMAKE_CXX_FLAGS_${config}}") + endforeach() + string(REPLACE "/MDd" "/MTd" CMAKE_CXX_FLAGS_DEBUG ${CMAKE_CXX_FLAGS_DEBUG}) + else() + message(STATUS "MSVC -> forcing use of dynamically-linked runtime.") + foreach(config ${CMAKE_CONFIGURATION_TYPES}) + string(TOUPPER ${config} config) + string(REPLACE /MT /MD CMAKE_C_FLAGS_${config} "${CMAKE_C_FLAGS_${config}}") + string(REPLACE /MT /MD CMAKE_CXX_FLAGS_${config} "${CMAKE_CXX_FLAGS_${config}}") + endforeach() + string(REPLACE "/MTd" "/MDd" CMAKE_CXX_FLAGS_DEBUG ${CMAKE_CXX_FLAGS_DEBUG}) + endif() + + # https://github.com/mozilla/sccache/issues/242 + if(CMAKE_CXX_COMPILER_LAUNCHER STREQUAL "sccache") + string(REGEX REPLACE "/Z[iI7]" "" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}") + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /Z7") + endif() +endif() diff --git a/src/external/libigl-2.3.0/cmake/OSXFixDylibReferences.cmake b/src/external/libigl-2.3.0/cmake/OSXFixDylibReferences.cmake new file mode 100644 index 000000000..9c6e44bd9 --- /dev/null +++ b/src/external/libigl-2.3.0/cmake/OSXFixDylibReferences.cmake @@ -0,0 +1,151 @@ +# OS X requires a Mach-O dynamic library to have a baked "install name", that is used by other modules to link to it. Depending +# on how the library is built, the install name is not always an absolute path, nor necessarily the same as the name of the +# library file itself. This macro takes as input the name of a target, and a list of libraries that it links to (the output of +# FIND_PACKAGE or FIND_LIBRARY calls), and generates a set of custom, post-build commands that, for each linked dylib, changes +# the name the target uses to refer to it with a fully-qualified (absolute) version of the library's own install name. This +# helps ensure that the target can be used from any location while still being able to locate the linked dynamic libraries. +# +# Note that this script does NOT handle the case when a linked library itself refers to another library using a non-absolute +# name (Boost is a notorious example). To avoid such issues, it is recommended to use a static library instead of a shared one +# in a non-standard location. Alternatively, set DYLD_LIBRARY_PATH to include these non-standard locations when running the +# program (not recommended). +# +# Author: Siddhartha Chaudhuri, 2009. +# + +# Set the minimum required CMake version +CMAKE_MINIMUM_REQUIRED(VERSION 2.8) + +# See cmake --help-policy CMP0011 for details on this one +IF(POLICY CMP0011) + CMAKE_POLICY(SET CMP0011 NEW) +ENDIF(POLICY CMP0011) + +# See cmake --help-policy CMP0026 for details on this one +IF(POLICY CMP0026) + CMAKE_POLICY(SET CMP0026 NEW) +ENDIF(POLICY CMP0026) + +# See cmake --help-policy CMP0045 for details on this one +IF(POLICY CMP0045) + CMAKE_POLICY(SET CMP0045 NEW) +ENDIF(POLICY CMP0045) + +MACRO(OSX_FIX_DYLIB_REFERENCES target libraries) + + IF(APPLE) + SET(OFIN_${target}_RPATHS ) + + FOREACH(OFIN_${target}_Library ${libraries}) + IF(${OFIN_${target}_Library} MATCHES "[.]dylib$" + OR ${OFIN_${target}_Library} MATCHES "[.]framework/.+") + + # Resolve symlinks and get absolute location + GET_FILENAME_COMPONENT(OFIN_${target}_LibraryAbsolute ${OFIN_${target}_Library} ABSOLUTE) + + # Get the baked install name of the library + EXECUTE_PROCESS(COMMAND otool -D ${OFIN_${target}_LibraryAbsolute} + OUTPUT_VARIABLE OFIN_${target}_LibraryInstallNameOutput + OUTPUT_STRIP_TRAILING_WHITESPACE) + STRING(REGEX REPLACE "[\r\n]" " " OFIN_${target}_LibraryInstallNameOutput ${OFIN_${target}_LibraryInstallNameOutput}) + SEPARATE_ARGUMENTS(OFIN_${target}_LibraryInstallNameOutput) + LIST(GET OFIN_${target}_LibraryInstallNameOutput 1 OFIN_${target}_LibraryInstallName) + + IF(${OFIN_${target}_LibraryInstallName} MATCHES "^[@]rpath/") + + # Ideally, we want to eliminate the longest common suffix of the install name and the absolute path. Whatever's left + # will be the desired rpath. But this is difficult to do (especially if there are naming variations, e.g. + # "Versions/Current" vs "Versions/5" is a common culprit). So we'll add various candidate rpaths and hope at least one + # is correct. + + # Typically, the rpath to a library within a framework looks like this: + # @rpath/A.framework/Versions/5/libFoo.dylib + # + # Hence, we'll extract for the path unit immediately following the @rpath (in this case A.framework) and then look for + # it in the library's actual path. Everything before this location will be put in the rpath. + SET(OFIN_${target}_PathPrefix ${OFIN_${target}_LibraryInstallName}) + SET(OFIN_${target}_RpathFirstChild ) + WHILE(NOT OFIN_${target}_PathPrefix STREQUAL "@rpath") + GET_FILENAME_COMPONENT(OFIN_${target}_RpathFirstChild ${OFIN_${target}_PathPrefix} NAME) + GET_FILENAME_COMPONENT(OFIN_${target}_PathPrefix ${OFIN_${target}_PathPrefix} PATH) + + IF(NOT OFIN_${target}_PathPrefix) # should never happen but just in case + BREAK() + ENDIF(NOT OFIN_${target}_PathPrefix) + + IF(OFIN_${target}_PathPrefix STREQUAL "/") # should never happen but just in case + BREAK() + ENDIF(OFIN_${target}_PathPrefix STREQUAL "/") + ENDWHILE(NOT OFIN_${target}_PathPrefix STREQUAL "@rpath") + + IF(OFIN_${target}_RpathFirstChild) + SET(OFIN_${target}_PathPrefix ${OFIN_${target}_LibraryAbsolute}) + SET(OFIN_${target}_PathUnit ) + WHILE(NOT OFIN_${target}_PathUnit STREQUAL ${OFIN_${target}_RpathFirstChild}) + GET_FILENAME_COMPONENT(OFIN_${target}_PathUnit ${OFIN_${target}_PathPrefix} NAME) + GET_FILENAME_COMPONENT(OFIN_${target}_PathPrefix ${OFIN_${target}_PathPrefix} PATH) + + IF(NOT OFIN_${target}_PathPrefix) + BREAK() + ENDIF(NOT OFIN_${target}_PathPrefix) + + IF(OFIN_${target}_PathPrefix STREQUAL "/") + BREAK() + ENDIF(OFIN_${target}_PathPrefix STREQUAL "/") + ENDWHILE(NOT OFIN_${target}_PathUnit STREQUAL ${OFIN_${target}_RpathFirstChild}) + + IF(OFIN_${target}_PathPrefix) + SET(OFIN_${target}_RPATHS ${OFIN_${target}_RPATHS} "${OFIN_${target}_PathPrefix}") + ENDIF(OFIN_${target}_PathPrefix) + ENDIF(OFIN_${target}_RpathFirstChild) + + # Add the directory containing the library + GET_FILENAME_COMPONENT(OFIN_${target}_LibraryAbsolutePath ${OFIN_${target}_LibraryAbsolute} PATH) + SET(OFIN_${target}_RPATHS ${OFIN_${target}_RPATHS} "${OFIN_${target}_LibraryAbsolutePath}") + + # Add paths specified as library search prefixes + FOREACH(prefix ${CMAKE_PREFIX_PATH}) + SET(OFIN_${target}_RPATHS ${OFIN_${target}_RPATHS} "${CMAKE_PREFIX_PATH}") + SET(OFIN_${target}_RPATHS ${OFIN_${target}_RPATHS} "${CMAKE_PREFIX_PATH}/lib") + ENDFOREACH() + + ELSEIF(NOT ${OFIN_${target}_LibraryInstallName} MATCHES "^[@/]") # just a relative path + + # Replace the unqualified filename, if it appears, with the absolute location, either by directly changing the path or + # by editing the rpath + + # -- handle the case when the actual filename is baked in + GET_FILENAME_COMPONENT(OFIN_${target}_LibraryFilename ${OFIN_${target}_LibraryAbsolute} NAME) + ADD_CUSTOM_COMMAND(TARGET ${target} POST_BUILD + COMMAND install_name_tool + ARGS -change + ${OFIN_${target}_LibraryFilename} + ${OFIN_${target}_LibraryAbsolute} + $) + + # -- handle the case when the install name is baked in + ADD_CUSTOM_COMMAND(TARGET ${target} POST_BUILD + COMMAND install_name_tool + ARGS -change + ${OFIN_${target}_LibraryInstallName} + ${OFIN_${target}_LibraryAbsolute} + $) + ENDIF() + + ENDIF() + ENDFOREACH(OFIN_${target}_Library) + + # Add the collected rpaths + IF(OFIN_${target}_RPATHS) + LIST(REMOVE_DUPLICATES OFIN_${target}_RPATHS) + + FOREACH(rpath ${OFIN_${target}_RPATHS}) + ADD_CUSTOM_COMMAND(TARGET ${target} POST_BUILD + COMMAND bash + ARGS -c "install_name_tool -add_rpath '${rpath}' '$' > /dev/null 2>&1 || true" + VERBATIM) + ENDFOREACH() + ENDIF() + ENDIF() + +ENDMACRO(OSX_FIX_DYLIB_REFERENCES) diff --git a/src/external/libigl-2.3.0/cmake/libigl-cgal.yml b/src/external/libigl-2.3.0/cmake/libigl-cgal.yml new file mode 100644 index 000000000..411f830dd --- /dev/null +++ b/src/external/libigl-2.3.0/cmake/libigl-cgal.yml @@ -0,0 +1,8 @@ +# This is a conda environment that can be used to compile libigl with CGAL on Windows +# Only boost is required to be installed on the system, CGAL is automatically downloaded +# by CMake and is built with libigl. +name: libigl-cgal +channels: + - conda-forge +dependencies: + - boost-cpp=1.65.0 diff --git a/src/external/libigl-2.3.0/cmake/libigl-config.cmake.in b/src/external/libigl-2.3.0/cmake/libigl-config.cmake.in new file mode 100644 index 000000000..21aa2468a --- /dev/null +++ b/src/external/libigl-2.3.0/cmake/libigl-config.cmake.in @@ -0,0 +1,31 @@ +@PACKAGE_INIT@ + +include(${CMAKE_CURRENT_LIST_DIR}/libigl-export.cmake) + +# Check if Eigen3 target is avaiable, if not try to locate it +# with find_package. +message(STATUS "[libigl] Looking for Eigen3") +if (NOT TARGET Eigen3::Eigen) + # Try if Eigen3 can be found with find_package + find_package(Eigen3 CONFIG REQUIRED) +endif() + + +if (TARGET igl::core) + if (TARGET Eigen3::Eigen) + # Inject dependency + set_target_properties(igl::core PROPERTIES INTERFACE_LINK_LIBRARIES Eigen3::Eigen) + set(libigl_core_FOUND TRUE) + endif() +endif() + +if (TARGET igl::common) + if (TARGET Eigen3::Eigen) + # Inject dependency + set_target_properties(igl::common PROPERTIES INTERFACE_LINK_LIBRARIES Eigen3::Eigen) + set(libigl_common_FOUND TRUE) + endif() +endif() + +check_required_components(libigl) + diff --git a/src/external/libigl-2.3.0/cmake/libigl.cmake b/src/external/libigl-2.3.0/cmake/libigl.cmake new file mode 100644 index 000000000..6de1b418d --- /dev/null +++ b/src/external/libigl-2.3.0/cmake/libigl.cmake @@ -0,0 +1,577 @@ +cmake_minimum_required(VERSION 3.8) + +# https://github.com/libigl/libigl/issues/751 +# http://lists.llvm.org/pipermail/llvm-commits/Week-of-Mon-20160425/351643.html +if(APPLE) + if(NOT CMAKE_LIBTOOL) + find_program(CMAKE_LIBTOOL NAMES libtool) + endif() + if(CMAKE_LIBTOOL) + set(CMAKE_LIBTOOL ${CMAKE_LIBTOOL} CACHE PATH "libtool executable") + message(STATUS "Found libtool - ${CMAKE_LIBTOOL}") + get_property(languages GLOBAL PROPERTY ENABLED_LANGUAGES) + foreach(lang ${languages}) + # Added -c + set(CMAKE_${lang}_CREATE_STATIC_LIBRARY + "${CMAKE_LIBTOOL} -c -static -o ") + endforeach() + endif() +endif() + +### Available options ### +option(LIBIGL_USE_STATIC_LIBRARY "Use libigl as static library" OFF) +option(LIBIGL_WITH_CGAL "Use CGAL" OFF) +option(LIBIGL_WITH_COMISO "Use CoMiso" OFF) +option(LIBIGL_WITH_CORK "Use Cork" OFF) +option(LIBIGL_WITH_EMBREE "Use Embree" OFF) +option(LIBIGL_WITH_MATLAB "Use Matlab" OFF) +option(LIBIGL_WITH_MOSEK "Use MOSEK" OFF) +option(LIBIGL_WITH_OPENGL "Use OpenGL" OFF) +option(LIBIGL_WITH_OPENGL_GLFW "Use GLFW" OFF) +option(LIBIGL_WITH_OPENGL_GLFW_IMGUI "Use ImGui" OFF) +option(LIBIGL_WITH_PNG "Use PNG" OFF) +option(LIBIGL_WITH_TETGEN "Use Tetgen" OFF) +option(LIBIGL_WITH_TRIANGLE "Use Triangle" OFF) +option(LIBIGL_WITH_PREDICATES "Use exact predicates" OFF) +option(LIBIGL_WITH_XML "Use XML" OFF) +option(LIBIGL_WITHOUT_COPYLEFT "Disable Copyleft libraries" OFF) +option(LIBIGL_EXPORT_TARGETS "Export libigl CMake targets" OFF) + +if(LIBIGL_BUILD_PYTHON) + message(FATAL_ERROR "Python bindings have been removed in this version. Please use an older version of libigl, or wait for the new bindings to be released.") +endif() + +################################################################################ + +### Configuration +set(LIBIGL_ROOT "${CMAKE_CURRENT_LIST_DIR}/..") +set(LIBIGL_SOURCE_DIR "${LIBIGL_ROOT}/include") +set(LIBIGL_EXTERNAL "${LIBIGL_ROOT}/external") + +# Dependencies are linked as INTERFACE targets unless libigl is compiled as a static library +if(LIBIGL_USE_STATIC_LIBRARY) + set(IGL_SCOPE PUBLIC) +else() + set(IGL_SCOPE INTERFACE) +endif() + +# Download and update 3rdparty libraries +list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}) +include(LibiglDownloadExternal) + +# Provides igl_set_folders() to set folders for Visual Studio/Xcode +include(LibiglFolders) + +################################################################################ +### IGL Common +################################################################################ + +add_library(igl_common INTERFACE) +target_include_directories(igl_common SYSTEM INTERFACE + $ + $ +) +# Export igl_common as igl::common +set_property(TARGET igl_common PROPERTY EXPORT_NAME igl::common) +if(LIBIGL_USE_STATIC_LIBRARY) + target_compile_definitions(igl_common INTERFACE -DIGL_STATIC_LIBRARY) +endif() + +# Transitive C++11 flags +include(CXXFeatures) +target_compile_features(igl_common INTERFACE ${CXX11_FEATURES}) + +# Other compilation flags +if(MSVC) + # Enable parallel compilation for Visual Studio + target_compile_options(igl_common INTERFACE /MP /bigobj) + target_compile_definitions(igl_common INTERFACE -DNOMINMAX) +endif() + +# Controls whether to use the static MSVC runtime or not +include(LibiglWindows) + +if(BUILD_SHARED_LIBS) + # Generate position independent code + set_target_properties(igl_common PROPERTIES INTERFACE_POSITION_INDEPENDENT_CODE ON) +endif() + +if(UNIX AND NOT HUNTER_ENABLED) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC") +endif() + +if(HUNTER_ENABLED) + hunter_add_package(Eigen) + find_package(Eigen3 CONFIG REQUIRED) +endif() + +# Eigen +if(NOT TARGET Eigen3::Eigen) + igl_download_eigen() + add_library(igl_eigen INTERFACE) + target_include_directories(igl_eigen SYSTEM INTERFACE + $ + $ + ) + set_property(TARGET igl_eigen PROPERTY EXPORT_NAME Eigen3::Eigen) + add_library(Eigen3::Eigen ALIAS igl_eigen) +endif() +target_link_libraries(igl_common INTERFACE Eigen3::Eigen) + +# C++11 Thread library +find_package(Threads REQUIRED) +target_link_libraries(igl_common INTERFACE ${CMAKE_THREAD_LIBS_INIT}) + +################################################################################ + +## CGAL dependencies on Windows: GMP & MPFR +function(igl_download_cgal_deps) + if(WIN32) + igl_download_project(gmp + URL https://cgal.geometryfactory.com/CGAL/precompiled_libs/auxiliary/x64/GMP/5.0.1/gmp-all-CGAL-3.9.zip + URL_MD5 508c1292319c832609329116a8234c9f + ) + igl_download_project(mpfr + URL https://cgal.geometryfactory.com/CGAL/precompiled_libs/auxiliary/x64/MPFR/3.0.0/mpfr-all-CGAL-3.9.zip + URL_MD5 48840454eef0ff18730050c05028734b + ) + set(ENV{GMP_DIR} "${LIBIGL_EXTERNAL}/gmp") + set(ENV{MPFR_DIR} "${LIBIGL_EXTERNAL}/mpfr") + endif() +endfunction() + +################################################################################ + +function(compile_igl_module module_dir) + string(REPLACE "/" "_" module_name "${module_dir}") + if(module_name STREQUAL "core") + set(module_libname "igl") + else() + set(module_libname "igl_${module_name}") + endif() + if(LIBIGL_USE_STATIC_LIBRARY) + file(GLOB SOURCES_IGL_${module_name} + "${LIBIGL_SOURCE_DIR}/igl/${module_dir}/*.cpp" + "${LIBIGL_SOURCE_DIR}/igl/${module_dir}/*.h*" + ) + if(NOT LIBIGL_WITHOUT_COPYLEFT) + file(GLOB COPYLEFT_SOURCES_IGL_${module_name} + "${LIBIGL_SOURCE_DIR}/igl/copyleft/${module_dir}/*.cpp" + "${LIBIGL_SOURCE_DIR}/igl/copyleft/${module_dir}/*.h*" + ) + list(APPEND SOURCES_IGL_${module_name} ${COPYLEFT_SOURCES_IGL_${module_name}}) + endif() + add_library(${module_libname} STATIC ${SOURCES_IGL_${module_name}} ${ARGN}) + if(MSVC) + # Silencing some compile warnings + target_compile_options(${module_libname} PRIVATE + # Type conversion warnings. These can be fixed with some effort and possibly more verbose code. + /wd4267 # conversion from 'size_t' to 'type', possible loss of data + /wd4244 # conversion from 'type1' to 'type2', possible loss of data + /wd4018 # signed/unsigned mismatch + /wd4305 # truncation from 'double' to 'float' + # This one is from template instantiations generated by autoexplicit.sh: + /wd4667 # no function template defined that matches forced instantiation () + # This one is easy to fix, just need to switch to safe version of C functions + /wd4996 # this function or variable may be unsafe + # This one is when using bools in adjacency matrices + /wd4804 #'+=': unsafe use of type 'bool' in operation + ) + endif() + else() + add_library(${module_libname} INTERFACE) + endif() + + target_link_libraries(${module_libname} ${IGL_SCOPE} igl_common) + if(NOT module_name STREQUAL "core") + target_link_libraries(${module_libname} ${IGL_SCOPE} igl) + endif() + + # Alias target because it looks nicer + message(STATUS "Creating target: igl::${module_name} (${module_libname})") + add_library(igl::${module_name} ALIAS ${module_libname}) + # Export as igl::${module_name} + set_property(TARGET ${module_libname} PROPERTY EXPORT_NAME igl::${module_name}) +endfunction() + +################################################################################ +### IGL Core +################################################################################ + +if(LIBIGL_USE_STATIC_LIBRARY) + file(GLOB SOURCES_IGL + "${LIBIGL_SOURCE_DIR}/igl/*.cpp" + "${LIBIGL_SOURCE_DIR}/igl/*.h*" + "${LIBIGL_SOURCE_DIR}/igl/copyleft/*.cpp" + "${LIBIGL_SOURCE_DIR}/igl/copyleft/*.h*" + ) +endif() +compile_igl_module("core" ${SOURCES_IGL}) + +################################################################################ +### Download the python part ### +if(LIBIGL_WITH_PYTHON) +endif() + +################################################################################ +### Compile the CGAL part ### +if(LIBIGL_WITH_CGAL) + # Try to find the CGAL library + # CGAL Core is needed for + # `Exact_predicates_exact_constructions_kernel_with_sqrt` + if(NOT TARGET CGAL::CGAL) + set(CGAL_DIR "${LIBIGL_EXTERNAL}/cgal") + igl_download_cgal() + igl_download_cgal_deps() + message("BOOST_ROOT: ${BOOST_ROOT}") + if(EXISTS ${LIBIGL_EXTERNAL}/boost) + set(BOOST_ROOT "${LIBIGL_EXTERNAL}/boost") + endif() + option(CGAL_Boost_USE_STATIC_LIBS "Use static Boost libs with CGAL" ON) + + find_package(CGAL CONFIG COMPONENTS Core PATHS ${CGAL_DIR} NO_DEFAULT_PATH) + endif() + + # If CGAL has been found, then build the libigl module + if(TARGET CGAL::CGAL AND TARGET CGAL::CGAL_Core) + compile_igl_module("cgal") + target_link_libraries(igl_cgal ${IGL_SCOPE} CGAL::CGAL CGAL::CGAL_Core) + else() + message(FATAL_ERROR "Could not define CGAL::CGAL and CGAL::CGAL_Core.") + endif() +endif() + +# Helper function for `igl_copy_cgal_dll()` +function(igl_copy_imported_dll src_target dst_target) + get_target_property(other_libs ${src_target} INTERFACE_LINK_LIBRARIES) + set(locations) + list(APPEND locations ${main_lib} ${other_libs}) + foreach(location ${locations}) + string(REGEX MATCH "^(.*)\\.[^.]*$" dummy ${location}) + set(location "${CMAKE_MATCH_1}.dll") + if(EXISTS "${location}" AND location MATCHES "^.*\\.dll$") + add_custom_command(TARGET ${dst_target} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different "${location}" $) + endif() + endforeach() +endfunction() + +# Convenient functions to copy CGAL dlls into a target (executable) destination folder (for Windows) +function(igl_copy_cgal_dll target) + if(WIN32 AND LIBIGL_WITH_CGAL) + igl_copy_imported_dll(CGAL::CGAL ${target}) + igl_copy_imported_dll(CGAL::CGAL_Core ${target}) + endif() +endfunction() + +################################################################################ +### Compile the CoMISo part ### +# NOTE: this cmakefile works only with the +# comiso available here: https://github.com/libigl/CoMISo +if(LIBIGL_WITH_COMISO) + compile_igl_module("comiso") + if(NOT TARGET CoMISo) + igl_download_comiso() + add_subdirectory("${LIBIGL_EXTERNAL}/CoMISo" CoMISo) + endif() + target_link_libraries(igl_comiso ${IGL_SCOPE} CoMISo) +endif() + +################################################################################ +### Compile the cork part ### +if(LIBIGL_WITH_CORK) + set(CORK_DIR "${LIBIGL_EXTERNAL}/cork") + if(NOT TARGET cork) + # call this "lib-cork" instead of "cork", otherwise cmake gets confused about + # "cork" executable + igl_download_cork() + add_subdirectory("${CORK_DIR}" "lib-cork") + endif() + compile_igl_module("cork") + target_include_directories(igl_cork ${IGL_SCOPE} cork) + target_include_directories(igl_cork ${IGL_SCOPE} "${CORK_DIR}/src") + target_link_libraries(igl_cork ${IGL_SCOPE} cork) +endif() + +################################################################################ +### Compile the embree part ### +if(LIBIGL_WITH_EMBREE) + set(EMBREE_DIR "${LIBIGL_EXTERNAL}/embree") + + if(NOT TARGET embree) + igl_download_embree() + + # Note: On macOS, building embree as a static lib can only be done with a single ISA target. + set(EMBREE_MAX_ISA "DEFAULT" CACHE STRING "Selects highest ISA to support.") + set(EMBREE_TESTING_INTENSITY 0 CACHE STRING "") + set(EMBREE_ISPC_SUPPORT OFF CACHE BOOL " ") + set(EMBREE_TASKING_SYSTEM "INTERNAL" CACHE BOOL " ") + set(EMBREE_TUTORIALS OFF CACHE BOOL " ") + set(EMBREE_STATIC_LIB ON CACHE BOOL " ") + if(MSVC) + set(EMBREE_STATIC_RUNTIME ${IGL_STATIC_RUNTIME} CACHE BOOL "Use the static version of the C/C++ runtime library.") + endif() + + add_subdirectory("${EMBREE_DIR}" "embree" EXCLUDE_FROM_ALL) + endif() + + compile_igl_module("embree") + target_link_libraries(igl_embree ${IGL_SCOPE} embree) + target_include_directories(igl_embree ${IGL_SCOPE} ${EMBREE_DIR}/include) + target_compile_definitions(igl_embree ${IGL_SCOPE} -DEMBREE_STATIC_LIB) +endif() + +################################################################################ +### Compile the matlab part ### +if(LIBIGL_WITH_MATLAB) + find_package(Matlab REQUIRED COMPONENTS MEX_COMPILER MX_LIBRARY ENG_LIBRARY MAT_LIBRARY) + compile_igl_module("matlab") + target_link_libraries(igl_matlab ${IGL_SCOPE} ${Matlab_LIBRARIES}) + target_include_directories(igl_matlab ${IGL_SCOPE} ${Matlab_INCLUDE_DIRS}) +endif() + +################################################################################ +### Compile the mosek part ### +if(LIBIGL_WITH_MOSEK) + find_package(MOSEK REQUIRED) + compile_igl_module("mosek") + target_link_libraries(igl_mosek ${IGL_SCOPE} ${MOSEK_LIBRARIES}) + target_include_directories(igl_mosek ${IGL_SCOPE} ${MOSEK_INCLUDE_DIRS}) + target_compile_definitions(igl_mosek ${IGL_SCOPE} -DLIBIGL_WITH_MOSEK) +endif() + +################################################################################ +### Compile the opengl part ### +if(LIBIGL_WITH_OPENGL) + # OpenGL module + compile_igl_module("opengl") + + # OpenGL library + if (NOT CMAKE_VERSION VERSION_LESS "3.11") + cmake_policy(SET CMP0072 NEW) + endif() + find_package(OpenGL REQUIRED) + if(TARGET OpenGL::GL) + target_link_libraries(igl_opengl ${IGL_SCOPE} OpenGL::GL) + else() + target_link_libraries(igl_opengl ${IGL_SCOPE} ${OPENGL_gl_LIBRARY}) + target_include_directories(igl_opengl SYSTEM ${IGL_SCOPE} ${OPENGL_INCLUDE_DIR}) + endif() + + # glad module + if(NOT TARGET glad) + igl_download_glad() + add_subdirectory(${LIBIGL_EXTERNAL}/glad glad) + endif() + target_link_libraries(igl_opengl ${IGL_SCOPE} glad) +endif() + +################################################################################ +### Compile the GLFW part ### +if(LIBIGL_WITH_OPENGL_GLFW) + if(TARGET igl::opengl) + # GLFW module + compile_igl_module("opengl/glfw") + if(NOT TARGET glfw) + igl_download_glfw() + option(GLFW_BUILD_EXAMPLES "Build the GLFW example programs" OFF) + option(GLFW_BUILD_TESTS "Build the GLFW test programs" OFF) + option(GLFW_BUILD_DOCS "Build the GLFW documentation" OFF) + option(GLFW_INSTALL "Generate installation target" OFF) + if(IGL_STATIC_RUNTIME) + set(USE_MSVC_RUNTIME_LIBRARY_DLL OFF CACHE BOOL "Use MSVC runtime library DLL" FORCE) + else() + set(USE_MSVC_RUNTIME_LIBRARY_DLL ON CACHE BOOL "Use MSVC runtime library DLL" FORCE) + endif() + add_subdirectory(${LIBIGL_EXTERNAL}/glfw glfw) + endif() + target_link_libraries(igl_opengl_glfw ${IGL_SCOPE} igl_opengl glfw) + endif() +endif() + +################################################################################ +### Compile the ImGui part ### +if(LIBIGL_WITH_OPENGL_GLFW_IMGUI) + if(TARGET igl::opengl_glfw) + # ImGui module + compile_igl_module("opengl/glfw/imgui") + if(NOT TARGET imgui) + igl_download_imgui() + add_subdirectory(${LIBIGL_EXTERNAL}/libigl-imgui imgui) + endif() + if(NOT TARGET imguizmo) + igl_download_imguizmo() + add_library(imguizmo ${LIBIGL_EXTERNAL}/imguizmo/ImGuizmo.cpp ${LIBIGL_EXTERNAL}/imguizmo/ImGuizmo.h) + target_compile_features(imguizmo PUBLIC cxx_std_11) + target_link_libraries(imguizmo PUBLIC imgui) + endif() + target_link_libraries(igl_opengl_glfw_imgui ${IGL_SCOPE} igl_opengl_glfw imgui imguizmo) + endif() +endif() + +################################################################################ +### Compile the png part ### +if(LIBIGL_WITH_PNG) + # png/ module is anomalous because it also depends on opengl it really should + # be moved into the opengl/ directory and namespace ... + if(TARGET igl_opengl) + if(NOT TARGET stb_image) + igl_download_stb() + add_subdirectory(${LIBIGL_EXTERNAL}/stb stb_image) + endif() + compile_igl_module("png" "") + target_link_libraries(igl_png ${IGL_SCOPE} igl_stb_image igl_opengl) + endif() +endif() + +################################################################################ +### Compile the tetgen part ### +if(LIBIGL_WITH_TETGEN) + set(TETGEN_DIR "${LIBIGL_EXTERNAL}/tetgen") + if(NOT TARGET tetgen) + igl_download_tetgen() + add_subdirectory("${TETGEN_DIR}" "tetgen") + endif() + compile_igl_module("tetgen") + target_link_libraries(igl_tetgen ${IGL_SCOPE} tetgen) + target_include_directories(igl_tetgen ${IGL_SCOPE} ${TETGEN_DIR}) +endif() + +################################################################################ +### Compile the triangle part ### +if(LIBIGL_WITH_TRIANGLE) + set(TRIANGLE_DIR "${LIBIGL_EXTERNAL}/triangle") + if(NOT TARGET triangle) + igl_download_triangle() + add_subdirectory("${TRIANGLE_DIR}" "triangle") + endif() + compile_igl_module("triangle") + target_link_libraries(igl_triangle ${IGL_SCOPE} triangle) + target_include_directories(igl_triangle ${IGL_SCOPE} ${TRIANGLE_DIR}) +endif() + +################################################################################ +### Compile the predicates part ### +if(LIBIGL_WITH_PREDICATES) + set(PREDICATES_DIR "${LIBIGL_EXTERNAL}/predicates") + if(NOT TARGET predicates) + igl_download_predicates() + add_subdirectory("${PREDICATES_DIR}" "predicates") + endif() + compile_igl_module("predicates") + target_link_libraries(igl_predicates ${IGL_SCOPE} predicates) + target_include_directories(igl_predicates ${IGL_SCOPE} ${PREDICATES_DIR}) + target_compile_definitions(igl_predicates ${IGL_SCOPE} -DLIBIGL_WITH_PREDICATES) +endif() + +################################################################################ +### Compile the xml part ### +if(LIBIGL_WITH_XML) + set(TINYXML2_DIR "${LIBIGL_EXTERNAL}/tinyxml2") + if(NOT TARGET tinyxml2) + igl_download_tinyxml2() + add_library(tinyxml2 STATIC ${TINYXML2_DIR}/tinyxml2.cpp ${TINYXML2_DIR}/tinyxml2.h) + target_include_directories(tinyxml2 PUBLIC ${TINYXML2_DIR}) + set_target_properties(tinyxml2 PROPERTIES + COMPILE_DEFINITIONS "TINYXML2_EXPORT" + VERSION "3.0.0" + SOVERSION "3") + endif() + compile_igl_module("xml") + target_link_libraries(igl_xml ${IGL_SCOPE} tinyxml2) + target_include_directories(igl_xml ${IGL_SCOPE} ${TINYXML2_DIR}) +endif() + +################################################################################ +### Install and export all modules + +if(NOT LIBIGL_EXPORT_TARGETS) + return() +endif() + +function(install_dir_files dir_name) + if (dir_name STREQUAL "core") + set(subpath "") + else() + set(subpath "/${dir_name}") + endif() + + file(GLOB public_headers + ${CMAKE_CURRENT_SOURCE_DIR}/include/igl${subpath}/*.h + ${CMAKE_CURRENT_SOURCE_DIR}/include/igl${subpath}/*.hpp + ) + + set(files_to_install ${public_headers}) + + if(NOT LIBIGL_USE_STATIC_LIBRARY) + file(GLOB public_sources + ${CMAKE_CURRENT_SOURCE_DIR}/include/igl${subpath}/*.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/include/igl${subpath}/*.c + ) + endif() + list(APPEND files_to_install ${public_sources}) + + install( + FILES ${files_to_install} + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/igl${subpath} + ) +endfunction() + +################################################################################ + +include(GNUInstallDirs) +include(CMakePackageConfigHelpers) + +if(TARGET igl_eigen) + set(IGL_EIGEN igl_eigen) +else() + set(IGL_EIGEN) + message(WARNING "Trying to export igl targets while using an imported target for Eigen.") +endif() + +# Install and export core library +install( + TARGETS + igl + igl_common + ${IGL_EIGEN} + EXPORT igl-export + PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} +) +export( + TARGETS + igl + igl_common + ${IGL_EIGEN} + FILE libigl-export.cmake +) + +# Install headers for core library +install_dir_files(core) +install_dir_files(copyleft) + +# Write package configuration file +configure_package_config_file( + ${CMAKE_CURRENT_LIST_DIR}/libigl-config.cmake.in + ${CMAKE_BINARY_DIR}/libigl-config.cmake + INSTALL_DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/libigl/cmake +) +install( + FILES + ${CMAKE_BINARY_DIR}/libigl-config.cmake + DESTINATION + ${CMAKE_INSTALL_DATADIR}/libigl/cmake +) + +# Write export file +export(EXPORT igl-export + FILE "${CMAKE_BINARY_DIR}/libigl-export.cmake" +) +install(EXPORT igl-export DESTINATION ${CMAKE_INSTALL_DATADIR}/libigl/cmake FILE libigl-export.cmake) + + +export(PACKAGE libigl) + diff --git a/src/external/libigl-2.3.0/include/igl/AABB.cpp b/src/external/libigl-2.3.0/include/igl/AABB.cpp new file mode 100644 index 000000000..672e9b705 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/AABB.cpp @@ -0,0 +1,1070 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "AABB.h" +#include "EPS.h" +#include "barycenter.h" +#include "colon.h" +#include "doublearea.h" +#include "point_simplex_squared_distance.h" +#include "project_to_line_segment.h" +#include "sort.h" +#include "volume.h" +#include "ray_box_intersect.h" +#include "parallel_for.h" +#include "ray_mesh_intersect.h" +#include +#include +#include +#include +#include +#include + +template +template +IGL_INLINE void igl::AABB::init( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & Ele, + const Eigen::MatrixBase & bb_mins, + const Eigen::MatrixBase & bb_maxs, + const Eigen::MatrixBase & elements, + const int i) +{ + using namespace std; + using namespace Eigen; + deinit(); + if(bb_mins.size() > 0) + { + assert(bb_mins.rows() == bb_maxs.rows() && "Serial tree arrays must match"); + assert(bb_mins.cols() == V.cols() && "Serial tree array dim must match V"); + assert(bb_mins.cols() == bb_maxs.cols() && "Serial tree arrays must match"); + assert(bb_mins.rows() == elements.rows() && + "Serial tree arrays must match"); + // construct from serialization + m_box.extend(bb_mins.row(i).transpose()); + m_box.extend(bb_maxs.row(i).transpose()); + m_primitive = elements(i); + // Not leaf then recurse + if(m_primitive == -1) + { + m_left = new AABB(); + m_left->init( V,Ele,bb_mins,bb_maxs,elements,2*i+1); + m_right = new AABB(); + m_right->init( V,Ele,bb_mins,bb_maxs,elements,2*i+2); + //m_depth = std::max( m_left->m_depth, m_right->m_depth)+1; + } + }else + { + VectorXi allI = colon(0,Ele.rows()-1); + MatrixXDIMS BC; + if(Ele.cols() == 1) + { + // points + BC = V; + }else + { + // Simplices + barycenter(V,Ele,BC); + } + MatrixXi SI(BC.rows(),BC.cols()); + { + MatrixXDIMS _; + MatrixXi IS; + igl::sort(BC,1,true,_,IS); + // Need SI(i) to tell which place i would be sorted into + const int dim = IS.cols(); + for(int i = 0;i +template +void igl::AABB::init( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & Ele) +{ + using namespace Eigen; + // deinit will be immediately called... + return init(V,Ele,MatrixXDIMS(),MatrixXDIMS(),VectorXi(),0); +} + + template +template < + typename DerivedEle, + typename DerivedSI, + typename DerivedI> +IGL_INLINE void igl::AABB::init( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & Ele, + const Eigen::MatrixBase & SI, + const Eigen::MatrixBase & I) +{ + using namespace Eigen; + using namespace std; + deinit(); + if(V.size() == 0 || Ele.size() == 0 || I.size() == 0) + { + return; + } + assert(DIM == V.cols() && "V.cols() should matched declared dimension"); + //const Scalar inf = numeric_limits::infinity(); + m_box = AlignedBox(); + // Compute bounding box + for(int i = 0;iint + { + size_t n = (A.size()-1)/2; + nth_element(A.data(),A.data()+n,A.data()+A.size()); + return A(n); + }; + const int med = median(SIdI); + VectorXi LI((I.rows()+1)/2),RI(I.rows()/2); + assert(LI.rows()+RI.rows() == I.rows()); + // Distribute left and right + { + int li = 0; + int ri = 0; + for(int i = 0;i0) + { + m_left = new AABB(); + m_left->init(V,Ele,SI,LI); + //m_depth = std::max(m_depth, m_left->m_depth+1); + } + if(RI.rows()>0) + { + m_right = new AABB(); + m_right->init(V,Ele,SI,RI); + //m_depth = std::max(m_depth, m_right->m_depth+1); + } + } + } +} + +template +IGL_INLINE bool igl::AABB::is_leaf() const +{ + return m_primitive != -1; +} + +template +template +IGL_INLINE std::vector igl::AABB::find( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & Ele, + const Eigen::MatrixBase & q, + const bool first) const +{ + using namespace std; + using namespace Eigen; + assert(q.size() == DIM && + "Query dimension should match aabb dimension"); + assert(Ele.cols() == V.cols()+1 && + "AABB::find only makes sense for (d+1)-simplices"); + const Scalar epsilon = igl::EPS(); + // Check if outside bounding box + bool inside = m_box.contains(q.transpose()); + if(!inside) + { + return std::vector(); + } + assert(m_primitive==-1 || (m_left == NULL && m_right == NULL)); + if(is_leaf()) + { + // Initialize to some value > -epsilon + Scalar a1=0,a2=0,a3=0,a4=0; + switch(DIM) + { + case 3: + { + // Barycentric coordinates + typedef Eigen::Matrix RowVector3S; + const RowVector3S V1 = V.row(Ele(m_primitive,0)); + const RowVector3S V2 = V.row(Ele(m_primitive,1)); + const RowVector3S V3 = V.row(Ele(m_primitive,2)); + const RowVector3S V4 = V.row(Ele(m_primitive,3)); + a1 = volume_single(V2,V4,V3,(RowVector3S)q); + a2 = volume_single(V1,V3,V4,(RowVector3S)q); + a3 = volume_single(V1,V4,V2,(RowVector3S)q); + a4 = volume_single(V1,V2,V3,(RowVector3S)q); + break; + } + case 2: + { + // Barycentric coordinates + typedef Eigen::Matrix Vector2S; + const Vector2S V1 = V.row(Ele(m_primitive,0)); + const Vector2S V2 = V.row(Ele(m_primitive,1)); + const Vector2S V3 = V.row(Ele(m_primitive,2)); + // Hack for now to keep templates simple. If becomes bottleneck + // consider using std::enable_if_t + const Vector2S q2 = q.head(2); + a1 = doublearea_single(V1,V2,q2); + a2 = doublearea_single(V2,V3,q2); + a3 = doublearea_single(V3,V1,q2); + break; + } + default:assert(false); + } + // Normalization is important for correcting sign + Scalar sum = a1+a2+a3+a4; + a1 /= sum; + a2 /= sum; + a3 /= sum; + a4 /= sum; + if( + a1>=-epsilon && + a2>=-epsilon && + a3>=-epsilon && + a4>=-epsilon) + { + return std::vector(1,m_primitive); + }else + { + return std::vector(); + } + } + std::vector left = m_left->find(V,Ele,q,first); + if(first && !left.empty()) + { + return left; + } + std::vector right = m_right->find(V,Ele,q,first); + if(first) + { + return right; + } + left.insert(left.end(),right.begin(),right.end()); + return left; +} + +template +IGL_INLINE int igl::AABB::subtree_size() const +{ + // 1 for self + int n = 1; + int n_left = 0,n_right = 0; + if(m_left != NULL) + { + n_left = m_left->subtree_size(); + } + if(m_right != NULL) + { + n_right = m_right->subtree_size(); + } + n += 2*std::max(n_left,n_right); + return n; +} + + +template +template +IGL_INLINE void igl::AABB::serialize( + Eigen::PlainObjectBase & bb_mins, + Eigen::PlainObjectBase & bb_maxs, + Eigen::PlainObjectBase & elements, + const int i) const +{ + using namespace std; + using namespace Eigen; + // Calling for root then resize output + if(i==0) + { + const int m = subtree_size(); + //cout<<"m: "<serialize(bb_mins,bb_maxs,elements,2*i+1); + } + if(m_right != NULL) + { + m_right->serialize(bb_mins,bb_maxs,elements,2*i+2); + } +} + +template +template +IGL_INLINE typename igl::AABB::Scalar +igl::AABB::squared_distance( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & Ele, + const RowVectorDIMS & p, + int & i, + Eigen::PlainObjectBase & c) const +{ + return squared_distance(V,Ele,p,std::numeric_limits::infinity(),i,c); +} + + +template +template +IGL_INLINE typename igl::AABB::Scalar +igl::AABB::squared_distance( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & Ele, + const RowVectorDIMS & p, + Scalar low_sqr_d, + Scalar up_sqr_d, + int & i, + Eigen::PlainObjectBase & c) const +{ + using namespace Eigen; + using namespace std; + //assert(low_sqr_d <= up_sqr_d); + if(low_sqr_d > up_sqr_d) + { + return low_sqr_d; + } + Scalar sqr_d = up_sqr_d; + //assert(DIM == 3 && "Code has only been tested for DIM == 3"); + assert((Ele.cols() == 3 || Ele.cols() == 2 || Ele.cols() == 1) + && "Code has only been tested for simplex sizes 3,2,1"); + + assert(m_primitive==-1 || (m_left == NULL && m_right == NULL)); + if(is_leaf()) + { + leaf_squared_distance(V,Ele,p,low_sqr_d,sqr_d,i,c); + }else + { + bool looked_left = false; + bool looked_right = false; + const auto & look_left = [&]() + { + int i_left; + RowVectorDIMS c_left = c; + Scalar sqr_d_left = + m_left->squared_distance(V,Ele,p,low_sqr_d,sqr_d,i_left,c_left); + this->set_min(p,sqr_d_left,i_left,c_left,sqr_d,i,c); + looked_left = true; + }; + const auto & look_right = [&]() + { + int i_right; + RowVectorDIMS c_right = c; + Scalar sqr_d_right = + m_right->squared_distance(V,Ele,p,low_sqr_d,sqr_d,i_right,c_right); + this->set_min(p,sqr_d_right,i_right,c_right,sqr_d,i,c); + looked_right = true; + }; + + // must look left or right if in box + if(m_left->m_box.contains(p.transpose())) + { + look_left(); + } + if(m_right->m_box.contains(p.transpose())) + { + look_right(); + } + // if haven't looked left and could be less than current min, then look + Scalar left_up_sqr_d = + m_left->m_box.squaredExteriorDistance(p.transpose()); + Scalar right_up_sqr_d = + m_right->m_box.squaredExteriorDistance(p.transpose()); + if(left_up_sqr_d < right_up_sqr_d) + { + if(!looked_left && left_up_sqr_d +template +IGL_INLINE typename igl::AABB::Scalar +igl::AABB::squared_distance( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & Ele, + const RowVectorDIMS & p, + Scalar up_sqr_d, + int & i, + Eigen::PlainObjectBase & c) const +{ + return squared_distance(V,Ele,p,0.0,up_sqr_d,i,c); +} + +template +template < + typename DerivedEle, + typename DerivedP, + typename DerivedsqrD, + typename DerivedI, + typename DerivedC> +IGL_INLINE void igl::AABB::squared_distance( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & Ele, + const Eigen::MatrixBase & P, + Eigen::PlainObjectBase & sqrD, + Eigen::PlainObjectBase & I, + Eigen::PlainObjectBase & C) const +{ + assert(P.cols() == V.cols() && "cols in P should match dim of cols in V"); + sqrD.resize(P.rows(),1); + I.resize(P.rows(),1); + C.resizeLike(P); + // O( #P * log #Ele ), where log #Ele is really the depth of this AABB + // hierarchy + //for(int p = 0;p +template < + typename DerivedEle, + typename Derivedother_V, + typename Derivedother_Ele, + typename DerivedsqrD, + typename DerivedI, + typename DerivedC> +IGL_INLINE void igl::AABB::squared_distance( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & Ele, + const AABB & other, + const Eigen::MatrixBase & other_V, + const Eigen::MatrixBase & other_Ele, + Eigen::PlainObjectBase & sqrD, + Eigen::PlainObjectBase & I, + Eigen::PlainObjectBase & C) const +{ + assert(other_Ele.cols() == 1 && + "Only implemented for other as list of points"); + assert(other_V.cols() == V.cols() && "other must match this dimension"); + sqrD.setConstant(other_Ele.rows(),1,std::numeric_limits::infinity()); + I.resize(other_Ele.rows(),1); + C.resize(other_Ele.rows(),other_V.cols()); + // All points in other_V currently think they need to check against root of + // this. The point of using another AABB is to quickly prune chunks of + // other_V so that most points just check some subtree of this. + + // This holds a conservative estimate of max(sqr_D) where sqr_D is the + // current best minimum squared distance for all points in this subtree + double up_sqr_d = std::numeric_limits::infinity(); + squared_distance_helper( + V,Ele,&other,other_V,other_Ele,0,up_sqr_d,sqrD,I,C); +} + +template +template < + typename DerivedEle, + typename Derivedother_V, + typename Derivedother_Ele, + typename DerivedsqrD, + typename DerivedI, + typename DerivedC> +IGL_INLINE typename igl::AABB::Scalar + igl::AABB::squared_distance_helper( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & Ele, + const AABB * other, + const Eigen::MatrixBase & other_V, + const Eigen::MatrixBase & other_Ele, + const Scalar /*up_sqr_d*/, + Eigen::PlainObjectBase & sqrD, + Eigen::PlainObjectBase & I, + Eigen::PlainObjectBase & C) const +{ + using namespace std; + using namespace Eigen; + + // This implementation is a bit disappointing. There's no major speed up. Any + // performance gains seem to come from accidental cache coherency and + // diminish for larger "other" (the opposite of what was intended). + + // Base case + if(other->is_leaf() && this->is_leaf()) + { + Scalar sqr_d = sqrD(other->m_primitive); + int i = I(other->m_primitive); + RowVectorDIMS c = C.row( other->m_primitive); + RowVectorDIMS p = other_V.row(other->m_primitive); + leaf_squared_distance(V,Ele,p,sqr_d,i,c); + sqrD( other->m_primitive) = sqr_d; + I( other->m_primitive) = i; + C.row(other->m_primitive) = c; + //cout<<"leaf: "<m_low_sqr_d = sqr_d; + return sqr_d; + } + + if(other->is_leaf()) + { + Scalar sqr_d = sqrD(other->m_primitive); + int i = I(other->m_primitive); + RowVectorDIMS c = C.row( other->m_primitive); + RowVectorDIMS p = other_V.row(other->m_primitive); + sqr_d = squared_distance(V,Ele,p,sqr_d,i,c); + sqrD( other->m_primitive) = sqr_d; + I( other->m_primitive) = i; + C.row(other->m_primitive) = c; + //other->m_low_sqr_d = sqr_d; + return sqr_d; + } + + //// Exact minimum squared distance between arbitrary primitives inside this and + //// othre's bounding boxes + //const auto & min_squared_distance = [&]( + // const AABB * A, + // const AABB * B)->Scalar + //{ + // return A->m_box.squaredExteriorDistance(B->m_box); + //}; + + if(this->is_leaf()) + { + //if(min_squared_distance(this,other) < other->m_low_sqr_d) + if(true) + { + this->squared_distance_helper( + V,Ele,other->m_left,other_V,other_Ele,0,sqrD,I,C); + this->squared_distance_helper( + V,Ele,other->m_right,other_V,other_Ele,0,sqrD,I,C); + }else + { + // This is never reached... + } + //// we know other is not a leaf + //other->m_low_sqr_d = std::max(other->m_left->m_low_sqr_d,other->m_right->m_low_sqr_d); + return 0; + } + + // FORCE DOWN TO OTHER LEAF EVAL + //if(min_squared_distance(this,other) < other->m_low_sqr_d) + if(true) + { + if(true) + { + this->squared_distance_helper( + V,Ele,other->m_left,other_V,other_Ele,0,sqrD,I,C); + this->squared_distance_helper( + V,Ele,other->m_right,other_V,other_Ele,0,sqrD,I,C); + }else // this direction never seems to be faster + { + this->m_left->squared_distance_helper( + V,Ele,other,other_V,other_Ele,0,sqrD,I,C); + this->m_right->squared_distance_helper( + V,Ele,other,other_V,other_Ele,0,sqrD,I,C); + } + }else + { + // this is never reached ... :-( + } + //// we know other is not a leaf + //other->m_low_sqr_d = std::max(other->m_left->m_low_sqr_d,other->m_right->m_low_sqr_d); + + return 0; +#if 0 // False + + // _Very_ conservative approximation of maximum squared distance between + // primitives inside this and other's bounding boxes + const auto & max_squared_distance = []( + const AABB * A, + const AABB * B)->Scalar + { + AlignedBox combo = A->m_box; + combo.extend(B->m_box); + return combo.diagonal().squaredNorm(); + }; + + //// other base-case + //if(other->is_leaf()) + //{ + // double sqr_d = sqrD(other->m_primitive); + // int i = I(other->m_primitive); + // RowVectorDIMS c = C.row(m_primitive); + // RowVectorDIMS p = other_V.row(m_primitive); + // leaf_squared_distance(V,Ele,p,sqr_d,i,c); + // sqrD(other->m_primitive) = sqr_d; + // I(other->m_primitive) = i; + // C.row(m_primitive) = c; + // return; + //} + std::vector * > this_list; + if(this->is_leaf()) + { + this_list.push_back(this); + }else + { + assert(this->m_left); + this_list.push_back(this->m_left); + assert(this->m_right); + this_list.push_back(this->m_right); + } + std::vector *> other_list; + if(other->is_leaf()) + { + other_list.push_back(other); + }else + { + assert(other->m_left); + other_list.push_back(other->m_left); + assert(other->m_right); + other_list.push_back(other->m_right); + } + + //const std::function * other) + // > low_sqr_d = [&sqrD,&low_sqr_d](const AABB * other)->Scalar + // { + // if(other->is_leaf()) + // { + // return sqrD(other->m_primitive); + // }else + // { + // return std::max(low_sqr_d(other->m_left),low_sqr_d(other->m_right)); + // } + // }; + + //// Potentially recurse on all pairs, if minimum distance is less than running + //// bound + //Eigen::Matrix other_low_sqr_d = + // Eigen::Matrix::Constant(other_list.size(),1,up_sqr_d); + for(size_t child = 0;child this_low_sqr_d(this_list.size(),1); + for(size_t t = 0;t this_low_sqr_d(1)) + ) + { + std::swap(this_list[0],this_list[1]); + //std::swap(this_low_sqr_d(0),this_low_sqr_d(1)); + } + const Scalar sqr_d = this_low_sqr_d.minCoeff(); + + + for(size_t t = 0;tm_low_sqr_d) + { + //cout<<"before: "<squared_distance_helper( + // V,Ele,other_tree,other_V,other_Ele,other_low_sqr_d(child),sqrD,I,C)); + //cout<<"after: "<squared_distance_helper( + V,Ele,other_tree,other_V,other_Ele,0,sqrD,I,C); + } + } + } + //const Scalar ret = other_low_sqr_d.maxCoeff(); + //const auto mm = low_sqr_d(other); + //assert(mm == ret); + //cout<<"non-leaf: "<is_leaf()) + { + other->m_low_sqr_d = std::max(other->m_left->m_low_sqr_d,other->m_right->m_low_sqr_d); + } + return 0; +#endif +} + +template +template +IGL_INLINE void igl::AABB::leaf_squared_distance( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & Ele, + const RowVectorDIMS & p, + const Scalar low_sqr_d, + Scalar & sqr_d, + int & i, + Eigen::PlainObjectBase & c) const +{ + using namespace Eigen; + using namespace std; + if(low_sqr_d > sqr_d) + { + sqr_d = low_sqr_d; + return; + } + RowVectorDIMS c_candidate; + Scalar sqr_d_candidate; + igl::point_simplex_squared_distance( + p,V,Ele,m_primitive,sqr_d_candidate,c_candidate); + set_min(p,sqr_d_candidate,m_primitive,c_candidate,sqr_d,i,c); +} + +template +template +IGL_INLINE void igl::AABB::leaf_squared_distance( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & Ele, + const RowVectorDIMS & p, + Scalar & sqr_d, + int & i, + Eigen::PlainObjectBase & c) const +{ + return leaf_squared_distance(V,Ele,p,0,sqr_d,i,c); +} + + +template +IGL_INLINE void igl::AABB::set_min( + const RowVectorDIMS & +#ifndef NDEBUG + p +#endif + , + const Scalar sqr_d_candidate, + const int i_candidate, + const RowVectorDIMS & c_candidate, + Scalar & sqr_d, + int & i, + Eigen::PlainObjectBase & c) const +{ +#ifndef NDEBUG + //std::cout< +template +IGL_INLINE bool +igl::AABB::intersect_ray( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & Ele, + const RowVectorDIMS & origin, + const RowVectorDIMS & dir, + std::vector & hits) const +{ + hits.clear(); + const Scalar t0 = 0; + const Scalar t1 = std::numeric_limits::infinity(); + { + Scalar _1,_2; + if(!ray_box_intersect(origin,dir,m_box,t0,t1,_1,_2)) + { + return false; + } + } + if(this->is_leaf()) + { + // Actually process elements + assert((Ele.size() == 0 || Ele.cols() == 3) && "Elements should be triangles"); + // Cheesecake way of hitting element + bool ret = ray_mesh_intersect(origin,dir,V,Ele.row(m_primitive),hits); + // Since we only gave ray_mesh_intersect a single face, it will have set + // any hits to id=0. Set these to this primitive's id + for(auto & hit : hits) + { + hit.id = m_primitive; + } + return ret; + } + std::vector left_hits; + std::vector right_hits; + const bool left_ret = m_left->intersect_ray(V,Ele,origin,dir,left_hits); + const bool right_ret = m_right->intersect_ray(V,Ele,origin,dir,right_hits); + hits.insert(hits.end(),left_hits.begin(),left_hits.end()); + hits.insert(hits.end(),right_hits.begin(),right_hits.end()); + return left_ret || right_ret; +} + +template +template +IGL_INLINE bool +igl::AABB::intersect_ray( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & Ele, + const RowVectorDIMS & origin, + const RowVectorDIMS & dir, + igl::Hit & hit) const +{ +#if false + // BFS + std::queue Q; + // Or DFS + //std::stack Q; + Q.push(this); + bool any_hit = false; + hit.t = std::numeric_limits::infinity(); + while(!Q.empty()) + { + const AABB * tree = Q.front(); + //const AABB * tree = Q.top(); + Q.pop(); + { + Scalar _1,_2; + if(!ray_box_intersect( + origin,dir,tree->m_box,Scalar(0),Scalar(hit.t),_1,_2)) + { + continue; + } + } + if(tree->is_leaf()) + { + // Actually process elements + assert((Ele.size() == 0 || Ele.cols() == 3) && "Elements should be triangles"); + igl::Hit leaf_hit; + if( + ray_mesh_intersect(origin,dir,V,Ele.row(tree->m_primitive),leaf_hit)&& + leaf_hit.t < hit.t) + { + // correct the id + leaf_hit.id = tree->m_primitive; + hit = leaf_hit; + } + continue; + } + // Add children to queue + Q.push(tree->m_left); + Q.push(tree->m_right); + } + return any_hit; +#else + // DFS + return intersect_ray( + V,Ele,origin,dir,std::numeric_limits::infinity(),hit); +#endif +} + +template +template +IGL_INLINE bool +igl::AABB::intersect_ray( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & Ele, + const RowVectorDIMS & origin, + const RowVectorDIMS & dir, + const Scalar _min_t, + igl::Hit & hit) const +{ + //// Naive, slow + //std::vector hits; + //intersect_ray(V,Ele,origin,dir,hits); + //if(hits.size() > 0) + //{ + // hit = hits.front(); + // return true; + //}else + //{ + // return false; + //} + Scalar min_t = _min_t; + const Scalar t0 = 0; + { + Scalar _1,_2; + if(!ray_box_intersect(origin,dir,m_box,t0,min_t,_1,_2)) + { + return false; + } + } + if(this->is_leaf()) + { + // Actually process elements + assert((Ele.size() == 0 || Ele.cols() == 3) && "Elements should be triangles"); + // Cheesecake way of hitting element + bool ret = ray_mesh_intersect(origin,dir,V,Ele.row(m_primitive),hit); + hit.id = m_primitive; + return ret; + } + + // Doesn't seem like smartly choosing left before/after right makes a + // differnce + igl::Hit left_hit; + igl::Hit right_hit; + bool left_ret = m_left->intersect_ray(V,Ele,origin,dir,min_t,left_hit); + if(left_ret && left_hit.tintersect_ray(V,Ele,origin,dir,min_t,right_hit); + if(right_ret && right_hit.t template<> IGL_INLINE float AABB, 2>::squared_distance( Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::Matrix const&, int&, Eigen::PlainObjectBase >&) const { assert(false);return -1;}; + template<> template<> IGL_INLINE float igl::AABB, 2>::squared_distance( Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::Matrix const&, float, float, int&, Eigen::PlainObjectBase >&) const { assert(false);return -1;}; + template<> template<> IGL_INLINE void igl::AABB, 2>::init (Eigen::MatrixBase > const&, Eigen::MatrixBase > const&) { assert(false);}; + template<> template<> IGL_INLINE double AABB, 2>::squared_distance( Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::Matrix const&, int&, Eigen::PlainObjectBase >&) const { assert(false);return -1;}; + template<> template<> IGL_INLINE double igl::AABB, 2>::squared_distance( Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::Matrix const&, double, double, int&, Eigen::PlainObjectBase >&) const { assert(false);return -1;}; + template<> template<> IGL_INLINE void igl::AABB, 2>::init (Eigen::MatrixBase > const&, Eigen::MatrixBase > const&) { assert(false);}; + template<> template<> IGL_INLINE void igl::AABB, 2>::init(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&) {assert(false);}; + template<> template<> IGL_INLINE float igl::AABB, 2>::squared_distance(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::Matrix const&, float, float, int&, Eigen::PlainObjectBase >&) const { assert(false);return -1;}; +} + + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::AABB, 3>::squared_distance, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&) const; +// generated by autoexplicit.sh +template void igl::AABB, 3>::init >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&); +template bool igl::AABB, 3>::intersect_ray >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::Matrix const&, Eigen::Matrix const&, igl::Hit&) const; +template double igl::AABB, 2>::squared_distance >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::Matrix const&, int&, Eigen::PlainObjectBase >&) const; +template double igl::AABB, 3>::squared_distance >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::Matrix const&, double, int&, Eigen::PlainObjectBase >&) const; +template double igl::AABB, 3>::squared_distance >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::Matrix const&, int&, Eigen::PlainObjectBase >&) const; +template double igl::AABB, 3>::squared_distance >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::Matrix const&, double, double, int&, Eigen::PlainObjectBase >&) const; +template float igl::AABB, 3>::squared_distance >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::Matrix const&, float, float, int&, Eigen::PlainObjectBase >&) const; +template float igl::AABB, 3>::squared_distance >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::Matrix const&, int&, Eigen::PlainObjectBase >&) const; +template std::vector > igl::AABB, 2>::find, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, bool) const; +template std::vector > igl::AABB, 3>::find, Eigen::Block const, 1, -1, false> >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase const, 1, -1, false> > const&, bool) const; +template std::vector > igl::AABB, 3>::find, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, bool) const; +template void igl::AABB, 2>::init >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&); +template void igl::AABB, 2>::init, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, int); +template void igl::AABB, 2>::init >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&); +template void igl::AABB, 2>::serialize, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, int) const; +template void igl::AABB, 2>::squared_distance, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&) const; +template void igl::AABB, 2>::squared_distance, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&) const; +template void igl::AABB, 2>::squared_distance, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&) const; +template void igl::AABB, 2>::squared_distance, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&) const; +template void igl::AABB, 2>::squared_distance, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&) const; +template void igl::AABB, 3>::init >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&); +template void igl::AABB, 3>::init, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, int); +template void igl::AABB, 3>::init >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&); +template void igl::AABB, 3>::serialize, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, int) const; +template void igl::AABB, 3>::squared_distance, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&) const; +template void igl::AABB, 3>::squared_distance, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&) const; +template void igl::AABB, 3>::squared_distance, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&) const; +template void igl::AABB, 3>::squared_distance, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&) const; +template void igl::AABB, 3>::squared_distance, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&) const; +template void igl::AABB, 3>::squared_distance, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&) const; +template void igl::AABB, 3>::squared_distance, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&) const; +template void igl::AABB, 3>::init >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&); +template void igl::AABB, 3>::init >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&); +template void igl::AABB, 3>::init >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&); +template double igl::AABB, 3>::squared_distance >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::Matrix const&, int&, Eigen::PlainObjectBase >&) const; +template double igl::AABB, 2>::squared_distance >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::Matrix const&, int&, Eigen::PlainObjectBase >&) const; +#ifdef WIN32 +template void igl::AABB,2>::squared_distance,class Eigen::Matrix,class Eigen::Matrix,class Eigen::Matrix<__int64,-1,1,0,-1,1>,class Eigen::Matrix >(class Eigen::MatrixBase > const &,class Eigen::MatrixBase > const &,class Eigen::MatrixBase > const &,class Eigen::PlainObjectBase > &,class Eigen::PlainObjectBase > &,class Eigen::PlainObjectBase > &)const; +template void igl::AABB,3>::squared_distance,class Eigen::Matrix,class Eigen::Matrix,class Eigen::Matrix<__int64,-1,1,0,-1,1>,class Eigen::Matrix >(class Eigen::MatrixBase > const &,class Eigen::MatrixBase > const &,class Eigen::MatrixBase > const &,class Eigen::PlainObjectBase > &,class Eigen::PlainObjectBase > &,class Eigen::PlainObjectBase > &)const; +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/AABB.h b/src/external/libigl-2.3.0/include/igl/AABB.h new file mode 100644 index 000000000..891481aa0 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/AABB.h @@ -0,0 +1,413 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_AABB_H +#define IGL_AABB_H + +#include "Hit.h" +#include "igl_inline.h" +#include +#include +#include +namespace igl +{ + // Implementation of semi-general purpose axis-aligned bounding box hierarchy. + // The mesh (V,Ele) is stored and managed by the caller and each routine here + // simply takes it as references (it better not change between calls). + // + // It's a little annoying that the Dimension is a template parameter and not + // picked up at run time from V. This leads to duplicated code for 2d/3d (up to + // dim). + template + class AABB + { +public: + typedef typename DerivedV::Scalar Scalar; + typedef Eigen::Matrix RowVectorDIMS; + typedef Eigen::Matrix VectorDIMS; + typedef Eigen::Matrix MatrixXDIMS; + // Shared pointers are slower... + AABB * m_left; + AABB * m_right; + Eigen::AlignedBox m_box; + // -1 non-leaf + int m_primitive; + //Scalar m_low_sqr_d; + //int m_depth; + AABB(): + m_left(NULL), m_right(NULL), + m_box(), m_primitive(-1) + //m_low_sqr_d(std::numeric_limits::infinity()), + //m_depth(0) + {} + // http://stackoverflow.com/a/3279550/148668 + AABB(const AABB& other): + m_left(other.m_left ? new AABB(*other.m_left) : NULL), + m_right(other.m_right ? new AABB(*other.m_right) : NULL), + m_box(other.m_box), + m_primitive(other.m_primitive) + //m_low_sqr_d(other.m_low_sqr_d), + //m_depth(std::max( + // m_left ? m_left->m_depth + 1 : 0, + // m_right ? m_right->m_depth + 1 : 0)) + { + } + // copy-swap idiom + friend void swap(AABB& first, AABB& second) + { + // Enable ADL + using std::swap; + swap(first.m_left,second.m_left); + swap(first.m_right,second.m_right); + swap(first.m_box,second.m_box); + swap(first.m_primitive,second.m_primitive); + //swap(first.m_low_sqr_d,second.m_low_sqr_d); + //swap(first.m_depth,second.m_depth); + } + // Pass-by-value (aka copy) + AABB& operator=(AABB other) + { + swap(*this,other); + return *this; + } + AABB(AABB&& other): + // initialize via default constructor + AABB() + { + swap(*this,other); + } + // Seems like there should have been an elegant solution to this using + // the copy-swap idiom above: + IGL_INLINE void deinit() + { + m_primitive = -1; + m_box = Eigen::AlignedBox(); + delete m_left; + m_left = NULL; + delete m_right; + m_right = NULL; + } + ~AABB() + { + deinit(); + } + // Build an Axis-Aligned Bounding Box tree for a given mesh and given + // serialization of a previous AABB tree. + // + // Inputs: + // V #V by dim list of mesh vertex positions. + // Ele #Ele by dim+1 list of mesh indices into #V. + // bb_mins max_tree by dim list of bounding box min corner positions + // bb_maxs max_tree by dim list of bounding box max corner positions + // elements max_tree list of element or (not leaf id) indices into Ele + // i recursive call index {0} + template < + typename DerivedEle, + typename Derivedbb_mins, + typename Derivedbb_maxs, + typename Derivedelements> + IGL_INLINE void init( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & Ele, + const Eigen::MatrixBase & bb_mins, + const Eigen::MatrixBase & bb_maxs, + const Eigen::MatrixBase & elements, + const int i = 0); + // Wrapper for root with empty serialization + template + IGL_INLINE void init( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & Ele); + // Build an Axis-Aligned Bounding Box tree for a given mesh. + // + // Inputs: + // V #V by dim list of mesh vertex positions. + // Ele #Ele by dim+1 list of mesh indices into #V. + // SI #Ele by dim list revealing for each coordinate where Ele's + // barycenters would be sorted: SI(e,d) = i --> the dth coordinate of + // the barycenter of the eth element would be placed at position i in a + // sorted list. + // I #I list of indices into Ele of elements to include (for recursive + // calls) + // + template + IGL_INLINE void init( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & Ele, + const Eigen::MatrixBase & SI, + const Eigen::MatrixBase& I); + // Return whether at leaf node + IGL_INLINE bool is_leaf() const; + // Find the indices of elements containing given point: this makes sense + // when Ele is a co-dimension 0 simplex (tets in 3D, triangles in 2D). + // + // Inputs: + // V #V by dim list of mesh vertex positions. **Should be same as used to + // construct mesh.** + // Ele #Ele by dim+1 list of mesh indices into #V. **Should be same as used to + // construct mesh.** + // q dim row-vector query position + // first whether to only return first element containing q + // Returns: + // list of indices of elements containing q + template + IGL_INLINE std::vector find( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & Ele, + const Eigen::MatrixBase & q, + const bool first=false) const; + + // If number of elements m then total tree size should be 2*h where h is + // the deepest depth 2^ceil(log(#Ele*2-1)) + IGL_INLINE int subtree_size() const; + + // Serialize this class into 3 arrays (so we can pass it pack to matlab) + // + // Outputs: + // bb_mins max_tree by dim list of bounding box min corner positions + // bb_maxs max_tree by dim list of bounding box max corner positions + // elements max_tree list of element or (not leaf id) indices into Ele + // i recursive call index into these arrays {0} + template < + typename Derivedbb_mins, + typename Derivedbb_maxs, + typename Derivedelements> + IGL_INLINE void serialize( + Eigen::PlainObjectBase & bb_mins, + Eigen::PlainObjectBase & bb_maxs, + Eigen::PlainObjectBase & elements, + const int i = 0) const; + // Compute squared distance to a query point + // + // Inputs: + // V #V by dim list of vertex positions + // Ele #Ele by dim list of simplex indices + // p dim-long query point + // Outputs: + // i facet index corresponding to smallest distances + // c closest point + // Returns squared distance + // + // Known bugs: currently assumes Elements are triangles regardless of + // dimension. + template + IGL_INLINE Scalar squared_distance( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & Ele, + const RowVectorDIMS & p, + int & i, + Eigen::PlainObjectBase & c) const; +//private: + // Compute squared distance to a query point + // + // Inputs: + // V #V by dim list of vertex positions + // Ele #Ele by dim list of simplex indices + // p dim-long query point + // low_sqr_d lower bound on squared distance, specified maximum squared + // distance + // up_sqr_d current upper bounded on squared distance, current minimum + // squared distance (only consider distances less than this), see + // output. + // Outputs: + // up_sqr_d updated current minimum squared distance + // i facet index corresponding to smallest distances + // c closest point + // Returns squared distance + // + // Known bugs: currently assumes Elements are triangles regardless of + // dimension. + template + IGL_INLINE Scalar squared_distance( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & Ele, + const RowVectorDIMS & p, + const Scalar low_sqr_d, + const Scalar up_sqr_d, + int & i, + Eigen::PlainObjectBase & c) const; + // Default low_sqr_d + template + IGL_INLINE Scalar squared_distance( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & Ele, + const RowVectorDIMS & p, + const Scalar up_sqr_d, + int & i, + Eigen::PlainObjectBase & c) const; + // All hits + template + IGL_INLINE bool intersect_ray( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & Ele, + const RowVectorDIMS & origin, + const RowVectorDIMS & dir, + std::vector & hits) const; + // First hit + template + IGL_INLINE bool intersect_ray( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & Ele, + const RowVectorDIMS & origin, + const RowVectorDIMS & dir, + igl::Hit & hit) const; +//private: + template + IGL_INLINE bool intersect_ray( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & Ele, + const RowVectorDIMS & origin, + const RowVectorDIMS & dir, + const Scalar min_t, + igl::Hit & hit) const; + + +public: + // Compute the squared distance from all query points in P to the + // _closest_ points on the primitives stored in the AABB hierarchy for + // the mesh (V,Ele). + // + // Inputs: + // V #V by dim list of vertex positions + // Ele #Ele by dim list of simplex indices + // P #P by dim list of query points + // Outputs: + // sqrD #P list of squared distances + // I #P list of indices into Ele of closest primitives + // C #P by dim list of closest points + template < + typename DerivedEle, + typename DerivedP, + typename DerivedsqrD, + typename DerivedI, + typename DerivedC> + IGL_INLINE void squared_distance( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & Ele, + const Eigen::MatrixBase & P, + Eigen::PlainObjectBase & sqrD, + Eigen::PlainObjectBase & I, + Eigen::PlainObjectBase & C) const; + + // Compute the squared distance from all query points in P already stored + // in its own AABB hierarchy to the _closest_ points on the primitives + // stored in the AABB hierarchy for the mesh (V,Ele). + // + // Inputs: + // V #V by dim list of vertex positions + // Ele #Ele by dim list of simplex indices + // other AABB hierarchy of another set of primitives (must be points) + // other_V #other_V by dim list of query points + // other_Ele #other_Ele by ss list of simplex indices into other_V + // (must be simple list of points: ss == 1) + // Outputs: + // sqrD #P list of squared distances + // I #P list of indices into Ele of closest primitives + // C #P by dim list of closest points + template < + typename DerivedEle, + typename Derivedother_V, + typename Derivedother_Ele, + typename DerivedsqrD, + typename DerivedI, + typename DerivedC> + IGL_INLINE void squared_distance( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & Ele, + const AABB & other, + const Eigen::MatrixBase & other_V, + const Eigen::MatrixBase & other_Ele, + Eigen::PlainObjectBase & sqrD, + Eigen::PlainObjectBase & I, + Eigen::PlainObjectBase & C) const; +private: + template < + typename DerivedEle, + typename Derivedother_V, + typename Derivedother_Ele, + typename DerivedsqrD, + typename DerivedI, + typename DerivedC> + IGL_INLINE Scalar squared_distance_helper( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & Ele, + const AABB * other, + const Eigen::MatrixBase & other_V, + const Eigen::MatrixBase& other_Ele, + const Scalar up_sqr_d, + Eigen::PlainObjectBase & sqrD, + Eigen::PlainObjectBase & I, + Eigen::PlainObjectBase & C) const; + // Compute the squared distance to the primitive in this node: assumes + // that this is indeed a leaf node. + // + // Inputs: + // V #V by dim list of vertex positions + // Ele #Ele by dim list of simplex indices + // p dim-long query point + // sqr_d current minimum distance for this query, see output + // i current index into Ele of closest point, see output + // c dim-long current closest point, see output + // Outputs: + // sqr_d minimum of initial value and squared distance to this + // primitive + // i possibly updated index into Ele of closest point + // c dim-long possibly updated closest point + template + IGL_INLINE void leaf_squared_distance( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & Ele, + const RowVectorDIMS & p, + const Scalar low_sqr_d, + Scalar & sqr_d, + int & i, + Eigen::PlainObjectBase & c) const; + // Default low_sqr_d + template + IGL_INLINE void leaf_squared_distance( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & Ele, + const RowVectorDIMS & p, + Scalar & sqr_d, + int & i, + Eigen::PlainObjectBase & c) const; + // If new distance (sqr_d_candidate) is less than current distance + // (sqr_d), then update this distance and its associated values + // _in-place_: + // + // Inputs: + // p dim-long query point (only used in DEBUG mode) + // sqr_d candidate minimum distance for this query, see output + // i candidate index into Ele of closest point, see output + // c dim-long candidate closest point, see output + // sqr_d current minimum distance for this query, see output + // i current index into Ele of closest point, see output + // c dim-long current closest point, see output + // Outputs: + // sqr_d minimum of initial value and squared distance to this + // primitive + // i possibly updated index into Ele of closest point + // c dim-long possibly updated closest point + IGL_INLINE void set_min( + const RowVectorDIMS & p, + const Scalar sqr_d_candidate, + const int i_candidate, + const RowVectorDIMS & c_candidate, + Scalar & sqr_d, + int & i, + Eigen::PlainObjectBase & c) const; +public: + EIGEN_MAKE_ALIGNED_OPERATOR_NEW + }; +} + + +#ifndef IGL_STATIC_LIBRARY +# include "AABB.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/ARAPEnergyType.h b/src/external/libigl-2.3.0/include/igl/ARAPEnergyType.h new file mode 100644 index 000000000..68be24f5d --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/ARAPEnergyType.h @@ -0,0 +1,36 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_ARAPENERGYTYPE_H +#define IGL_ARAPENERGYTYPE_H +namespace igl +{ + // ARAP_ENERGY_TYPE_SPOKES "As-rigid-as-possible Surface Modeling" by [Sorkine and + // Alexa 2007], rotations defined at vertices affecting incident edges, + // default + // ARAP_ENERGY_TYPE_SPOKES-AND-RIMS Adapted version of "As-rigid-as-possible Surface + // Modeling" by [Sorkine and Alexa 2007] presented in section 4.2 of or + // "A simple geometric model for elastic deformation" by [Chao et al. + // 2010], rotations defined at vertices affecting incident edges and + // opposite edges + // ARAP_ENERGY_TYPE_ELEMENTS "A local-global approach to mesh parameterization" by + // [Liu et al. 2010] or "A simple geometric model for elastic + // deformation" by [Chao et al. 2010], rotations defined at elements + // (triangles or tets) + // ARAP_ENERGY_TYPE_DEFAULT Choose one automatically: spokes and rims + // for surfaces, elements for planar meshes and tets (not fully + // supported) + enum ARAPEnergyType + { + ARAP_ENERGY_TYPE_SPOKES = 0, + ARAP_ENERGY_TYPE_SPOKES_AND_RIMS = 1, + ARAP_ENERGY_TYPE_ELEMENTS = 2, + ARAP_ENERGY_TYPE_DEFAULT = 3, + NUM_ARAP_ENERGY_TYPES = 4 + }; +} +#endif diff --git a/src/external/libigl-2.3.0/include/igl/AtA_cached.cpp b/src/external/libigl-2.3.0/include/igl/AtA_cached.cpp new file mode 100644 index 000000000..af7d0ad86 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/AtA_cached.cpp @@ -0,0 +1,130 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2017 Daniele Panozzo +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "AtA_cached.h" + +#include +#include +#include + +template +IGL_INLINE void igl::AtA_cached_precompute( + const Eigen::SparseMatrix& A, + igl::AtA_cached_data& data, + Eigen::SparseMatrix& AtA) +{ + // 1 Compute At (this could be avoided, but performance-wise it will not make a difference) + std::vector > Col_RowPtr; + std::vector > Col_IndexPtr; + + Col_RowPtr.resize(A.cols()); + Col_IndexPtr.resize(A.cols()); + + for (unsigned k=0; k= 0); + assert(row < A.rows()); + assert(row >= 0); + assert(value_index >= 0); + assert(value_index < A.nonZeros()); + + Col_RowPtr[col].push_back(row); + Col_IndexPtr[col].push_back(value_index); + } + } + + Eigen::SparseMatrix At = A.transpose(); + At.makeCompressed(); + AtA = At * A; + AtA.makeCompressed(); + + assert(AtA.isCompressed()); + + // If weights are not provided, use 1 + if (data.W.size() == 0) + data.W = Eigen::VectorXd::Ones(A.rows()); + assert(data.W.size() == A.rows()); + + data.I_outer.reserve(AtA.outerSize()); + data.I_row.reserve(2*AtA.nonZeros()); + data.I_col.reserve(2*AtA.nonZeros()); + data.I_w.reserve(2*AtA.nonZeros()); + + // 2 Construct the rules + for (unsigned k=0; k= 0); + assert(row < AtA.rows()); + assert(row >= 0); + assert(value_index >= 0); + assert(value_index < AtA.nonZeros()); + + data.I_outer.push_back(data.I_row.size()); + + // Find correspondences + unsigned i=0; + unsigned j=0; + while (i Col_RowPtr[col][j]) + ++j; + else + ++i; + + } + } + } + data.I_outer.push_back(data.I_row.size()); // makes it more efficient to iterate later on + + igl::AtA_cached(A,data,AtA); +} + +template +IGL_INLINE void igl::AtA_cached( + const Eigen::SparseMatrix& A, + const igl::AtA_cached_data& data, + Eigen::SparseMatrix& AtA) +{ + for (unsigned i=0; i(Eigen::SparseMatrix const&, igl::AtA_cached_data const&, Eigen::SparseMatrix&); +template void igl::AtA_cached_precompute(Eigen::SparseMatrix const&, igl::AtA_cached_data&, Eigen::SparseMatrix&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/AtA_cached.h b/src/external/libigl-2.3.0/include/igl/AtA_cached.h new file mode 100644 index 000000000..776825411 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/AtA_cached.h @@ -0,0 +1,70 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2017 Daniele Panozzo +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_ATA_CACHED_H +#define IGL_ATA_CACHED_H +#include "igl_inline.h" +#define EIGEN_YES_I_KNOW_SPARSE_MODULE_IS_NOT_STABLE_YET +#include +#include +namespace igl +{ + struct AtA_cached_data + { + // Weights + Eigen::VectorXd W; + + // Flatten composition rules + std::vector I_row; + std::vector I_col; + std::vector I_w; + + // For each entry of AtA, points to the beginning + // of the composition rules + std::vector I_outer; + }; + + // Computes At * W * A, where A is sparse and W is diagonal. Divides the + // construction in two phases, one + // for fixing the sparsity pattern, and one to populate it with values. Compared to + // evaluating it directly, this version is slower for the first time (since it requires a + // precomputation), but faster to the subsequent evaluations. + // + // Input: + // A m x n sparse matrix + // data stores the precomputed sparsity pattern, data.W contains the optional diagonal weights (stored as a dense vector). If W is not provided, it is replaced by the identity. + // Outputs: + // AtA m by m matrix computed as AtA * W * A + // + // Example: + // AtA_data = igl::AtA_cached_data(); + // AtA_data.W = W; + // if (s.AtA.rows() == 0) + // igl::AtA_cached_precompute(s.A,s.AtA_data,s.AtA); + // else + // igl::AtA_cached(s.A,s.AtA_data,s.AtA); + template + IGL_INLINE void AtA_cached_precompute( + const Eigen::SparseMatrix& A, + AtA_cached_data& data, + Eigen::SparseMatrix& AtA + ); + + template + IGL_INLINE void AtA_cached( + const Eigen::SparseMatrix& A, + const AtA_cached_data& data, + Eigen::SparseMatrix& AtA + ); + +} + +#ifndef IGL_STATIC_LIBRARY +# include "AtA_cached.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/C_STR.h b/src/external/libigl-2.3.0/include/igl/C_STR.h new file mode 100644 index 000000000..9844b35a5 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/C_STR.h @@ -0,0 +1,18 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_C_STR_H +#define IGL_C_STR_H +// http://stackoverflow.com/a/2433143/148668 +// Suppose you have a function: +// void func(const char * c); +// Then you can write: +// func(C_STR("foo"<<1<<"bar")); +#include +#include +#define C_STR(X) static_cast(std::ostringstream().flush() << X).str().c_str() +#endif diff --git a/src/external/libigl-2.3.0/include/igl/Camera.h b/src/external/libigl-2.3.0/include/igl/Camera.h new file mode 100644 index 000000000..c812df8b4 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/Camera.h @@ -0,0 +1,359 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_CAMERA_H +#define IGL_CAMERA_H + +// you're idiot, M$! +#if defined(_WIN32) +#undef far +#undef near +#endif + +#include +#include +#include "PI.h" + +#define IGL_CAMERA_MIN_ANGLE 5.0 +namespace igl +{ + + // A simple camera class. The camera stores projection parameters (field of + // view angle, aspect ratio, near and far clips) as well as a rigid + // transformation *of the camera as if it were also a scene object*. Thus, the + // **inverse** of this rigid transformation is the modelview transformation. + class Camera + { + public: + // On windows you might need: -fno-delayed-template-parsing + //static constexpr double IGL_CAMERA_MIN_ANGLE = 5.; + // m_angle Field of view angle in degrees {45} + // m_aspect Aspect ratio {1} + // m_near near clipping plane {1e-2} + // m_far far clipping plane {100} + // m_at_dist distance of looking at point {1} + // m_orthographic whether to use othrographic projection {false} + // m_rotation_conj Conjugate of rotation part of rigid transformation of + // camera {identity}. Note: we purposefully store the conjugate because + // this is what TW_TYPE_QUAT4D is expecting. + // m_translation Translation part of rigid transformation of camera + // {(0,0,1)} + double m_angle, m_aspect, m_near, m_far, m_at_dist; + bool m_orthographic; + Eigen::Quaterniond m_rotation_conj; + Eigen::Vector3d m_translation; + public: + inline Camera(); + inline virtual ~Camera(){} + // Return projection matrix that takes relative camera coordinates and + // transforms it to viewport coordinates + // + // Note: + // + // if(m_angle > 0) + // { + // gluPerspective(m_angle,m_aspect,m_near,m_at_dist+m_far); + // }else + // { + // gluOrtho(-0.5*aspect,0.5*aspect,-0.5,0.5,m_at_dist+m_near,m_far); + // } + // + // Is equivalent to + // + // glMultMatrixd(projection().data()); + // + inline Eigen::Matrix4d projection() const; + // Return an Affine transformation (rigid actually) that + // takes relative coordinates and tramsforms them into world 3d + // coordinates: moves the camera into the scene. + inline Eigen::Affine3d affine() const; + // Return an Affine transformation (rigid actually) that puts the takes a + // world 3d coordinate and transforms it into the relative camera + // coordinates: moves the scene in front of the camera. + // + // Note: + // + // gluLookAt( + // eye()(0), eye()(1), eye()(2), + // at()(0), at()(1), at()(2), + // up()(0), up()(1), up()(2)); + // + // Is equivalent to + // + // glMultMatrixd(camera.inverse().matrix().data()); + // + // See also: affine, eye, at, up + inline Eigen::Affine3d inverse() const; + // Returns world coordinates position of center or "eye" of camera. + inline Eigen::Vector3d eye() const; + // Returns world coordinate position of a point "eye" is looking at. + inline Eigen::Vector3d at() const; + // Returns world coordinate unit vector of "up" vector + inline Eigen::Vector3d up() const; + // Return top right corner of unit plane in relative coordinates, that is + // (w/2,h/2,1) + inline Eigen::Vector3d unit_plane() const; + // Move dv in the relative coordinate frame of the camera (move the FPS) + // + // Inputs: + // dv (x,y,z) displacement vector + // + inline void dolly(const Eigen::Vector3d & dv); + // "Scale zoom": Move `eye`, but leave `at` + // + // Input: + // s amount to scale distance to at + inline void push_away(const double s); + // Aka "Hitchcock", "Vertigo", "Spielberg" or "Trombone" zoom: + // simultaneously dolly while changing angle so that `at` not only stays + // put in relative coordinates but also projected coordinates. That is + // + // Inputs: + // da change in angle in degrees + inline void dolly_zoom(const double da); + // Turn around eye so that rotation is now q + // + // Inputs: + // q new rotation as quaternion + inline void turn_eye(const Eigen::Quaterniond & q); + // Orbit around at so that rotation is now q + // + // Inputs: + // q new rotation as quaternion + inline void orbit(const Eigen::Quaterniond & q); + // Rotate and translate so that camera is situated at "eye" looking at "at" + // with "up" pointing up. + // + // Inputs: + // eye (x,y,z) coordinates of eye position + // at (x,y,z) coordinates of at position + // up (x,y,z) coordinates of up vector + inline void look_at( + const Eigen::Vector3d & eye, + const Eigen::Vector3d & at, + const Eigen::Vector3d & up); + // Needed any time Eigen Structures are used as class members + // http://eigen.tuxfamily.org/dox-devel/group__TopicStructHavingEigenMembers.html + public: + EIGEN_MAKE_ALIGNED_OPERATOR_NEW + }; +} + +// Implementation +#include "PI.h" +#include "EPS.h" +#include +#include +#include + +inline igl::Camera::Camera(): + m_angle(45.0),m_aspect(1),m_near(1e-2),m_far(100),m_at_dist(1), + m_orthographic(false), + m_rotation_conj(1,0,0,0), + m_translation(0,0,1) +{ +} + +inline Eigen::Matrix4d igl::Camera::projection() const +{ + Eigen::Matrix4d P; + using namespace std; + const double far = m_at_dist + m_far; + const double near = m_near; + // http://stackoverflow.com/a/3738696/148668 + if(m_orthographic) + { + const double f = 0.5; + const double left = -f*m_aspect; + const double right = f*m_aspect; + const double bottom = -f; + const double top = f; + const double tx = (right+left)/(right-left); + const double ty = (top+bottom)/(top-bottom); + const double tz = (far+near)/(far-near); + const double z_fix = 0.5 /m_at_dist / tan(m_angle*0.5 * (igl::PI/180.) ); + P<< + z_fix*2./(right-left), 0, 0, -tx, + 0, z_fix*2./(top-bottom), 0, -ty, + 0, 0, -z_fix*2./(far-near), -tz, + 0, 0, 0, 1; + }else + { + const double yScale = tan(PI*0.5 - 0.5*m_angle*PI/180.); + // http://stackoverflow.com/a/14975139/148668 + const double xScale = yScale/m_aspect; + P<< + xScale, 0, 0, 0, + 0, yScale, 0, 0, + 0, 0, -(far+near)/(far-near), -1, + 0, 0, -2.*near*far/(far-near), 0; + P = P.transpose().eval(); + } + return P; +} + +inline Eigen::Affine3d igl::Camera::affine() const +{ + using namespace Eigen; + Affine3d t = Affine3d::Identity(); + t.rotate(m_rotation_conj.conjugate()); + t.translate(m_translation); + return t; +} + +inline Eigen::Affine3d igl::Camera::inverse() const +{ + using namespace Eigen; + Affine3d t = Affine3d::Identity(); + t.translate(-m_translation); + t.rotate(m_rotation_conj); + return t; +} + +inline Eigen::Vector3d igl::Camera::eye() const +{ + using namespace Eigen; + return affine() * Vector3d(0,0,0); +} + +inline Eigen::Vector3d igl::Camera::at() const +{ + using namespace Eigen; + return affine() * (Vector3d(0,0,-1)*m_at_dist); +} + +inline Eigen::Vector3d igl::Camera::up() const +{ + using namespace Eigen; + Affine3d t = Affine3d::Identity(); + t.rotate(m_rotation_conj.conjugate()); + return t * Vector3d(0,1,0); +} + +inline Eigen::Vector3d igl::Camera::unit_plane() const +{ + // Distance of center pixel to eye + const double d = 1.0; + const double a = m_aspect; + const double theta = m_angle*PI/180.; + const double w = + 2.*sqrt(-d*d/(a*a*pow(tan(0.5*theta),2.)-1.))*a*tan(0.5*theta); + const double h = w/a; + return Eigen::Vector3d(w*0.5,h*0.5,-d); +} + +inline void igl::Camera::dolly(const Eigen::Vector3d & dv) +{ + m_translation += dv; +} + +inline void igl::Camera::push_away(const double s) +{ + using namespace Eigen; +#ifndef NDEBUG + Vector3d old_at = at(); +#endif + const double old_at_dist = m_at_dist; + m_at_dist = old_at_dist * s; + dolly(Vector3d(0,0,1)*(m_at_dist - old_at_dist)); + assert((old_at-at()).squaredNorm() < DOUBLE_EPS); +} + +inline void igl::Camera::dolly_zoom(const double da) +{ + using namespace std; + using namespace Eigen; +#ifndef NDEBUG + Vector3d old_at = at(); +#endif + const double old_angle = m_angle; + if(old_angle + da < IGL_CAMERA_MIN_ANGLE) + { + m_orthographic = true; + }else if(old_angle + da > IGL_CAMERA_MIN_ANGLE) + { + m_orthographic = false; + } + if(!m_orthographic) + { + m_angle += da; + m_angle = min(89.,max(IGL_CAMERA_MIN_ANGLE,m_angle)); + // change in distance + const double s = + (2.*tan(old_angle/2./180.*igl::PI)) / + (2.*tan(m_angle/2./180.*igl::PI)) ; + const double old_at_dist = m_at_dist; + m_at_dist = old_at_dist * s; + dolly(Vector3d(0,0,1)*(m_at_dist - old_at_dist)); + assert((old_at-at()).squaredNorm() < DOUBLE_EPS); + } +} + +inline void igl::Camera::turn_eye(const Eigen::Quaterniond & q) +{ + using namespace Eigen; + Vector3d old_eye = eye(); + // eye should be fixed + // + // eye_1 = R_1 * t_1 = eye_0 + // t_1 = R_1' * eye_0 + m_rotation_conj = q.conjugate(); + m_translation = m_rotation_conj * old_eye; + assert((old_eye - eye()).squaredNorm() < DOUBLE_EPS); +} + +inline void igl::Camera::orbit(const Eigen::Quaterniond & q) +{ + using namespace Eigen; + Vector3d old_at = at(); + // at should be fixed + // + // at_1 = R_1 * t_1 - R_1 * z = at_0 + // t_1 = R_1' * (at_0 + R_1 * z) + m_rotation_conj = q.conjugate(); + m_translation = + m_rotation_conj * + (old_at + + m_rotation_conj.conjugate() * Vector3d(0,0,1) * m_at_dist); + assert((old_at - at()).squaredNorm() < DOUBLE_EPS); +} + +inline void igl::Camera::look_at( + const Eigen::Vector3d & eye, + const Eigen::Vector3d & at, + const Eigen::Vector3d & up) +{ + using namespace Eigen; + using namespace std; + // http://www.opengl.org/sdk/docs/man2/xhtml/gluLookAt.xml + // Normalize vector from at to eye + Vector3d F = eye-at; + m_at_dist = F.norm(); + F.normalize(); + // Project up onto plane orthogonal to F and normalize + assert(up.cross(F).norm() > DOUBLE_EPS && "(eye-at) x up ≈ 0"); + const Vector3d proj_up = (up-(up.dot(F))*F).normalized(); + Quaterniond a,b; + a.setFromTwoVectors(Vector3d(0,0,-1),-F); + b.setFromTwoVectors(a*Vector3d(0,1,0),proj_up); + m_rotation_conj = (b*a).conjugate(); + m_translation = m_rotation_conj * eye; + //cout<<"m_at_dist: "<eye().transpose()<at().transpose()<eye()-this->at()).normalized().transpose()<eye(): "<<(eye-this->eye()).squaredNorm()<eye()).squaredNorm() < DOUBLE_EPS); + //assert((F-(this->eye()-this->at()).normalized()).squaredNorm() < + // DOUBLE_EPS); + assert( (at-this->at()).squaredNorm() < DOUBLE_EPS); + //assert( (proj_up-this->up()).squaredNorm() < DOUBLE_EPS); +} + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/EPS.cpp b/src/external/libigl-2.3.0/include/igl/EPS.cpp new file mode 100644 index 000000000..fc592cc2a --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/EPS.cpp @@ -0,0 +1,30 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "EPS.h" + +template <> IGL_INLINE float igl::EPS() +{ + return igl::FLOAT_EPS; +} +template <> IGL_INLINE double igl::EPS() +{ + return igl::DOUBLE_EPS; +} + +template <> IGL_INLINE float igl::EPS_SQ() +{ + return igl::FLOAT_EPS_SQ; +} +template <> IGL_INLINE double igl::EPS_SQ() +{ + return igl::DOUBLE_EPS_SQ; +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +#endif diff --git a/src/external/libigl-2.3.0/include/igl/EPS.h b/src/external/libigl-2.3.0/include/igl/EPS.h new file mode 100644 index 000000000..d65007a64 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/EPS.h @@ -0,0 +1,32 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_EPS_H +#define IGL_EPS_H +#include "igl_inline.h" +namespace igl +{ + // Define a standard value for double epsilon + const double DOUBLE_EPS = 1.0e-14; + const double DOUBLE_EPS_SQ = 1.0e-28; + const float FLOAT_EPS = 1.0e-7f; + const float FLOAT_EPS_SQ = 1.0e-14f; + // Function returning EPS for corresponding type + template IGL_INLINE S_type EPS(); + template IGL_INLINE S_type EPS_SQ(); + // Template specializations for float and double + template <> IGL_INLINE float EPS(); + template <> IGL_INLINE double EPS(); + template <> IGL_INLINE float EPS_SQ(); + template <> IGL_INLINE double EPS_SQ(); +} + +#ifndef IGL_STATIC_LIBRARY +# include "EPS.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/FastWindingNumberForSoups.h b/src/external/libigl-2.3.0/include/igl/FastWindingNumberForSoups.h new file mode 100644 index 000000000..215735076 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/FastWindingNumberForSoups.h @@ -0,0 +1,7400 @@ +// This header created by issuing: `echo "// This header created by issuing: \`$BASH_COMMAND\` $(echo "" | cat - LICENSE README.md | sed -e "s#^..*#\/\/ &#") $(echo "" | cat - SYS_Types.h SYS_Math.h VM_SSEFunc.h VM_SIMD.h UT_Array.h UT_ArrayImpl.h UT_SmallArray.h UT_FixedVector.h UT_ParallelUtil.h UT_BVH.h UT_BVHImpl.h UT_SolidAngle.h UT_Array.cpp UT_SolidAngle.cpp | sed -e "s/^#.*include *\".*$//g")" > ../FastWindingNumberForSoups.h` +// MIT License + +// Copyright (c) 2018 Side Effects Software Inc. + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// # Fast Winding Numbers for Soups + +// https://github.com/alecjacobson/WindingNumber + +// Implementation of the _ACM SIGGRAPH_ 2018 paper, + +// "Fast Winding Numbers for Soups and Clouds" + +// Gavin Barill¹, Neil Dickson², Ryan Schmidt³, David I.W. Levin¹, Alec Jacobson¹ + +// ¹University of Toronto, ²SideFX, ³Gradient Space + + +// _Note: this implementation is for triangle soups only, not point clouds._ + +// This version does _not_ depend on Intel TBB. Instead it depends on +// [libigl](https://github.com/libigl/libigl)'s simpler `igl::parallel_for` (which +// uses `std::thread`) + +// This code, as written, depends on Intel's Threading Building Blocks (TBB) library for parallelism, but it should be fairly easy to change it to use any other means of threading, since it only uses parallel for loops with simple partitioning. + +// The main class of interest is UT_SolidAngle and its init and computeSolidAngle functions, which you can use by including UT_SolidAngle.h, and whose implementation is mostly in UT_SolidAngle.cpp, using a 4-way bounding volume hierarchy (BVH) implemented in the UT_BVH.h and UT_BVHImpl.h headers. The rest of the files are mostly various supporting code. UT_SubtendedAngle, for computing angles subtended by 2D curves, can also be found in UT_SolidAngle.h and UT_SolidAngle.cpp . + +// An example of very similar code and how to use it to create a geometry operator (SOP) in Houdini can be found in the HDK examples (toolkit/samples/SOP/SOP_WindingNumber) for Houdini 16.5.121 and later. Query points go in the first input and the mesh geometry goes in the second input. + + +// Create a single header using: + +// echo "// This header created by issuing: \`$BASH_COMMAND\` $(echo "" | cat - LICENSE README.md | sed -e "s#^..*#\/\/&#") $(echo "" | cat - SYS_Types.h SYS_Math.h VM_SSEFunc.h VM_SIMD.h UT_Array.h UT_ArrayImpl.h UT_SmallArray.h UT_FixedVector.h UT_ParallelUtil.h UT_BVH.h UT_BVHImpl.h UT_SolidAngle.h UT_Array.cpp UT_SolidAngle.cpp | sed -e "s/^#.*include *\".*$//g")" +/* + * Copyright (c) 2018 Side Effects Software Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * COMMENTS: + * Common type definitions. + */ + +#pragma once + +#ifndef __SYS_Types__ +#define __SYS_Types__ + +/* Include system types */ +#include +#include +#include +#include + +namespace igl { namespace FastWindingNumber { + +/* + * Integer types + */ +typedef signed char int8; +typedef unsigned char uint8; +typedef short int16; +typedef unsigned short uint16; +typedef int int32; +typedef unsigned int uint32; + +#ifndef MBSD +typedef unsigned int uint; +#endif + +/* + * Avoid using uint64. + * The extra bit of precision is NOT worth the cost in pain and suffering + * induced by use of unsigned. + */ +#if defined(_WIN32) + typedef __int64 int64; + typedef unsigned __int64 uint64; +#elif defined(MBSD) + // On MBSD, int64/uint64 are also defined in the system headers so we must + // declare these in the same way or else we get conflicts. + typedef int64_t int64; + typedef uint64_t uint64; +#elif defined(AMD64) + typedef long int64; + typedef unsigned long uint64; +#else + typedef long long int64; + typedef unsigned long long uint64; +#endif + +/// The problem with int64 is that it implies that it is a fixed 64-bit quantity +/// that is saved to disk. Therefore, we need another integral type for +/// indexing our arrays. +typedef int64 exint; + +/// Mark function to be inlined. If this is done, taking the address of such +/// a function is not allowed. +#if defined(__GNUC__) || defined(__clang__) +#define SYS_FORCE_INLINE __attribute__ ((always_inline)) inline +#elif defined(_MSC_VER) +#define SYS_FORCE_INLINE __forceinline +#else +#define SYS_FORCE_INLINE inline +#endif + +/// Floating Point Types +typedef float fpreal32; +typedef double fpreal64; + +/// SYS_FPRealUnionT for type-safe casting with integral types +template +union SYS_FPRealUnionT; + +template <> +union SYS_FPRealUnionT +{ + typedef int32 int_type; + typedef uint32 uint_type; + typedef fpreal32 fpreal_type; + + enum { + EXPONENT_BITS = 8, + MANTISSA_BITS = 23, + EXPONENT_BIAS = 127 }; + + int_type ival; + uint_type uval; + fpreal_type fval; + + struct + { + uint_type mantissa_val: 23; + uint_type exponent_val: 8; + uint_type sign_val: 1; + }; +}; + +template <> +union SYS_FPRealUnionT +{ + typedef int64 int_type; + typedef uint64 uint_type; + typedef fpreal64 fpreal_type; + + enum { + EXPONENT_BITS = 11, + MANTISSA_BITS = 52, + EXPONENT_BIAS = 1023 }; + + int_type ival; + uint_type uval; + fpreal_type fval; + + struct + { + uint_type mantissa_val: 52; + uint_type exponent_val: 11; + uint_type sign_val: 1; + }; +}; + +typedef union SYS_FPRealUnionT SYS_FPRealUnionF; +typedef union SYS_FPRealUnionT SYS_FPRealUnionD; + +/// Asserts are disabled +/// @{ +#define UT_ASSERT_P(ZZ) ((void)0) +#define UT_ASSERT(ZZ) ((void)0) +#define UT_ASSERT_MSG_P(ZZ, MM) ((void)0) +#define UT_ASSERT_MSG(ZZ, MM) ((void)0) +/// @} +}} + +#endif +/* + * Copyright (c) 2018 Side Effects Software Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * COMMENTS: + * Miscellaneous math functions. + */ + +#pragma once + +#ifndef __SYS_Math__ +#define __SYS_Math__ + + + +#include +#include +#include + +namespace igl { namespace FastWindingNumber { + +// NOTE: +// These have been carefully written so that in the case of equality +// we always return the first parameter. This is so that NANs in +// in the second parameter are suppressed. +#define h_min(a, b) (((a) > (b)) ? (b) : (a)) +#define h_max(a, b) (((a) < (b)) ? (b) : (a)) +// DO NOT CHANGE THE ABOVE WITHOUT READING THE COMMENT +#define h_abs(a) (((a) > 0) ? (a) : -(a)) + +static constexpr inline int16 SYSmin(int16 a, int16 b) { return h_min(a,b); } +static constexpr inline int16 SYSmax(int16 a, int16 b) { return h_max(a,b); } +static constexpr inline int16 SYSabs(int16 a) { return h_abs(a); } +static constexpr inline int32 SYSmin(int32 a, int32 b) { return h_min(a,b); } +static constexpr inline int32 SYSmax(int32 a, int32 b) { return h_max(a,b); } +static constexpr inline int32 SYSabs(int32 a) { return h_abs(a); } +static constexpr inline int64 SYSmin(int64 a, int64 b) { return h_min(a,b); } +static constexpr inline int64 SYSmax(int64 a, int64 b) { return h_max(a,b); } +static constexpr inline int64 SYSmin(int32 a, int64 b) { return h_min(a,b); } +static constexpr inline int64 SYSmax(int32 a, int64 b) { return h_max(a,b); } +static constexpr inline int64 SYSmin(int64 a, int32 b) { return h_min(a,b); } +static constexpr inline int64 SYSmax(int64 a, int32 b) { return h_max(a,b); } +static constexpr inline int64 SYSabs(int64 a) { return h_abs(a); } +static constexpr inline uint16 SYSmin(uint16 a, uint16 b) { return h_min(a,b); } +static constexpr inline uint16 SYSmax(uint16 a, uint16 b) { return h_max(a,b); } +static constexpr inline uint32 SYSmin(uint32 a, uint32 b) { return h_min(a,b); } +static constexpr inline uint32 SYSmax(uint32 a, uint32 b) { return h_max(a,b); } +static constexpr inline uint64 SYSmin(uint64 a, uint64 b) { return h_min(a,b); } +static constexpr inline uint64 SYSmax(uint64 a, uint64 b) { return h_max(a,b); } +static constexpr inline fpreal32 SYSmin(fpreal32 a, fpreal32 b) { return h_min(a,b); } +static constexpr inline fpreal32 SYSmax(fpreal32 a, fpreal32 b) { return h_max(a,b); } +static constexpr inline fpreal64 SYSmin(fpreal64 a, fpreal64 b) { return h_min(a,b); } +static constexpr inline fpreal64 SYSmax(fpreal64 a, fpreal64 b) { return h_max(a,b); } + +// Some systems have size_t as a seperate type from uint. Some don't. +#if (defined(LINUX) && defined(IA64)) || defined(MBSD) +static constexpr inline size_t SYSmin(size_t a, size_t b) { return h_min(a,b); } +static constexpr inline size_t SYSmax(size_t a, size_t b) { return h_max(a,b); } +#endif + +#undef h_min +#undef h_max +#undef h_abs + +#define h_clamp(val, min, max, tol) \ + ((val <= min+tol) ? min : ((val >= max-tol) ? max : val)) + + static constexpr inline int + SYSclamp(int v, int min, int max) + { return h_clamp(v, min, max, 0); } + + static constexpr inline uint + SYSclamp(uint v, uint min, uint max) + { return h_clamp(v, min, max, 0); } + + static constexpr inline int64 + SYSclamp(int64 v, int64 min, int64 max) + { return h_clamp(v, min, max, int64(0)); } + + static constexpr inline uint64 + SYSclamp(uint64 v, uint64 min, uint64 max) + { return h_clamp(v, min, max, uint64(0)); } + + static constexpr inline fpreal32 + SYSclamp(fpreal32 v, fpreal32 min, fpreal32 max, fpreal32 tol=(fpreal32)0) + { return h_clamp(v, min, max, tol); } + + static constexpr inline fpreal64 + SYSclamp(fpreal64 v, fpreal64 min, fpreal64 max, fpreal64 tol=(fpreal64)0) + { return h_clamp(v, min, max, tol); } + +#undef h_clamp + +static inline fpreal64 SYSsqrt(fpreal64 arg) +{ return ::sqrt(arg); } +static inline fpreal32 SYSsqrt(fpreal32 arg) +{ return ::sqrtf(arg); } +static inline fpreal64 SYSatan2(fpreal64 a, fpreal64 b) +{ return ::atan2(a, b); } +static inline fpreal32 SYSatan2(fpreal32 a, fpreal32 b) +{ return ::atan2(a, b); } + +static inline fpreal32 SYSabs(fpreal32 a) { return ::fabsf(a); } +static inline fpreal64 SYSabs(fpreal64 a) { return ::fabs(a); } + +}} + +#endif +/* + * Copyright (c) 2018 Side Effects Software Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * COMMENTS: + * SIMD wrapper functions for SSE instructions + */ + +#pragma once + +#ifndef __VM_SSEFunc__ +#define __VM_SSEFunc__ + + + +#if defined(_MSC_VER) + #pragma warning(push) + #pragma warning(disable:4799) +#endif + +#define CPU_HAS_SIMD_INSTR 1 +#define VM_SSE_STYLE 1 + +#include + +#if defined(__SSE4_1__) +#define VM_SSE41_STYLE 1 +#include +#endif + +#if defined(_MSC_VER) + #pragma warning(pop) +#endif + +namespace igl { namespace FastWindingNumber { + +typedef __m128 v4sf; +typedef __m128i v4si; + +// Plain casting (no conversion) +// MSVC has problems casting between __m128 and __m128i, so we implement a +// custom casting routine specifically for windows. + +#if defined(_MSC_VER) + +static SYS_FORCE_INLINE v4sf +vm_v4sf(const v4si &a) +{ + union { + v4si ival; + v4sf fval; + }; + ival = a; + return fval; +} + +static SYS_FORCE_INLINE v4si +vm_v4si(const v4sf &a) +{ + union { + v4si ival; + v4sf fval; + }; + fval = a; + return ival; +} + +#define V4SF(A) vm_v4sf(A) +#define V4SI(A) vm_v4si(A) + +#else + +#define V4SF(A) (v4sf)A +#define V4SI(A) (v4si)A + +#endif + +#define VM_SHUFFLE_MASK(a0,a1, b0,b1) ((b1)<<6|(b0)<<4 | (a1)<<2|(a0)) + +template +static SYS_FORCE_INLINE v4sf +vm_shuffle(const v4sf &a, const v4sf &b) +{ + return _mm_shuffle_ps(a, b, mask); +} + +template +static SYS_FORCE_INLINE v4si +vm_shuffle(const v4si &a, const v4si &b) +{ + return V4SI(_mm_shuffle_ps(V4SF(a), V4SF(b), mask)); +} + +template +static SYS_FORCE_INLINE T +vm_shuffle(const T &a, const T &b) +{ + return vm_shuffle(a, b); +} + +template +static SYS_FORCE_INLINE T +vm_shuffle(const T &a) +{ + return vm_shuffle(a, a); +} + +template +static SYS_FORCE_INLINE T +vm_shuffle(const T &a) +{ + return vm_shuffle(a, a); +} + +#if defined(VM_SSE41_STYLE) + +static SYS_FORCE_INLINE v4si +vm_insert(const v4si v, int32 a, int n) +{ + switch (n) + { + case 0: return _mm_insert_epi32(v, a, 0); + case 1: return _mm_insert_epi32(v, a, 1); + case 2: return _mm_insert_epi32(v, a, 2); + case 3: return _mm_insert_epi32(v, a, 3); + } + return v; +} + +static SYS_FORCE_INLINE v4sf +vm_insert(const v4sf v, float a, int n) +{ + switch (n) + { + case 0: return _mm_insert_ps(v, _mm_set_ss(a), _MM_MK_INSERTPS_NDX(0,0,0)); + case 1: return _mm_insert_ps(v, _mm_set_ss(a), _MM_MK_INSERTPS_NDX(0,1,0)); + case 2: return _mm_insert_ps(v, _mm_set_ss(a), _MM_MK_INSERTPS_NDX(0,2,0)); + case 3: return _mm_insert_ps(v, _mm_set_ss(a), _MM_MK_INSERTPS_NDX(0,3,0)); + } + return v; +} + +static SYS_FORCE_INLINE int +vm_extract(const v4si v, int n) +{ + switch (n) + { + case 0: return _mm_extract_epi32(v, 0); + case 1: return _mm_extract_epi32(v, 1); + case 2: return _mm_extract_epi32(v, 2); + case 3: return _mm_extract_epi32(v, 3); + } + return 0; +} + +static SYS_FORCE_INLINE float +vm_extract(const v4sf v, int n) +{ + SYS_FPRealUnionF tmp; + switch (n) + { + case 0: tmp.ival = _mm_extract_ps(v, 0); break; + case 1: tmp.ival = _mm_extract_ps(v, 1); break; + case 2: tmp.ival = _mm_extract_ps(v, 2); break; + case 3: tmp.ival = _mm_extract_ps(v, 3); break; + } + return tmp.fval; +} + +#else + +static SYS_FORCE_INLINE v4si +vm_insert(const v4si v, int32 a, int n) +{ + union { v4si vector; int32 comp[4]; }; + vector = v; + comp[n] = a; + return vector; +} + +static SYS_FORCE_INLINE v4sf +vm_insert(const v4sf v, float a, int n) +{ + union { v4sf vector; float comp[4]; }; + vector = v; + comp[n] = a; + return vector; +} + +static SYS_FORCE_INLINE int +vm_extract(const v4si v, int n) +{ + union { v4si vector; int32 comp[4]; }; + vector = v; + return comp[n]; +} + +static SYS_FORCE_INLINE float +vm_extract(const v4sf v, int n) +{ + union { v4sf vector; float comp[4]; }; + vector = v; + return comp[n]; +} + +#endif + +static SYS_FORCE_INLINE v4sf +vm_splats(float a) +{ + return _mm_set1_ps(a); +} + +static SYS_FORCE_INLINE v4si +vm_splats(uint32 a) +{ + SYS_FPRealUnionF tmp; + tmp.uval = a; + return V4SI(vm_splats(tmp.fval)); +} + +static SYS_FORCE_INLINE v4si +vm_splats(int32 a) +{ + SYS_FPRealUnionF tmp; + tmp.ival = a; + return V4SI(vm_splats(tmp.fval)); +} + +static SYS_FORCE_INLINE v4sf +vm_splats(float a, float b, float c, float d) +{ + return vm_shuffle<0,2,0,2>( + vm_shuffle<0>(_mm_set_ss(a), _mm_set_ss(b)), + vm_shuffle<0>(_mm_set_ss(c), _mm_set_ss(d))); +} + +static SYS_FORCE_INLINE v4si +vm_splats(uint32 a, uint32 b, uint32 c, uint32 d) +{ + SYS_FPRealUnionF af, bf, cf, df; + af.uval = a; + bf.uval = b; + cf.uval = c; + df.uval = d; + return V4SI(vm_splats(af.fval, bf.fval, cf.fval, df.fval)); +} + +static SYS_FORCE_INLINE v4si +vm_splats(int32 a, int32 b, int32 c, int32 d) +{ + SYS_FPRealUnionF af, bf, cf, df; + af.ival = a; + bf.ival = b; + cf.ival = c; + df.ival = d; + return V4SI(vm_splats(af.fval, bf.fval, cf.fval, df.fval)); +} + +static SYS_FORCE_INLINE v4si +vm_load(const int32 v[4]) +{ + return V4SI(_mm_loadu_ps((const float *)v)); +} + +static SYS_FORCE_INLINE v4sf +vm_load(const float v[4]) +{ + return _mm_loadu_ps(v); +} + +static SYS_FORCE_INLINE void +vm_store(float dst[4], v4sf value) +{ + _mm_storeu_ps(dst, value); +} + +static SYS_FORCE_INLINE v4sf +vm_negate(v4sf a) +{ + return _mm_sub_ps(_mm_setzero_ps(), a); +} + +static SYS_FORCE_INLINE v4sf +vm_abs(v4sf a) +{ + return _mm_max_ps(a, vm_negate(a)); +} + +static SYS_FORCE_INLINE v4sf +vm_fdiv(v4sf a, v4sf b) +{ + return _mm_mul_ps(a, _mm_rcp_ps(b)); +} + +static SYS_FORCE_INLINE v4sf +vm_fsqrt(v4sf a) +{ + return _mm_rcp_ps(_mm_rsqrt_ps(a)); +} + +static SYS_FORCE_INLINE v4sf +vm_madd(v4sf a, v4sf b, v4sf c) +{ + return _mm_add_ps(_mm_mul_ps(a, b), c); +} + +static const v4si theSSETrue = vm_splats(0xFFFFFFFF); + +static SYS_FORCE_INLINE bool +vm_allbits(const v4si &a) +{ + return _mm_movemask_ps(V4SF(_mm_cmpeq_epi32(a, theSSETrue))) == 0xF; +} + + +#define VM_EXTRACT vm_extract +#define VM_INSERT vm_insert +#define VM_SPLATS vm_splats +#define VM_LOAD vm_load +#define VM_STORE vm_store + +#define VM_CMPLT(A,B) V4SI(_mm_cmplt_ps(A,B)) +#define VM_CMPLE(A,B) V4SI(_mm_cmple_ps(A,B)) +#define VM_CMPGT(A,B) V4SI(_mm_cmpgt_ps(A,B)) +#define VM_CMPGE(A,B) V4SI(_mm_cmpge_ps(A,B)) +#define VM_CMPEQ(A,B) V4SI(_mm_cmpeq_ps(A,B)) +#define VM_CMPNE(A,B) V4SI(_mm_cmpneq_ps(A,B)) + +#define VM_ICMPLT _mm_cmplt_epi32 +#define VM_ICMPGT _mm_cmpgt_epi32 +#define VM_ICMPEQ _mm_cmpeq_epi32 + +#define VM_IADD _mm_add_epi32 +#define VM_ISUB _mm_sub_epi32 + +#define VM_ADD _mm_add_ps +#define VM_SUB _mm_sub_ps +#define VM_MUL _mm_mul_ps +#define VM_DIV _mm_div_ps +#define VM_SQRT _mm_sqrt_ps +#define VM_ISQRT _mm_rsqrt_ps +#define VM_INVERT _mm_rcp_ps +#define VM_ABS vm_abs + +#define VM_FDIV vm_fdiv +#define VM_NEG vm_negate +#define VM_FSQRT vm_fsqrt +#define VM_MADD vm_madd + +#define VM_MIN _mm_min_ps +#define VM_MAX _mm_max_ps + +#define VM_AND _mm_and_si128 +#define VM_ANDNOT _mm_andnot_si128 +#define VM_OR _mm_or_si128 +#define VM_XOR _mm_xor_si128 + +#define VM_ALLBITS vm_allbits + +#define VM_SHUFFLE vm_shuffle + +// Integer to float conversions +#define VM_SSE_ROUND_MASK 0x6000 +#define VM_SSE_ROUND_ZERO 0x6000 +#define VM_SSE_ROUND_UP 0x4000 +#define VM_SSE_ROUND_DOWN 0x2000 +#define VM_SSE_ROUND_NEAR 0x0000 + +#define GETROUND() (_mm_getcsr()&VM_SSE_ROUND_MASK) +#define SETROUND(x) (_mm_setcsr(x|(_mm_getcsr()&~VM_SSE_ROUND_MASK))) + +// The P functions must be invoked before FLOOR, the E functions invoked +// afterwards to reset the state. + +#define VM_P_FLOOR() uint rounding = GETROUND(); \ + SETROUND(VM_SSE_ROUND_DOWN); +#define VM_FLOOR _mm_cvtps_epi32 +#define VM_INT _mm_cvttps_epi32 +#define VM_E_FLOOR() SETROUND(rounding); + +// Float to integer conversion +#define VM_IFLOAT _mm_cvtepi32_ps +}} + +#endif +/* + * Copyright (c) 2018 Side Effects Software Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * COMMENTS: + * SIMD wrapper classes for 4 floats or 4 ints + */ + +#pragma once + +#ifndef __HDK_VM_SIMD__ +#define __HDK_VM_SIMD__ + + +#include + +//#define FORCE_NON_SIMD + + +namespace igl { namespace FastWindingNumber { + +class v4uf; + +class v4uu { +public: + SYS_FORCE_INLINE v4uu() {} + SYS_FORCE_INLINE v4uu(const v4si &v) : vector(v) {} + SYS_FORCE_INLINE v4uu(const v4uu &v) : vector(v.vector) {} + explicit SYS_FORCE_INLINE v4uu(int32 v) { vector = VM_SPLATS(v); } + explicit SYS_FORCE_INLINE v4uu(const int32 v[4]) + { vector = VM_LOAD(v); } + SYS_FORCE_INLINE v4uu(int32 a, int32 b, int32 c, int32 d) + { vector = VM_SPLATS(a, b, c, d); } + + // Assignment + SYS_FORCE_INLINE v4uu operator=(int32 v) + { vector = v4uu(v).vector; return *this; } + SYS_FORCE_INLINE v4uu operator=(v4si v) + { vector = v; return *this; } + SYS_FORCE_INLINE v4uu operator=(const v4uu &v) + { vector = v.vector; return *this; } + + SYS_FORCE_INLINE void condAssign(const v4uu &val, const v4uu &c) + { *this = (c & val) | ((!c) & *this); } + + // Comparison + SYS_FORCE_INLINE v4uu operator == (const v4uu &v) const + { return v4uu(VM_ICMPEQ(vector, v.vector)); } + SYS_FORCE_INLINE v4uu operator != (const v4uu &v) const + { return ~(*this == v); } + SYS_FORCE_INLINE v4uu operator > (const v4uu &v) const + { return v4uu(VM_ICMPGT(vector, v.vector)); } + SYS_FORCE_INLINE v4uu operator < (const v4uu &v) const + { return v4uu(VM_ICMPLT(vector, v.vector)); } + SYS_FORCE_INLINE v4uu operator >= (const v4uu &v) const + { return ~(*this < v); } + SYS_FORCE_INLINE v4uu operator <= (const v4uu &v) const + { return ~(*this > v); } + + SYS_FORCE_INLINE v4uu operator == (int32 v) const { return *this == v4uu(v); } + SYS_FORCE_INLINE v4uu operator != (int32 v) const { return *this != v4uu(v); } + SYS_FORCE_INLINE v4uu operator > (int32 v) const { return *this > v4uu(v); } + SYS_FORCE_INLINE v4uu operator < (int32 v) const { return *this < v4uu(v); } + SYS_FORCE_INLINE v4uu operator >= (int32 v) const { return *this >= v4uu(v); } + SYS_FORCE_INLINE v4uu operator <= (int32 v) const { return *this <= v4uu(v); } + + // Basic math + SYS_FORCE_INLINE v4uu operator+(const v4uu &r) const + { return v4uu(VM_IADD(vector, r.vector)); } + SYS_FORCE_INLINE v4uu operator-(const v4uu &r) const + { return v4uu(VM_ISUB(vector, r.vector)); } + SYS_FORCE_INLINE v4uu operator+=(const v4uu &r) { return (*this = *this + r); } + SYS_FORCE_INLINE v4uu operator-=(const v4uu &r) { return (*this = *this - r); } + SYS_FORCE_INLINE v4uu operator+(int32 r) const { return *this + v4uu(r); } + SYS_FORCE_INLINE v4uu operator-(int32 r) const { return *this - v4uu(r); } + SYS_FORCE_INLINE v4uu operator+=(int32 r) { return (*this = *this + r); } + SYS_FORCE_INLINE v4uu operator-=(int32 r) { return (*this = *this - r); } + + // logical/bitwise + + SYS_FORCE_INLINE v4uu operator||(const v4uu &r) const + { return v4uu(VM_OR(vector, r.vector)); } + SYS_FORCE_INLINE v4uu operator&&(const v4uu &r) const + { return v4uu(VM_AND(vector, r.vector)); } + SYS_FORCE_INLINE v4uu operator^(const v4uu &r) const + { return v4uu(VM_XOR(vector, r.vector)); } + SYS_FORCE_INLINE v4uu operator!() const + { return *this == v4uu(0); } + + SYS_FORCE_INLINE v4uu operator|(const v4uu &r) const { return *this || r; } + SYS_FORCE_INLINE v4uu operator&(const v4uu &r) const { return *this && r; } + SYS_FORCE_INLINE v4uu operator~() const + { return *this ^ v4uu(0xFFFFFFFF); } + + // component + SYS_FORCE_INLINE int32 operator[](int idx) const { return VM_EXTRACT(vector, idx); } + SYS_FORCE_INLINE void setComp(int idx, int32 v) { vector = VM_INSERT(vector, v, idx); } + + v4uf toFloat() const; + +public: + v4si vector; +}; + +class v4uf { +public: + SYS_FORCE_INLINE v4uf() {} + SYS_FORCE_INLINE v4uf(const v4sf &v) : vector(v) {} + SYS_FORCE_INLINE v4uf(const v4uf &v) : vector(v.vector) {} + explicit SYS_FORCE_INLINE v4uf(float v) { vector = VM_SPLATS(v); } + explicit SYS_FORCE_INLINE v4uf(const float v[4]) + { vector = VM_LOAD(v); } + SYS_FORCE_INLINE v4uf(float a, float b, float c, float d) + { vector = VM_SPLATS(a, b, c, d); } + + // Assignment + SYS_FORCE_INLINE v4uf operator=(float v) + { vector = v4uf(v).vector; return *this; } + SYS_FORCE_INLINE v4uf operator=(v4sf v) + { vector = v; return *this; } + SYS_FORCE_INLINE v4uf operator=(const v4uf &v) + { vector = v.vector; return *this; } + + SYS_FORCE_INLINE void condAssign(const v4uf &val, const v4uu &c) + { *this = (val & c) | (*this & ~c); } + + // Comparison + SYS_FORCE_INLINE v4uu operator == (const v4uf &v) const + { return v4uu(VM_CMPEQ(vector, v.vector)); } + SYS_FORCE_INLINE v4uu operator != (const v4uf &v) const + { return v4uu(VM_CMPNE(vector, v.vector)); } + SYS_FORCE_INLINE v4uu operator > (const v4uf &v) const + { return v4uu(VM_CMPGT(vector, v.vector)); } + SYS_FORCE_INLINE v4uu operator < (const v4uf &v) const + { return v4uu(VM_CMPLT(vector, v.vector)); } + SYS_FORCE_INLINE v4uu operator >= (const v4uf &v) const + { return v4uu(VM_CMPGE(vector, v.vector)); } + SYS_FORCE_INLINE v4uu operator <= (const v4uf &v) const + { return v4uu(VM_CMPLE(vector, v.vector)); } + + SYS_FORCE_INLINE v4uu operator == (float v) const { return *this == v4uf(v); } + SYS_FORCE_INLINE v4uu operator != (float v) const { return *this != v4uf(v); } + SYS_FORCE_INLINE v4uu operator > (float v) const { return *this > v4uf(v); } + SYS_FORCE_INLINE v4uu operator < (float v) const { return *this < v4uf(v); } + SYS_FORCE_INLINE v4uu operator >= (float v) const { return *this >= v4uf(v); } + SYS_FORCE_INLINE v4uu operator <= (float v) const { return *this <= v4uf(v); } + + + // Basic math + SYS_FORCE_INLINE v4uf operator+(const v4uf &r) const + { return v4uf(VM_ADD(vector, r.vector)); } + SYS_FORCE_INLINE v4uf operator-(const v4uf &r) const + { return v4uf(VM_SUB(vector, r.vector)); } + SYS_FORCE_INLINE v4uf operator-() const + { return v4uf(VM_NEG(vector)); } + SYS_FORCE_INLINE v4uf operator*(const v4uf &r) const + { return v4uf(VM_MUL(vector, r.vector)); } + SYS_FORCE_INLINE v4uf operator/(const v4uf &r) const + { return v4uf(VM_DIV(vector, r.vector)); } + + SYS_FORCE_INLINE v4uf operator+=(const v4uf &r) { return (*this = *this + r); } + SYS_FORCE_INLINE v4uf operator-=(const v4uf &r) { return (*this = *this - r); } + SYS_FORCE_INLINE v4uf operator*=(const v4uf &r) { return (*this = *this * r); } + SYS_FORCE_INLINE v4uf operator/=(const v4uf &r) { return (*this = *this / r); } + + SYS_FORCE_INLINE v4uf operator+(float r) const { return *this + v4uf(r); } + SYS_FORCE_INLINE v4uf operator-(float r) const { return *this - v4uf(r); } + SYS_FORCE_INLINE v4uf operator*(float r) const { return *this * v4uf(r); } + SYS_FORCE_INLINE v4uf operator/(float r) const { return *this / v4uf(r); } + SYS_FORCE_INLINE v4uf operator+=(float r) { return (*this = *this + r); } + SYS_FORCE_INLINE v4uf operator-=(float r) { return (*this = *this - r); } + SYS_FORCE_INLINE v4uf operator*=(float r) { return (*this = *this * r); } + SYS_FORCE_INLINE v4uf operator/=(float r) { return (*this = *this / r); } + + // logical/bitwise + + SYS_FORCE_INLINE v4uf operator||(const v4uu &r) const + { return v4uf(V4SF(VM_OR(V4SI(vector), r.vector))); } + SYS_FORCE_INLINE v4uf operator&&(const v4uu &r) const + { return v4uf(V4SF(VM_AND(V4SI(vector), r.vector))); } + SYS_FORCE_INLINE v4uf operator^(const v4uu &r) const + { return v4uf(V4SF(VM_XOR(V4SI(vector), r.vector))); } + SYS_FORCE_INLINE v4uf operator!() const + { return v4uf(V4SF((*this == v4uf(0.0F)).vector)); } + + SYS_FORCE_INLINE v4uf operator||(const v4uf &r) const + { return v4uf(V4SF(VM_OR(V4SI(vector), V4SI(r.vector)))); } + SYS_FORCE_INLINE v4uf operator&&(const v4uf &r) const + { return v4uf(V4SF(VM_AND(V4SI(vector), V4SI(r.vector)))); } + SYS_FORCE_INLINE v4uf operator^(const v4uf &r) const + { return v4uf(V4SF(VM_XOR(V4SI(vector), V4SI(r.vector)))); } + + SYS_FORCE_INLINE v4uf operator|(const v4uu &r) const { return *this || r; } + SYS_FORCE_INLINE v4uf operator&(const v4uu &r) const { return *this && r; } + SYS_FORCE_INLINE v4uf operator~() const + { return *this ^ v4uu(0xFFFFFFFF); } + + SYS_FORCE_INLINE v4uf operator|(const v4uf &r) const { return *this || r; } + SYS_FORCE_INLINE v4uf operator&(const v4uf &r) const { return *this && r; } + + // component + SYS_FORCE_INLINE float operator[](int idx) const { return VM_EXTRACT(vector, idx); } + SYS_FORCE_INLINE void setComp(int idx, float v) { vector = VM_INSERT(vector, v, idx); } + + // more math + SYS_FORCE_INLINE v4uf abs() const { return v4uf(VM_ABS(vector)); } + SYS_FORCE_INLINE v4uf clamp(const v4uf &low, const v4uf &high) const + { return v4uf( + VM_MIN(VM_MAX(vector, low.vector), high.vector)); } + SYS_FORCE_INLINE v4uf clamp(float low, float high) const + { return v4uf(VM_MIN(VM_MAX(vector, + v4uf(low).vector), v4uf(high).vector)); } + SYS_FORCE_INLINE v4uf recip() const { return v4uf(VM_INVERT(vector)); } + + /// This is a lie, it is a signed int. + SYS_FORCE_INLINE v4uu toUnsignedInt() const { return VM_INT(vector); } + SYS_FORCE_INLINE v4uu toSignedInt() const { return VM_INT(vector); } + + v4uu floor() const + { + VM_P_FLOOR(); + v4uu result = VM_FLOOR(vector); + VM_E_FLOOR(); + return result; + } + + /// Returns the integer part of this float, this becomes the + /// 0..1 fractional component. + v4uu splitFloat() + { + v4uu base = toSignedInt(); + *this -= base.toFloat(); + return base; + } + + template + SYS_FORCE_INLINE v4uf swizzle() const + { + return VM_SHUFFLE(vector); + } + + SYS_FORCE_INLINE v4uu isFinite() const + { + // If the exponent is the maximum value, it's either infinite or NaN. + const v4si mask = VM_SPLATS(0x7F800000); + return ~v4uu(VM_ICMPEQ(VM_AND(V4SI(vector), mask), mask)); + } + +public: + v4sf vector; +}; + +SYS_FORCE_INLINE v4uf +v4uu::toFloat() const +{ + return v4uf(VM_IFLOAT(vector)); +} + +// +// Custom vector operations +// + +static SYS_FORCE_INLINE v4uf +sqrt(const v4uf &a) +{ + return v4uf(VM_SQRT(a.vector)); +} + +static SYS_FORCE_INLINE v4uf +fabs(const v4uf &a) +{ + return a.abs(); +} + +// Use this operation to mask disabled values to 0 +// rval = !a ? b : 0; + +static SYS_FORCE_INLINE v4uf +andn(const v4uu &a, const v4uf &b) +{ + return v4uf(V4SF(VM_ANDNOT(a.vector, V4SI(b.vector)))); +} + +static SYS_FORCE_INLINE v4uu +andn(const v4uu &a, const v4uu &b) +{ + return v4uu(VM_ANDNOT(a.vector, b.vector)); +} + +// rval = a ? b : c; +static SYS_FORCE_INLINE v4uf +ternary(const v4uu &a, const v4uf &b, const v4uf &c) +{ + return (b & a) | andn(a, c); +} + +static SYS_FORCE_INLINE v4uu +ternary(const v4uu &a, const v4uu &b, const v4uu &c) +{ + return (b & a) | andn(a, c); +} + +// rval = !(a && b) +static SYS_FORCE_INLINE v4uu +nand(const v4uu &a, const v4uu &b) +{ + return !v4uu(VM_AND(a.vector, b.vector)); +} + +static SYS_FORCE_INLINE v4uf +vmin(const v4uf &a, const v4uf &b) +{ + return v4uf(VM_MIN(a.vector, b.vector)); +} + +static SYS_FORCE_INLINE v4uf +vmax(const v4uf &a, const v4uf &b) +{ + return v4uf(VM_MAX(a.vector, b.vector)); +} + +static SYS_FORCE_INLINE v4uf +clamp(const v4uf &a, const v4uf &b, const v4uf &c) +{ + return vmax(vmin(a, c), b); +} + +static SYS_FORCE_INLINE v4uf +clamp(const v4uf &a, float b, float c) +{ + return vmax(vmin(a, v4uf(c)), v4uf(b)); +} + +static SYS_FORCE_INLINE bool +allbits(const v4uu &a) +{ + return vm_allbits(a.vector); +} + +static SYS_FORCE_INLINE bool +anybits(const v4uu &a) +{ + return !allbits(~a); +} + +static SYS_FORCE_INLINE v4uf +madd(const v4uf &v, const v4uf &f, const v4uf &a) +{ + return v4uf(VM_MADD(v.vector, f.vector, a.vector)); +} + +static SYS_FORCE_INLINE v4uf +madd(const v4uf &v, float f, float a) +{ + return v4uf(VM_MADD(v.vector, v4uf(f).vector, v4uf(a).vector)); +} + +static SYS_FORCE_INLINE v4uf +madd(const v4uf &v, float f, const v4uf &a) +{ + return v4uf(VM_MADD(v.vector, v4uf(f).vector, a.vector)); +} + +static SYS_FORCE_INLINE v4uf +msub(const v4uf &v, const v4uf &f, const v4uf &s) +{ + return madd(v, f, -s); +} + +static SYS_FORCE_INLINE v4uf +msub(const v4uf &v, float f, float s) +{ + return madd(v, f, -s); +} + +static SYS_FORCE_INLINE v4uf +lerp(const v4uf &a, const v4uf &b, const v4uf &w) +{ + v4uf w1 = v4uf(1.0F) - w; + return madd(a, w1, b*w); +} + +static SYS_FORCE_INLINE v4uf +luminance(const v4uf &r, const v4uf &g, const v4uf &b, + float rw, float gw, float bw) +{ + return v4uf(madd(r, v4uf(rw), madd(g, v4uf(gw), b * bw))); +} + +static SYS_FORCE_INLINE float +dot3(const v4uf &a, const v4uf &b) +{ + v4uf res = a*b; + return res[0] + res[1] + res[2]; +} + +static SYS_FORCE_INLINE float +dot4(const v4uf &a, const v4uf &b) +{ + v4uf res = a*b; + return res[0] + res[1] + res[2] + res[3]; +} + +static SYS_FORCE_INLINE float +length(const v4uf &a) +{ + return SYSsqrt(dot3(a, a)); +} + +static SYS_FORCE_INLINE v4uf +normalize(const v4uf &a) +{ + return a / length(a); +} + +static SYS_FORCE_INLINE v4uf +cross(const v4uf &a, const v4uf &b) +{ + return v4uf(a[1]*b[2] - a[2]*b[1], + a[2]*b[0] - a[0]*b[2], + a[0]*b[1] - a[1]*b[0], 0); +} + +// Currently there is no specific support for signed integers +typedef v4uu v4ui; + +// Assuming that ptr is an array of elements of type STYPE, this operation +// will return the index of the first element that is aligned to (1< +#include +#include +#include + +namespace igl { namespace FastWindingNumber { + + /// This routine describes how to change the size of an array. + /// It must increase the current_size by at least one! + /// + /// Current expected sequence of small sizes: + /// 4, 8, 16, 32, 48, 64, 80, 96, 112, + /// 128, 256, 384, 512, 640, 768, 896, 1024, + /// (increases by approx factor of 1.125 each time after this) +template +static inline T +UTbumpAlloc(T current_size) +{ + // NOTE: These must be powers of two. See below. + constexpr T SMALL_ALLOC(16); + constexpr T BIG_ALLOC(128); + + // For small values, we increment by fixed amounts. For + // large values, we increment by one eighth of the current size. + // This prevents n^2 behaviour with allocation one element at a time. + // A factor of 1/8 will waste 1/16 the memory on average, and will + // double the size of the array in approximately 6 reallocations. + if (current_size < T(8)) + { + return (current_size < T(4)) ? T(4) : T(8); + } + if (current_size < T(BIG_ALLOC)) + { + // Snap up to next multiple of SMALL_ALLOC (must be power of 2) + return (current_size + T(SMALL_ALLOC)) & ~T(SMALL_ALLOC-1); + } + if (current_size < T(BIG_ALLOC * 8)) + { + // Snap up to next multiple of BIG_ALLOC (must be power of 2) + return (current_size + T(BIG_ALLOC)) & ~T(BIG_ALLOC-1); + } + + T bump = current_size >> 3; // Divided by 8. + current_size += bump; + return current_size; +} + +template +class UT_Array +{ +public: + typedef T value_type; + + typedef int (*Comparator)(const T *, const T *); + + /// Copy constructor. It duplicates the data. + /// It's marked explicit so that it's not accidentally passed by value. + /// You can always pass by reference and then copy it, if needed. + /// If you have a line like: + /// UT_Array a = otherarray; + /// and it really does need to copy instead of referencing, + /// you can rewrite it as: + /// UT_Array a(otherarray); + inline explicit UT_Array(const UT_Array &a); + + /// Move constructor. Steals the working data from the original. + inline UT_Array(UT_Array &&a) noexcept; + + /// Construct based on given capacity and size + UT_Array(exint capacity, exint size) + { + myData = capacity ? allocateCapacity(capacity) : NULL; + if (capacity < size) + size = capacity; + mySize = size; + myCapacity = capacity; + trivialConstructRange(myData, mySize); + } + + /// Construct based on given capacity with a size of 0 + explicit UT_Array(exint capacity = 0) : myCapacity(capacity), mySize(0) + { + myData = capacity ? allocateCapacity(capacity) : NULL; + } + + /// Construct with the contents of an initializer list + inline explicit UT_Array(std::initializer_list init); + + inline ~UT_Array(); + + inline void swap(UT_Array &other); + + /// Append an element to the current elements and return its index in the + /// array, or insert the element at a specified position; if necessary, + /// insert() grows the array to accommodate the element. The insert + /// methods use the assignment operator '=' to place the element into the + /// right spot; be aware that '=' works differently on objects and pointers. + /// The test for duplicates uses the logical equal operator '=='; as with + /// '=', the behaviour of the equality operator on pointers versus objects + /// is not the same. + /// Use the subscript operators instead of insert() if you are appending + /// to the array, or if you don't mind overwriting the element already + /// inserted at the given index. + exint append(void) { return insert(mySize); } + exint append(const T &t) { return appendImpl(t); } + exint append(T &&t) { return appendImpl(std::move(t)); } + inline void append(const T *pt, exint count); + inline void appendMultiple(const T &t, exint count); + inline exint insert(exint index); + exint insert(const T &t, exint i) + { return insertImpl(t, i); } + exint insert(T &&t, exint i) + { return insertImpl(std::move(t), i); } + + /// Adds a new element to the array (resizing if necessary) and forwards + /// the given arguments to T's constructor. + /// NOTE: Unlike append(), the arguments cannot reference any existing + /// elements in the array. Checking for and handling such cases would + /// remove most of the performance gain versus append(T(...)). Debug builds + /// will assert that the arguments are valid. + template + inline exint emplace_back(S&&... s); + + /// Takes another T array and concatenate it onto my end + inline exint concat(const UT_Array &a); + + /// Insert an element "count" times at the given index. Return the index. + inline exint multipleInsert(exint index, exint count); + + /// An alias for unique element insertion at a certain index. Also used by + /// the other insertion methods. + exint insertAt(const T &t, exint index) + { return insertImpl(t, index); } + + /// Return true if given index is valid. + bool isValidIndex(exint index) const + { return (index >= 0 && index < mySize); } + + /// Remove one element from the array given its + /// position in the list, and fill the gap by shifting the elements down + /// by one position. Return the index of the element removed or -1 if + /// the index was out of bounds. + exint removeIndex(exint index) + { + return isValidIndex(index) ? removeAt(index) : -1; + } + void removeLast() + { + if (mySize) removeAt(mySize-1); + } + + /// Remove the range [begin_i,end_i) of elements from the array. + inline void removeRange(exint begin_i, exint end_i); + + /// Remove the range [begin_i, end_i) of elements from this array and place + /// them in the dest array, shrinking/growing the dest array as necessary. + inline void extractRange(exint begin_i, exint end_i, + UT_Array& dest); + + /// Removes all matching elements from the list, shuffling down and changing + /// the size appropriately. + /// Returns the number of elements left. + template + inline exint removeIf(IsEqual is_equal); + + /// Remove all matching elements. Also sets the capacity of the array. + template + void collapseIf(IsEqual is_equal) + { + removeIf(is_equal); + setCapacity(size()); + } + + /// Move howMany objects starting at index srcIndex to destIndex; + /// This method will remove the elements at [srcIdx, srcIdx+howMany) and + /// then insert them at destIdx. This method can be used in place of + /// the old shift() operation. + inline void move(exint srcIdx, exint destIdx, exint howMany); + + /// Cyclically shifts the entire array by howMany + inline void cycle(exint howMany); + + /// Quickly set the array to a single value. + inline void constant(const T &v); + /// Zeros the array if a POD type, else trivial constructs if a class type. + inline void zero(); + + /// The fastest search possible, which does pointer arithmetic to find the + /// index of the element. WARNING: index() does no out-of-bounds checking. + exint index(const T &t) const { return &t - myData; } + exint safeIndex(const T &t) const + { + return (&t >= myData && &t < (myData + mySize)) + ? &t - myData : -1; + } + + /// Set the capacity of the array, i.e. grow it or shrink it. The + /// function copies the data after reallocating space for the array. + inline void setCapacity(exint newcapacity); + void setCapacityIfNeeded(exint mincapacity) + { + if (capacity() < mincapacity) + setCapacity(mincapacity); + } + /// If the capacity is smaller than mincapacity, expand the array + /// to at least mincapacity and to at least a constant factor of the + /// array's previous capacity, to avoid having a linear number of + /// reallocations in a linear number of calls to bumpCapacity. + void bumpCapacity(exint mincapacity) + { + if (capacity() >= mincapacity) + return; + // The following 4 lines are just + // SYSmax(mincapacity, UTbumpAlloc(capacity())), avoiding SYSmax + exint bumped = UTbumpAlloc(capacity()); + exint newcapacity = mincapacity; + if (bumped > mincapacity) + newcapacity = bumped; + setCapacity(newcapacity); + } + + /// First bumpCapacity to ensure that there's space for newsize, + /// expanding either not at all or by at least a constant factor + /// of the array's previous capacity, + /// then set the size to newsize. + void bumpSize(exint newsize) + { + bumpCapacity(newsize); + setSize(newsize); + } + /// NOTE: bumpEntries() will be deprecated in favour of bumpSize() in a + /// future version. + void bumpEntries(exint newsize) + { + bumpSize(newsize); + } + + /// Query the capacity, i.e. the allocated length of the array. + /// NOTE: capacity() >= size(). + exint capacity() const { return myCapacity; } + /// Query the size, i.e. the number of occupied elements in the array. + /// NOTE: capacity() >= size(). + exint size() const { return mySize; } + /// Alias of size(). size() is preferred. + exint entries() const { return mySize; } + /// Returns true iff there are no occupied elements in the array. + bool isEmpty() const { return mySize==0; } + + /// Set the size, the number of occupied elements in the array. + /// NOTE: This will not do bumpCapacity, so if you call this + /// n times to increase the size, it may take + /// n^2 time. + void setSize(exint newsize) + { + if (newsize < 0) + newsize = 0; + if (newsize == mySize) + return; + setCapacityIfNeeded(newsize); + if (mySize > newsize) + trivialDestructRange(myData + newsize, mySize - newsize); + else // newsize > mySize + trivialConstructRange(myData + mySize, newsize - mySize); + mySize = newsize; + } + /// Alias of setSize(). setSize() is preferred. + void entries(exint newsize) + { + setSize(newsize); + } + /// Set the size, but unlike setSize(newsize), this function + /// will not initialize new POD elements to zero. Non-POD data types + /// will still have their constructors called. + /// This function is faster than setSize(ne) if you intend to fill in + /// data for all elements. + void setSizeNoInit(exint newsize) + { + if (newsize < 0) + newsize = 0; + if (newsize == mySize) + return; + setCapacityIfNeeded(newsize); + if (mySize > newsize) + trivialDestructRange(myData + newsize, mySize - newsize); + else if (!isPOD()) // newsize > mySize + trivialConstructRange(myData + mySize, newsize - mySize); + mySize = newsize; + } + + /// Decreases, but never expands, to the given maxsize. + void truncate(exint maxsize) + { + if (maxsize >= 0 && size() > maxsize) + setSize(maxsize); + } + /// Resets list to an empty list. + void clear() { + // Don't call setSize(0) since that would require a valid default + // constructor. + trivialDestructRange(myData, mySize); + mySize = 0; + } + + /// Assign array a to this array by copying each of a's elements with + /// memcpy for POD types, and with copy construction for class types. + inline UT_Array & operator=(const UT_Array &a); + + /// Replace the contents with those from the initializer_list ilist + inline UT_Array & operator=(std::initializer_list ilist); + + /// Move the contents of array a to this array. + inline UT_Array & operator=(UT_Array &&a); + + /// Compare two array and return true if they are equal and false otherwise. + /// Two elements are checked against each other using operator '==' or + /// compare() respectively. + /// NOTE: The capacities of the arrays are not checked when + /// determining whether they are equal. + inline bool operator==(const UT_Array &a) const; + inline bool operator!=(const UT_Array &a) const; + + /// Subscript operator + /// NOTE: This does NOT do any bounds checking unless paranoid + /// asserts are enabled. + T & operator()(exint i) + { + UT_ASSERT_P(i >= 0 && i < mySize); + return myData[i]; + } + /// Const subscript operator + /// NOTE: This does NOT do any bounds checking unless paranoid + /// asserts are enabled. + const T & operator()(exint i) const + { + UT_ASSERT_P(i >= 0 && i < mySize); + return myData[i]; + } + + /// Subscript operator + /// NOTE: This does NOT do any bounds checking unless paranoid + /// asserts are enabled. + T & operator[](exint i) + { + UT_ASSERT_P(i >= 0 && i < mySize); + return myData[i]; + } + /// Const subscript operator + /// NOTE: This does NOT do any bounds checking unless paranoid + /// asserts are enabled. + const T & operator[](exint i) const + { + UT_ASSERT_P(i >= 0 && i < mySize); + return myData[i]; + } + + /// forcedRef(exint) will grow the array if necessary, initializing any + /// new elements to zero for POD types and default constructing for + /// class types. + T & forcedRef(exint i) + { + UT_ASSERT_P(i >= 0); + if (i >= mySize) + bumpSize(i+1); + return myData[i]; + } + + /// forcedGet(exint) does NOT grow the array, and will return default + /// objects for out of bound array indices. + T forcedGet(exint i) const + { + return (i >= 0 && i < mySize) ? myData[i] : T(); + } + + T & last() + { + UT_ASSERT_P(mySize); + return myData[mySize-1]; + } + const T & last() const + { + UT_ASSERT_P(mySize); + return myData[mySize-1]; + } + + T * getArray() const { return myData; } + const T * getRawArray() const { return myData; } + + T * array() { return myData; } + const T * array() const { return myData; } + + T * data() { return myData; } + const T * data() const { return myData; } + + /// This method allows you to swap in a new raw T array, which must be + /// the same size as myCapacity. Use caution with this method. + T * aliasArray(T *newdata) + { T *data = myData; myData = newdata; return data; } + + template + class base_iterator : + public std::iterator + { + public: + typedef IT& reference; + typedef IT* pointer; + + // Note: When we drop gcc 4.4 support and allow range-based for + // loops, we should also drop atEnd(), which means we can drop + // myEnd here. + base_iterator() : myCurrent(NULL), myEnd(NULL) {} + + // Allow iterator to const_iterator conversion + template + base_iterator(const base_iterator &src) + : myCurrent(src.myCurrent), myEnd(src.myEnd) {} + + pointer operator->() const + { return FORWARD ? myCurrent : myCurrent - 1; } + + reference operator*() const + { return FORWARD ? *myCurrent : myCurrent[-1]; } + + reference item() const + { return FORWARD ? *myCurrent : myCurrent[-1]; } + + reference operator[](exint n) const + { return FORWARD ? myCurrent[n] : myCurrent[-n - 1]; } + + /// Pre-increment operator + base_iterator &operator++() + { + if (FORWARD) ++myCurrent; else --myCurrent; + return *this; + } + /// Post-increment operator + base_iterator operator++(int) + { + base_iterator tmp = *this; + if (FORWARD) ++myCurrent; else --myCurrent; + return tmp; + } + /// Pre-decrement operator + base_iterator &operator--() + { + if (FORWARD) --myCurrent; else ++myCurrent; + return *this; + } + /// Post-decrement operator + base_iterator operator--(int) + { + base_iterator tmp = *this; + if (FORWARD) --myCurrent; else ++myCurrent; + return tmp; + } + + base_iterator &operator+=(exint n) + { + if (FORWARD) + myCurrent += n; + else + myCurrent -= n; + return *this; + } + base_iterator operator+(exint n) const + { + if (FORWARD) + return base_iterator(myCurrent + n, myEnd); + else + return base_iterator(myCurrent - n, myEnd); + } + + base_iterator &operator-=(exint n) + { return (*this) += (-n); } + base_iterator operator-(exint n) const + { return (*this) + (-n); } + + bool atEnd() const { return myCurrent == myEnd; } + void advance() { this->operator++(); } + + // Comparators + template + bool operator==(const base_iterator &r) const + { return myCurrent == r.myCurrent; } + + template + bool operator!=(const base_iterator &r) const + { return myCurrent != r.myCurrent; } + + template + bool operator<(const base_iterator &r) const + { + if (FORWARD) + return myCurrent < r.myCurrent; + else + return r.myCurrent < myCurrent; + } + + template + bool operator>(const base_iterator &r) const + { + if (FORWARD) + return myCurrent > r.myCurrent; + else + return r.myCurrent > myCurrent; + } + + template + bool operator<=(const base_iterator &r) const + { + if (FORWARD) + return myCurrent <= r.myCurrent; + else + return r.myCurrent <= myCurrent; + } + + template + bool operator>=(const base_iterator &r) const + { + if (FORWARD) + return myCurrent >= r.myCurrent; + else + return r.myCurrent >= myCurrent; + } + + // Difference operator for std::distance + template + exint operator-(const base_iterator &r) const + { + if (FORWARD) + return exint(myCurrent - r.myCurrent); + else + return exint(r.myCurrent - myCurrent); + } + + + protected: + friend class UT_Array; + base_iterator(IT *c, IT *e) : myCurrent(c), myEnd(e) {} + private: + + IT *myCurrent; + IT *myEnd; + }; + + typedef base_iterator iterator; + typedef base_iterator const_iterator; + typedef base_iterator reverse_iterator; + typedef base_iterator const_reverse_iterator; + typedef const_iterator traverser; // For backward compatibility + + /// Begin iterating over the array. The contents of the array may be + /// modified during the traversal. + iterator begin() + { + return iterator(myData, myData + mySize); + } + /// End iterator. + iterator end() + { + return iterator(myData + mySize, + myData + mySize); + } + + /// Begin iterating over the array. The array may not be modified during + /// the traversal. + const_iterator begin() const + { + return const_iterator(myData, myData + mySize); + } + /// End const iterator. Consider using it.atEnd() instead. + const_iterator end() const + { + return const_iterator(myData + mySize, + myData + mySize); + } + + /// Begin iterating over the array in reverse. + reverse_iterator rbegin() + { + return reverse_iterator(myData + mySize, + myData); + } + /// End reverse iterator. + reverse_iterator rend() + { + return reverse_iterator(myData, myData); + } + /// Begin iterating over the array in reverse. + const_reverse_iterator rbegin() const + { + return const_reverse_iterator(myData + mySize, + myData); + } + /// End reverse iterator. Consider using it.atEnd() instead. + const_reverse_iterator rend() const + { + return const_reverse_iterator(myData, myData); + } + + /// Remove item specified by the reverse_iterator. + void removeItem(const reverse_iterator &it) + { + removeAt(&it.item() - myData); + } + + + /// Very dangerous methods to share arrays. + /// The array is not aware of the sharing, so ensure you clear + /// out the array prior a destructor or setCapacity operation. + void unsafeShareData(UT_Array &src) + { + myData = src.myData; + myCapacity = src.myCapacity; + mySize = src.mySize; + } + void unsafeShareData(T *src, exint srcsize) + { + myData = src; + myCapacity = srcsize; + mySize = srcsize; + } + void unsafeShareData(T *src, exint size, exint capacity) + { + myData = src; + mySize = size; + myCapacity = capacity; + } + void unsafeClearData() + { + myData = NULL; + myCapacity = 0; + mySize = 0; + } + + /// Returns true if the data used by the array was allocated on the heap. + inline bool isHeapBuffer() const + { + return (myData != (T *)(((char*)this) + sizeof(*this))); + } + inline bool isHeapBuffer(T* data) const + { + return (data != (T *)(((char*)this) + sizeof(*this))); + } + +protected: + // Check whether T may have a constructor, destructor, or copy + // constructor. This test is conservative in that some POD types will + // not be recognized as POD by this function. To mark your type as POD, + // use the SYS_DECLARE_IS_POD() macro in SYS_TypeDecorate.h. + static constexpr SYS_FORCE_INLINE bool isPOD() + { + return std::is_pod::value; + } + + /// Implements both append(const T &) and append(T &&) via perfect + /// forwarding. Unlike the variadic emplace_back(), its argument may be a + /// reference to another element in the array. + template + inline exint appendImpl(S &&s); + + /// Similar to appendImpl() but for insertion. + template + inline exint insertImpl(S &&s, exint index); + + // Construct the given type + template + static void construct(T &dst, S&&... s) + { + new (&dst) T(std::forward(s)...); + } + + // Copy construct the given type + static void copyConstruct(T &dst, const T &src) + { + if (isPOD()) + dst = src; + else + new (&dst) T(src); + } + static void copyConstructRange(T *dst, const T *src, exint n) + { + if (isPOD()) + { + if (n > 0) + { + ::memcpy((void *)dst, (const void *)src, + n * sizeof(T)); + } + } + else + { + for (exint i = 0; i < n; i++) + new (&dst[i]) T(src[i]); + } + } + + /// Element Constructor + static void trivialConstruct(T &dst) + { + if (!isPOD()) + new (&dst) T(); + else + memset((void *)&dst, 0, sizeof(T)); + } + static void trivialConstructRange(T *dst, exint n) + { + if (!isPOD()) + { + for (exint i = 0; i < n; i++) + new (&dst[i]) T(); + } + else if (n == 1) + { + // Special case for n == 1. If the size parameter + // passed to memset is known at compile time, this + // function call will be inlined. This results in + // much faster performance than a real memset + // function call which is required in the case + // below, where n is not known until runtime. + // This makes calls to append() much faster. + memset((void *)dst, 0, sizeof(T)); + } + else + memset((void *)dst, 0, sizeof(T) * n); + } + + /// Element Destructor + static void trivialDestruct(T &dst) + { + if (!isPOD()) + dst.~T(); + } + static void trivialDestructRange(T *dst, exint n) + { + if (!isPOD()) + { + for (exint i = 0; i < n; i++) + dst[i].~T(); + } + } + +private: + /// Pointer to the array of elements of type T + T *myData; + + /// The number of elements for which we have allocated memory + exint myCapacity; + + /// The actual number of valid elements in the array + exint mySize; + + // The guts of the remove() methods. + inline exint removeAt(exint index); + + inline T * allocateCapacity(exint num_items); +}; +}} + + + +#endif // __UT_ARRAY_H_INCLUDED__ +/* + * Copyright (c) 2018 Side Effects Software Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * COMMENTS: + * This is meant to be included by UT_Array.h and includes + * the template implementations needed by external code. + */ + +#pragma once + +#ifndef __UT_ARRAYIMPL_H_INCLUDED__ +#define __UT_ARRAYIMPL_H_INCLUDED__ + + + + +#include +#include +#include +#include + +namespace igl { namespace FastWindingNumber { + +// Implemented in UT_Array.C +extern void ut_ArrayImplFree(void *p); + + +template +inline UT_Array::UT_Array(const UT_Array &a) + : myCapacity(a.size()), mySize(a.size()) +{ + if (myCapacity) + { + myData = allocateCapacity(myCapacity); + copyConstructRange(myData, a.array(), mySize); + } + else + { + myData = nullptr; + } +} + +template +inline UT_Array::UT_Array(std::initializer_list init) + : myCapacity(init.size()), mySize(init.size()) +{ + if (myCapacity) + { + myData = allocateCapacity(myCapacity); + copyConstructRange(myData, init.begin(), mySize); + } + else + { + myData = nullptr; + } +} + +template +inline UT_Array::UT_Array(UT_Array &&a) noexcept +{ + if (!a.isHeapBuffer()) + { + myData = nullptr; + myCapacity = 0; + mySize = 0; + operator=(std::move(a)); + return; + } + + myCapacity = a.myCapacity; + mySize = a.mySize; + myData = a.myData; + a.myCapacity = a.mySize = 0; + a.myData = nullptr; +} + + +template +inline UT_Array::~UT_Array() +{ + // NOTE: We call setCapacity to ensure that we call trivialDestructRange, + // then call free on myData. + setCapacity(0); +} + +template +inline T * +UT_Array::allocateCapacity(exint capacity) +{ + T *data = (T *)malloc(capacity * sizeof(T)); + // Avoid degenerate case if we happen to be aliased the wrong way + if (!isHeapBuffer(data)) + { + T *prev = data; + data = (T *)malloc(capacity * sizeof(T)); + ut_ArrayImplFree(prev); + } + return data; +} + +template +inline void +UT_Array::swap( UT_Array &other ) +{ + std::swap( myData, other.myData ); + std::swap( myCapacity, other.myCapacity ); + std::swap( mySize, other.mySize ); +} + + +template +inline exint +UT_Array::insert(exint index) +{ + if (index >= mySize) + { + bumpCapacity(index + 1); + + trivialConstructRange(myData + mySize, index - mySize + 1); + + mySize = index+1; + return index; + } + bumpCapacity(mySize + 1); + + UT_ASSERT_P(index >= 0); + ::memmove((void *)&myData[index+1], (void *)&myData[index], + ((mySize-index)*sizeof(T))); + + trivialConstruct(myData[index]); + + mySize++; + return index; +} + +template +template +inline exint +UT_Array::appendImpl(S &&s) +{ + if (mySize == myCapacity) + { + exint idx = safeIndex(s); + + // NOTE: UTbumpAlloc always returns a strictly larger value. + setCapacity(UTbumpAlloc(myCapacity)); + if (idx >= 0) + construct(myData[mySize], std::forward(myData[idx])); + else + construct(myData[mySize], std::forward(s)); + } + else + { + construct(myData[mySize], std::forward(s)); + } + return mySize++; +} + +template +template +inline exint +UT_Array::emplace_back(S&&... s) +{ + if (mySize == myCapacity) + setCapacity(UTbumpAlloc(myCapacity)); + + construct(myData[mySize], std::forward(s)...); + return mySize++; +} + +template +inline void +UT_Array::append(const T *pt, exint count) +{ + bumpCapacity(mySize + count); + copyConstructRange(myData + mySize, pt, count); + mySize += count; +} + +template +inline void +UT_Array::appendMultiple(const T &t, exint count) +{ + UT_ASSERT_P(count >= 0); + if (count <= 0) + return; + if (mySize + count >= myCapacity) + { + exint tidx = safeIndex(t); + + bumpCapacity(mySize + count); + + for (exint i = 0; i < count; i++) + copyConstruct(myData[mySize+i], tidx >= 0 ? myData[tidx] : t); + } + else + { + for (exint i = 0; i < count; i++) + copyConstruct(myData[mySize+i], t); + } + mySize += count; +} + +template +inline exint +UT_Array::concat(const UT_Array &a) +{ + bumpCapacity(mySize + a.mySize); + copyConstructRange(myData + mySize, a.myData, a.mySize); + mySize += a.mySize; + + return mySize; +} + +template +inline exint +UT_Array::multipleInsert(exint beg_index, exint count) +{ + exint end_index = beg_index + count; + + if (beg_index >= mySize) + { + bumpCapacity(end_index); + + trivialConstructRange(myData + mySize, end_index - mySize); + + mySize = end_index; + return beg_index; + } + bumpCapacity(mySize+count); + + ::memmove((void *)&myData[end_index], (void *)&myData[beg_index], + ((mySize-beg_index)*sizeof(T))); + mySize += count; + + trivialConstructRange(myData + beg_index, count); + + return beg_index; +} + +template +template +inline exint +UT_Array::insertImpl(S &&s, exint index) +{ + if (index == mySize) + { + // This case avoids an extraneous call to trivialConstructRange() + // which the compiler may not optimize out. + (void) appendImpl(std::forward(s)); + } + else if (index > mySize) + { + exint src_i = safeIndex(s); + + bumpCapacity(index + 1); + + trivialConstructRange(myData + mySize, index - mySize); + + if (src_i >= 0) + construct(myData[index], std::forward(myData[src_i])); + else + construct(myData[index], std::forward(s)); + + mySize = index + 1; + } + else // (index < mySize) + { + exint src_i = safeIndex(s); + + bumpCapacity(mySize + 1); + + ::memmove((void *)&myData[index+1], (void *)&myData[index], + ((mySize-index)*sizeof(T))); + + if (src_i >= index) + ++src_i; + + if (src_i >= 0) + construct(myData[index], std::forward(myData[src_i])); + else + construct(myData[index], std::forward(s)); + + ++mySize; + } + + return index; +} + +template +inline exint +UT_Array::removeAt(exint idx) +{ + trivialDestruct(myData[idx]); + if (idx != --mySize) + { + ::memmove((void *)&myData[idx], (void *)&myData[idx+1], + ((mySize-idx)*sizeof(T))); + } + + return idx; +} + +template +inline void +UT_Array::removeRange(exint begin_i, exint end_i) +{ + UT_ASSERT(begin_i <= end_i); + UT_ASSERT(end_i <= size()); + if (end_i < size()) + { + trivialDestructRange(myData + begin_i, end_i - begin_i); + ::memmove((void *)&myData[begin_i], (void *)&myData[end_i], + (mySize - end_i)*sizeof(T)); + } + setSize(mySize - (end_i - begin_i)); +} + +template +inline void +UT_Array::extractRange(exint begin_i, exint end_i, UT_Array& dest) +{ + UT_ASSERT_P(begin_i >= 0); + UT_ASSERT_P(begin_i <= end_i); + UT_ASSERT_P(end_i <= size()); + UT_ASSERT(this != &dest); + + exint nelements = end_i - begin_i; + + // grow the raw array if necessary. + dest.setCapacityIfNeeded(nelements); + + ::memmove((void*)dest.myData, (void*)&myData[begin_i], + nelements * sizeof(T)); + dest.mySize = nelements; + + // we just asserted this was true, but just in case + if (this != &dest) + { + if (end_i < size()) + { + ::memmove((void*)&myData[begin_i], (void*)&myData[end_i], + (mySize - end_i) * sizeof(T)); + } + setSize(mySize - nelements); + } +} + +template +inline void +UT_Array::move(exint srcIdx, exint destIdx, exint howMany) +{ + // Make sure all the parameters are valid. + if( srcIdx < 0 ) + srcIdx = 0; + if( destIdx < 0 ) + destIdx = 0; + // If we are told to move a set of elements that would extend beyond the + // end of the current array, trim the group. + if( srcIdx + howMany > size() ) + howMany = size() - srcIdx; + // If the destIdx would have us move the source beyond the end of the + // current array, move the destIdx back. + if( destIdx + howMany > size() ) + destIdx = size() - howMany; + if( srcIdx != destIdx && howMany > 0 ) + { + void **tmp = 0; + exint savelen; + + savelen = SYSabs(srcIdx - destIdx); + tmp = (void **)::malloc(savelen*sizeof(T)); + if( srcIdx > destIdx && howMany > 0 ) + { + // We're moving the group backwards. Save all the stuff that + // we would overwrite, plus everything beyond that to the + // start of the source group. Then move the source group, then + // tack the saved data onto the end of the moved group. + ::memcpy(tmp, (void *)&myData[destIdx], (savelen*sizeof(T))); + ::memmove((void *)&myData[destIdx], (void *)&myData[srcIdx], + (howMany*sizeof(T))); + ::memcpy((void *)&myData[destIdx+howMany], tmp, (savelen*sizeof(T))); + } + if( srcIdx < destIdx && howMany > 0 ) + { + // We're moving the group forwards. Save from the end of the + // group being moved to the end of the where the destination + // group will end up. Then copy the source to the destination. + // Then move back up to the original source location and drop + // in our saved data. + ::memcpy(tmp, (void *)&myData[srcIdx+howMany], (savelen*sizeof(T))); + ::memmove((void *)&myData[destIdx], (void *)&myData[srcIdx], + (howMany*sizeof(T))); + ::memcpy((void *)&myData[srcIdx], tmp, (savelen*sizeof(T))); + } + ::free(tmp); + } +} + +template +template +inline exint +UT_Array::removeIf(IsEqual is_equal) +{ + // Move dst to the first element to remove. + exint dst; + for (dst = 0; dst < mySize; dst++) + { + if (is_equal(myData[dst])) + break; + } + // Now start looking at all the elements past the first one to remove. + for (exint idx = dst+1; idx < mySize; idx++) + { + if (!is_equal(myData[idx])) + { + UT_ASSERT(idx != dst); + myData[dst] = myData[idx]; + dst++; + } + // On match, ignore. + } + // New size + mySize = dst; + return mySize; +} + +template +inline void +UT_Array::cycle(exint howMany) +{ + char *tempPtr; + exint numShift; // The number of items we shift + exint remaining; // mySize - numShift + + if (howMany == 0 || mySize < 1) return; + + numShift = howMany % (exint)mySize; + if (numShift < 0) numShift += mySize; + remaining = mySize - numShift; + tempPtr = new char[numShift*sizeof(T)]; + + ::memmove(tempPtr, (void *)&myData[remaining], (numShift * sizeof(T))); + ::memmove((void *)&myData[numShift], (void *)&myData[0], (remaining * sizeof(T))); + ::memmove((void *)&myData[0], tempPtr, (numShift * sizeof(T))); + + delete [] tempPtr; +} + +template +inline void +UT_Array::constant(const T &value) +{ + for (exint i = 0; i < mySize; i++) + { + myData[i] = value; + } +} + +template +inline void +UT_Array::zero() +{ + if (isPOD()) + ::memset((void *)myData, 0, mySize*sizeof(T)); + else + trivialConstructRange(myData, mySize); +} + +template +inline void +UT_Array::setCapacity(exint capacity) +{ + // Do nothing when new capacity is the same as the current + if (capacity == myCapacity) + return; + + // Special case for non-heap buffers + if (!isHeapBuffer()) + { + if (capacity < mySize) + { + // Destroy the extra elements without changing myCapacity + trivialDestructRange(myData + capacity, mySize - capacity); + mySize = capacity; + } + else if (capacity > myCapacity) + { + T *prev = myData; + myData = (T *)malloc(sizeof(T) * capacity); + // myData is safe because we're already a stack buffer + UT_ASSERT_P(isHeapBuffer()); + if (mySize > 0) + memcpy((void *)myData, (void *)prev, sizeof(T) * mySize); + myCapacity = capacity; + } + else + { + // Keep myCapacity unchanged in this case + UT_ASSERT_P(capacity >= mySize && capacity <= myCapacity); + } + return; + } + + if (capacity == 0) + { + if (myData) + { + trivialDestructRange(myData, mySize); + free(myData); + } + myData = 0; + myCapacity = 0; + mySize = 0; + return; + } + + if (capacity < mySize) + { + trivialDestructRange(myData + capacity, mySize - capacity); + mySize = capacity; + } + + if (myData) + myData = (T *)realloc(myData, capacity*sizeof(T)); + else + myData = (T *)malloc(sizeof(T) * capacity); + + // Avoid degenerate case if we happen to be aliased the wrong way + if (!isHeapBuffer()) + { + T *prev = myData; + myData = (T *)malloc(sizeof(T) * capacity); + if (mySize > 0) + memcpy((void *)myData, (void *)prev, sizeof(T) * mySize); + ut_ArrayImplFree(prev); + } + + myCapacity = capacity; + UT_ASSERT(myData); +} + +template +inline UT_Array & +UT_Array::operator=(const UT_Array &a) +{ + if (this == &a) + return *this; + + // Grow the raw array if necessary. + setCapacityIfNeeded(a.size()); + + // Make sure destructors and constructors are called on all elements + // being removed/added. + trivialDestructRange(myData, mySize); + copyConstructRange(myData, a.myData, a.size()); + + mySize = a.size(); + + return *this; +} + +template +inline UT_Array & +UT_Array::operator=(std::initializer_list a) +{ + const exint new_size = a.size(); + + // Grow the raw array if necessary. + setCapacityIfNeeded(new_size); + + // Make sure destructors and constructors are called on all elements + // being removed/added. + trivialDestructRange(myData, mySize); + + copyConstructRange(myData, a.begin(), new_size); + + mySize = new_size; + + return *this; +} + +template +inline UT_Array & +UT_Array::operator=(UT_Array &&a) +{ + if (!a.isHeapBuffer()) + { + // Cannot steal from non-heap buffers + clear(); + const exint n = a.size(); + setCapacityIfNeeded(n); + if (isPOD()) + { + if (n > 0) + memcpy(myData, a.myData, n * sizeof(T)); + } + else + { + for (exint i = 0; i < n; ++i) + new (&myData[i]) T(std::move(a.myData[i])); + } + mySize = a.mySize; + a.mySize = 0; + return *this; + } + // else, just steal even if we're a small buffer + + // Destroy all the elements we're currently holding. + if (myData) + { + trivialDestructRange(myData, mySize); + if (isHeapBuffer()) + ::free(myData); + } + + // Move the contents of the other array to us and empty the other container + // so that it destructs cleanly. + myCapacity = a.myCapacity; + mySize = a.mySize; + myData = a.myData; + a.myCapacity = a.mySize = 0; + a.myData = nullptr; + + return *this; +} + + +template +inline bool +UT_Array::operator==(const UT_Array &a) const +{ + if (this == &a) return true; + if (mySize != a.size()) return false; + for (exint i = 0; i < mySize; i++) + if (!(myData[i] == a(i))) return false; + return true; +} + +template +inline bool +UT_Array::operator!=(const UT_Array &a) const +{ + return (!operator==(a)); +} + +}} + +#endif // __UT_ARRAYIMPL_H_INCLUDED__ +/* + * Copyright (c) 2018 Side Effects Software Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * COMMENTS: + * Special case for arrays that are usually small, + * to avoid a heap allocation when the array really is small. + */ + +#pragma once + +#ifndef __UT_SMALLARRAY_H_INCLUDED__ +#define __UT_SMALLARRAY_H_INCLUDED__ + + + +#include +#include +namespace igl { namespace FastWindingNumber { + +/// An array class with the small buffer optimization, making it ideal for +/// cases when you know it will only contain a few elements at the expense of +/// increasing the object size by MAX_BYTES (subject to alignment). +template +class UT_SmallArray : public UT_Array +{ + // As many elements that fit into MAX_BYTES with 1 item minimum + enum { MAX_ELEMS = MAX_BYTES/sizeof(T) < 1 ? 1 : MAX_BYTES/sizeof(T) }; + +public: + +// gcc falsely warns about our use of offsetof() on non-POD types. We can't +// easily suppress this because it has to be done in the caller at +// instantiation time. Instead, punt to a runtime check instead. +#if defined(__clang__) || defined(_MSC_VER) + #define UT_SMALL_ARRAY_SIZE_ASSERT() \ + using ThisT = UT_SmallArray; \ + static_assert(offsetof(ThisT, myBuffer) == sizeof(UT_Array), \ + "In order for UT_Array's checks for whether it needs to free the buffer to work, " \ + "the buffer must be exactly following the base class memory.") +#else + #define UT_SMALL_ARRAY_SIZE_ASSERT() \ + UT_ASSERT_P(!UT_Array::isHeapBuffer()); +#endif + + /// Default construction + UT_SmallArray() + : UT_Array(/*capacity*/0) + { + UT_Array::unsafeShareData((T*)myBuffer, 0, MAX_ELEMS); + UT_SMALL_ARRAY_SIZE_ASSERT(); + } + + /// Copy constructor + /// @{ + explicit UT_SmallArray(const UT_Array ©) + : UT_Array(/*capacity*/0) + { + UT_Array::unsafeShareData((T*)myBuffer, 0, MAX_ELEMS); + UT_SMALL_ARRAY_SIZE_ASSERT(); + UT_Array::operator=(copy); + } + explicit UT_SmallArray(const UT_SmallArray ©) + : UT_Array(/*capacity*/0) + { + UT_Array::unsafeShareData((T*)myBuffer, 0, MAX_ELEMS); + UT_SMALL_ARRAY_SIZE_ASSERT(); + UT_Array::operator=(copy); + } + /// @} + + /// Move constructor + /// @{ + UT_SmallArray(UT_Array &&movable) noexcept + { + UT_Array::unsafeShareData((T*)myBuffer, 0, MAX_ELEMS); + UT_SMALL_ARRAY_SIZE_ASSERT(); + UT_Array::operator=(std::move(movable)); + } + UT_SmallArray(UT_SmallArray &&movable) noexcept + { + UT_Array::unsafeShareData((T*)myBuffer, 0, MAX_ELEMS); + UT_SMALL_ARRAY_SIZE_ASSERT(); + UT_Array::operator=(std::move(movable)); + } + /// @} + + /// Initializer list constructor + explicit UT_SmallArray(std::initializer_list init) + { + UT_Array::unsafeShareData((T*)myBuffer, 0, MAX_ELEMS); + UT_SMALL_ARRAY_SIZE_ASSERT(); + UT_Array::operator=(init); + } + +#undef UT_SMALL_ARRAY_SIZE_ASSERT + + /// Assignment operator + /// @{ + UT_SmallArray & + operator=(const UT_SmallArray ©) + { + UT_Array::operator=(copy); + return *this; + } + UT_SmallArray & + operator=(const UT_Array ©) + { + UT_Array::operator=(copy); + return *this; + } + /// @} + + /// Move operator + /// @{ + UT_SmallArray & + operator=(UT_SmallArray &&movable) + { + UT_Array::operator=(std::move(movable)); + return *this; + } + UT_SmallArray & + operator=(UT_Array &&movable) + { + UT_Array::operator=(std::move(movable)); + return *this; + } + /// @} + + UT_SmallArray & + operator=(std::initializer_list src) + { + UT_Array::operator=(src); + return *this; + } +private: + alignas(T) char myBuffer[MAX_ELEMS*sizeof(T)]; +}; +}} + +#endif // __UT_SMALLARRAY_H_INCLUDED__ +/* + * Copyright (c) 2018 Side Effects Software Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * COMMENTS: + * A vector class templated on its size and data type. + */ + +#pragma once + +#ifndef __UT_FixedVector__ +#define __UT_FixedVector__ + + + + +namespace igl { namespace FastWindingNumber { + +template +class UT_FixedVector +{ +public: + typedef UT_FixedVector ThisType; + typedef T value_type; + typedef T theType; + static const exint theSize = SIZE; + + T vec[SIZE]; + + SYS_FORCE_INLINE UT_FixedVector() = default; + + /// Initializes every component to the same value + SYS_FORCE_INLINE explicit UT_FixedVector(T that) noexcept + { + for (exint i = 0; i < SIZE; ++i) + vec[i] = that; + } + + SYS_FORCE_INLINE UT_FixedVector(const ThisType &that) = default; + SYS_FORCE_INLINE UT_FixedVector(ThisType &&that) = default; + + /// Converts vector of S into vector of T, + /// or just copies if same type. + template + SYS_FORCE_INLINE UT_FixedVector(const UT_FixedVector &that) noexcept + { + for (exint i = 0; i < SIZE; ++i) + vec[i] = that[i]; + } + + template + SYS_FORCE_INLINE UT_FixedVector(const S that[SIZE]) noexcept + { + for (exint i = 0; i < SIZE; ++i) + vec[i] = that[i]; + } + + SYS_FORCE_INLINE const T &operator[](exint i) const noexcept + { + UT_ASSERT_P(i >= 0 && i < SIZE); + return vec[i]; + } + SYS_FORCE_INLINE T &operator[](exint i) noexcept + { + UT_ASSERT_P(i >= 0 && i < SIZE); + return vec[i]; + } + + SYS_FORCE_INLINE constexpr const T *data() const noexcept + { + return vec; + } + SYS_FORCE_INLINE T *data() noexcept + { + return vec; + } + + SYS_FORCE_INLINE ThisType &operator=(const ThisType &that) = default; + SYS_FORCE_INLINE ThisType &operator=(ThisType &&that) = default; + + template + SYS_FORCE_INLINE ThisType &operator=(const UT_FixedVector &that) noexcept + { + for (exint i = 0; i < SIZE; ++i) + vec[i] = that[i]; + return *this; + } + SYS_FORCE_INLINE const ThisType &operator=(T that) noexcept + { + for (exint i = 0; i < SIZE; ++i) + vec[i] = that; + return *this; + } + template + SYS_FORCE_INLINE void operator+=(const UT_FixedVector &that) + { + for (exint i = 0; i < SIZE; ++i) + vec[i] += that[i]; + } + SYS_FORCE_INLINE void operator+=(T that) + { + for (exint i = 0; i < SIZE; ++i) + vec[i] += that; + } + template + SYS_FORCE_INLINE auto operator+(const UT_FixedVector &that) const -> UT_FixedVector + { + using Type = decltype(vec[0]+that[0]); + UT_FixedVector result; + for (exint i = 0; i < SIZE; ++i) + result[i] = vec[i] + that[i]; + return result; + } + template + SYS_FORCE_INLINE void operator-=(const UT_FixedVector &that) + { + for (exint i = 0; i < SIZE; ++i) + vec[i] -= that[i]; + } + SYS_FORCE_INLINE void operator-=(T that) + { + for (exint i = 0; i < SIZE; ++i) + vec[i] -= that; + } + template + SYS_FORCE_INLINE auto operator-(const UT_FixedVector &that) const -> UT_FixedVector + { + using Type = decltype(vec[0]-that[0]); + UT_FixedVector result; + for (exint i = 0; i < SIZE; ++i) + result[i] = vec[i] - that[i]; + return result; + } + template + SYS_FORCE_INLINE void operator*=(const UT_FixedVector &that) + { + for (exint i = 0; i < SIZE; ++i) + vec[i] *= that[i]; + } + template + SYS_FORCE_INLINE auto operator*(const UT_FixedVector &that) const -> UT_FixedVector + { + using Type = decltype(vec[0]*that[0]); + UT_FixedVector result; + for (exint i = 0; i < SIZE; ++i) + result[i] = vec[i] * that[i]; + return result; + } + SYS_FORCE_INLINE void operator*=(T that) + { + for (exint i = 0; i < SIZE; ++i) + vec[i] *= that; + } + SYS_FORCE_INLINE UT_FixedVector operator*(T that) const + { + UT_FixedVector result; + for (exint i = 0; i < SIZE; ++i) + result[i] = vec[i] * that; + return result; + } + template + SYS_FORCE_INLINE void operator/=(const UT_FixedVector &that) + { + for (exint i = 0; i < SIZE; ++i) + vec[i] /= that[i]; + } + template + SYS_FORCE_INLINE auto operator/(const UT_FixedVector &that) const -> UT_FixedVector + { + using Type = decltype(vec[0]/that[0]); + UT_FixedVector result; + for (exint i = 0; i < SIZE; ++i) + result[i] = vec[i] / that[i]; + return result; + } + + SYS_FORCE_INLINE void operator/=(T that) + { + if (std::is_integral::value) + { + for (exint i = 0; i < SIZE; ++i) + vec[i] /= that; + } + else + { + that = 1/that; + for (exint i = 0; i < SIZE; ++i) + vec[i] *= that; + } + } + SYS_FORCE_INLINE UT_FixedVector operator/(T that) const + { + UT_FixedVector result; + if (std::is_integral::value) + { + for (exint i = 0; i < SIZE; ++i) + result[i] = vec[i] / that; + } + else + { + that = 1/that; + for (exint i = 0; i < SIZE; ++i) + result[i] = vec[i] * that; + } + return result; + } + SYS_FORCE_INLINE void negate() + { + for (exint i = 0; i < SIZE; ++i) + vec[i] = -vec[i]; + } + + SYS_FORCE_INLINE UT_FixedVector operator-() const + { + UT_FixedVector result; + for (exint i = 0; i < SIZE; ++i) + result[i] = -vec[i]; + return result; + } + + template + SYS_FORCE_INLINE bool operator==(const UT_FixedVector &that) const noexcept + { + for (exint i = 0; i < SIZE; ++i) + { + if (vec[i] != T(that[i])) + return false; + } + return true; + } + template + SYS_FORCE_INLINE bool operator!=(const UT_FixedVector &that) const noexcept + { + return !(*this==that); + } + SYS_FORCE_INLINE bool isZero() const noexcept + { + for (exint i = 0; i < SIZE; ++i) + { + if (vec[i] != T(0)) + return false; + } + return true; + } + SYS_FORCE_INLINE T maxComponent() const + { + T v = vec[0]; + for (exint i = 1; i < SIZE; ++i) + v = (vec[i] > v) ? vec[i] : v; + return v; + } + SYS_FORCE_INLINE T minComponent() const + { + T v = vec[0]; + for (exint i = 1; i < SIZE; ++i) + v = (vec[i] < v) ? vec[i] : v; + return v; + } + SYS_FORCE_INLINE T avgComponent() const + { + T v = vec[0]; + for (exint i = 1; i < SIZE; ++i) + v += vec[i]; + return v / SIZE; + } + + SYS_FORCE_INLINE T length2() const noexcept + { + T a0(vec[0]); + T result(a0*a0); + for (exint i = 1; i < SIZE; ++i) + { + T ai(vec[i]); + result += ai*ai; + } + return result; + } + SYS_FORCE_INLINE T length() const + { + T len2 = length2(); + return SYSsqrt(len2); + } + template + SYS_FORCE_INLINE auto dot(const UT_FixedVector &that) const -> decltype(vec[0]*that[0]) + { + using TheType = decltype(vec[0]*that.vec[0]); + TheType result(vec[0]*that[0]); + for (exint i = 1; i < SIZE; ++i) + result += vec[i]*that[i]; + return result; + } + template + SYS_FORCE_INLINE auto distance2(const UT_FixedVector &that) const -> decltype(vec[0]-that[0]) + { + using TheType = decltype(vec[0]-that[0]); + TheType v(vec[0] - that[0]); + TheType result(v*v); + for (exint i = 1; i < SIZE; ++i) + { + v = vec[i] - that[i]; + result += v*v; + } + return result; + } + template + SYS_FORCE_INLINE auto distance(const UT_FixedVector &that) const -> decltype(vec[0]-that[0]) + { + auto dist2 = distance2(that); + return SYSsqrt(dist2); + } + + SYS_FORCE_INLINE T normalize() + { + T len2 = length2(); + if (len2 == T(0)) + return T(0); + if (len2 == T(1)) + return T(1); + T len = SYSsqrt(len2); + // Check if the square root is equal 1. sqrt(1+dx) ~ 1+dx/2, + // so it may get rounded to 1 when it wasn't 1 before. + if (len != T(1)) + (*this) /= len; + return len; + } +}; + +/// NOTE: Strictly speaking, this should use decltype(that*a[0]), +/// but in the interests of avoiding accidental precision escalation, +/// it uses T. +template +SYS_FORCE_INLINE UT_FixedVector operator*(const S &that,const UT_FixedVector &a) +{ + T t(that); + UT_FixedVector result; + for (exint i = 0; i < SIZE; ++i) + result[i] = t * a[i]; + return result; +} + +template +SYS_FORCE_INLINE auto +dot(const UT_FixedVector &a, const UT_FixedVector &b) -> decltype(a[0]*b[0]) +{ + return a.dot(b); +} + +template +SYS_FORCE_INLINE auto +SYSmin(const UT_FixedVector &a, const UT_FixedVector &b) -> UT_FixedVector +{ + using Type = decltype(a[0]+b[1]); + UT_FixedVector result; + for (exint i = 0; i < SIZE; ++i) + result[i] = SYSmin(Type(a[i]), Type(b[i])); + return result; +} + +template +SYS_FORCE_INLINE auto +SYSmax(const UT_FixedVector &a, const UT_FixedVector &b) -> UT_FixedVector +{ + using Type = decltype(a[0]+b[1]); + UT_FixedVector result; + for (exint i = 0; i < SIZE; ++i) + result[i] = SYSmax(Type(a[i]), Type(b[i])); + return result; +} + +template +struct UT_FixedVectorTraits +{ + typedef UT_FixedVector FixedVectorType; + typedef T DataType; + static const exint TupleSize = 1; + static const bool isVectorType = false; +}; + +template +struct UT_FixedVectorTraits > +{ + typedef UT_FixedVector FixedVectorType; + typedef T DataType; + static const exint TupleSize = SIZE; + static const bool isVectorType = true; +}; +}} + +#endif +/* + * Copyright (c) 2018 Side Effects Software Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * COMMENTS: + * Simple wrappers on tbb interface + */ + +#ifndef __UT_ParallelUtil__ +#define __UT_ParallelUtil__ + + + +#include // This is just included for std::thread::hardware_concurrency() +namespace igl { namespace FastWindingNumber { +namespace UT_Thread { inline int getNumProcessors() { + return std::thread::hardware_concurrency(); +}} + +//#include "tbb/blocked_range.h" +//#include "tbb/parallel_for.h" +////namespace tbb { class split; } +// +///// Declare prior to use. +//template +//using UT_BlockedRange = tbb::blocked_range; +// +//// Default implementation that calls range.size() +//template< typename RANGE > +//struct UT_EstimatorNumItems +//{ +// UT_EstimatorNumItems() {} +// +// size_t operator()(const RANGE& range) const +// { +// return range.size(); +// } +//}; +// +///// This is needed by UT_CoarsenedRange +//template +//inline size_t UTestimatedNumItems(const RANGE& range) +//{ +// return UT_EstimatorNumItems()(range); +//} +// +///// UT_CoarsenedRange: This should be used only inside +///// UT_ParallelFor and UT_ParallelReduce +///// This class wraps an existing range with a new range. +///// This allows us to use simple_partitioner, rather than +///// auto_partitioner, which has disastrous performance with +///// the default grain size in ttb 4. +//template< typename RANGE > +//class UT_CoarsenedRange : public RANGE +//{ +//public: +// // Compiler-generated versions are fine: +// // ~UT_CoarsenedRange(); +// // UT_CoarsenedRange(const UT_CoarsenedRange&); +// +// // Split into two sub-ranges: +// UT_CoarsenedRange(UT_CoarsenedRange& range, tbb::split spl) : +// RANGE(range, spl), +// myGrainSize(range.myGrainSize) +// { +// } +// +// // Inherited: bool empty() const +// +// bool is_divisible() const +// { +// return +// RANGE::is_divisible() && +// (UTestimatedNumItems(static_cast(*this)) > myGrainSize); +// } +// +//private: +// size_t myGrainSize; +// +// UT_CoarsenedRange(const RANGE& base_range, const size_t grain_size) : +// RANGE(base_range), +// myGrainSize(grain_size) +// { +// } +// +// template +// friend void UTparallelFor( +// const Range &range, const Body &body, +// const int subscribe_ratio, const int min_grain_size +// ); +//}; +// +///// Run the @c body function over a range in parallel. +///// UTparallelFor attempts to spread the range out over at most +///// subscribe_ratio * num_processor tasks. +///// The factor subscribe_ratio can be used to help balance the load. +///// UTparallelFor() uses tbb for its implementation. +///// The used grain size is the maximum of min_grain_size and +///// if UTestimatedNumItems(range) / (subscribe_ratio * num_processor). +///// If subscribe_ratio == 0, then a grain size of min_grain_size will be used. +///// A range can be split only when UTestimatedNumItems(range) exceeds the +///// grain size the range is divisible. +// +///// +///// Requirements for the Range functor are: +///// - the requirements of the tbb Range Concept +///// - UT_estimatorNumItems must return the the estimated number of work items +///// for the range. When Range::size() is not the correct estimate, then a +///// (partial) specialization of UT_estimatorNumItemsimatorRange must be provided +///// for the type Range. +///// +///// Requirements for the Body function are: +///// - @code Body(const Body &); @endcode @n +///// Copy Constructor +///// - @code Body()::~Body(); @endcode @n +///// Destructor +///// - @code void Body::operator()(const Range &range) const; @endcode +///// Function call to perform operation on the range. Note the operator is +///// @b const. +///// +///// The requirements for a Range object are: +///// - @code Range::Range(const Range&); @endcode @n +///// Copy constructor +///// - @code Range::~Range(); @endcode @n +///// Destructor +///// - @code bool Range::is_divisible() const; @endcode @n +///// True if the range can be partitioned into two sub-ranges +///// - @code bool Range::empty() const; @endcode @n +///// True if the range is empty +///// - @code Range::Range(Range &r, UT_Split) const; @endcode @n +///// Split the range @c r into two sub-ranges (i.e. modify @c r and *this) +///// +///// Example: @code +///// class Square { +///// public: +///// Square(double *data) : myData(data) {} +///// ~Square(); +///// void operator()(const UT_BlockedRange &range) const +///// { +///// for (int64 i = range.begin(); i != range.end(); ++i) +///// myData[i] *= myData[i]; +///// } +///// double *myData; +///// }; +///// ... +///// +///// void +///// parallel_square(double *array, int64 length) +///// { +///// UTparallelFor(UT_BlockedRange(0, length), Square(array)); +///// } +///// @endcode +///// +///// @see UTparallelReduce(), UT_BlockedRange() +// +//template +//void UTparallelFor( +// const Range &range, const Body &body, +// const int subscribe_ratio = 2, +// const int min_grain_size = 1 +//) +//{ +// const size_t num_processors( UT_Thread::getNumProcessors() ); +// +// UT_ASSERT( num_processors >= 1 ); +// UT_ASSERT( min_grain_size >= 1 ); +// UT_ASSERT( subscribe_ratio >= 0 ); +// +// const size_t est_range_size( UTestimatedNumItems(range) ); +// +// // Don't run on an empty range! +// if (est_range_size == 0) +// return; +// +// // Avoid tbb overhead if entire range needs to be single threaded +// if (num_processors == 1 || est_range_size <= min_grain_size) +// { +// body(range); +// return; +// } +// +// size_t grain_size(min_grain_size); +// if( subscribe_ratio > 0 ) +// grain_size = std::max( +// grain_size, +// est_range_size / (subscribe_ratio * num_processors) +// ); +// +// UT_CoarsenedRange< Range > coarsened_range(range, grain_size); +// +// tbb::parallel_for(coarsened_range, body, tbb::simple_partitioner()); +//} +// +///// Version of UTparallelFor that is tuned for the case where the range +///// consists of lightweight items, for example, +///// float additions or matrix-vector multiplications. +//template +//void +//UTparallelForLightItems(const Range &range, const Body &body) +//{ +// UTparallelFor(range, body, 2, 1024); +//} +// +///// UTserialFor can be used as a debugging tool to quickly replace a parallel +///// for with a serial for. +//template +//void UTserialFor(const Range &range, const Body &body) +// { body(range); } +// +}} +#endif +/* + * Copyright (c) 2018 Side Effects Software Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * COMMENTS: + * Bounding Volume Hierarchy (BVH) implementation. + * To call functions not implemented here, also include UT_BVHImpl.h + */ + +#pragma once + +#ifndef __HDK_UT_BVH_h__ +#define __HDK_UT_BVH_h__ + + + + +#include +#include +namespace igl { namespace FastWindingNumber { + +template class UT_Array; +class v4uf; +class v4uu; + +namespace HDK_Sample { + +namespace UT { + +template +struct Box { + T vals[NAXES][2]; + + SYS_FORCE_INLINE Box() noexcept = default; + SYS_FORCE_INLINE constexpr Box(const Box &other) noexcept = default; + SYS_FORCE_INLINE constexpr Box(Box &&other) noexcept = default; + SYS_FORCE_INLINE Box& operator=(const Box &other) noexcept = default; + SYS_FORCE_INLINE Box& operator=(Box &&other) noexcept = default; + + template + SYS_FORCE_INLINE Box(const Box& other) noexcept { + static_assert((std::is_pod>::value) || !std::is_pod::value, + "UT::Box should be POD, for better performance in UT_Array, etc."); + + for (uint axis = 0; axis < NAXES; ++axis) { + vals[axis][0] = T(other.vals[axis][0]); + vals[axis][1] = T(other.vals[axis][1]); + } + } + template + SYS_FORCE_INLINE Box(const UT_FixedVector& pt) noexcept { + for (uint axis = 0; axis < NAXES; ++axis) { + vals[axis][0] = pt[axis]; + vals[axis][1] = pt[axis]; + } + } + template + SYS_FORCE_INLINE Box& operator=(const Box& other) noexcept { + for (uint axis = 0; axis < NAXES; ++axis) { + vals[axis][0] = T(other.vals[axis][0]); + vals[axis][1] = T(other.vals[axis][1]); + } + return *this; + } + + SYS_FORCE_INLINE const T* operator[](const size_t axis) const noexcept { + UT_ASSERT_P(axis < NAXES); + return vals[axis]; + } + SYS_FORCE_INLINE T* operator[](const size_t axis) noexcept { + UT_ASSERT_P(axis < NAXES); + return vals[axis]; + } + + SYS_FORCE_INLINE void initBounds() noexcept { + for (uint axis = 0; axis < NAXES; ++axis) { + vals[axis][0] = std::numeric_limits::max(); + vals[axis][1] = -std::numeric_limits::max(); + } + } + /// Copy the source box. + /// NOTE: This is so that in templated code that may have a Box or a + /// UT_FixedVector, it can call initBounds and still work. + SYS_FORCE_INLINE void initBounds(const Box& src) noexcept { + for (uint axis = 0; axis < NAXES; ++axis) { + vals[axis][0] = src.vals[axis][0]; + vals[axis][1] = src.vals[axis][1]; + } + } + /// Initialize with the union of the source boxes. + /// NOTE: This is so that in templated code that may have Box's or a + /// UT_FixedVector's, it can call initBounds and still work. + SYS_FORCE_INLINE void initBoundsUnordered(const Box& src0, const Box& src1) noexcept { + for (uint axis = 0; axis < NAXES; ++axis) { + vals[axis][0] = SYSmin(src0.vals[axis][0], src1.vals[axis][0]); + vals[axis][1] = SYSmax(src0.vals[axis][1], src1.vals[axis][1]); + } + } + SYS_FORCE_INLINE void combine(const Box& src) noexcept { + for (uint axis = 0; axis < NAXES; ++axis) { + T& minv = vals[axis][0]; + T& maxv = vals[axis][1]; + const T curminv = src.vals[axis][0]; + const T curmaxv = src.vals[axis][1]; + minv = (minv < curminv) ? minv : curminv; + maxv = (maxv > curmaxv) ? maxv : curmaxv; + } + } + SYS_FORCE_INLINE void enlargeBounds(const Box& src) noexcept { + combine(src); + } + + template + SYS_FORCE_INLINE + void initBounds(const UT_FixedVector& pt) noexcept { + for (uint axis = 0; axis < NAXES; ++axis) { + vals[axis][0] = pt[axis]; + vals[axis][1] = pt[axis]; + } + } + template + SYS_FORCE_INLINE + void initBounds(const UT_FixedVector& min, const UT_FixedVector& max) noexcept { + for (uint axis = 0; axis < NAXES; ++axis) { + vals[axis][0] = min[axis]; + vals[axis][1] = max[axis]; + } + } + template + SYS_FORCE_INLINE + void initBoundsUnordered(const UT_FixedVector& p0, const UT_FixedVector& p1) noexcept { + for (uint axis = 0; axis < NAXES; ++axis) { + vals[axis][0] = SYSmin(p0[axis], p1[axis]); + vals[axis][1] = SYSmax(p0[axis], p1[axis]); + } + } + template + SYS_FORCE_INLINE + void enlargeBounds(const UT_FixedVector& pt) noexcept { + for (uint axis = 0; axis < NAXES; ++axis) { + vals[axis][0] = SYSmin(vals[axis][0], pt[axis]); + vals[axis][1] = SYSmax(vals[axis][1], pt[axis]); + } + } + + SYS_FORCE_INLINE + UT_FixedVector getMin() const noexcept { + UT_FixedVector v; + for (uint axis = 0; axis < NAXES; ++axis) { + v[axis] = vals[axis][0]; + } + return v; + } + + SYS_FORCE_INLINE + UT_FixedVector getMax() const noexcept { + UT_FixedVector v; + for (uint axis = 0; axis < NAXES; ++axis) { + v[axis] = vals[axis][1]; + } + return v; + } + + T diameter2() const noexcept { + T diff = (vals[0][1]-vals[0][0]); + T sum = diff*diff; + for (uint axis = 1; axis < NAXES; ++axis) { + diff = (vals[axis][1]-vals[axis][0]); + sum += diff*diff; + } + return sum; + } + T volume() const noexcept { + T product = (vals[0][1]-vals[0][0]); + for (uint axis = 1; axis < NAXES; ++axis) { + product *= (vals[axis][1]-vals[axis][0]); + } + return product; + } + T half_surface_area() const noexcept { + if (NAXES==1) { + // NOTE: Although this should technically be 1, + // that doesn't make any sense as a heuristic, + // so we fall back to the "volume" of this box. + return (vals[0][1]-vals[0][0]); + } + if (NAXES==2) { + const T d0 = (vals[0][1]-vals[0][0]); + const T d1 = (vals[1][1]-vals[1][0]); + return d0 + d1; + } + if (NAXES==3) { + const T d0 = (vals[0][1]-vals[0][0]); + const T d1 = (vals[1][1]-vals[1][0]); + const T d2 = (vals[2][1]-vals[2][0]); + return d0*d1 + d1*d2 + d2*d0; + } + if (NAXES==4) { + const T d0 = (vals[0][1]-vals[0][0]); + const T d1 = (vals[1][1]-vals[1][0]); + const T d2 = (vals[2][1]-vals[2][0]); + const T d3 = (vals[3][1]-vals[3][0]); + // This is just d0d1d2 + d1d2d3 + d2d3d0 + d3d0d1 refactored. + const T d0d1 = d0*d1; + const T d2d3 = d2*d3; + return d0d1*(d2+d3) + d2d3*(d0+d1); + } + + T sum = 0; + for (uint skipped_axis = 0; skipped_axis < NAXES; ++skipped_axis) { + T product = 1; + for (uint axis = 0; axis < NAXES; ++axis) { + if (axis != skipped_axis) { + product *= (vals[axis][1]-vals[axis][0]); + } + } + sum += product; + } + return sum; + } + T axis_sum() const noexcept { + T sum = (vals[0][1]-vals[0][0]); + for (uint axis = 1; axis < NAXES; ++axis) { + sum += (vals[axis][1]-vals[axis][0]); + } + return sum; + } + template + SYS_FORCE_INLINE void intersect( + T &box_tmin, + T &box_tmax, + const UT_FixedVector &signs, + const UT_FixedVector &origin, + const UT_FixedVector &inverse_direction + ) const noexcept { + for (int axis = 0; axis < NAXES; ++axis) + { + uint sign = signs[axis]; + T t1 = (vals[axis][sign] - origin[axis]) * inverse_direction[axis]; + T t2 = (vals[axis][sign^1] - origin[axis]) * inverse_direction[axis]; + box_tmin = SYSmax(t1, box_tmin); + box_tmax = SYSmin(t2, box_tmax); + } + } + SYS_FORCE_INLINE void intersect(const Box& other, Box& dest) const noexcept { + for (int axis = 0; axis < NAXES; ++axis) + { + dest.vals[axis][0] = SYSmax(vals[axis][0], other.vals[axis][0]); + dest.vals[axis][1] = SYSmin(vals[axis][1], other.vals[axis][1]); + } + } + template + SYS_FORCE_INLINE T minDistance2( + const UT_FixedVector &p + ) const noexcept { + T diff = SYSmax(SYSmax(vals[0][0]-p[0], p[0]-vals[0][1]), T(0.0f)); + T d2 = diff*diff; + for (int axis = 1; axis < NAXES; ++axis) + { + diff = SYSmax(SYSmax(vals[axis][0]-p[axis], p[axis]-vals[axis][1]), T(0.0f)); + d2 += diff*diff; + } + return d2; + } + template + SYS_FORCE_INLINE T maxDistance2( + const UT_FixedVector &p + ) const noexcept { + T diff = SYSmax(p[0]-vals[0][0], vals[0][1]-p[0]); + T d2 = diff*diff; + for (int axis = 1; axis < NAXES; ++axis) + { + diff = SYSmax(p[axis]-vals[axis][0], vals[axis][1]-p[axis]); + d2 += diff*diff; + } + return d2; + } +}; + +/// Used by BVH::init to specify the heuristic to use for choosing between different box splits. +/// I tried putting this inside the BVH class, but I had difficulty getting it to compile. +enum class BVH_Heuristic { + /// Tries to minimize the sum of axis lengths of the boxes. + /// This is useful for applications where the probability of a box being applicable to a + /// query is proportional to the "length", e.g. the probability of a random infinite plane + /// intersecting the box. + BOX_PERIMETER, + + /// Tries to minimize the "surface area" of the boxes. + /// In 3D, uses the surface area; in 2D, uses the perimeter; in 1D, uses the axis length. + /// This is what most applications, e.g. ray tracing, should use, particularly when the + /// probability of a box being applicable to a query is proportional to the surface "area", + /// e.g. the probability of a random ray hitting the box. + /// + /// NOTE: USE THIS ONE IF YOU ARE UNSURE! + BOX_AREA, + + /// Tries to minimize the "volume" of the boxes. + /// Uses the product of all axis lengths as a heuristic, (volume in 3D, area in 2D, length in 1D). + /// This is useful for applications where the probability of a box being applicable to a + /// query is proportional to the "volume", e.g. the probability of a random point being inside the box. + BOX_VOLUME, + + /// Tries to minimize the "radii" of the boxes (i.e. the distance from the centre to a corner). + /// This is useful for applications where the probability of a box being applicable to a + /// query is proportional to the distance to the box centre, e.g. the probability of a random + /// infinite plane being within the "radius" of the centre. + BOX_RADIUS, + + /// Tries to minimize the squared "radii" of the boxes (i.e. the squared distance from the centre to a corner). + /// This is useful for applications where the probability of a box being applicable to a + /// query is proportional to the squared distance to the box centre, e.g. the probability of a random + /// ray passing within the "radius" of the centre. + BOX_RADIUS2, + + /// Tries to minimize the cubed "radii" of the boxes (i.e. the cubed distance from the centre to a corner). + /// This is useful for applications where the probability of a box being applicable to a + /// query is proportional to the cubed distance to the box centre, e.g. the probability of a random + /// point being within the "radius" of the centre. + BOX_RADIUS3, + + /// Tries to minimize the depth of the tree by primarily splitting at the median of the max axis. + /// It may fall back to minimizing the area, but the tree depth should be unaffected. + /// + /// FIXME: This is not fully implemented yet. + MEDIAN_MAX_AXIS +}; + +template +class BVH { +public: + using INT_TYPE = uint; + struct Node { + INT_TYPE child[N]; + + static constexpr INT_TYPE theN = N; + static constexpr INT_TYPE EMPTY = INT_TYPE(-1); + static constexpr INT_TYPE INTERNAL_BIT = (INT_TYPE(1)<<(sizeof(INT_TYPE)*8 - 1)); + SYS_FORCE_INLINE static INT_TYPE markInternal(INT_TYPE internal_node_num) noexcept { + return internal_node_num | INTERNAL_BIT; + } + SYS_FORCE_INLINE static bool isInternal(INT_TYPE node_int) noexcept { + return (node_int & INTERNAL_BIT) != 0; + } + SYS_FORCE_INLINE static INT_TYPE getInternalNum(INT_TYPE node_int) noexcept { + return node_int & ~INTERNAL_BIT; + } + }; +private: + struct FreeDeleter { + SYS_FORCE_INLINE void operator()(Node* p) const { + if (p) { + // The pointer was allocated with malloc by UT_Array, + // so it must be freed with free. + free(p); + } + } + }; + + std::unique_ptr myRoot; + INT_TYPE myNumNodes; +public: + SYS_FORCE_INLINE BVH() noexcept : myRoot(nullptr), myNumNodes(0) {} + + template + inline void init(const BOX_TYPE* boxes, const INT_TYPE nboxes, SRC_INT_TYPE* indices=nullptr, bool reorder_indices=false, INT_TYPE max_items_per_leaf=1) noexcept; + + template + inline void init(Box axes_minmax, const BOX_TYPE* boxes, INT_TYPE nboxes, SRC_INT_TYPE* indices=nullptr, bool reorder_indices=false, INT_TYPE max_items_per_leaf=1) noexcept; + + SYS_FORCE_INLINE + INT_TYPE getNumNodes() const noexcept + { + return myNumNodes; + } + SYS_FORCE_INLINE + const Node *getNodes() const noexcept + { + return myRoot.get(); + } + + SYS_FORCE_INLINE + void clear() noexcept { + myRoot.reset(); + myNumNodes = 0; + } + + /// For each node, this effectively does: + /// LOCAL_DATA local_data[MAX_ORDER]; + /// bool descend = functors.pre(nodei, parent_data); + /// if (!descend) + /// return; + /// for each child { + /// if (isitem(child)) + /// functors.item(getitemi(child), nodei, local_data[child]); + /// else if (isnode(child)) + /// recurse(getnodei(child), local_data); + /// } + /// functors.post(nodei, parent_nodei, data_for_parent, num_children, local_data); + template + inline void traverse( + FUNCTORS &functors, + LOCAL_DATA *data_for_parent=nullptr) const noexcept; + + /// This acts like the traverse function, except if the number of nodes in two subtrees + /// of a node contain at least parallel_threshold nodes, they may be executed in parallel. + /// If parallel_threshold is 0, even item_functor may be executed on items in parallel. + /// NOTE: Make sure that your functors don't depend on the order that they're executed in, + /// e.g. don't add values from sibling nodes together except in post functor, + /// else they might have nondeterministic roundoff or miss some values entirely. + template + inline void traverseParallel( + INT_TYPE parallel_threshold, + FUNCTORS &functors, + LOCAL_DATA *data_for_parent=nullptr) const noexcept; + + /// For each node, this effectively does: + /// LOCAL_DATA local_data[MAX_ORDER]; + /// uint descend = functors.pre(nodei, parent_data); + /// if (!descend) + /// return; + /// for each child { + /// if (!(descend & (1< + inline void traverseVector( + FUNCTORS &functors, + LOCAL_DATA *data_for_parent=nullptr) const noexcept; + + /// Prints a text representation of the tree to stdout. + inline void debugDump() const; + + template + static inline void createTrivialIndices(SRC_INT_TYPE* indices, const INT_TYPE n) noexcept; + +private: + template + inline void traverseHelper( + INT_TYPE nodei, + INT_TYPE parent_nodei, + FUNCTORS &functors, + LOCAL_DATA *data_for_parent=nullptr) const noexcept; + + template + inline void traverseParallelHelper( + INT_TYPE nodei, + INT_TYPE parent_nodei, + INT_TYPE parallel_threshold, + INT_TYPE next_node_id, + FUNCTORS &functors, + LOCAL_DATA *data_for_parent=nullptr) const noexcept; + + template + inline void traverseVectorHelper( + INT_TYPE nodei, + INT_TYPE parent_nodei, + FUNCTORS &functors, + LOCAL_DATA *data_for_parent=nullptr) const noexcept; + + template + static inline void computeFullBoundingBox(Box& axes_minmax, const BOX_TYPE* boxes, const INT_TYPE nboxes, SRC_INT_TYPE* indices) noexcept; + + template + static inline void initNode(UT_Array& nodes, Node &node, const Box& axes_minmax, const BOX_TYPE* boxes, SRC_INT_TYPE* indices, const INT_TYPE nboxes) noexcept; + + template + static inline void initNodeReorder(UT_Array& nodes, Node &node, const Box& axes_minmax, const BOX_TYPE* boxes, SRC_INT_TYPE* indices, const INT_TYPE nboxes, const INT_TYPE indices_offset, const INT_TYPE max_items_per_leaf) noexcept; + + template + static inline void multiSplit(const Box& axes_minmax, const BOX_TYPE* boxes, SRC_INT_TYPE* indices, INT_TYPE nboxes, SRC_INT_TYPE* sub_indices[N+1], Box sub_boxes[N]) noexcept; + + template + static inline void split(const Box& axes_minmax, const BOX_TYPE* boxes, SRC_INT_TYPE* indices, INT_TYPE nboxes, SRC_INT_TYPE*& split_indices, Box* split_boxes) noexcept; + + template + static inline void adjustParallelChildNodes(INT_TYPE nparallel, UT_Array& nodes, Node& node, UT_Array* parallel_nodes, SRC_INT_TYPE* sub_indices) noexcept; + + template + static inline void nthElement(const BOX_TYPE* boxes, SRC_INT_TYPE* indices, const SRC_INT_TYPE* indices_end, const uint axis, SRC_INT_TYPE*const nth) noexcept; + + template + static inline void partitionByCentre(const BOX_TYPE* boxes, SRC_INT_TYPE*const indices, const SRC_INT_TYPE*const indices_end, const uint axis, const T pivotx2, SRC_INT_TYPE*& ppivot_start, SRC_INT_TYPE*& ppivot_end) noexcept; + + /// An overestimate of the number of nodes needed. + /// At worst, we could have only 2 children in every leaf, and + /// then above that, we have a geometric series with r=1/N and a=(sub_nboxes/2)/N + /// The true worst case might be a little worst than this, but + /// it's probably fairly unlikely. + SYS_FORCE_INLINE static INT_TYPE nodeEstimate(const INT_TYPE nboxes) noexcept { + return nboxes/2 + nboxes/(2*(N-1)); + } + + template + SYS_FORCE_INLINE static T unweightedHeuristic(const Box& box) noexcept { + if (H == BVH_Heuristic::BOX_PERIMETER) { + return box.axis_sum(); + } + if (H == BVH_Heuristic::BOX_AREA) { + return box.half_surface_area(); + } + if (H == BVH_Heuristic::BOX_VOLUME) { + return box.volume(); + } + if (H == BVH_Heuristic::BOX_RADIUS) { + T diameter2 = box.diameter2(); + return SYSsqrt(diameter2); + } + if (H == BVH_Heuristic::BOX_RADIUS2) { + return box.diameter2(); + } + if (H == BVH_Heuristic::BOX_RADIUS3) { + T diameter2 = box.diameter2(); + return diameter2*SYSsqrt(diameter2); + } + UT_ASSERT_MSG(0, "BVH_Heuristic::MEDIAN_MAX_AXIS should be handled separately by caller!"); + return T(1); + } + + /// 16 equal-length spans (15 evenly-spaced splits) should be enough for a decent heuristic + static constexpr INT_TYPE NSPANS = 16; + static constexpr INT_TYPE NSPLITS = NSPANS-1; + + /// At least 1/16 of all boxes must be on each side, else we could end up with a very deep tree + static constexpr INT_TYPE MIN_FRACTION = 16; +}; + +} // UT namespace + +template +using UT_BVH = UT::BVH; + +} // End HDK_Sample namespace +}} +#endif +/* + * Copyright (c) 2018 Side Effects Software Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * COMMENTS: + * Bounding Volume Hierarchy (BVH) implementation. + * The main file is UT_BVH.h; this file is separate so that + * files that don't actually need to call functions on the BVH + * won't have unnecessary headers and functions included. + */ + +#pragma once + +#ifndef __HDK_UT_BVHImpl_h__ +#define __HDK_UT_BVHImpl_h__ + + + + + + + + +#include + +#include +#include + +namespace igl { namespace FastWindingNumber { +namespace HDK_Sample { + +namespace UT { + +template +SYS_FORCE_INLINE bool utBoxExclude(const UT::Box& box) noexcept { + bool has_nan_or_inf = !SYSisFinite(box[0][0]); + has_nan_or_inf |= !SYSisFinite(box[0][1]); + for (uint axis = 1; axis < NAXES; ++axis) + { + has_nan_or_inf |= !SYSisFinite(box[axis][0]); + has_nan_or_inf |= !SYSisFinite(box[axis][1]); + } + return has_nan_or_inf; +} +template +SYS_FORCE_INLINE bool utBoxExclude(const UT::Box& box) noexcept { + const int32 *pboxints = reinterpret_cast(&box); + // Fast check for NaN or infinity: check if exponent bits are 0xFF. + bool has_nan_or_inf = ((pboxints[0] & 0x7F800000) == 0x7F800000); + has_nan_or_inf |= ((pboxints[1] & 0x7F800000) == 0x7F800000); + for (uint axis = 1; axis < NAXES; ++axis) + { + has_nan_or_inf |= ((pboxints[2*axis] & 0x7F800000) == 0x7F800000); + has_nan_or_inf |= ((pboxints[2*axis + 1] & 0x7F800000) == 0x7F800000); + } + return has_nan_or_inf; +} +template +SYS_FORCE_INLINE T utBoxCenter(const UT::Box& box, uint axis) noexcept { + const T* v = box.vals[axis]; + return v[0] + v[1]; +} +template +struct ut_BoxCentre { + constexpr static uint scale = 2; +}; +template +SYS_FORCE_INLINE T utBoxExclude(const UT_FixedVector& position) noexcept { + bool has_nan_or_inf = !SYSisFinite(position[0]); + for (uint axis = 1; axis < NAXES; ++axis) + has_nan_or_inf |= !SYSisFinite(position[axis]); + return has_nan_or_inf; +} +template +SYS_FORCE_INLINE bool utBoxExclude(const UT_FixedVector& position) noexcept { + const int32 *ppositionints = reinterpret_cast(&position); + // Fast check for NaN or infinity: check if exponent bits are 0xFF. + bool has_nan_or_inf = ((ppositionints[0] & 0x7F800000) == 0x7F800000); + for (uint axis = 1; axis < NAXES; ++axis) + has_nan_or_inf |= ((ppositionints[axis] & 0x7F800000) == 0x7F800000); + return has_nan_or_inf; +} +template +SYS_FORCE_INLINE T utBoxCenter(const UT_FixedVector& position, uint axis) noexcept { + return position[axis]; +} +template +struct ut_BoxCentre> { + constexpr static uint scale = 1; +}; + +template +inline INT_TYPE utExcludeNaNInfBoxIndices(const BOX_TYPE* boxes, SRC_INT_TYPE* indices, INT_TYPE& nboxes) noexcept +{ + constexpr INT_TYPE PARALLEL_THRESHOLD = 65536; + INT_TYPE ntasks = 1; + //if (nboxes >= PARALLEL_THRESHOLD) + //{ + // INT_TYPE nprocessors = UT_Thread::getNumProcessors(); + // ntasks = (nprocessors > 1) ? SYSmin(4*nprocessors, nboxes/(PARALLEL_THRESHOLD/2)) : 1; + //} + //if (ntasks == 1) + { + // Serial: easy case; just loop through. + + const SRC_INT_TYPE* indices_end = indices + nboxes; + + // Loop through forward once + SRC_INT_TYPE* psrc_index = indices; + for (; psrc_index != indices_end; ++psrc_index) + { + const bool exclude = utBoxExclude(boxes[*psrc_index]); + if (exclude) + break; + } + if (psrc_index == indices_end) + return 0; + + // First NaN or infinite box + SRC_INT_TYPE* nan_start = psrc_index; + for (++psrc_index; psrc_index != indices_end; ++psrc_index) + { + const bool exclude = utBoxExclude(boxes[*psrc_index]); + if (!exclude) + { + *nan_start = *psrc_index; + ++nan_start; + } + } + nboxes = nan_start-indices; + return indices_end - nan_start; + } + +} + +template +template +inline void BVH::init(const BOX_TYPE* boxes, const INT_TYPE nboxes, SRC_INT_TYPE* indices, bool reorder_indices, INT_TYPE max_items_per_leaf) noexcept { + Box axes_minmax; + computeFullBoundingBox(axes_minmax, boxes, nboxes, indices); + + init(axes_minmax, boxes, nboxes, indices, reorder_indices, max_items_per_leaf); +} + +template +template +inline void BVH::init(Box axes_minmax, const BOX_TYPE* boxes, INT_TYPE nboxes, SRC_INT_TYPE* indices, bool reorder_indices, INT_TYPE max_items_per_leaf) noexcept { + // Clear the tree in advance to save memory. + myRoot.reset(); + + if (nboxes == 0) { + myNumNodes = 0; + return; + } + + UT_Array local_indices; + if (!indices) { + local_indices.setSizeNoInit(nboxes); + indices = local_indices.array(); + createTrivialIndices(indices, nboxes); + } + + // Exclude any boxes with NaNs or infinities by shifting down indices + // over the bad box indices and updating nboxes. + INT_TYPE nexcluded = utExcludeNaNInfBoxIndices(boxes, indices, nboxes); + if (nexcluded != 0) { + if (nboxes == 0) { + myNumNodes = 0; + return; + } + computeFullBoundingBox(axes_minmax, boxes, nboxes, indices); + } + + UT_Array nodes; + // Preallocate an overestimate of the number of nodes needed. + nodes.setCapacity(nodeEstimate(nboxes)); + nodes.setSize(1); + if (reorder_indices) + initNodeReorder(nodes, nodes[0], axes_minmax, boxes, indices, nboxes, 0, max_items_per_leaf); + else + initNode(nodes, nodes[0], axes_minmax, boxes, indices, nboxes); + + // If capacity is more than 12.5% over the size, rellocate. + if (8*nodes.capacity() > 9*nodes.size()) { + nodes.setCapacity(nodes.size()); + } + // Steal ownership of the array from the UT_Array + myRoot.reset(nodes.array()); + myNumNodes = nodes.size(); + nodes.unsafeClearData(); +} + +template +template +inline void BVH::traverse( + FUNCTORS &functors, + LOCAL_DATA* data_for_parent) const noexcept +{ + if (!myRoot) + return; + + // NOTE: The root is always index 0. + traverseHelper(0, INT_TYPE(-1), functors, data_for_parent); +} +template +template +inline void BVH::traverseHelper( + INT_TYPE nodei, + INT_TYPE parent_nodei, + FUNCTORS &functors, + LOCAL_DATA* data_for_parent) const noexcept +{ + const Node &node = myRoot[nodei]; + bool descend = functors.pre(nodei, data_for_parent); + if (!descend) + return; + LOCAL_DATA local_data[N]; + INT_TYPE s; + for (s = 0; s < N; ++s) { + const INT_TYPE node_int = node.child[s]; + if (Node::isInternal(node_int)) { + if (node_int == Node::EMPTY) { + // NOTE: Anything after this will be empty too, so we can break. + break; + } + traverseHelper(Node::getInternalNum(node_int), nodei, functors, &local_data[s]); + } + else { + functors.item(node_int, nodei, local_data[s]); + } + } + // NOTE: s is now the number of non-empty entries in this node. + functors.post(nodei, parent_nodei, data_for_parent, s, local_data); +} + +template +template +inline void BVH::traverseParallel( + INT_TYPE parallel_threshold, + FUNCTORS& functors, + LOCAL_DATA* data_for_parent) const noexcept +{ + if (!myRoot) + return; + + // NOTE: The root is always index 0. + traverseParallelHelper(0, INT_TYPE(-1), parallel_threshold, myNumNodes, functors, data_for_parent); +} +template +template +inline void BVH::traverseParallelHelper( + INT_TYPE nodei, + INT_TYPE parent_nodei, + INT_TYPE parallel_threshold, + INT_TYPE next_node_id, + FUNCTORS& functors, + LOCAL_DATA* data_for_parent) const noexcept +{ + const Node &node = myRoot[nodei]; + bool descend = functors.pre(nodei, data_for_parent); + if (!descend) + return; + + // To determine the number of nodes in a child's subtree, we take the next + // node ID minus the current child's node ID. + INT_TYPE next_nodes[N]; + INT_TYPE nnodes[N]; + INT_TYPE nchildren = N; + INT_TYPE nparallel = 0; + // s is currently unsigned, so we check s < N for bounds check. + // The s >= 0 check is in case s ever becomes signed, and should be + // automatically removed by the compiler for unsigned s. + for (INT_TYPE s = N-1; (std::is_signed::value ? (s >= 0) : (s < N)); --s) { + const INT_TYPE node_int = node.child[s]; + if (node_int == Node::EMPTY) { + --nchildren; + continue; + } + next_nodes[s] = next_node_id; + if (Node::isInternal(node_int)) { + // NOTE: This depends on BVH::initNode appending the child nodes + // in between their content, instead of all at once. + INT_TYPE child_node_id = Node::getInternalNum(node_int); + nnodes[s] = next_node_id - child_node_id; + next_node_id = child_node_id; + } + else { + nnodes[s] = 0; + } + nparallel += (nnodes[s] >= parallel_threshold); + } + + LOCAL_DATA local_data[N]; + if (nparallel >= 2) { + // Do any non-parallel ones first + if (nparallel < nchildren) { + for (INT_TYPE s = 0; s < N; ++s) { + if (nnodes[s] >= parallel_threshold) { + continue; + } + const INT_TYPE node_int = node.child[s]; + if (Node::isInternal(node_int)) { + if (node_int == Node::EMPTY) { + // NOTE: Anything after this will be empty too, so we can break. + break; + } + traverseHelper(Node::getInternalNum(node_int), nodei, functors, &local_data[s]); + } + else { + functors.item(node_int, nodei, local_data[s]); + } + } + } + // Now do the parallel ones + igl::parallel_for( + nparallel, + [this,nodei,&node,&nnodes,&next_nodes,¶llel_threshold,&functors,&local_data](int taski) + { + INT_TYPE parallel_count = 0; + // NOTE: The check for s < N is just so that the compiler can + // (hopefully) figure out that it can fully unroll the loop. + INT_TYPE s; + for (s = 0; s < N; ++s) { + if (nnodes[s] < parallel_threshold) { + continue; + } + if (parallel_count == taski) { + break; + } + ++parallel_count; + } + const INT_TYPE node_int = node.child[s]; + if (Node::isInternal(node_int)) { + UT_ASSERT_MSG_P(node_int != Node::EMPTY, "Empty entries should have been excluded above."); + traverseParallelHelper(Node::getInternalNum(node_int), nodei, parallel_threshold, next_nodes[s], functors, &local_data[s]); + } + else { + functors.item(node_int, nodei, local_data[s]); + } + }); + } + else { + // All in serial + for (INT_TYPE s = 0; s < N; ++s) { + const INT_TYPE node_int = node.child[s]; + if (Node::isInternal(node_int)) { + if (node_int == Node::EMPTY) { + // NOTE: Anything after this will be empty too, so we can break. + break; + } + traverseHelper(Node::getInternalNum(node_int), nodei, functors, &local_data[s]); + } + else { + functors.item(node_int, nodei, local_data[s]); + } + } + } + functors.post(nodei, parent_nodei, data_for_parent, nchildren, local_data); +} + +template +template +inline void BVH::traverseVector( + FUNCTORS &functors, + LOCAL_DATA* data_for_parent) const noexcept +{ + if (!myRoot) + return; + + // NOTE: The root is always index 0. + traverseVectorHelper(0, INT_TYPE(-1), functors, data_for_parent); +} +template +template +inline void BVH::traverseVectorHelper( + INT_TYPE nodei, + INT_TYPE parent_nodei, + FUNCTORS &functors, + LOCAL_DATA* data_for_parent) const noexcept +{ + const Node &node = myRoot[nodei]; + INT_TYPE descend = functors.pre(nodei, data_for_parent); + if (!descend) + return; + LOCAL_DATA local_data[N]; + INT_TYPE s; + for (s = 0; s < N; ++s) { + if ((descend>>s) & 1) { + const INT_TYPE node_int = node.child[s]; + if (Node::isInternal(node_int)) { + if (node_int == Node::EMPTY) { + // NOTE: Anything after this will be empty too, so we can break. + descend &= (INT_TYPE(1)< +template +inline void BVH::createTrivialIndices(SRC_INT_TYPE* indices, const INT_TYPE n) noexcept { + igl::parallel_for(n, [indices,n](INT_TYPE i) { indices[i] = i; }, 65536); +} + +template +template +inline void BVH::computeFullBoundingBox(Box& axes_minmax, const BOX_TYPE* boxes, const INT_TYPE nboxes, SRC_INT_TYPE* indices) noexcept { + if (!nboxes) { + axes_minmax.initBounds(); + return; + } + INT_TYPE ntasks = 1; + if (nboxes >= 2*4096) { + INT_TYPE nprocessors = UT_Thread::getNumProcessors(); + ntasks = (nprocessors > 1) ? SYSmin(4*nprocessors, nboxes/4096) : 1; + } + if (ntasks == 1) { + Box box; + if (indices) { + box.initBounds(boxes[indices[0]]); + for (INT_TYPE i = 1; i < nboxes; ++i) { + box.combine(boxes[indices[i]]); + } + } + else { + box.initBounds(boxes[0]); + for (INT_TYPE i = 1; i < nboxes; ++i) { + box.combine(boxes[i]); + } + } + axes_minmax = box; + } + else { + UT_SmallArray> parallel_boxes; + Box box; + igl::parallel_for( + nboxes, + [¶llel_boxes](int n){parallel_boxes.setSize(n);}, + [¶llel_boxes,indices,&boxes](int i, int t) + { + if(indices) + { + parallel_boxes[t].combine(boxes[indices[i]]); + }else + { + parallel_boxes[t].combine(boxes[i]); + } + }, + [¶llel_boxes,&box](int t) + { + if(t == 0) + { + box = parallel_boxes[0]; + }else + { + box.combine(parallel_boxes[t]); + } + }); + + axes_minmax = box; + } +} + +template +template +inline void BVH::initNode(UT_Array& nodes, Node &node, const Box& axes_minmax, const BOX_TYPE* boxes, SRC_INT_TYPE* indices, const INT_TYPE nboxes) noexcept { + if (nboxes <= N) { + // Fits in one node + for (INT_TYPE i = 0; i < nboxes; ++i) { + node.child[i] = indices[i]; + } + for (INT_TYPE i = nboxes; i < N; ++i) { + node.child[i] = Node::EMPTY; + } + return; + } + + SRC_INT_TYPE* sub_indices[N+1]; + Box sub_boxes[N]; + + if (N == 2) { + sub_indices[0] = indices; + sub_indices[2] = indices+nboxes; + split(axes_minmax, boxes, indices, nboxes, sub_indices[1], &sub_boxes[0]); + } + else { + multiSplit(axes_minmax, boxes, indices, nboxes, sub_indices, sub_boxes); + } + + // Count the number of nodes to run in parallel and fill in single items in this node + INT_TYPE nparallel = 0; + static constexpr INT_TYPE PARALLEL_THRESHOLD = 1024; + for (INT_TYPE i = 0; i < N; ++i) { + INT_TYPE sub_nboxes = sub_indices[i+1]-sub_indices[i]; + if (sub_nboxes == 1) { + node.child[i] = sub_indices[i][0]; + } + else if (sub_nboxes >= PARALLEL_THRESHOLD) { + ++nparallel; + } + } + + // NOTE: Child nodes of this node need to be placed just before the nodes in + // their corresponding subtree, in between the subtrees, because + // traverseParallel uses the difference between the child node IDs + // to determine the number of nodes in the subtree. + + // Recurse + if (nparallel >= 2) { + UT_SmallArray> parallel_nodes; + UT_SmallArray parallel_parent_nodes; + parallel_nodes.setSize(nparallel); + parallel_parent_nodes.setSize(nparallel); + igl::parallel_for( + nparallel, + [¶llel_nodes,¶llel_parent_nodes,&sub_indices,boxes,&sub_boxes](int taski) + { + // First, find which child this is + INT_TYPE counted_parallel = 0; + INT_TYPE sub_nboxes; + INT_TYPE childi; + for (childi = 0; childi < N; ++childi) { + sub_nboxes = sub_indices[childi+1]-sub_indices[childi]; + if (sub_nboxes >= PARALLEL_THRESHOLD) { + if (counted_parallel == taski) { + break; + } + ++counted_parallel; + } + } + UT_ASSERT_P(counted_parallel == taski); + + UT_Array& local_nodes = parallel_nodes[taski]; + // Preallocate an overestimate of the number of nodes needed. + // At worst, we could have only 2 children in every leaf, and + // then above that, we have a geometric series with r=1/N and a=(sub_nboxes/2)/N + // The true worst case might be a little worst than this, but + // it's probably fairly unlikely. + local_nodes.setCapacity(nodeEstimate(sub_nboxes)); + Node& parent_node = parallel_parent_nodes[taski]; + + // We'll have to fix the internal node numbers in parent_node and local_nodes later + initNode(local_nodes, parent_node, sub_boxes[childi], boxes, sub_indices[childi], sub_nboxes); + }); + + INT_TYPE counted_parallel = 0; + for (INT_TYPE i = 0; i < N; ++i) { + INT_TYPE sub_nboxes = sub_indices[i+1]-sub_indices[i]; + if (sub_nboxes != 1) { + INT_TYPE local_nodes_start = nodes.size(); + node.child[i] = Node::markInternal(local_nodes_start); + if (sub_nboxes >= PARALLEL_THRESHOLD) { + // First, adjust the root child node + Node child_node = parallel_parent_nodes[counted_parallel]; + ++local_nodes_start; + for (INT_TYPE childi = 0; childi < N; ++childi) { + INT_TYPE child_child = child_node.child[childi]; + if (Node::isInternal(child_child) && child_child != Node::EMPTY) { + child_child += local_nodes_start; + child_node.child[childi] = child_child; + } + } + + // Make space in the array for the sub-child nodes + const UT_Array& local_nodes = parallel_nodes[counted_parallel]; + ++counted_parallel; + INT_TYPE n = local_nodes.size(); + nodes.bumpCapacity(local_nodes_start + n); + nodes.setSizeNoInit(local_nodes_start + n); + nodes[local_nodes_start-1] = child_node; + } + else { + nodes.bumpCapacity(local_nodes_start + 1); + nodes.setSizeNoInit(local_nodes_start + 1); + initNode(nodes, nodes[local_nodes_start], sub_boxes[i], boxes, sub_indices[i], sub_nboxes); + } + } + } + + // Now, adjust and copy all sub-child nodes that were made in parallel + adjustParallelChildNodes(nparallel, nodes, node, parallel_nodes.array(), sub_indices); + } + else { + for (INT_TYPE i = 0; i < N; ++i) { + INT_TYPE sub_nboxes = sub_indices[i+1]-sub_indices[i]; + if (sub_nboxes != 1) { + INT_TYPE local_nodes_start = nodes.size(); + node.child[i] = Node::markInternal(local_nodes_start); + nodes.bumpCapacity(local_nodes_start + 1); + nodes.setSizeNoInit(local_nodes_start + 1); + initNode(nodes, nodes[local_nodes_start], sub_boxes[i], boxes, sub_indices[i], sub_nboxes); + } + } + } +} + +template +template +inline void BVH::initNodeReorder(UT_Array& nodes, Node &node, const Box& axes_minmax, const BOX_TYPE* boxes, SRC_INT_TYPE* indices, INT_TYPE nboxes, const INT_TYPE indices_offset, const INT_TYPE max_items_per_leaf) noexcept { + if (nboxes <= N) { + // Fits in one node + for (INT_TYPE i = 0; i < nboxes; ++i) { + node.child[i] = indices_offset+i; + } + for (INT_TYPE i = nboxes; i < N; ++i) { + node.child[i] = Node::EMPTY; + } + return; + } + + SRC_INT_TYPE* sub_indices[N+1]; + Box sub_boxes[N]; + + if (N == 2) { + sub_indices[0] = indices; + sub_indices[2] = indices+nboxes; + split(axes_minmax, boxes, indices, nboxes, sub_indices[1], &sub_boxes[0]); + } + else { + multiSplit(axes_minmax, boxes, indices, nboxes, sub_indices, sub_boxes); + } + + // Move any children with max_items_per_leaf or fewer indices before any children with more, + // for better cache coherence when we're accessing data in a corresponding array. + INT_TYPE nleaves = 0; + UT_SmallArray leaf_indices; + SRC_INT_TYPE leaf_sizes[N]; + INT_TYPE sub_nboxes0 = sub_indices[1]-sub_indices[0]; + if (sub_nboxes0 <= max_items_per_leaf) { + leaf_sizes[0] = sub_nboxes0; + for (int j = 0; j < sub_nboxes0; ++j) + leaf_indices.append(sub_indices[0][j]); + ++nleaves; + } + INT_TYPE sub_nboxes1 = sub_indices[2]-sub_indices[1]; + if (sub_nboxes1 <= max_items_per_leaf) { + leaf_sizes[nleaves] = sub_nboxes1; + for (int j = 0; j < sub_nboxes1; ++j) + leaf_indices.append(sub_indices[1][j]); + ++nleaves; + } + for (INT_TYPE i = 2; i < N; ++i) { + INT_TYPE sub_nboxes = sub_indices[i+1]-sub_indices[i]; + if (sub_nboxes <= max_items_per_leaf) { + leaf_sizes[nleaves] = sub_nboxes; + for (int j = 0; j < sub_nboxes; ++j) + leaf_indices.append(sub_indices[i][j]); + ++nleaves; + } + } + if (nleaves > 0) { + // NOTE: i < N condition is because INT_TYPE is unsigned. + // i >= 0 condition is in case INT_TYPE is changed to signed. + INT_TYPE move_distance = 0; + INT_TYPE index_move_distance = 0; + for (INT_TYPE i = N-1; (std::is_signed::value ? (i >= 0) : (i < N)); --i) { + INT_TYPE sub_nboxes = sub_indices[i+1]-sub_indices[i]; + if (sub_nboxes <= max_items_per_leaf) { + ++move_distance; + index_move_distance += sub_nboxes; + } + else if (move_distance > 0) { + SRC_INT_TYPE *start_src_index = sub_indices[i]; + for (SRC_INT_TYPE *src_index = sub_indices[i+1]-1; src_index >= start_src_index; --src_index) { + src_index[index_move_distance] = src_index[0]; + } + sub_indices[i+move_distance] = sub_indices[i]+index_move_distance; + } + } + index_move_distance = 0; + for (INT_TYPE i = 0; i < nleaves; ++i) { + INT_TYPE sub_nboxes = leaf_sizes[i]; + sub_indices[i] = indices+index_move_distance; + for (int j = 0; j < sub_nboxes; ++j) + indices[index_move_distance+j] = leaf_indices[index_move_distance+j]; + index_move_distance += sub_nboxes; + } + } + + // Count the number of nodes to run in parallel and fill in single items in this node + INT_TYPE nparallel = 0; + static constexpr INT_TYPE PARALLEL_THRESHOLD = 1024; + for (INT_TYPE i = 0; i < N; ++i) { + INT_TYPE sub_nboxes = sub_indices[i+1]-sub_indices[i]; + if (sub_nboxes <= max_items_per_leaf) { + node.child[i] = indices_offset+(sub_indices[i]-sub_indices[0]); + } + else if (sub_nboxes >= PARALLEL_THRESHOLD) { + ++nparallel; + } + } + + // NOTE: Child nodes of this node need to be placed just before the nodes in + // their corresponding subtree, in between the subtrees, because + // traverseParallel uses the difference between the child node IDs + // to determine the number of nodes in the subtree. + + // Recurse + if (nparallel >= 2 && false) { + assert(false && "Not implemented; should never get here"); + exit(1); + // // Do the parallel ones first, so that they can be inserted in the right place. + // // Although the choice may seem somewhat arbitrary, we need the results to be + // // identical whether we choose to parallelize or not, and in case we change the + // // threshold later. + // UT_SmallArray,4*sizeof(UT_Array)> parallel_nodes; + // parallel_nodes.setSize(nparallel); + // UT_SmallArray parallel_parent_nodes; + // parallel_parent_nodes.setSize(nparallel); + // UTparallelFor(UT_BlockedRange(0,nparallel), [¶llel_nodes,¶llel_parent_nodes,&sub_indices,boxes,&sub_boxes,indices_offset,max_items_per_leaf](const UT_BlockedRange& r) { + // for (INT_TYPE taski = r.begin(), end = r.end(); taski < end; ++taski) { + // // First, find which child this is + // INT_TYPE counted_parallel = 0; + // INT_TYPE sub_nboxes; + // INT_TYPE childi; + // for (childi = 0; childi < N; ++childi) { + // sub_nboxes = sub_indices[childi+1]-sub_indices[childi]; + // if (sub_nboxes >= PARALLEL_THRESHOLD) { + // if (counted_parallel == taski) { + // break; + // } + // ++counted_parallel; + // } + // } + // UT_ASSERT_P(counted_parallel == taski); + + // UT_Array& local_nodes = parallel_nodes[taski]; + // // Preallocate an overestimate of the number of nodes needed. + // // At worst, we could have only 2 children in every leaf, and + // // then above that, we have a geometric series with r=1/N and a=(sub_nboxes/2)/N + // // The true worst case might be a little worst than this, but + // // it's probably fairly unlikely. + // local_nodes.setCapacity(nodeEstimate(sub_nboxes)); + // Node& parent_node = parallel_parent_nodes[taski]; + + // // We'll have to fix the internal node numbers in parent_node and local_nodes later + // initNodeReorder(local_nodes, parent_node, sub_boxes[childi], boxes, sub_indices[childi], sub_nboxes, + // indices_offset+(sub_indices[childi]-sub_indices[0]), max_items_per_leaf); + // } + // }, 0, 1); + + // INT_TYPE counted_parallel = 0; + // for (INT_TYPE i = 0; i < N; ++i) { + // INT_TYPE sub_nboxes = sub_indices[i+1]-sub_indices[i]; + // if (sub_nboxes > max_items_per_leaf) { + // INT_TYPE local_nodes_start = nodes.size(); + // node.child[i] = Node::markInternal(local_nodes_start); + // if (sub_nboxes >= PARALLEL_THRESHOLD) { + // // First, adjust the root child node + // Node child_node = parallel_parent_nodes[counted_parallel]; + // ++local_nodes_start; + // for (INT_TYPE childi = 0; childi < N; ++childi) { + // INT_TYPE child_child = child_node.child[childi]; + // if (Node::isInternal(child_child) && child_child != Node::EMPTY) { + // child_child += local_nodes_start; + // child_node.child[childi] = child_child; + // } + // } + + // // Make space in the array for the sub-child nodes + // const UT_Array& local_nodes = parallel_nodes[counted_parallel]; + // ++counted_parallel; + // INT_TYPE n = local_nodes.size(); + // nodes.bumpCapacity(local_nodes_start + n); + // nodes.setSizeNoInit(local_nodes_start + n); + // nodes[local_nodes_start-1] = child_node; + // } + // else { + // nodes.bumpCapacity(local_nodes_start + 1); + // nodes.setSizeNoInit(local_nodes_start + 1); + // initNodeReorder(nodes, nodes[local_nodes_start], sub_boxes[i], boxes, sub_indices[i], sub_nboxes, + // indices_offset+(sub_indices[i]-sub_indices[0]), max_items_per_leaf); + // } + // } + // } + + // // Now, adjust and copy all sub-child nodes that were made in parallel + // adjustParallelChildNodes(nparallel, nodes, node, parallel_nodes.array(), sub_indices); + } + else { + for (INT_TYPE i = 0; i < N; ++i) { + INT_TYPE sub_nboxes = sub_indices[i+1]-sub_indices[i]; + if (sub_nboxes > max_items_per_leaf) { + INT_TYPE local_nodes_start = nodes.size(); + node.child[i] = Node::markInternal(local_nodes_start); + nodes.bumpCapacity(local_nodes_start + 1); + nodes.setSizeNoInit(local_nodes_start + 1); + initNodeReorder(nodes, nodes[local_nodes_start], sub_boxes[i], boxes, sub_indices[i], sub_nboxes, + indices_offset+(sub_indices[i]-sub_indices[0]), max_items_per_leaf); + } + } + } +} + +template +template +inline void BVH::multiSplit(const Box& axes_minmax, const BOX_TYPE* boxes, SRC_INT_TYPE* indices, INT_TYPE nboxes, SRC_INT_TYPE* sub_indices[N+1], Box sub_boxes[N]) noexcept { + sub_indices[0] = indices; + sub_indices[2] = indices+nboxes; + split(axes_minmax, boxes, indices, nboxes, sub_indices[1], &sub_boxes[0]); + + if (N == 2) { + return; + } + + if (H == BVH_Heuristic::MEDIAN_MAX_AXIS) { + SRC_INT_TYPE* sub_indices_startend[2*N]; + Box sub_boxes_unsorted[N]; + sub_boxes_unsorted[0] = sub_boxes[0]; + sub_boxes_unsorted[1] = sub_boxes[1]; + sub_indices_startend[0] = sub_indices[0]; + sub_indices_startend[1] = sub_indices[1]; + sub_indices_startend[2] = sub_indices[1]; + sub_indices_startend[3] = sub_indices[2]; + for (INT_TYPE nsub = 2; nsub < N; ++nsub) { + SRC_INT_TYPE* selected_start = sub_indices_startend[0]; + SRC_INT_TYPE* selected_end = sub_indices_startend[1]; + Box sub_box = sub_boxes_unsorted[0]; + + // Shift results back. + for (INT_TYPE i = 0; i < nsub-1; ++i) { + sub_indices_startend[2*i ] = sub_indices_startend[2*i+2]; + sub_indices_startend[2*i+1] = sub_indices_startend[2*i+3]; + } + for (INT_TYPE i = 0; i < nsub-1; ++i) { + sub_boxes_unsorted[i] = sub_boxes_unsorted[i-1]; + } + + // Do the split + split(sub_box, boxes, selected_start, selected_end-selected_start, sub_indices_startend[2*nsub-1], &sub_boxes_unsorted[nsub]); + sub_indices_startend[2*nsub-2] = selected_start; + sub_indices_startend[2*nsub] = sub_indices_startend[2*nsub-1]; + sub_indices_startend[2*nsub+1] = selected_end; + + // Sort pointers so that they're in the correct order + sub_indices[N] = indices+nboxes; + for (INT_TYPE i = 0; i < N; ++i) { + SRC_INT_TYPE* prev_pointer = (i != 0) ? sub_indices[i-1] : nullptr; + SRC_INT_TYPE* min_pointer = nullptr; + Box box; + for (INT_TYPE j = 0; j < N; ++j) { + SRC_INT_TYPE* cur_pointer = sub_indices_startend[2*j]; + if ((cur_pointer > prev_pointer) && (!min_pointer || (cur_pointer < min_pointer))) { + min_pointer = cur_pointer; + box = sub_boxes_unsorted[j]; + } + } + UT_ASSERT_P(min_pointer); + sub_indices[i] = min_pointer; + sub_boxes[i] = box; + } + } + } + else { + T sub_box_areas[N]; + sub_box_areas[0] = unweightedHeuristic(sub_boxes[0]); + sub_box_areas[1] = unweightedHeuristic(sub_boxes[1]); + for (INT_TYPE nsub = 2; nsub < N; ++nsub) { + // Choose which one to split + INT_TYPE split_choice = INT_TYPE(-1); + T max_heuristic; + for (INT_TYPE i = 0; i < nsub; ++i) { + const INT_TYPE index_count = (sub_indices[i+1]-sub_indices[i]); + if (index_count > 1) { + const T heuristic = sub_box_areas[i]*index_count; + if (split_choice == INT_TYPE(-1) || heuristic > max_heuristic) { + split_choice = i; + max_heuristic = heuristic; + } + } + } + UT_ASSERT_MSG_P(split_choice != INT_TYPE(-1), "There should always be at least one that can be split!"); + + SRC_INT_TYPE* selected_start = sub_indices[split_choice]; + SRC_INT_TYPE* selected_end = sub_indices[split_choice+1]; + + // Shift results over; we can skip the one we selected. + for (INT_TYPE i = nsub; i > split_choice; --i) { + sub_indices[i+1] = sub_indices[i]; + } + for (INT_TYPE i = nsub-1; i > split_choice; --i) { + sub_boxes[i+1] = sub_boxes[i]; + } + for (INT_TYPE i = nsub-1; i > split_choice; --i) { + sub_box_areas[i+1] = sub_box_areas[i]; + } + + // Do the split + split(sub_boxes[split_choice], boxes, selected_start, selected_end-selected_start, sub_indices[split_choice+1], &sub_boxes[split_choice]); + sub_box_areas[split_choice] = unweightedHeuristic(sub_boxes[split_choice]); + sub_box_areas[split_choice+1] = unweightedHeuristic(sub_boxes[split_choice+1]); + } + } +} + +template +template +inline void BVH::split(const Box& axes_minmax, const BOX_TYPE* boxes, SRC_INT_TYPE* indices, INT_TYPE nboxes, SRC_INT_TYPE*& split_indices, Box* split_boxes) noexcept { + if (nboxes == 2) { + split_boxes[0].initBounds(boxes[indices[0]]); + split_boxes[1].initBounds(boxes[indices[1]]); + split_indices = indices+1; + return; + } + UT_ASSERT_MSG_P(nboxes > 2, "Cases with less than 3 boxes should have already been handled!"); + + if (H == BVH_Heuristic::MEDIAN_MAX_AXIS) { + UT_ASSERT_MSG(0, "FIXME: Implement this!!!"); + } + + constexpr INT_TYPE SMALL_LIMIT = 6; + if (nboxes <= SMALL_LIMIT) { + // Special case for a small number of boxes: check all (2^(n-1))-1 partitions. + // Without loss of generality, we assume that box 0 is in partition 0, + // and that not all boxes are in partition 0. + Box local_boxes[SMALL_LIMIT]; + for (INT_TYPE box = 0; box < nboxes; ++box) { + local_boxes[box].initBounds(boxes[indices[box]]); + //printf("Box %u: (%f-%f)x(%f-%f)x(%f-%f)\n", uint(box), local_boxes[box].vals[0][0], local_boxes[box].vals[0][1], local_boxes[box].vals[1][0], local_boxes[box].vals[1][1], local_boxes[box].vals[2][0], local_boxes[box].vals[2][1]); + } + const INT_TYPE partition_limit = (INT_TYPE(1)<<(nboxes-1)); + INT_TYPE best_partition = INT_TYPE(-1); + T best_heuristic; + for (INT_TYPE partition_bits = 1; partition_bits < partition_limit; ++partition_bits) { + Box sub_boxes[2]; + sub_boxes[0] = local_boxes[0]; + sub_boxes[1].initBounds(); + INT_TYPE sub_counts[2] = {1,0}; + for (INT_TYPE bit = 0; bit < nboxes-1; ++bit) { + INT_TYPE dest = (partition_bits>>bit)&1; + sub_boxes[dest].combine(local_boxes[bit+1]); + ++sub_counts[dest]; + } + //printf("Partition bits %u: sub_box[0]: (%f-%f)x(%f-%f)x(%f-%f)\n", uint(partition_bits), sub_boxes[0].vals[0][0], sub_boxes[0].vals[0][1], sub_boxes[0].vals[1][0], sub_boxes[0].vals[1][1], sub_boxes[0].vals[2][0], sub_boxes[0].vals[2][1]); + //printf("Partition bits %u: sub_box[1]: (%f-%f)x(%f-%f)x(%f-%f)\n", uint(partition_bits), sub_boxes[1].vals[0][0], sub_boxes[1].vals[0][1], sub_boxes[1].vals[1][0], sub_boxes[1].vals[1][1], sub_boxes[1].vals[2][0], sub_boxes[1].vals[2][1]); + const T heuristic = + unweightedHeuristic(sub_boxes[0])*sub_counts[0] + + unweightedHeuristic(sub_boxes[1])*sub_counts[1]; + //printf("Partition bits %u: heuristic = %f (= %f*%u + %f*%u)\n",uint(partition_bits),heuristic, unweightedHeuristic(sub_boxes[0]), uint(sub_counts[0]), unweightedHeuristic(sub_boxes[1]), uint(sub_counts[1])); + if (best_partition == INT_TYPE(-1) || heuristic < best_heuristic) { + //printf(" New best\n"); + best_partition = partition_bits; + best_heuristic = heuristic; + split_boxes[0] = sub_boxes[0]; + split_boxes[1] = sub_boxes[1]; + } + } + +#if 0 // This isn't actually necessary with the current design, because I changed how the number of subtree nodes is determined. + // If best_partition is partition_limit-1, there's only 1 box + // in partition 0. We should instead put this in partition 1, + // so that we can help always have the internal node indices first + // in each node. That gets used to (fairly) quickly determine + // the number of nodes in a sub-tree. + if (best_partition == partition_limit - 1) { + // Put the first index last. + SRC_INT_TYPE last_index = indices[0]; + SRC_INT_TYPE* dest_indices = indices; + SRC_INT_TYPE* local_split_indices = indices + nboxes-1; + for (; dest_indices != local_split_indices; ++dest_indices) { + dest_indices[0] = dest_indices[1]; + } + *local_split_indices = last_index; + split_indices = local_split_indices; + + // Swap the boxes + const Box temp_box = sub_boxes[0]; + sub_boxes[0] = sub_boxes[1]; + sub_boxes[1] = temp_box; + return; + } +#endif + + // Reorder the indices. + // NOTE: Index 0 is always in partition 0, so can stay put. + SRC_INT_TYPE local_indices[SMALL_LIMIT-1]; + for (INT_TYPE box = 0; box < nboxes-1; ++box) { + local_indices[box] = indices[box+1]; + } + SRC_INT_TYPE* dest_indices = indices+1; + SRC_INT_TYPE* src_indices = local_indices; + // Copy partition 0 + for (INT_TYPE bit = 0; bit < nboxes-1; ++bit, ++src_indices) { + if (!((best_partition>>bit)&1)) { + //printf("Copying %u into partition 0\n",uint(*src_indices)); + *dest_indices = *src_indices; + ++dest_indices; + } + } + split_indices = dest_indices; + // Copy partition 1 + src_indices = local_indices; + for (INT_TYPE bit = 0; bit < nboxes-1; ++bit, ++src_indices) { + if ((best_partition>>bit)&1) { + //printf("Copying %u into partition 1\n",uint(*src_indices)); + *dest_indices = *src_indices; + ++dest_indices; + } + } + return; + } + + uint max_axis = 0; + T max_axis_length = axes_minmax.vals[0][1] - axes_minmax.vals[0][0]; + for (uint axis = 1; axis < NAXES; ++axis) { + const T axis_length = axes_minmax.vals[axis][1] - axes_minmax.vals[axis][0]; + if (axis_length > max_axis_length) { + max_axis = axis; + max_axis_length = axis_length; + } + } + + if (!(max_axis_length > T(0))) { + // All boxes are a single point or NaN. + // Pick an arbitrary split point. + split_indices = indices + nboxes/2; + split_boxes[0] = axes_minmax; + split_boxes[1] = axes_minmax; + return; + } + + const INT_TYPE axis = max_axis; + + constexpr INT_TYPE MID_LIMIT = 2*NSPANS; + if (nboxes <= MID_LIMIT) { + // Sort along axis, and try all possible splits. + +#if 1 + // First, compute midpoints + T midpointsx2[MID_LIMIT]; + for (INT_TYPE i = 0; i < nboxes; ++i) { + midpointsx2[i] = utBoxCenter(boxes[indices[i]], axis); + } + SRC_INT_TYPE local_indices[MID_LIMIT]; + for (INT_TYPE i = 0; i < nboxes; ++i) { + local_indices[i] = i; + } + + const INT_TYPE chunk_starts[5] = {0, nboxes/4, nboxes/2, INT_TYPE((3*uint64(nboxes))/4), nboxes}; + + // For sorting, insertion sort 4 chunks and merge them + for (INT_TYPE chunk = 0; chunk < 4; ++chunk) { + const INT_TYPE start = chunk_starts[chunk]; + const INT_TYPE end = chunk_starts[chunk+1]; + for (INT_TYPE i = start+1; i < end; ++i) { + SRC_INT_TYPE indexi = local_indices[i]; + T vi = midpointsx2[indexi]; + for (INT_TYPE j = start; j < i; ++j) { + SRC_INT_TYPE indexj = local_indices[j]; + T vj = midpointsx2[indexj]; + if (vi < vj) { + do { + local_indices[j] = indexi; + indexi = indexj; + ++j; + if (j == i) { + local_indices[j] = indexi; + break; + } + indexj = local_indices[j]; + } while (true); + break; + } + } + } + } + // Merge chunks into another buffer + SRC_INT_TYPE local_indices_temp[MID_LIMIT]; + std::merge(local_indices, local_indices+chunk_starts[1], + local_indices+chunk_starts[1], local_indices+chunk_starts[2], + local_indices_temp, [&midpointsx2](const SRC_INT_TYPE a, const SRC_INT_TYPE b)->bool { + return midpointsx2[a] < midpointsx2[b]; + }); + std::merge(local_indices+chunk_starts[2], local_indices+chunk_starts[3], + local_indices+chunk_starts[3], local_indices+chunk_starts[4], + local_indices_temp+chunk_starts[2], [&midpointsx2](const SRC_INT_TYPE a, const SRC_INT_TYPE b)->bool { + return midpointsx2[a] < midpointsx2[b]; + }); + std::merge(local_indices_temp, local_indices_temp+chunk_starts[2], + local_indices_temp+chunk_starts[2], local_indices_temp+chunk_starts[4], + local_indices, [&midpointsx2](const SRC_INT_TYPE a, const SRC_INT_TYPE b)->bool { + return midpointsx2[a] < midpointsx2[b]; + }); + + // Translate local_indices into indices + for (INT_TYPE i = 0; i < nboxes; ++i) { + local_indices[i] = indices[local_indices[i]]; + } + // Copy back + for (INT_TYPE i = 0; i < nboxes; ++i) { + indices[i] = local_indices[i]; + } +#else + std::stable_sort(indices, indices+nboxes, [boxes,max_axis](SRC_INT_TYPE a, SRC_INT_TYPE b)->bool { + return utBoxCenter(boxes[a], max_axis) < utBoxCenter(boxes[b], max_axis); + }); +#endif + + // Accumulate boxes + Box left_boxes[MID_LIMIT-1]; + Box right_boxes[MID_LIMIT-1]; + const INT_TYPE nsplits = nboxes-1; + Box box_accumulator(boxes[local_indices[0]]); + left_boxes[0] = box_accumulator; + for (INT_TYPE i = 1; i < nsplits; ++i) { + box_accumulator.combine(boxes[local_indices[i]]); + left_boxes[i] = box_accumulator; + } + box_accumulator.initBounds(boxes[local_indices[nsplits-1]]); + right_boxes[nsplits-1] = box_accumulator; + for (INT_TYPE i = nsplits-1; i > 0; --i) { + box_accumulator.combine(boxes[local_indices[i]]); + right_boxes[i-1] = box_accumulator; + } + + INT_TYPE best_split = 0; + T best_local_heuristic = + unweightedHeuristic(left_boxes[0]) + + unweightedHeuristic(right_boxes[0])*(nboxes-1); + for (INT_TYPE split = 1; split < nsplits; ++split) { + const T heuristic = + unweightedHeuristic(left_boxes[split])*(split+1) + + unweightedHeuristic(right_boxes[split])*(nboxes-(split+1)); + if (heuristic < best_local_heuristic) { + best_split = split; + best_local_heuristic = heuristic; + } + } + split_indices = indices+best_split+1; + split_boxes[0] = left_boxes[best_split]; + split_boxes[1] = right_boxes[best_split]; + return; + } + + const T axis_min = axes_minmax.vals[max_axis][0]; + const T axis_length = max_axis_length; + Box span_boxes[NSPANS]; + for (INT_TYPE i = 0; i < NSPANS; ++i) { + span_boxes[i].initBounds(); + } + INT_TYPE span_counts[NSPANS]; + for (INT_TYPE i = 0; i < NSPANS; ++i) { + span_counts[i] = 0; + } + + const T axis_min_x2 = ut_BoxCentre::scale*axis_min; + // NOTE: Factor of 0.5 is factored out of the average when using the average value to determine the span that a box lies in. + const T axis_index_scale = (T(1.0/ut_BoxCentre::scale)*NSPANS)/axis_length; + constexpr INT_TYPE BOX_SPANS_PARALLEL_THRESHOLD = 2048; + INT_TYPE ntasks = 1; + if (nboxes >= BOX_SPANS_PARALLEL_THRESHOLD) { + INT_TYPE nprocessors = UT_Thread::getNumProcessors(); + ntasks = (nprocessors > 1) ? SYSmin(4*nprocessors, nboxes/(BOX_SPANS_PARALLEL_THRESHOLD/2)) : 1; + } + if (ntasks == 1) { + for (INT_TYPE indexi = 0; indexi < nboxes; ++indexi) { + const auto& box = boxes[indices[indexi]]; + const T sum = utBoxCenter(box, axis); + const uint span_index = SYSclamp(int((sum-axis_min_x2)*axis_index_scale), int(0), int(NSPANS-1)); + ++span_counts[span_index]; + Box& span_box = span_boxes[span_index]; + span_box.combine(box); + } + } + else { + UT_SmallArray> parallel_boxes; + UT_SmallArray parallel_counts; + igl::parallel_for( + nboxes, + [¶llel_boxes,¶llel_counts](int n) + { + parallel_boxes.setSize( NSPANS*n); + parallel_counts.setSize(NSPANS*n); + for(int t = 0;t& span_box = parallel_boxes[t*NSPANS+span_index]; + span_box.combine(box); + }, + [¶llel_boxes,¶llel_counts,&span_boxes,&span_counts](int t) + { + for(int i = 0;i left_boxes[NSPLITS]; + // Spans 1 to NSPANS-1 + Box right_boxes[NSPLITS]; + + // Accumulate boxes + Box box_accumulator = span_boxes[0]; + left_boxes[0] = box_accumulator; + for (INT_TYPE i = 1; i < NSPLITS; ++i) { + box_accumulator.combine(span_boxes[i]); + left_boxes[i] = box_accumulator; + } + box_accumulator = span_boxes[NSPANS-1]; + right_boxes[NSPLITS-1] = box_accumulator; + for (INT_TYPE i = NSPLITS-1; i > 0; --i) { + box_accumulator.combine(span_boxes[i]); + right_boxes[i-1] = box_accumulator; + } + + INT_TYPE left_counts[NSPLITS]; + + // Accumulate counts + INT_TYPE count_accumulator = span_counts[0]; + left_counts[0] = count_accumulator; + for (INT_TYPE spliti = 1; spliti < NSPLITS; ++spliti) { + count_accumulator += span_counts[spliti]; + left_counts[spliti] = count_accumulator; + } + + // Check which split is optimal, making sure that at least 1/MIN_FRACTION of all boxes are on each side. + const INT_TYPE min_count = nboxes/MIN_FRACTION; + UT_ASSERT_MSG_P(min_count > 0, "MID_LIMIT above should have been large enough that nboxes would be > MIN_FRACTION"); + const INT_TYPE max_count = ((MIN_FRACTION-1)*uint64(nboxes))/MIN_FRACTION; + UT_ASSERT_MSG_P(max_count < nboxes, "I'm not sure how this could happen mathematically, but it needs to be checked."); + T smallest_heuristic = std::numeric_limits::infinity(); + INT_TYPE split_index = -1; + for (INT_TYPE spliti = 0; spliti < NSPLITS; ++spliti) { + const INT_TYPE left_count = left_counts[spliti]; + if (left_count < min_count || left_count > max_count) { + continue; + } + const INT_TYPE right_count = nboxes-left_count; + const T heuristic = + left_count*unweightedHeuristic(left_boxes[spliti]) + + right_count*unweightedHeuristic(right_boxes[spliti]); + if (heuristic < smallest_heuristic) { + smallest_heuristic = heuristic; + split_index = spliti; + } + } + + SRC_INT_TYPE*const indices_end = indices+nboxes; + + if (split_index == -1) { + // No split was anywhere close to balanced, so we fall back to searching for one. + + // First, find the span containing the "balance" point, namely where left_counts goes from + // being less than min_count to more than max_count. + // If that's span 0, use max_count as the ordered index to select, + // if it's span NSPANS-1, use min_count as the ordered index to select, + // else use nboxes/2 as the ordered index to select. + //T min_pivotx2 = -std::numeric_limits::infinity(); + //T max_pivotx2 = std::numeric_limits::infinity(); + SRC_INT_TYPE* nth_index; + if (left_counts[0] > max_count) { + // Search for max_count ordered index + nth_index = indices+max_count; + //max_pivotx2 = max_axis_min_x2 + max_axis_length/(NSPANS/ut_BoxCentre::scale); + } + else if (left_counts[NSPLITS-1] < min_count) { + // Search for min_count ordered index + nth_index = indices+min_count; + //min_pivotx2 = max_axis_min_x2 + max_axis_length - max_axis_length/(NSPANS/ut_BoxCentre::scale); + } + else { + // Search for nboxes/2 ordered index + nth_index = indices+nboxes/2; + //for (INT_TYPE spliti = 1; spliti < NSPLITS; ++spliti) { + // // The second condition should be redundant, but is just in case. + // if (left_counts[spliti] > max_count || spliti == NSPLITS-1) { + // min_pivotx2 = max_axis_min_x2 + spliti*max_axis_length/(NSPANS/ut_BoxCentre::scale); + // max_pivotx2 = max_axis_min_x2 + (spliti+1)*max_axis_length/(NSPANS/ut_BoxCentre::scale); + // break; + // } + //} + } + nthElement(boxes,indices,indices+nboxes,max_axis,nth_index);//,min_pivotx2,max_pivotx2); + + split_indices = nth_index; + Box left_box(boxes[indices[0]]); + for (SRC_INT_TYPE* left_indices = indices+1; left_indices < nth_index; ++left_indices) { + left_box.combine(boxes[*left_indices]); + } + Box right_box(boxes[nth_index[0]]); + for (SRC_INT_TYPE* right_indices = nth_index+1; right_indices < indices_end; ++right_indices) { + right_box.combine(boxes[*right_indices]); + } + split_boxes[0] = left_box; + split_boxes[1] = right_box; + } + else { + const T pivotx2 = axis_min_x2 + (split_index+1)*axis_length/(NSPANS/ut_BoxCentre::scale); + SRC_INT_TYPE* ppivot_start; + SRC_INT_TYPE* ppivot_end; + partitionByCentre(boxes,indices,indices+nboxes,max_axis,pivotx2,ppivot_start,ppivot_end); + + split_indices = indices + left_counts[split_index]; + + // Ignoring roundoff error, we would have + // split_indices >= ppivot_start && split_indices <= ppivot_end, + // but it may not always be in practice. + if (split_indices >= ppivot_start && split_indices <= ppivot_end) { + split_boxes[0] = left_boxes[split_index]; + split_boxes[1] = right_boxes[split_index]; + return; + } + + // Roundoff error changed the split, so we need to recompute the boxes. + if (split_indices < ppivot_start) { + split_indices = ppivot_start; + } + else {//(split_indices > ppivot_end) + split_indices = ppivot_end; + } + + // Emergency checks, just in case + if (split_indices == indices) { + ++split_indices; + } + else if (split_indices == indices_end) { + --split_indices; + } + + Box left_box(boxes[indices[0]]); + for (SRC_INT_TYPE* left_indices = indices+1; left_indices < split_indices; ++left_indices) { + left_box.combine(boxes[*left_indices]); + } + Box right_box(boxes[split_indices[0]]); + for (SRC_INT_TYPE* right_indices = split_indices+1; right_indices < indices_end; ++right_indices) { + right_box.combine(boxes[*right_indices]); + } + split_boxes[0] = left_box; + split_boxes[1] = right_box; + } +} + +template +template +inline void BVH::adjustParallelChildNodes(INT_TYPE nparallel, UT_Array& nodes, Node& node, UT_Array* parallel_nodes, SRC_INT_TYPE* sub_indices) noexcept +{ + // Alec: No need to parallelize this... + //UTparallelFor(UT_BlockedRange(0,nparallel), [&node,&nodes,¶llel_nodes,&sub_indices](const UT_BlockedRange& r) { + INT_TYPE counted_parallel = 0; + INT_TYPE childi = 0; + for(int taski = 0;taski < nparallel; taski++) + { + //for (INT_TYPE taski = r.begin(), end = r.end(); taski < end; ++taski) { + // First, find which child this is + INT_TYPE sub_nboxes; + for (; childi < N; ++childi) { + sub_nboxes = sub_indices[childi+1]-sub_indices[childi]; + if (sub_nboxes >= PARALLEL_THRESHOLD) { + if (counted_parallel == taski) { + break; + } + ++counted_parallel; + } + } + UT_ASSERT_P(counted_parallel == taski); + + const UT_Array& local_nodes = parallel_nodes[counted_parallel]; + INT_TYPE n = local_nodes.size(); + INT_TYPE local_nodes_start = Node::getInternalNum(node.child[childi])+1; + ++counted_parallel; + ++childi; + + for (INT_TYPE j = 0; j < n; ++j) { + Node local_node = local_nodes[j]; + for (INT_TYPE childj = 0; childj < N; ++childj) { + INT_TYPE local_child = local_node.child[childj]; + if (Node::isInternal(local_child) && local_child != Node::EMPTY) { + local_child += local_nodes_start; + local_node.child[childj] = local_child; + } + } + nodes[local_nodes_start+j] = local_node; + } + } +} + +template +template +void BVH::nthElement(const BOX_TYPE* boxes, SRC_INT_TYPE* indices, const SRC_INT_TYPE* indices_end, const uint axis, SRC_INT_TYPE*const nth) noexcept {//, const T min_pivotx2, const T max_pivotx2) noexcept { + while (true) { + // Choose median of first, middle, and last as the pivot + T pivots[3] = { + utBoxCenter(boxes[indices[0]], axis), + utBoxCenter(boxes[indices[(indices_end-indices)/2]], axis), + utBoxCenter(boxes[*(indices_end-1)], axis) + }; + if (pivots[0] < pivots[1]) { + const T temp = pivots[0]; + pivots[0] = pivots[1]; + pivots[1] = temp; + } + if (pivots[0] < pivots[2]) { + const T temp = pivots[0]; + pivots[0] = pivots[2]; + pivots[2] = temp; + } + if (pivots[1] < pivots[2]) { + const T temp = pivots[1]; + pivots[1] = pivots[2]; + pivots[2] = temp; + } + T mid_pivotx2 = pivots[1]; +#if 0 + // We limit the pivot, because we know that the true value is between min and max + if (mid_pivotx2 < min_pivotx2) { + mid_pivotx2 = min_pivotx2; + } + else if (mid_pivotx2 > max_pivotx2) { + mid_pivotx2 = max_pivotx2; + } +#endif + SRC_INT_TYPE* pivot_start; + SRC_INT_TYPE* pivot_end; + partitionByCentre(boxes,indices,indices_end,axis,mid_pivotx2,pivot_start,pivot_end); + if (nth < pivot_start) { + indices_end = pivot_start; + } + else if (nth < pivot_end) { + // nth is in the middle of the pivot range, + // which is in the right place, so we're done. + return; + } + else { + indices = pivot_end; + } + if (indices_end <= indices+1) { + return; + } + } +} + +template +template +void BVH::partitionByCentre(const BOX_TYPE* boxes, SRC_INT_TYPE*const indices, const SRC_INT_TYPE*const indices_end, const uint axis, const T pivotx2, SRC_INT_TYPE*& ppivot_start, SRC_INT_TYPE*& ppivot_end) noexcept { + // TODO: Consider parallelizing this! + + // First element >= pivot + SRC_INT_TYPE* pivot_start = indices; + // First element > pivot + SRC_INT_TYPE* pivot_end = indices; + + // Loop through forward once + for (SRC_INT_TYPE* psrc_index = indices; psrc_index != indices_end; ++psrc_index) { + const T srcsum = utBoxCenter(boxes[*psrc_index], axis); + if (srcsum < pivotx2) { + if (psrc_index != pivot_start) { + if (pivot_start == pivot_end) { + // Common case: nothing equal to the pivot + const SRC_INT_TYPE temp = *psrc_index; + *psrc_index = *pivot_start; + *pivot_start = temp; + } + else { + // Less common case: at least one thing equal to the pivot + const SRC_INT_TYPE temp = *psrc_index; + *psrc_index = *pivot_end; + *pivot_end = *pivot_start; + *pivot_start = temp; + } + } + ++pivot_start; + ++pivot_end; + } + else if (srcsum == pivotx2) { + // Add to the pivot area + if (psrc_index != pivot_end) { + const SRC_INT_TYPE temp = *psrc_index; + *psrc_index = *pivot_end; + *pivot_end = temp; + } + ++pivot_end; + } + } + ppivot_start = pivot_start; + ppivot_end = pivot_end; +} + +#if 0 +template +void BVH::debugDump() const { + printf("\nNode 0: {\n"); + UT_WorkBuffer indent; + indent.append(80, ' '); + UT_Array stack; + stack.append(0); + stack.append(0); + while (!stack.isEmpty()) { + int depth = stack.size()/2; + if (indent.length() < 4*depth) { + indent.append(4, ' '); + } + INT_TYPE cur_nodei = stack[stack.size()-2]; + INT_TYPE cur_i = stack[stack.size()-1]; + if (cur_i == N) { + printf(indent.buffer()+indent.length()-(4*(depth-1))); + printf("}\n"); + stack.removeLast(); + stack.removeLast(); + continue; + } + ++stack[stack.size()-1]; + Node& cur_node = myRoot[cur_nodei]; + INT_TYPE child_nodei = cur_node.child[cur_i]; + if (Node::isInternal(child_nodei)) { + if (child_nodei == Node::EMPTY) { + printf(indent.buffer()+indent.length()-(4*(depth-1))); + printf("}\n"); + stack.removeLast(); + stack.removeLast(); + continue; + } + INT_TYPE internal_node = Node::getInternalNum(child_nodei); + printf(indent.buffer()+indent.length()-(4*depth)); + printf("Node %u: {\n", uint(internal_node)); + stack.append(internal_node); + stack.append(0); + continue; + } + else { + printf(indent.buffer()+indent.length()-(4*depth)); + printf("Tri %u\n", uint(child_nodei)); + } + } +} +#endif + +} // UT namespace +} // End HDK_Sample namespace +}} +#endif +/* + * Copyright (c) 2018 Side Effects Software Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * COMMENTS: + * Functions and structures for computing solid angles. + */ + +#pragma once + +#ifndef __HDK_UT_SolidAngle_h__ +#define __HDK_UT_SolidAngle_h__ + + + + + +#include + +namespace igl { namespace FastWindingNumber { +namespace HDK_Sample { + +template +using UT_Vector2T = UT_FixedVector; +template +using UT_Vector3T = UT_FixedVector; + +template +SYS_FORCE_INLINE T cross(const UT_Vector2T &v1, const UT_Vector2T &v2) +{ + return v1[0]*v2[1] - v1[1]*v2[0]; +} + +template +SYS_FORCE_INLINE +UT_Vector3T cross(const UT_Vector3T &v1, const UT_Vector3T &v2) +{ + UT_Vector3T result; + // compute the cross product: + result[0] = v1[1]*v2[2] - v1[2]*v2[1]; + result[1] = v1[2]*v2[0] - v1[0]*v2[2]; + result[2] = v1[0]*v2[1] - v1[1]*v2[0]; + return result; +} + +/// Returns the signed solid angle subtended by triangle abc +/// from query point. +/// +/// WARNING: This uses the right-handed normal convention, whereas most of +/// Houdini uses the left-handed normal convention, so either +/// negate the output, or swap b and c if you want it to be +/// positive inside and negative outside. +template +inline T UTsignedSolidAngleTri( + const UT_Vector3T &a, + const UT_Vector3T &b, + const UT_Vector3T &c, + const UT_Vector3T &query) +{ + // Make a, b, and c relative to query + UT_Vector3T qa = a-query; + UT_Vector3T qb = b-query; + UT_Vector3T qc = c-query; + + const T alength = qa.length(); + const T blength = qb.length(); + const T clength = qc.length(); + + // If any triangle vertices are coincident with query, + // query is on the surface, which we treat as no solid angle. + if (alength == 0 || blength == 0 || clength == 0) + return T(0); + + // Normalize the vectors + qa /= alength; + qb /= blength; + qc /= clength; + + // The formula on Wikipedia has roughly dot(qa,cross(qb,qc)), + // but that's unstable when qa, qb, and qc are very close, + // (e.g. if the input triangle was very far away). + // This should be equivalent, but more stable. + const T numerator = dot(qa, cross(qb-qa, qc-qa)); + + // If numerator is 0, regardless of denominator, query is on the + // surface, which we treat as no solid angle. + if (numerator == 0) + return T(0); + + const T denominator = T(1) + dot(qa,qb) + dot(qa,qc) + dot(qb,qc); + + return T(2)*SYSatan2(numerator, denominator); +} + +template +inline T UTsignedSolidAngleQuad( + const UT_Vector3T &a, + const UT_Vector3T &b, + const UT_Vector3T &c, + const UT_Vector3T &d, + const UT_Vector3T &query) +{ + // Make a, b, c, and d relative to query + UT_Vector3T v[4] = { + a-query, + b-query, + c-query, + d-query + }; + + const T lengths[4] = { + v[0].length(), + v[1].length(), + v[2].length(), + v[3].length() + }; + + // If any quad vertices are coincident with query, + // query is on the surface, which we treat as no solid angle. + // We could add the contribution from the non-planar part, + // but in the context of a mesh, we'd still miss some, like + // we do in the triangle case. + if (lengths[0] == T(0) || lengths[1] == T(0) || lengths[2] == T(0) || lengths[3] == T(0)) + return T(0); + + // Normalize the vectors + v[0] /= lengths[0]; + v[1] /= lengths[1]; + v[2] /= lengths[2]; + v[3] /= lengths[3]; + + // Compute (unnormalized, but consistently-scaled) barycentric coordinates + // for the query point inside the tetrahedron of points. + // If 0 or 4 of the coordinates are positive, (or slightly negative), the + // query is (approximately) inside, so the choice of triangulation matters. + // Otherwise, the triangulation doesn't matter. + + const UT_Vector3T diag02 = v[2]-v[0]; + const UT_Vector3T diag13 = v[3]-v[1]; + const UT_Vector3T v01 = v[1]-v[0]; + const UT_Vector3T v23 = v[3]-v[2]; + + T bary[4]; + bary[0] = dot(v[3],cross(v23,diag13)); + bary[1] = -dot(v[2],cross(v23,diag02)); + bary[2] = -dot(v[1],cross(v01,diag13)); + bary[3] = dot(v[0],cross(v01,diag02)); + + const T dot01 = dot(v[0],v[1]); + const T dot12 = dot(v[1],v[2]); + const T dot23 = dot(v[2],v[3]); + const T dot30 = dot(v[3],v[0]); + + T omega = T(0); + + // Equation of a bilinear patch in barycentric coordinates of its + // tetrahedron is x0*x2 = x1*x3. Less is one side; greater is other. + if (bary[0]*bary[2] < bary[1]*bary[3]) + { + // Split 0-2: triangles 0,1,2 and 0,2,3 + const T numerator012 = bary[3]; + const T numerator023 = bary[1]; + const T dot02 = dot(v[0],v[2]); + + // If numerator is 0, regardless of denominator, query is on the + // surface, which we treat as no solid angle. + if (numerator012 != T(0)) + { + const T denominator012 = T(1) + dot01 + dot12 + dot02; + omega = SYSatan2(numerator012, denominator012); + } + if (numerator023 != T(0)) + { + const T denominator023 = T(1) + dot02 + dot23 + dot30; + omega += SYSatan2(numerator023, denominator023); + } + } + else + { + // Split 1-3: triangles 0,1,3 and 1,2,3 + const T numerator013 = -bary[2]; + const T numerator123 = -bary[0]; + const T dot13 = dot(v[1],v[3]); + + // If numerator is 0, regardless of denominator, query is on the + // surface, which we treat as no solid angle. + if (numerator013 != T(0)) + { + const T denominator013 = T(1) + dot01 + dot13 + dot30; + omega = SYSatan2(numerator013, denominator013); + } + if (numerator123 != T(0)) + { + const T denominator123 = T(1) + dot12 + dot23 + dot13; + omega += SYSatan2(numerator123, denominator123); + } + } + return T(2)*omega; +} + +/// Class for quickly approximating signed solid angle of a large mesh +/// from many query points. This is useful for computing the +/// generalized winding number at many points. +/// +/// NOTE: This is currently only instantiated for . +template +class UT_SolidAngle +{ +public: + /// This is outlined so that we don't need to include UT_BVHImpl.h + inline UT_SolidAngle(); + /// This is outlined so that we don't need to include UT_BVHImpl.h + inline ~UT_SolidAngle(); + + /// NOTE: This does not take ownership over triangle_points or positions, + /// but does keep pointers to them, so the caller must keep them in + /// scope for the lifetime of this structure. + UT_SolidAngle( + const int ntriangles, + const int *const triangle_points, + const int npoints, + const UT_Vector3T *const positions, + const int order = 2) + : UT_SolidAngle() + { init(ntriangles, triangle_points, npoints, positions, order); } + + /// Initialize the tree and data. + /// NOTE: It is safe to call init on a UT_SolidAngle that has had init + /// called on it before, to re-initialize it. + inline void init( + const int ntriangles, + const int *const triangle_points, + const int npoints, + const UT_Vector3T *const positions, + const int order = 2); + + /// Frees myTree and myData, and clears the rest. + inline void clear(); + + /// Returns true if this is clear + bool isClear() const + { return myNTriangles == 0; } + + /// Returns an approximation of the signed solid angle of the mesh from the specified query_point + /// accuracy_scale is the value of (maxP/q) beyond which the approximation of the box will be used. + inline T computeSolidAngle(const UT_Vector3T &query_point, const T accuracy_scale = T(2.0)) const; + +private: + struct BoxData; + + static constexpr uint BVH_N = 4; + UT_BVH myTree; + int myNBoxes; + int myOrder; + std::unique_ptr myData; + int myNTriangles; + const int *myTrianglePoints; + int myNPoints; + const UT_Vector3T *myPositions; +}; + +template +inline T UTsignedAngleSegment( + const UT_Vector2T &a, + const UT_Vector2T &b, + const UT_Vector2T &query) +{ + // Make a and b relative to query + UT_Vector2T qa = a-query; + UT_Vector2T qb = b-query; + + // If any segment vertices are coincident with query, + // query is on the segment, which we treat as no angle. + if (qa.isZero() || qb.isZero()) + return T(0); + + // numerator = |qa||qb|sin(theta) + const T numerator = cross(qa, qb); + + // If numerator is 0, regardless of denominator, query is on the + // surface, which we treat as no solid angle. + if (numerator == 0) + return T(0); + + // denominator = |qa||qb|cos(theta) + const T denominator = dot(qa,qb); + + // numerator/denominator = tan(theta) + return SYSatan2(numerator, denominator); +} + +/// Class for quickly approximating signed subtended angle of a large curve +/// from many query points. This is useful for computing the +/// generalized winding number at many points. +/// +/// NOTE: This is currently only instantiated for . +template +class UT_SubtendedAngle +{ +public: + /// This is outlined so that we don't need to include UT_BVHImpl.h + inline UT_SubtendedAngle(); + /// This is outlined so that we don't need to include UT_BVHImpl.h + inline ~UT_SubtendedAngle(); + + /// NOTE: This does not take ownership over segment_points or positions, + /// but does keep pointers to them, so the caller must keep them in + /// scope for the lifetime of this structure. + UT_SubtendedAngle( + const int nsegments, + const int *const segment_points, + const int npoints, + const UT_Vector2T *const positions, + const int order = 2) + : UT_SubtendedAngle() + { init(nsegments, segment_points, npoints, positions, order); } + + /// Initialize the tree and data. + /// NOTE: It is safe to call init on a UT_SolidAngle that has had init + /// called on it before, to re-initialize it. + inline void init( + const int nsegments, + const int *const segment_points, + const int npoints, + const UT_Vector2T *const positions, + const int order = 2); + + /// Frees myTree and myData, and clears the rest. + inline void clear(); + + /// Returns true if this is clear + bool isClear() const + { return myNSegments == 0; } + + /// Returns an approximation of the signed solid angle of the mesh from the specified query_point + /// accuracy_scale is the value of (maxP/q) beyond which the approximation of the box will be used. + inline T computeAngle(const UT_Vector2T &query_point, const T accuracy_scale = T(2.0)) const; + +private: + struct BoxData; + + static constexpr uint BVH_N = 4; + UT_BVH myTree; + int myNBoxes; + int myOrder; + std::unique_ptr myData; + int myNSegments; + const int *mySegmentPoints; + int myNPoints; + const UT_Vector2T *myPositions; +}; + +} // End HDK_Sample namespace +}} +#endif +/* + * Copyright (c) 2018 Side Effects Software Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * COMMENTS: + * A wrapper function for the "free" function, used by UT_(Small)Array + */ + + + +#include + +namespace igl { namespace FastWindingNumber { + +// This needs to be here or else the warning suppression doesn't work because +// the templated calling code won't otherwise be compiled until after we've +// already popped the warning.state. So we just always disable this at file +// scope here. +#if defined(__GNUC__) && !defined(__clang__) + _Pragma("GCC diagnostic push") + _Pragma("GCC diagnostic ignored \"-Wfree-nonheap-object\"") +#endif +inline void ut_ArrayImplFree(void *p) +{ + free(p); +} +#if defined(__GNUC__) && !defined(__clang__) + _Pragma("GCC diagnostic pop") +#endif +} } +/* + * Copyright (c) 2018 Side Effects Software Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * COMMENTS: + * Functions and structures for computing solid angles. + */ + + + + + + + + +#include +#include +#include + +#define SOLID_ANGLE_TIME_PRECOMPUTE 0 + +#if SOLID_ANGLE_TIME_PRECOMPUTE +#include +#endif + +#define SOLID_ANGLE_DEBUG 0 +#if SOLID_ANGLE_DEBUG +#include +#endif + +#define TAYLOR_SERIES_ORDER 2 + +namespace igl { namespace FastWindingNumber { + +namespace HDK_Sample { + +template +struct UT_SolidAngle::BoxData +{ + void clear() + { + // Set everything to zero + memset(this,0,sizeof(*this)); + } + + using Type = typename std::conditional::value, v4uf, UT_FixedVector>::type; + using SType = typename std::conditional::value, v4uf, UT_FixedVector>::type; + + /// An upper bound on the squared distance from myAverageP to the farthest point in the box. + SType myMaxPDist2; + + /// Centre of mass of the mesh surface in this box + UT_FixedVector myAverageP; + + /// Unnormalized, area-weighted normal of the mesh in this box + UT_FixedVector myN; + +#if TAYLOR_SERIES_ORDER >= 1 + /// Values for Omega_1 + /// @{ + UT_FixedVector myNijDiag; // Nxx, Nyy, Nzz + Type myNxy_Nyx; // Nxy+Nyx + Type myNyz_Nzy; // Nyz+Nzy + Type myNzx_Nxz; // Nzx+Nxz + /// @} +#endif + +#if TAYLOR_SERIES_ORDER >= 2 + /// Values for Omega_2 + /// @{ + UT_FixedVector myNijkDiag; // Nxxx, Nyyy, Nzzz + Type mySumPermuteNxyz; // (Nxyz+Nxzy+Nyzx+Nyxz+Nzxy+Nzyx) = 2*(Nxyz+Nyzx+Nzxy) + Type my2Nxxy_Nyxx; // Nxxy+Nxyx+Nyxx = 2Nxxy+Nyxx + Type my2Nxxz_Nzxx; // Nxxz+Nxzx+Nzxx = 2Nxxz+Nzxx + Type my2Nyyz_Nzyy; // Nyyz+Nyzy+Nzyy = 2Nyyz+Nzyy + Type my2Nyyx_Nxyy; // Nyyx+Nyxy+Nxyy = 2Nyyx+Nxyy + Type my2Nzzx_Nxzz; // Nzzx+Nzxz+Nxzz = 2Nzzx+Nxzz + Type my2Nzzy_Nyzz; // Nzzy+Nzyz+Nyzz = 2Nzzy+Nyzz + /// @} +#endif +}; + +template +inline UT_SolidAngle::UT_SolidAngle() + : myTree() + , myNBoxes(0) + , myOrder(2) + , myData(nullptr) + , myNTriangles(0) + , myTrianglePoints(nullptr) + , myNPoints(0) + , myPositions(nullptr) +{} + +template +inline UT_SolidAngle::~UT_SolidAngle() +{ + // Default destruction works, but this needs to be outlined + // to avoid having to include UT_BVHImpl.h in the header, + // (for the UT_UniquePtr destructor.) +} + +template +inline void UT_SolidAngle::init( + const int ntriangles, + const int *const triangle_points, + const int npoints, + const UT_Vector3T *const positions, + const int order) +{ +#if SOLID_ANGLE_DEBUG + UTdebugFormat(""); + UTdebugFormat(""); + UTdebugFormat("Building BVH for {} ntriangles on {} points:", ntriangles, npoints); +#endif + myOrder = order; + myNTriangles = ntriangles; + myTrianglePoints = triangle_points; + myNPoints = npoints; + myPositions = positions; + +#if SOLID_ANGLE_TIME_PRECOMPUTE + UT_StopWatch timer; + timer.start(); +#endif + UT_SmallArray> triangle_boxes; + triangle_boxes.setSizeNoInit(ntriangles); + if (ntriangles < 16*1024) + { + const int *cur_triangle_points = triangle_points; + for (int i = 0; i < ntriangles; ++i, cur_triangle_points += 3) + { + UT::Box &box = triangle_boxes[i]; + box.initBounds(positions[cur_triangle_points[0]]); + box.enlargeBounds(positions[cur_triangle_points[1]]); + box.enlargeBounds(positions[cur_triangle_points[2]]); + } + } + else + { + igl::parallel_for(ntriangles, + [triangle_points,&triangle_boxes,positions](int i) + { + const int *cur_triangle_points = triangle_points + i*3; + UT::Box &box = triangle_boxes[i]; + box.initBounds(positions[cur_triangle_points[0]]); + box.enlargeBounds(positions[cur_triangle_points[1]]); + box.enlargeBounds(positions[cur_triangle_points[2]]); + }); + } +#if SOLID_ANGLE_TIME_PRECOMPUTE + double time = timer.stop(); + UTdebugFormat("{} s to create bounding boxes.", time); + timer.start(); +#endif + myTree.template init(triangle_boxes.array(), ntriangles); +#if SOLID_ANGLE_TIME_PRECOMPUTE + time = timer.stop(); + UTdebugFormat("{} s to initialize UT_BVH structure. {} nodes", time, myTree.getNumNodes()); +#endif + + //myTree.debugDump(); + + const int nnodes = myTree.getNumNodes(); + + myNBoxes = nnodes; + BoxData *box_data = new BoxData[nnodes]; + myData.reset(box_data); + + // Some data are only needed during initialization. + struct LocalData + { + // Bounding box + UT::Box myBox; + + // P and N are needed from each child for computing Nij. + UT_Vector3T myAverageP; + UT_Vector3T myAreaP; + UT_Vector3T myN; + + // Unsigned area is needed for computing the average position. + T myArea; + +#if TAYLOR_SERIES_ORDER >= 1 + // These are needed for computing Nijk. + UT_Vector3T myNijDiag; + T myNxy; T myNyx; + T myNyz; T myNzy; + T myNzx; T myNxz; +#endif + +#if TAYLOR_SERIES_ORDER >= 2 + UT_Vector3T myNijkDiag; // Nxxx, Nyyy, Nzzz + T mySumPermuteNxyz; // (Nxyz+Nxzy+Nyzx+Nyxz+Nzxy+Nzyx) = 2*(Nxyz+Nyzx+Nzxy) + T my2Nxxy_Nyxx; // Nxxy+Nxyx+Nyxx = 2Nxxy+Nyxx + T my2Nxxz_Nzxx; // Nxxz+Nxzx+Nzxx = 2Nxxz+Nzxx + T my2Nyyz_Nzyy; // Nyyz+Nyzy+Nzyy = 2Nyyz+Nzyy + T my2Nyyx_Nxyy; // Nyyx+Nyxy+Nxyy = 2Nyyx+Nxyy + T my2Nzzx_Nxzz; // Nzzx+Nzxz+Nxzz = 2Nzzx+Nxzz + T my2Nzzy_Nyzz; // Nzzy+Nzyz+Nyzz = 2Nzzy+Nyzz +#endif + }; + + struct PrecomputeFunctors + { + BoxData *const myBoxData; + const UT::Box *const myTriangleBoxes; + const int *const myTrianglePoints; + const UT_Vector3T *const myPositions; + const int myOrder; + + PrecomputeFunctors( + BoxData *box_data, + const UT::Box *triangle_boxes, + const int *triangle_points, + const UT_Vector3T *positions, + const int order) + : myBoxData(box_data) + , myTriangleBoxes(triangle_boxes) + , myTrianglePoints(triangle_points) + , myPositions(positions) + , myOrder(order) + {} + constexpr SYS_FORCE_INLINE bool pre(const int nodei, LocalData *data_for_parent) const + { + return true; + } + void item(const int itemi, const int parent_nodei, LocalData &data_for_parent) const + { + const UT_Vector3T *const positions = myPositions; + const int *const cur_triangle_points = myTrianglePoints + 3*itemi; + const UT_Vector3T a = positions[cur_triangle_points[0]]; + const UT_Vector3T b = positions[cur_triangle_points[1]]; + const UT_Vector3T c = positions[cur_triangle_points[2]]; + const UT_Vector3T ab = b-a; + const UT_Vector3T ac = c-a; + + const UT::Box &triangle_box = myTriangleBoxes[itemi]; + data_for_parent.myBox.initBounds(triangle_box.getMin(), triangle_box.getMax()); + + // Area-weighted normal (unnormalized) + const UT_Vector3T N = T(0.5)*cross(ab,ac); + const T area2 = N.length2(); + const T area = SYSsqrt(area2); + const UT_Vector3T P = (a+b+c)/3; + data_for_parent.myAverageP = P; + data_for_parent.myAreaP = P*area; + data_for_parent.myN = N; +#if SOLID_ANGLE_DEBUG + UTdebugFormat(""); + UTdebugFormat("Triangle {}: P = {}; N = {}; area = {}", itemi, P, N, area); + UTdebugFormat(" box = {}", data_for_parent.myBox); +#endif + + data_for_parent.myArea = area; +#if TAYLOR_SERIES_ORDER >= 1 + const int order = myOrder; + if (order < 1) + return; + + // NOTE: Due to P being at the centroid, triangles have Nij = 0 + // contributions to Nij. + data_for_parent.myNijDiag = T(0); + data_for_parent.myNxy = 0; data_for_parent.myNyx = 0; + data_for_parent.myNyz = 0; data_for_parent.myNzy = 0; + data_for_parent.myNzx = 0; data_for_parent.myNxz = 0; +#endif + +#if TAYLOR_SERIES_ORDER >= 2 + if (order < 2) + return; + + // If it's zero-length, the results are zero, so we can skip. + if (area == 0) + { + data_for_parent.myNijkDiag = T(0); + data_for_parent.mySumPermuteNxyz = 0; + data_for_parent.my2Nxxy_Nyxx = 0; + data_for_parent.my2Nxxz_Nzxx = 0; + data_for_parent.my2Nyyz_Nzyy = 0; + data_for_parent.my2Nyyx_Nxyy = 0; + data_for_parent.my2Nzzx_Nxzz = 0; + data_for_parent.my2Nzzy_Nyzz = 0; + return; + } + + // We need to use the NORMALIZED normal to multiply the integrals by. + UT_Vector3T n = N/area; + + // Figure out the order of a, b, and c in x, y, and z + // for use in computing the integrals for Nijk. + UT_Vector3T values[3] = {a, b, c}; + + int order_x[3] = {0,1,2}; + if (a[0] > b[0]) + std::swap(order_x[0],order_x[1]); + if (values[order_x[0]][0] > c[0]) + std::swap(order_x[0],order_x[2]); + if (values[order_x[1]][0] > values[order_x[2]][0]) + std::swap(order_x[1],order_x[2]); + T dx = values[order_x[2]][0] - values[order_x[0]][0]; + + int order_y[3] = {0,1,2}; + if (a[1] > b[1]) + std::swap(order_y[0],order_y[1]); + if (values[order_y[0]][1] > c[1]) + std::swap(order_y[0],order_y[2]); + if (values[order_y[1]][1] > values[order_y[2]][1]) + std::swap(order_y[1],order_y[2]); + T dy = values[order_y[2]][1] - values[order_y[0]][1]; + + int order_z[3] = {0,1,2}; + if (a[2] > b[2]) + std::swap(order_z[0],order_z[1]); + if (values[order_z[0]][2] > c[2]) + std::swap(order_z[0],order_z[2]); + if (values[order_z[1]][2] > values[order_z[2]][2]) + std::swap(order_z[1],order_z[2]); + T dz = values[order_z[2]][2] - values[order_z[0]][2]; + + auto &&compute_integrals = []( + const UT_Vector3T &a, + const UT_Vector3T &b, + const UT_Vector3T &c, + const UT_Vector3T &P, + T *integral_ii, + T *integral_ij, + T *integral_ik, + const int i) + { +#if SOLID_ANGLE_DEBUG + UTdebugFormat(" Splitting on {}; a = {}; b = {}; c = {}", char('x'+i), a, b, c); +#endif + // NOTE: a, b, and c must be in order of the i axis. + // We're splitting the triangle at the middle i coordinate. + const UT_Vector3T oab = b - a; + const UT_Vector3T oac = c - a; + const UT_Vector3T ocb = b - c; + UT_ASSERT_MSG_P(oac[i] > 0, "This should have been checked by the caller."); + const T t = oab[i]/oac[i]; + UT_ASSERT_MSG_P(t >= 0 && t <= 1, "Either sorting must have gone wrong, or there are input NaNs."); + + const int j = (i==2) ? 0 : (i+1); + const int k = (j==2) ? 0 : (j+1); + const T jdiff = t*oac[j] - oab[j]; + const T kdiff = t*oac[k] - oab[k]; + UT_Vector3T cross_a; + cross_a[0] = (jdiff*oab[k] - kdiff*oab[j]); + cross_a[1] = kdiff*oab[i]; + cross_a[2] = jdiff*oab[i]; + UT_Vector3T cross_c; + cross_c[0] = (jdiff*ocb[k] - kdiff*ocb[j]); + cross_c[1] = kdiff*ocb[i]; + cross_c[2] = jdiff*ocb[i]; + const T area_scale_a = cross_a.length(); + const T area_scale_c = cross_c.length(); + const T Pai = a[i] - P[i]; + const T Pci = c[i] - P[i]; + + // Integral over the area of the triangle of (pi^2)dA, + // by splitting the triangle into two at b, the a side + // and the c side. + const T int_ii_a = area_scale_a*(T(0.5)*Pai*Pai + T(2.0/3.0)*Pai*oab[i] + T(0.25)*oab[i]*oab[i]); + const T int_ii_c = area_scale_c*(T(0.5)*Pci*Pci + T(2.0/3.0)*Pci*ocb[i] + T(0.25)*ocb[i]*ocb[i]); + *integral_ii = int_ii_a + int_ii_c; +#if SOLID_ANGLE_DEBUG + UTdebugFormat(" integral_{}{}_a = {}; integral_{}{}_c = {}", char('x'+i), char('x'+i), int_ii_a, char('x'+i), char('x'+i), int_ii_c); +#endif + + int jk = j; + T *integral = integral_ij; + T diff = jdiff; + while (true) // This only does 2 iterations, one for j and one for k + { + if (integral) + { + T obmidj = b[jk] + T(0.5)*diff; + T oabmidj = obmidj - a[jk]; + T ocbmidj = obmidj - c[jk]; + T Paj = a[jk] - P[jk]; + T Pcj = c[jk] - P[jk]; + // Integral over the area of the triangle of (pi*pj)dA + const T int_ij_a = area_scale_a*(T(0.5)*Pai*Paj + T(1.0/3.0)*Pai*oabmidj + T(1.0/3.0)*Paj*oab[i] + T(0.25)*oab[i]*oabmidj); + const T int_ij_c = area_scale_c*(T(0.5)*Pci*Pcj + T(1.0/3.0)*Pci*ocbmidj + T(1.0/3.0)*Pcj*ocb[i] + T(0.25)*ocb[i]*ocbmidj); + *integral = int_ij_a + int_ij_c; +#if SOLID_ANGLE_DEBUG + UTdebugFormat(" integral_{}{}_a = {}; integral_{}{}_c = {}", char('x'+i), char('x'+jk), int_ij_a, char('x'+i), char('x'+jk), int_ij_c); +#endif + } + if (jk == k) + break; + jk = k; + integral = integral_ik; + diff = kdiff; + } + }; + + T integral_xx = 0; + T integral_xy = 0; + T integral_yy = 0; + T integral_yz = 0; + T integral_zz = 0; + T integral_zx = 0; + // Note that if the span of any axis is zero, the integral must be zero, + // since there's a factor of (p_i-P_i), i.e. value minus average, + // and every value must be equal to the average, giving zero. + if (dx > 0) + { + compute_integrals( + values[order_x[0]], values[order_x[1]], values[order_x[2]], P, + &integral_xx, ((dx >= dy && dy > 0) ? &integral_xy : nullptr), ((dx >= dz && dz > 0) ? &integral_zx : nullptr), 0); + } + if (dy > 0) + { + compute_integrals( + values[order_y[0]], values[order_y[1]], values[order_y[2]], P, + &integral_yy, ((dy >= dz && dz > 0) ? &integral_yz : nullptr), ((dx < dy && dx > 0) ? &integral_xy : nullptr), 1); + } + if (dz > 0) + { + compute_integrals( + values[order_z[0]], values[order_z[1]], values[order_z[2]], P, + &integral_zz, ((dx < dz && dx > 0) ? &integral_zx : nullptr), ((dy < dz && dy > 0) ? &integral_yz : nullptr), 2); + } + + UT_Vector3T Niii; + Niii[0] = integral_xx; + Niii[1] = integral_yy; + Niii[2] = integral_zz; + Niii *= n; + data_for_parent.myNijkDiag = Niii; + data_for_parent.mySumPermuteNxyz = 2*(n[0]*integral_yz + n[1]*integral_zx + n[2]*integral_xy); + T Nxxy = n[0]*integral_xy; + T Nxxz = n[0]*integral_zx; + T Nyyz = n[1]*integral_yz; + T Nyyx = n[1]*integral_xy; + T Nzzx = n[2]*integral_zx; + T Nzzy = n[2]*integral_yz; + data_for_parent.my2Nxxy_Nyxx = 2*Nxxy + n[1]*integral_xx; + data_for_parent.my2Nxxz_Nzxx = 2*Nxxz + n[2]*integral_xx; + data_for_parent.my2Nyyz_Nzyy = 2*Nyyz + n[2]*integral_yy; + data_for_parent.my2Nyyx_Nxyy = 2*Nyyx + n[0]*integral_yy; + data_for_parent.my2Nzzx_Nxzz = 2*Nzzx + n[0]*integral_zz; + data_for_parent.my2Nzzy_Nyzz = 2*Nzzy + n[1]*integral_zz; +#if SOLID_ANGLE_DEBUG + UTdebugFormat(" integral_xx = {}; yy = {}; zz = {}", integral_xx, integral_yy, integral_zz); + UTdebugFormat(" integral_xy = {}; yz = {}; zx = {}", integral_xy, integral_yz, integral_zx); +#endif +#endif + } + + void post(const int nodei, const int parent_nodei, LocalData *data_for_parent, const int nchildren, const LocalData *child_data_array) const + { + // NOTE: Although in the general case, data_for_parent may be null for the root call, + // this functor assumes that it's non-null, so the call below must pass a non-null pointer. + + BoxData ¤t_box_data = myBoxData[nodei]; + + UT_Vector3T N = child_data_array[0].myN; + ((T*)¤t_box_data.myN[0])[0] = N[0]; + ((T*)¤t_box_data.myN[1])[0] = N[1]; + ((T*)¤t_box_data.myN[2])[0] = N[2]; + UT_Vector3T areaP = child_data_array[0].myAreaP; + T area = child_data_array[0].myArea; + UT_Vector3T local_P = child_data_array[0].myAverageP; + ((T*)¤t_box_data.myAverageP[0])[0] = local_P[0]; + ((T*)¤t_box_data.myAverageP[1])[0] = local_P[1]; + ((T*)¤t_box_data.myAverageP[2])[0] = local_P[2]; + for (int i = 1; i < nchildren; ++i) + { + const UT_Vector3T local_N = child_data_array[i].myN; + N += local_N; + ((T*)¤t_box_data.myN[0])[i] = local_N[0]; + ((T*)¤t_box_data.myN[1])[i] = local_N[1]; + ((T*)¤t_box_data.myN[2])[i] = local_N[2]; + areaP += child_data_array[i].myAreaP; + area += child_data_array[i].myArea; + const UT_Vector3T local_P = child_data_array[i].myAverageP; + ((T*)¤t_box_data.myAverageP[0])[i] = local_P[0]; + ((T*)¤t_box_data.myAverageP[1])[i] = local_P[1]; + ((T*)¤t_box_data.myAverageP[2])[i] = local_P[2]; + } + for (int i = nchildren; i < BVH_N; ++i) + { + // Set to zero, just to avoid false positives for uses of uninitialized memory. + ((T*)¤t_box_data.myN[0])[i] = 0; + ((T*)¤t_box_data.myN[1])[i] = 0; + ((T*)¤t_box_data.myN[2])[i] = 0; + ((T*)¤t_box_data.myAverageP[0])[i] = 0; + ((T*)¤t_box_data.myAverageP[1])[i] = 0; + ((T*)¤t_box_data.myAverageP[2])[i] = 0; + } + data_for_parent->myN = N; + data_for_parent->myAreaP = areaP; + data_for_parent->myArea = area; + + UT::Box box(child_data_array[0].myBox); + for (int i = 1; i < nchildren; ++i) + box.enlargeBounds(child_data_array[i].myBox); + + // Normalize P + UT_Vector3T averageP; + if (area > 0) + averageP = areaP/area; + else + averageP = T(0.5)*(box.getMin() + box.getMax()); + data_for_parent->myAverageP = averageP; + + data_for_parent->myBox = box; + + for (int i = 0; i < nchildren; ++i) + { + const UT::Box &local_box(child_data_array[i].myBox); + const UT_Vector3T &local_P = child_data_array[i].myAverageP; + const UT_Vector3T maxPDiff = SYSmax(local_P-UT_Vector3T(local_box.getMin()), UT_Vector3T(local_box.getMax())-local_P); + ((T*)¤t_box_data.myMaxPDist2)[i] = maxPDiff.length2(); + } + for (int i = nchildren; i < BVH_N; ++i) + { + // This child is non-existent. If we set myMaxPDist2 to infinity, it will never + // use the approximation, and the traverseVector function can check for EMPTY. + ((T*)¤t_box_data.myMaxPDist2)[i] = std::numeric_limits::infinity(); + } + +#if TAYLOR_SERIES_ORDER >= 1 + const int order = myOrder; + if (order >= 1) + { + // We now have the current box's P, so we can adjust Nij and Nijk + data_for_parent->myNijDiag = child_data_array[0].myNijDiag; + data_for_parent->myNxy = 0; + data_for_parent->myNyx = 0; + data_for_parent->myNyz = 0; + data_for_parent->myNzy = 0; + data_for_parent->myNzx = 0; + data_for_parent->myNxz = 0; +#if TAYLOR_SERIES_ORDER >= 2 + data_for_parent->myNijkDiag = child_data_array[0].myNijkDiag; + data_for_parent->mySumPermuteNxyz = child_data_array[0].mySumPermuteNxyz; + data_for_parent->my2Nxxy_Nyxx = child_data_array[0].my2Nxxy_Nyxx; + data_for_parent->my2Nxxz_Nzxx = child_data_array[0].my2Nxxz_Nzxx; + data_for_parent->my2Nyyz_Nzyy = child_data_array[0].my2Nyyz_Nzyy; + data_for_parent->my2Nyyx_Nxyy = child_data_array[0].my2Nyyx_Nxyy; + data_for_parent->my2Nzzx_Nxzz = child_data_array[0].my2Nzzx_Nxzz; + data_for_parent->my2Nzzy_Nyzz = child_data_array[0].my2Nzzy_Nyzz; +#endif + + for (int i = 1; i < nchildren; ++i) + { + data_for_parent->myNijDiag += child_data_array[i].myNijDiag; +#if TAYLOR_SERIES_ORDER >= 2 + data_for_parent->myNijkDiag += child_data_array[i].myNijkDiag; + data_for_parent->mySumPermuteNxyz += child_data_array[i].mySumPermuteNxyz; + data_for_parent->my2Nxxy_Nyxx += child_data_array[i].my2Nxxy_Nyxx; + data_for_parent->my2Nxxz_Nzxx += child_data_array[i].my2Nxxz_Nzxx; + data_for_parent->my2Nyyz_Nzyy += child_data_array[i].my2Nyyz_Nzyy; + data_for_parent->my2Nyyx_Nxyy += child_data_array[i].my2Nyyx_Nxyy; + data_for_parent->my2Nzzx_Nxzz += child_data_array[i].my2Nzzx_Nxzz; + data_for_parent->my2Nzzy_Nyzz += child_data_array[i].my2Nzzy_Nyzz; +#endif + } + for (int j = 0; j < 3; ++j) + ((T*)¤t_box_data.myNijDiag[j])[0] = child_data_array[0].myNijDiag[j]; + ((T*)¤t_box_data.myNxy_Nyx)[0] = child_data_array[0].myNxy + child_data_array[0].myNyx; + ((T*)¤t_box_data.myNyz_Nzy)[0] = child_data_array[0].myNyz + child_data_array[0].myNzy; + ((T*)¤t_box_data.myNzx_Nxz)[0] = child_data_array[0].myNzx + child_data_array[0].myNxz; + for (int j = 0; j < 3; ++j) + ((T*)¤t_box_data.myNijkDiag[j])[0] = child_data_array[0].myNijkDiag[j]; + ((T*)¤t_box_data.mySumPermuteNxyz)[0] = child_data_array[0].mySumPermuteNxyz; + ((T*)¤t_box_data.my2Nxxy_Nyxx)[0] = child_data_array[0].my2Nxxy_Nyxx; + ((T*)¤t_box_data.my2Nxxz_Nzxx)[0] = child_data_array[0].my2Nxxz_Nzxx; + ((T*)¤t_box_data.my2Nyyz_Nzyy)[0] = child_data_array[0].my2Nyyz_Nzyy; + ((T*)¤t_box_data.my2Nyyx_Nxyy)[0] = child_data_array[0].my2Nyyx_Nxyy; + ((T*)¤t_box_data.my2Nzzx_Nxzz)[0] = child_data_array[0].my2Nzzx_Nxzz; + ((T*)¤t_box_data.my2Nzzy_Nyzz)[0] = child_data_array[0].my2Nzzy_Nyzz; + for (int i = 1; i < nchildren; ++i) + { + for (int j = 0; j < 3; ++j) + ((T*)¤t_box_data.myNijDiag[j])[i] = child_data_array[i].myNijDiag[j]; + ((T*)¤t_box_data.myNxy_Nyx)[i] = child_data_array[i].myNxy + child_data_array[i].myNyx; + ((T*)¤t_box_data.myNyz_Nzy)[i] = child_data_array[i].myNyz + child_data_array[i].myNzy; + ((T*)¤t_box_data.myNzx_Nxz)[i] = child_data_array[i].myNzx + child_data_array[i].myNxz; + for (int j = 0; j < 3; ++j) + ((T*)¤t_box_data.myNijkDiag[j])[i] = child_data_array[i].myNijkDiag[j]; + ((T*)¤t_box_data.mySumPermuteNxyz)[i] = child_data_array[i].mySumPermuteNxyz; + ((T*)¤t_box_data.my2Nxxy_Nyxx)[i] = child_data_array[i].my2Nxxy_Nyxx; + ((T*)¤t_box_data.my2Nxxz_Nzxx)[i] = child_data_array[i].my2Nxxz_Nzxx; + ((T*)¤t_box_data.my2Nyyz_Nzyy)[i] = child_data_array[i].my2Nyyz_Nzyy; + ((T*)¤t_box_data.my2Nyyx_Nxyy)[i] = child_data_array[i].my2Nyyx_Nxyy; + ((T*)¤t_box_data.my2Nzzx_Nxzz)[i] = child_data_array[i].my2Nzzx_Nxzz; + ((T*)¤t_box_data.my2Nzzy_Nyzz)[i] = child_data_array[i].my2Nzzy_Nyzz; + } + for (int i = nchildren; i < BVH_N; ++i) + { + // Set to zero, just to avoid false positives for uses of uninitialized memory. + for (int j = 0; j < 3; ++j) + ((T*)¤t_box_data.myNijDiag[j])[i] = 0; + ((T*)¤t_box_data.myNxy_Nyx)[i] = 0; + ((T*)¤t_box_data.myNyz_Nzy)[i] = 0; + ((T*)¤t_box_data.myNzx_Nxz)[i] = 0; + for (int j = 0; j < 3; ++j) + ((T*)¤t_box_data.myNijkDiag[j])[i] = 0; + ((T*)¤t_box_data.mySumPermuteNxyz)[i] = 0; + ((T*)¤t_box_data.my2Nxxy_Nyxx)[i] = 0; + ((T*)¤t_box_data.my2Nxxz_Nzxx)[i] = 0; + ((T*)¤t_box_data.my2Nyyz_Nzyy)[i] = 0; + ((T*)¤t_box_data.my2Nyyx_Nxyy)[i] = 0; + ((T*)¤t_box_data.my2Nzzx_Nxzz)[i] = 0; + ((T*)¤t_box_data.my2Nzzy_Nyzz)[i] = 0; + } + + for (int i = 0; i < nchildren; ++i) + { + const LocalData &child_data = child_data_array[i]; + UT_Vector3T displacement = child_data.myAverageP - UT_Vector3T(data_for_parent->myAverageP); + UT_Vector3T N = child_data.myN; + + // Adjust Nij for the change in centre P + data_for_parent->myNijDiag += N*displacement; + T Nxy = child_data.myNxy + N[0]*displacement[1]; + T Nyx = child_data.myNyx + N[1]*displacement[0]; + T Nyz = child_data.myNyz + N[1]*displacement[2]; + T Nzy = child_data.myNzy + N[2]*displacement[1]; + T Nzx = child_data.myNzx + N[2]*displacement[0]; + T Nxz = child_data.myNxz + N[0]*displacement[2]; + + data_for_parent->myNxy += Nxy; + data_for_parent->myNyx += Nyx; + data_for_parent->myNyz += Nyz; + data_for_parent->myNzy += Nzy; + data_for_parent->myNzx += Nzx; + data_for_parent->myNxz += Nxz; + +#if TAYLOR_SERIES_ORDER >= 2 + if (order >= 2) + { + // Adjust Nijk for the change in centre P + data_for_parent->myNijkDiag += T(2)*displacement*child_data.myNijDiag + displacement*displacement*child_data.myN; + data_for_parent->mySumPermuteNxyz += (displacement[0]*(Nyz+Nzy) + displacement[1]*(Nzx+Nxz) + displacement[2]*(Nxy+Nyx)); + data_for_parent->my2Nxxy_Nyxx += + 2*(displacement[1]*child_data.myNijDiag[0] + displacement[0]*child_data.myNxy + N[0]*displacement[0]*displacement[1]) + + 2*child_data.myNyx*displacement[0] + N[1]*displacement[0]*displacement[0]; + data_for_parent->my2Nxxz_Nzxx += + 2*(displacement[2]*child_data.myNijDiag[0] + displacement[0]*child_data.myNxz + N[0]*displacement[0]*displacement[2]) + + 2*child_data.myNzx*displacement[0] + N[2]*displacement[0]*displacement[0]; + data_for_parent->my2Nyyz_Nzyy += + 2*(displacement[2]*child_data.myNijDiag[1] + displacement[1]*child_data.myNyz + N[1]*displacement[1]*displacement[2]) + + 2*child_data.myNzy*displacement[1] + N[2]*displacement[1]*displacement[1]; + data_for_parent->my2Nyyx_Nxyy += + 2*(displacement[0]*child_data.myNijDiag[1] + displacement[1]*child_data.myNyx + N[1]*displacement[1]*displacement[0]) + + 2*child_data.myNxy*displacement[1] + N[0]*displacement[1]*displacement[1]; + data_for_parent->my2Nzzx_Nxzz += + 2*(displacement[0]*child_data.myNijDiag[2] + displacement[2]*child_data.myNzx + N[2]*displacement[2]*displacement[0]) + + 2*child_data.myNxz*displacement[2] + N[0]*displacement[2]*displacement[2]; + data_for_parent->my2Nzzy_Nyzz += + 2*(displacement[1]*child_data.myNijDiag[2] + displacement[2]*child_data.myNzy + N[2]*displacement[2]*displacement[1]) + + 2*child_data.myNyz*displacement[2] + N[1]*displacement[2]*displacement[2]; + } +#endif + } + } +#endif +#if SOLID_ANGLE_DEBUG + UTdebugFormat(""); + UTdebugFormat("Node {}: nchildren = {}; maxP = {}", nodei, nchildren, SYSsqrt(current_box_data.myMaxPDist2)); + UTdebugFormat(" P = {}; N = {}", current_box_data.myAverageP, current_box_data.myN); +#if TAYLOR_SERIES_ORDER >= 1 + UTdebugFormat(" Nii = {}", current_box_data.myNijDiag); + UTdebugFormat(" Nxy+Nyx = {}; Nyz+Nzy = {}; Nyz+Nzy = {}", current_box_data.myNxy_Nyx, current_box_data.myNyz_Nzy, current_box_data.myNzx_Nxz); +#if TAYLOR_SERIES_ORDER >= 2 + UTdebugFormat(" Niii = {}; 2(Nxyz+Nyzx+Nzxy) = {}", current_box_data.myNijkDiag, current_box_data.mySumPermuteNxyz); + UTdebugFormat(" 2Nxxy+Nyxx = {}; 2Nxxz+Nzxx = {}", current_box_data.my2Nxxy_Nyxx, current_box_data.my2Nxxz_Nzxx); + UTdebugFormat(" 2Nyyz+Nzyy = {}; 2Nyyx+Nxyy = {}", current_box_data.my2Nyyz_Nzyy, current_box_data.my2Nyyx_Nxyy); + UTdebugFormat(" 2Nzzx+Nxzz = {}; 2Nzzy+Nyzz = {}", current_box_data.my2Nzzx_Nxzz, current_box_data.my2Nzzy_Nyzz); +#endif +#endif +#endif + } + }; + +#if SOLID_ANGLE_TIME_PRECOMPUTE + timer.start(); +#endif + const PrecomputeFunctors functors(box_data, triangle_boxes.array(), triangle_points, positions, order); + // NOTE: post-functor relies on non-null data_for_parent, so we have to pass one. + LocalData local_data; + myTree.template traverseParallel(4096, functors, &local_data); + //myTree.template traverse(functors); +#if SOLID_ANGLE_TIME_PRECOMPUTE + time = timer.stop(); + UTdebugFormat("{} s to precompute coefficients.", time); +#endif +} + +template +inline void UT_SolidAngle::clear() +{ + myTree.clear(); + myNBoxes = 0; + myOrder = 2; + myData.reset(); + myNTriangles = 0; + myTrianglePoints = nullptr; + myNPoints = 0; + myPositions = nullptr; +} + +template +inline T UT_SolidAngle::computeSolidAngle(const UT_Vector3T &query_point, const T accuracy_scale) const +{ + const T accuracy_scale2 = accuracy_scale*accuracy_scale; + + struct SolidAngleFunctors + { + const BoxData *const myBoxData; + const UT_Vector3T myQueryPoint; + const T myAccuracyScale2; + const UT_Vector3T *const myPositions; + const int *const myTrianglePoints; + const int myOrder; + + SolidAngleFunctors( + const BoxData *const box_data, + const UT_Vector3T &query_point, + const T accuracy_scale2, + const int order, + const UT_Vector3T *const positions, + const int *const triangle_points) + : myBoxData(box_data) + , myQueryPoint(query_point) + , myAccuracyScale2(accuracy_scale2) + , myOrder(order) + , myPositions(positions) + , myTrianglePoints(triangle_points) + {} + uint pre(const int nodei, T *data_for_parent) const + { + const BoxData &data = myBoxData[nodei]; + const typename BoxData::Type maxP2 = data.myMaxPDist2; + UT_FixedVector q; + q[0] = typename BoxData::Type(myQueryPoint[0]); + q[1] = typename BoxData::Type(myQueryPoint[1]); + q[2] = typename BoxData::Type(myQueryPoint[2]); + q -= data.myAverageP; + const typename BoxData::Type qlength2 = q[0]*q[0] + q[1]*q[1] + q[2]*q[2]; + + // If the query point is within a factor of accuracy_scale of the box radius, + // it's assumed to be not a good enough approximation, so it needs to descend. + // TODO: Is there a way to estimate the error? + static_assert((std::is_same::value), "FIXME: Implement support for other tuple types!"); + v4uu descend_mask = (qlength2 <= maxP2*myAccuracyScale2); + uint descend_bitmask = _mm_movemask_ps(V4SF(descend_mask.vector)); + constexpr uint allchildbits = ((uint(1)<= 1 + const int order = myOrder; + if (order >= 1) + { + const UT_FixedVector q2 = q*q; + const typename BoxData::Type qlength_m3 = qlength_m2*qlength_m1; + const typename BoxData::Type Omega_1 = + qlength_m3*(data.myNijDiag[0] + data.myNijDiag[1] + data.myNijDiag[2] + -typename BoxData::Type(3.0)*(dot(q2,data.myNijDiag) + + q[0]*q[1]*data.myNxy_Nyx + + q[0]*q[2]*data.myNzx_Nxz + + q[1]*q[2]*data.myNyz_Nzy)); + Omega_approx += Omega_1; +#if TAYLOR_SERIES_ORDER >= 2 + if (order >= 2) + { + const UT_FixedVector q3 = q2*q; + const typename BoxData::Type qlength_m4 = qlength_m2*qlength_m2; + typename BoxData::Type temp0[3] = { + data.my2Nyyx_Nxyy+data.my2Nzzx_Nxzz, + data.my2Nzzy_Nyzz+data.my2Nxxy_Nyxx, + data.my2Nxxz_Nzxx+data.my2Nyyz_Nzyy + }; + typename BoxData::Type temp1[3] = { + q[1]*data.my2Nxxy_Nyxx + q[2]*data.my2Nxxz_Nzxx, + q[2]*data.my2Nyyz_Nzyy + q[0]*data.my2Nyyx_Nxyy, + q[0]*data.my2Nzzx_Nxzz + q[1]*data.my2Nzzy_Nyzz + }; + const typename BoxData::Type Omega_2 = + qlength_m4*(typename BoxData::Type(1.5)*dot(q, typename BoxData::Type(3)*data.myNijkDiag + UT_FixedVector(temp0)) + -typename BoxData::Type(7.5)*(dot(q3,data.myNijkDiag) + q[0]*q[1]*q[2]*data.mySumPermuteNxyz + dot(q2, UT_FixedVector(temp1)))); + Omega_approx += Omega_2; + } +#endif + } +#endif + + // If q is so small that we got NaNs and we just have a + // small bounding box, it needs to descend. + const v4uu mask = Omega_approx.isFinite() & ~descend_mask; + Omega_approx = Omega_approx & mask; + descend_bitmask = (~_mm_movemask_ps(V4SF(mask.vector))) & allchildbits; + + T sum = Omega_approx[0]; + for (int i = 1; i < BVH_N; ++i) + sum += Omega_approx[i]; + *data_for_parent = sum; + + return descend_bitmask; + } + void item(const int itemi, const int parent_nodei, T &data_for_parent) const + { + const UT_Vector3T *const positions = myPositions; + const int *const cur_triangle_points = myTrianglePoints + 3*itemi; + const UT_Vector3T a = positions[cur_triangle_points[0]]; + const UT_Vector3T b = positions[cur_triangle_points[1]]; + const UT_Vector3T c = positions[cur_triangle_points[2]]; + + data_for_parent = UTsignedSolidAngleTri(a, b, c, myQueryPoint); + } + SYS_FORCE_INLINE void post(const int nodei, const int parent_nodei, T *data_for_parent, const int nchildren, const T *child_data_array, const uint descend_bits) const + { + T sum = (descend_bits&1) ? child_data_array[0] : 0; + for (int i = 1; i < nchildren; ++i) + sum += ((descend_bits>>i)&1) ? child_data_array[i] : 0; + + *data_for_parent += sum; + } + }; + const SolidAngleFunctors functors(myData.get(), query_point, accuracy_scale2, myOrder, myPositions, myTrianglePoints); + + T sum; + myTree.traverseVector(functors, &sum); + return sum; +} + +template +struct UT_SubtendedAngle::BoxData +{ + void clear() + { + // Set everything to zero + memset(this,0,sizeof(*this)); + } + + using Type = typename std::conditional::value, v4uf, UT_FixedVector>::type; + using SType = typename std::conditional::value, v4uf, UT_FixedVector>::type; + + /// An upper bound on the squared distance from myAverageP to the farthest point in the box. + SType myMaxPDist2; + + /// Centre of mass of the mesh surface in this box + UT_FixedVector myAverageP; + + /// Unnormalized, area-weighted normal of the mesh in this box + UT_FixedVector myN; + + /// Values for Omega_1 + /// @{ + UT_FixedVector myNijDiag; // Nxx, Nyy + Type myNxy_Nyx; // Nxy+Nyx + /// @} + + /// Values for Omega_2 + /// @{ + UT_FixedVector myNijkDiag; // Nxxx, Nyyy + Type my2Nxxy_Nyxx; // Nxxy+Nxyx+Nyxx = 2Nxxy+Nyxx + Type my2Nyyx_Nxyy; // Nyyx+Nyxy+Nxyy = 2Nyyx+Nxyy + /// @} +}; + +template +inline UT_SubtendedAngle::UT_SubtendedAngle() + : myTree() + , myNBoxes(0) + , myOrder(2) + , myData(nullptr) + , myNSegments(0) + , mySegmentPoints(nullptr) + , myNPoints(0) + , myPositions(nullptr) +{} + +template +inline UT_SubtendedAngle::~UT_SubtendedAngle() +{ + // Default destruction works, but this needs to be outlined + // to avoid having to include UT_BVHImpl.h in the header, + // (for the UT_UniquePtr destructor.) +} + +template +inline void UT_SubtendedAngle::init( + const int nsegments, + const int *const segment_points, + const int npoints, + const UT_Vector2T *const positions, + const int order) +{ +#if SOLID_ANGLE_DEBUG + UTdebugFormat(""); + UTdebugFormat(""); + UTdebugFormat("Building BVH for {} segments on {} points:", nsegments, npoints); +#endif + myOrder = order; + myNSegments = nsegments; + mySegmentPoints = segment_points; + myNPoints = npoints; + myPositions = positions; + +#if SOLID_ANGLE_TIME_PRECOMPUTE + UT_StopWatch timer; + timer.start(); +#endif + UT_SmallArray> segment_boxes; + segment_boxes.setSizeNoInit(nsegments); + if (nsegments < 16*1024) + { + const int *cur_segment_points = segment_points; + for (int i = 0; i < nsegments; ++i, cur_segment_points += 2) + { + UT::Box &box = segment_boxes[i]; + box.initBounds(positions[cur_segment_points[0]]); + box.enlargeBounds(positions[cur_segment_points[1]]); + } + } + else + { + igl::parallel_for(nsegments, + [segment_points,&segment_boxes,positions](int i) + { + const int *cur_segment_points = segment_points + i*2; + UT::Box &box = segment_boxes[i]; + box.initBounds(positions[cur_segment_points[0]]); + box.enlargeBounds(positions[cur_segment_points[1]]); + }); + } +#if SOLID_ANGLE_TIME_PRECOMPUTE + double time = timer.stop(); + UTdebugFormat("{} s to create bounding boxes.", time); + timer.start(); +#endif + myTree.template init(segment_boxes.array(), nsegments); +#if SOLID_ANGLE_TIME_PRECOMPUTE + time = timer.stop(); + UTdebugFormat("{} s to initialize UT_BVH structure. {} nodes", time, myTree.getNumNodes()); +#endif + + //myTree.debugDump(); + + const int nnodes = myTree.getNumNodes(); + + myNBoxes = nnodes; + BoxData *box_data = new BoxData[nnodes]; + myData.reset(box_data); + + // Some data are only needed during initialization. + struct LocalData + { + // Bounding box + UT::Box myBox; + + // P and N are needed from each child for computing Nij. + UT_Vector2T myAverageP; + UT_Vector2T myLengthP; + UT_Vector2T myN; + + // Unsigned length is needed for computing the average position. + T myLength; + + // These are needed for computing Nijk. + UT_Vector2T myNijDiag; + T myNxy; T myNyx; + + UT_Vector2T myNijkDiag; // Nxxx, Nyyy + T my2Nxxy_Nyxx; // Nxxy+Nxyx+Nyxx = 2Nxxy+Nyxx + T my2Nyyx_Nxyy; // Nyyx+Nyxy+Nxyy = 2Nyyx+Nxyy + }; + + struct PrecomputeFunctors + { + BoxData *const myBoxData; + const UT::Box *const mySegmentBoxes; + const int *const mySegmentPoints; + const UT_Vector2T *const myPositions; + const int myOrder; + + PrecomputeFunctors( + BoxData *box_data, + const UT::Box *segment_boxes, + const int *segment_points, + const UT_Vector2T *positions, + const int order) + : myBoxData(box_data) + , mySegmentBoxes(segment_boxes) + , mySegmentPoints(segment_points) + , myPositions(positions) + , myOrder(order) + {} + constexpr SYS_FORCE_INLINE bool pre(const int nodei, LocalData *data_for_parent) const + { + return true; + } + void item(const int itemi, const int parent_nodei, LocalData &data_for_parent) const + { + const UT_Vector2T *const positions = myPositions; + const int *const cur_segment_points = mySegmentPoints + 2*itemi; + const UT_Vector2T a = positions[cur_segment_points[0]]; + const UT_Vector2T b = positions[cur_segment_points[1]]; + const UT_Vector2T ab = b-a; + + const UT::Box &segment_box = mySegmentBoxes[itemi]; + data_for_parent.myBox = segment_box; + + // Length-weighted normal (unnormalized) + UT_Vector2T N; + N[0] = ab[1]; + N[1] = -ab[0]; + const T length2 = ab.length2(); + const T length = SYSsqrt(length2); + const UT_Vector2T P = T(0.5)*(a+b); + data_for_parent.myAverageP = P; + data_for_parent.myLengthP = P*length; + data_for_parent.myN = N; +#if SOLID_ANGLE_DEBUG + UTdebugFormat(""); + UTdebugFormat("Triangle {}: P = {}; N = {}; length = {}", itemi, P, N, length); + UTdebugFormat(" box = {}", data_for_parent.myBox); +#endif + + data_for_parent.myLength = length; + const int order = myOrder; + if (order < 1) + return; + + // NOTE: Due to P being at the centroid, segments have Nij = 0 + // contributions to Nij. + data_for_parent.myNijDiag = T(0); + data_for_parent.myNxy = 0; data_for_parent.myNyx = 0; + + if (order < 2) + return; + + // If it's zero-length, the results are zero, so we can skip. + if (length == 0) + { + data_for_parent.myNijkDiag = T(0); + data_for_parent.my2Nxxy_Nyxx = 0; + data_for_parent.my2Nyyx_Nxyy = 0; + return; + } + + T integral_xx = ab[0]*ab[0]/T(12); + T integral_xy = ab[0]*ab[1]/T(12); + T integral_yy = ab[1]*ab[1]/T(12); + data_for_parent.myNijkDiag[0] = integral_xx*N[0]; + data_for_parent.myNijkDiag[1] = integral_yy*N[1]; + T Nxxy = N[0]*integral_xy; + T Nyxx = N[1]*integral_xx; + T Nyyx = N[1]*integral_xy; + T Nxyy = N[0]*integral_yy; + data_for_parent.my2Nxxy_Nyxx = 2*Nxxy + Nyxx; + data_for_parent.my2Nyyx_Nxyy = 2*Nyyx + Nxyy; +#if SOLID_ANGLE_DEBUG + UTdebugFormat(" integral_xx = {}; yy = {}", integral_xx, integral_yy); + UTdebugFormat(" integral_xy = {}", integral_xy); +#endif + } + + void post(const int nodei, const int parent_nodei, LocalData *data_for_parent, const int nchildren, const LocalData *child_data_array) const + { + // NOTE: Although in the general case, data_for_parent may be null for the root call, + // this functor assumes that it's non-null, so the call below must pass a non-null pointer. + + BoxData ¤t_box_data = myBoxData[nodei]; + + UT_Vector2T N = child_data_array[0].myN; + ((T*)¤t_box_data.myN[0])[0] = N[0]; + ((T*)¤t_box_data.myN[1])[0] = N[1]; + UT_Vector2T lengthP = child_data_array[0].myLengthP; + T length = child_data_array[0].myLength; + const UT_Vector2T local_P = child_data_array[0].myAverageP; + ((T*)¤t_box_data.myAverageP[0])[0] = local_P[0]; + ((T*)¤t_box_data.myAverageP[1])[0] = local_P[1]; + for (int i = 1; i < nchildren; ++i) + { + const UT_Vector2T local_N = child_data_array[i].myN; + N += local_N; + ((T*)¤t_box_data.myN[0])[i] = local_N[0]; + ((T*)¤t_box_data.myN[1])[i] = local_N[1]; + lengthP += child_data_array[i].myLengthP; + length += child_data_array[i].myLength; + const UT_Vector2T local_P = child_data_array[i].myAverageP; + ((T*)¤t_box_data.myAverageP[0])[i] = local_P[0]; + ((T*)¤t_box_data.myAverageP[1])[i] = local_P[1]; + } + for (int i = nchildren; i < BVH_N; ++i) + { + // Set to zero, just to avoid false positives for uses of uninitialized memory. + ((T*)¤t_box_data.myN[0])[i] = 0; + ((T*)¤t_box_data.myN[1])[i] = 0; + ((T*)¤t_box_data.myAverageP[0])[i] = 0; + ((T*)¤t_box_data.myAverageP[1])[i] = 0; + } + data_for_parent->myN = N; + data_for_parent->myLengthP = lengthP; + data_for_parent->myLength = length; + + UT::Box box(child_data_array[0].myBox); + for (int i = 1; i < nchildren; ++i) + box.combine(child_data_array[i].myBox); + + // Normalize P + UT_Vector2T averageP; + if (length > 0) + averageP = lengthP/length; + else + averageP = T(0.5)*(box.getMin() + box.getMax()); + data_for_parent->myAverageP = averageP; + + data_for_parent->myBox = box; + + for (int i = 0; i < nchildren; ++i) + { + const UT::Box &local_box(child_data_array[i].myBox); + const UT_Vector2T &local_P = child_data_array[i].myAverageP; + const UT_Vector2T maxPDiff = SYSmax(local_P-UT_Vector2T(local_box.getMin()), UT_Vector2T(local_box.getMax())-local_P); + ((T*)¤t_box_data.myMaxPDist2)[i] = maxPDiff.length2(); + } + for (int i = nchildren; i < BVH_N; ++i) + { + // This child is non-existent. If we set myMaxPDist2 to infinity, it will never + // use the approximation, and the traverseVector function can check for EMPTY. + ((T*)¤t_box_data.myMaxPDist2)[i] = std::numeric_limits::infinity(); + } + + const int order = myOrder; + if (order >= 1) + { + // We now have the current box's P, so we can adjust Nij and Nijk + data_for_parent->myNijDiag = child_data_array[0].myNijDiag; + data_for_parent->myNxy = 0; + data_for_parent->myNyx = 0; + data_for_parent->myNijkDiag = child_data_array[0].myNijkDiag; + data_for_parent->my2Nxxy_Nyxx = child_data_array[0].my2Nxxy_Nyxx; + data_for_parent->my2Nyyx_Nxyy = child_data_array[0].my2Nyyx_Nxyy; + + for (int i = 1; i < nchildren; ++i) + { + data_for_parent->myNijDiag += child_data_array[i].myNijDiag; + data_for_parent->myNijkDiag += child_data_array[i].myNijkDiag; + data_for_parent->my2Nxxy_Nyxx += child_data_array[i].my2Nxxy_Nyxx; + data_for_parent->my2Nyyx_Nxyy += child_data_array[i].my2Nyyx_Nxyy; + } + for (int j = 0; j < 2; ++j) + ((T*)¤t_box_data.myNijDiag[j])[0] = child_data_array[0].myNijDiag[j]; + ((T*)¤t_box_data.myNxy_Nyx)[0] = child_data_array[0].myNxy + child_data_array[0].myNyx; + for (int j = 0; j < 2; ++j) + ((T*)¤t_box_data.myNijkDiag[j])[0] = child_data_array[0].myNijkDiag[j]; + ((T*)¤t_box_data.my2Nxxy_Nyxx)[0] = child_data_array[0].my2Nxxy_Nyxx; + ((T*)¤t_box_data.my2Nyyx_Nxyy)[0] = child_data_array[0].my2Nyyx_Nxyy; + for (int i = 1; i < nchildren; ++i) + { + for (int j = 0; j < 2; ++j) + ((T*)¤t_box_data.myNijDiag[j])[i] = child_data_array[i].myNijDiag[j]; + ((T*)¤t_box_data.myNxy_Nyx)[i] = child_data_array[i].myNxy + child_data_array[i].myNyx; + for (int j = 0; j < 2; ++j) + ((T*)¤t_box_data.myNijkDiag[j])[i] = child_data_array[i].myNijkDiag[j]; + ((T*)¤t_box_data.my2Nxxy_Nyxx)[i] = child_data_array[i].my2Nxxy_Nyxx; + ((T*)¤t_box_data.my2Nyyx_Nxyy)[i] = child_data_array[i].my2Nyyx_Nxyy; + } + for (int i = nchildren; i < BVH_N; ++i) + { + // Set to zero, just to avoid false positives for uses of uninitialized memory. + for (int j = 0; j < 2; ++j) + ((T*)¤t_box_data.myNijDiag[j])[i] = 0; + ((T*)¤t_box_data.myNxy_Nyx)[i] = 0; + for (int j = 0; j < 2; ++j) + ((T*)¤t_box_data.myNijkDiag[j])[i] = 0; + ((T*)¤t_box_data.my2Nxxy_Nyxx)[i] = 0; + ((T*)¤t_box_data.my2Nyyx_Nxyy)[i] = 0; + } + + for (int i = 0; i < nchildren; ++i) + { + const LocalData &child_data = child_data_array[i]; + UT_Vector2T displacement = child_data.myAverageP - UT_Vector2T(data_for_parent->myAverageP); + UT_Vector2T N = child_data.myN; + + // Adjust Nij for the change in centre P + data_for_parent->myNijDiag += N*displacement; + T Nxy = child_data.myNxy + N[0]*displacement[1]; + T Nyx = child_data.myNyx + N[1]*displacement[0]; + + data_for_parent->myNxy += Nxy; + data_for_parent->myNyx += Nyx; + + if (order >= 2) + { + // Adjust Nijk for the change in centre P + data_for_parent->myNijkDiag += T(2)*displacement*child_data.myNijDiag + displacement*displacement*child_data.myN; + data_for_parent->my2Nxxy_Nyxx += + 2*(displacement[1]*child_data.myNijDiag[0] + displacement[0]*child_data.myNxy + N[0]*displacement[0]*displacement[1]) + + 2*child_data.myNyx*displacement[0] + N[1]*displacement[0]*displacement[0]; + data_for_parent->my2Nyyx_Nxyy += + 2*(displacement[0]*child_data.myNijDiag[1] + displacement[1]*child_data.myNyx + N[1]*displacement[1]*displacement[0]) + + 2*child_data.myNxy*displacement[1] + N[0]*displacement[1]*displacement[1]; + } + } + } +#if SOLID_ANGLE_DEBUG + UTdebugFormat(""); + UTdebugFormat("Node {}: nchildren = {}; maxP = {}", nodei, nchildren, SYSsqrt(current_box_data.myMaxPDist2)); + UTdebugFormat(" P = {}; N = {}", current_box_data.myAverageP, current_box_data.myN); + UTdebugFormat(" Nii = {}", current_box_data.myNijDiag); + UTdebugFormat(" Nxy+Nyx = {}", current_box_data.myNxy_Nyx); + UTdebugFormat(" Niii = {}", current_box_data.myNijkDiag); + UTdebugFormat(" 2Nxxy+Nyxx = {}; 2Nyyx+Nxyy = {}", current_box_data.my2Nxxy_Nyxx, current_box_data.my2Nyyx_Nxyy); +#endif + } + }; + +#if SOLID_ANGLE_TIME_PRECOMPUTE + timer.start(); +#endif + const PrecomputeFunctors functors(box_data, segment_boxes.array(), segment_points, positions, order); + // NOTE: post-functor relies on non-null data_for_parent, so we have to pass one. + LocalData local_data; + myTree.template traverseParallel(4096, functors, &local_data); + //myTree.template traverse(functors); +#if SOLID_ANGLE_TIME_PRECOMPUTE + time = timer.stop(); + UTdebugFormat("{} s to precompute coefficients.", time); +#endif +} + +template +inline void UT_SubtendedAngle::clear() +{ + myTree.clear(); + myNBoxes = 0; + myOrder = 2; + myData.reset(); + myNSegments = 0; + mySegmentPoints = nullptr; + myNPoints = 0; + myPositions = nullptr; +} + +template +inline T UT_SubtendedAngle::computeAngle(const UT_Vector2T &query_point, const T accuracy_scale) const +{ + const T accuracy_scale2 = accuracy_scale*accuracy_scale; + + struct AngleFunctors + { + const BoxData *const myBoxData; + const UT_Vector2T myQueryPoint; + const T myAccuracyScale2; + const UT_Vector2T *const myPositions; + const int *const mySegmentPoints; + const int myOrder; + + AngleFunctors( + const BoxData *const box_data, + const UT_Vector2T &query_point, + const T accuracy_scale2, + const int order, + const UT_Vector2T *const positions, + const int *const segment_points) + : myBoxData(box_data) + , myQueryPoint(query_point) + , myAccuracyScale2(accuracy_scale2) + , myOrder(order) + , myPositions(positions) + , mySegmentPoints(segment_points) + {} + uint pre(const int nodei, T *data_for_parent) const + { + const BoxData &data = myBoxData[nodei]; + const typename BoxData::Type maxP2 = data.myMaxPDist2; + UT_FixedVector q; + q[0] = typename BoxData::Type(myQueryPoint[0]); + q[1] = typename BoxData::Type(myQueryPoint[1]); + q -= data.myAverageP; + const typename BoxData::Type qlength2 = q[0]*q[0] + q[1]*q[1]; + + // If the query point is within a factor of accuracy_scale of the box radius, + // it's assumed to be not a good enough approximation, so it needs to descend. + // TODO: Is there a way to estimate the error? + static_assert((std::is_same::value), "FIXME: Implement support for other tuple types!"); + v4uu descend_mask = (qlength2 <= maxP2*myAccuracyScale2); + uint descend_bitmask = _mm_movemask_ps(V4SF(descend_mask.vector)); + constexpr uint allchildbits = ((uint(1)<= 1) + { + const UT_FixedVector q2 = q*q; + const typename BoxData::Type Omega_1 = + qlength_m2*(data.myNijDiag[0] + data.myNijDiag[1] + -typename BoxData::Type(2.0)*(dot(q2,data.myNijDiag) + + q[0]*q[1]*data.myNxy_Nyx)); + Omega_approx += Omega_1; + if (order >= 2) + { + const UT_FixedVector q3 = q2*q; + const typename BoxData::Type qlength_m3 = qlength_m2*qlength_m1; + typename BoxData::Type temp0[2] = { + data.my2Nyyx_Nxyy, + data.my2Nxxy_Nyxx + }; + typename BoxData::Type temp1[2] = { + q[1]*data.my2Nxxy_Nyxx, + q[0]*data.my2Nyyx_Nxyy + }; + const typename BoxData::Type Omega_2 = + qlength_m3*(dot(q, typename BoxData::Type(3)*data.myNijkDiag + UT_FixedVector(temp0)) + -typename BoxData::Type(4.0)*(dot(q3,data.myNijkDiag) + dot(q2, UT_FixedVector(temp1)))); + Omega_approx += Omega_2; + } + } + + // If q is so small that we got NaNs and we just have a + // small bounding box, it needs to descend. + const v4uu mask = Omega_approx.isFinite() & ~descend_mask; + Omega_approx = Omega_approx & mask; + descend_bitmask = (~_mm_movemask_ps(V4SF(mask.vector))) & allchildbits; + + T sum = Omega_approx[0]; + for (int i = 1; i < BVH_N; ++i) + sum += Omega_approx[i]; + *data_for_parent = sum; + + return descend_bitmask; + } + void item(const int itemi, const int parent_nodei, T &data_for_parent) const + { + const UT_Vector2T *const positions = myPositions; + const int *const cur_segment_points = mySegmentPoints + 2*itemi; + const UT_Vector2T a = positions[cur_segment_points[0]]; + const UT_Vector2T b = positions[cur_segment_points[1]]; + + data_for_parent = UTsignedAngleSegment(a, b, myQueryPoint); + } + SYS_FORCE_INLINE void post(const int nodei, const int parent_nodei, T *data_for_parent, const int nchildren, const T *child_data_array, const uint descend_bits) const + { + T sum = (descend_bits&1) ? child_data_array[0] : 0; + for (int i = 1; i < nchildren; ++i) + sum += ((descend_bits>>i)&1) ? child_data_array[i] : 0; + + *data_for_parent += sum; + } + }; + const AngleFunctors functors(myData.get(), query_point, accuracy_scale2, myOrder, myPositions, mySegmentPoints); + + T sum; + myTree.traverseVector(functors, &sum); + return sum; +} + +// Instantiate our templates. +//template class UT_SolidAngle; +// FIXME: The SIMD parts will need to be handled differently in order to support fpreal64. +//template class UT_SolidAngle; +//template class UT_SolidAngle; +//template class UT_SubtendedAngle; +//template class UT_SubtendedAngle; +//template class UT_SubtendedAngle; + +} // End HDK_Sample namespace +}} diff --git a/src/external/libigl-2.3.0/include/igl/FileEncoding.h b/src/external/libigl-2.3.0/include/igl/FileEncoding.h new file mode 100644 index 000000000..4b5011abb --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/FileEncoding.h @@ -0,0 +1,21 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2020 Jérémie Dumas +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_FILEENCODING_H +#define IGL_FILEENCODING_H + +namespace igl +{ + +enum class FileEncoding { + Binary, + Ascii +}; + +} + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/HalfEdgeIterator.cpp b/src/external/libigl-2.3.0/include/igl/HalfEdgeIterator.cpp new file mode 100644 index 000000000..982c295f0 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/HalfEdgeIterator.cpp @@ -0,0 +1,162 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Daniele Panozzo +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +#include "HalfEdgeIterator.h" + +template +IGL_INLINE igl::HalfEdgeIterator::HalfEdgeIterator( + const Eigen::MatrixBase& _F, + const Eigen::MatrixBase& _FF, + const Eigen::MatrixBase& _FFi, + int _fi, + int _ei, + bool _reverse +) +: fi(_fi), ei(_ei), reverse(_reverse), F(_F), FF(_FF), FFi(_FFi) +{} + +template +IGL_INLINE void igl::HalfEdgeIterator::flipF() +{ + if (isBorder()) + return; + + int fin = (FF)(fi,ei); + int ein = (FFi)(fi,ei); + + fi = fin; + ei = ein; + reverse = !reverse; +} + + +// Change Edge +template +IGL_INLINE void igl::HalfEdgeIterator::flipE() +{ + if (!reverse) + ei = (ei+2)%3; // ei-1 + else + ei = (ei+1)%3; + + reverse = !reverse; +} + +// Change Vertex +template +IGL_INLINE void igl::HalfEdgeIterator::flipV() +{ + reverse = !reverse; +} + +template +IGL_INLINE bool igl::HalfEdgeIterator::isBorder() +{ + return (FF)(fi,ei) == -1; +} + +/*! + * Returns the next edge skipping the border + * _________ + * /\ c | b /\ + * / \ | / \ + * / d \ | / a \ + * /______\|/______\ + * v + * In this example, if a and d are of-border and the pos is iterating counterclockwise, this method iterate through the faces incident on vertex v, + * producing the sequence a, b, c, d, a, b, c, ... + */ +template +IGL_INLINE bool igl::HalfEdgeIterator::NextFE() +{ + if ( isBorder() ) // we are on a border + { + do + { + flipF(); + flipE(); + } while (!isBorder()); + flipE(); + return false; + } + else + { + flipF(); + flipE(); + return true; + } +} + +// Get vertex index +template +IGL_INLINE int igl::HalfEdgeIterator::Vi() +{ + assert(fi >= 0); + assert(fi < F.rows()); + assert(ei >= 0); + assert(ei <= 2); + + if (!reverse) + return (F)(fi,ei); + else + return (F)(fi,(ei+1)%3); +} + +// Get face index +template +IGL_INLINE int igl::HalfEdgeIterator::Fi() +{ + return fi; +} + +// Get edge index +template +IGL_INLINE int igl::HalfEdgeIterator::Ei() +{ + return ei; +} + + +template +IGL_INLINE bool igl::HalfEdgeIterator::operator==(HalfEdgeIterator& p2) +{ + return + ( + (fi == p2.fi) && + (ei == p2.ei) && + (reverse == p2.reverse) && + (F == p2.F) && + (FF == p2.FF) && + (FFi == p2.FFi) + ); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +template igl::HalfEdgeIterator ,Eigen::Matrix ,Eigen::Matrix >::HalfEdgeIterator(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, int, int, bool); +template igl::HalfEdgeIterator, Eigen::Matrix, Eigen::Matrix >::HalfEdgeIterator(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, int, int, bool); +template bool igl::HalfEdgeIterator,Eigen::Matrix,Eigen::Matrix >::NextFE(); +template int igl::HalfEdgeIterator,Eigen::Matrix,Eigen::Matrix >::Ei(); +template int igl::HalfEdgeIterator ,Eigen::Matrix,Eigen::Matrix >::Ei(); +template int igl::HalfEdgeIterator ,Eigen::Matrix ,Eigen::Matrix >::Ei(); +template int igl::HalfEdgeIterator ,Eigen::Matrix ,Eigen::Matrix >::Fi(); +template bool igl::HalfEdgeIterator ,Eigen::Matrix ,Eigen::Matrix >::NextFE(); +template int igl::HalfEdgeIterator,Eigen::Matrix,Eigen::Matrix >::Vi(); +template igl::HalfEdgeIterator,Eigen::Matrix,Eigen::Matrix >::HalfEdgeIterator(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, int, int, bool); +template int igl::HalfEdgeIterator,Eigen::Matrix,Eigen::Matrix >::Fi(); +template void igl::HalfEdgeIterator,Eigen::Matrix,Eigen::Matrix >::flipE(); +template void igl::HalfEdgeIterator, Eigen::Matrix, Eigen::Matrix >::flipE(); +template void igl::HalfEdgeIterator,Eigen::Matrix,Eigen::Matrix >::flipF(); +template void igl::HalfEdgeIterator, Eigen::Matrix, Eigen::Matrix >::flipF(); +template void igl::HalfEdgeIterator,Eigen::Matrix,Eigen::Matrix >::flipV(); +template bool igl::HalfEdgeIterator,Eigen::Matrix,Eigen::Matrix >::operator==(igl::HalfEdgeIterator,Eigen::Matrix,Eigen::Matrix >&); +template int igl::HalfEdgeIterator, Eigen::Matrix, Eigen::Matrix >::Fi(); +template bool igl::HalfEdgeIterator, Eigen::Matrix, Eigen::Matrix >::NextFE(); +template bool igl::HalfEdgeIterator, Eigen::Matrix, Eigen::Matrix >::isBorder(); +template bool igl::HalfEdgeIterator, Eigen::Matrix, Eigen::Matrix >::isBorder(); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/HalfEdgeIterator.h b/src/external/libigl-2.3.0/include/igl/HalfEdgeIterator.h new file mode 100644 index 000000000..e1351e5f0 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/HalfEdgeIterator.h @@ -0,0 +1,114 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Daniele Panozzo +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_HALFEDGEITERATOR_H +#define IGL_HALFEDGEITERATOR_H + +#include + +#include +#include + +// This file violates many of the libigl style guidelines. + +namespace igl +{ + // HalfEdgeIterator - Fake halfedge for fast and easy navigation + // on triangle meshes with vertex_triangle_adjacency and + // triangle_triangle adjacency + // + // Note: this is different to classical Half Edge data structure. + // Instead, it follows cell-tuple in [Brisson, 1989] + // "Representing geometric structures in d dimensions: topology and order." + // This class can achieve local navigation similar to half edge in OpenMesh + // But the logic behind each atom operation is different. + // So this should be more properly called TriangleTupleIterator. + // + // Each tuple contains information on (face, edge, vertex) + // and encoded by (face, edge \in {0,1,2}, bool reverse) + // + // Inputs: + // F #F by 3 list of "faces" + // FF #F by 3 list of triangle-triangle adjacency. + // FFi #F by 3 list of FF inverse. For FF and FFi, refer to + // "triangle_triangle_adjacency.h" + // Usages: + // FlipF/E/V changes solely one actual face/edge/vertex resp. + // NextFE iterates through one-ring of a vertex robustly. + // + template < + typename DerivedF, + typename DerivedFF, + typename DerivedFFi> + class HalfEdgeIterator + { + public: + // Init the HalfEdgeIterator by specifying Face,Edge Index and Orientation + IGL_INLINE HalfEdgeIterator( + const Eigen::MatrixBase& _F, + const Eigen::MatrixBase& _FF, + const Eigen::MatrixBase& _FFi, + int _fi, + int _ei, + bool _reverse = false + ); + + // Change Face + IGL_INLINE void flipF(); + + // Change Edge + IGL_INLINE void flipE(); + + // Change Vertex + IGL_INLINE void flipV(); + + IGL_INLINE bool isBorder(); + + /*! + * Returns the next edge skipping the border + * _________ + * /\ c | b /\ + * / \ | / \ + * / d \ | / a \ + * /______\|/______\ + * v + * In this example, if a and d are of-border and the pos is iterating + counterclockwise, this method iterate through the faces incident on vertex + v, + * producing the sequence a, b, c, d, a, b, c, ... + */ + IGL_INLINE bool NextFE(); + + // Get vertex index + IGL_INLINE int Vi(); + + // Get face index + IGL_INLINE int Fi(); + + // Get edge index + IGL_INLINE int Ei(); + + IGL_INLINE bool operator==(HalfEdgeIterator& p2); + + private: + int fi; + int ei; + bool reverse; + + // All the same type? This is likely to break. + const Eigen::MatrixBase & F; + const Eigen::MatrixBase & FF; + const Eigen::MatrixBase & FFi; + }; + +} + +#ifndef IGL_STATIC_LIBRARY +# include "HalfEdgeIterator.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/Hit.h b/src/external/libigl-2.3.0/include/igl/Hit.h new file mode 100644 index 000000000..e0034efcf --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/Hit.h @@ -0,0 +1,29 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// 2014 Christian Schüller +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_HIT_H +#define IGL_HIT_H + +namespace igl +{ + // Reimplementation of the embree::Hit struct from embree1.0 + // + // TODO: template on floating point type + struct Hit + { + int id; // primitive id + int gid; // geometry id (not used) + // barycentric coordinates so that + // pos = V.row(F(id,0))*(1-u-v)+V.row(F(id,1))*u+V.row(F(id,2))*v; + float u,v; + // parametric distance so that + // pos = origin + t * dir + float t; + }; +} +#endif diff --git a/src/external/libigl-2.3.0/include/igl/IO b/src/external/libigl-2.3.0/include/igl/IO new file mode 100644 index 000000000..f054d8c99 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/IO @@ -0,0 +1,28 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_IO +#define IGL_IO +// Input and output functions +#include "read_triangle_mesh.h" +#include "readDMAT.h" +#include "readMESH.h" +#include "readNODE.h" +#include "readOBJ.h" +#include "readOFF.h" +#include "readTGF.h" +#include "readWRL.h" +#include "readCSV.h" +#include "file_contents_as_string.h" +#include "write_triangle_mesh.h" +#include "writeDMAT.h" +#include "writeMESH.h" +#include "writeOBJ.h" +#include "writeOFF.h" +#include "writeTGF.h" + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/IndexComparison.h b/src/external/libigl-2.3.0/include/igl/IndexComparison.h new file mode 100644 index 000000000..44515df51 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/IndexComparison.h @@ -0,0 +1,117 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_INDEXCOMPARISON_H +#define IGL_INDEXCOMPARISON_H +#include +namespace igl{ + // Comparison struct used by sort + // http://bytes.com/topic/c/answers/132045-sort-get-index + + // For use with functions like std::sort + template struct IndexLessThan + { + IndexLessThan(const T arr) : arr(arr) {} + bool operator()(const size_t a, const size_t b) const + { + return arr[a] < arr[b]; + } + const T arr; + }; + + // For use with functions like std::unique + template struct IndexEquals + { + IndexEquals(const T arr) : arr(arr) {} + bool operator()(const size_t a, const size_t b) const + { + return arr[a] == arr[b]; + } + const T arr; + }; + + // For use with functions like std::sort + template struct IndexVectorLessThan + { + IndexVectorLessThan(const T & vec) : vec ( vec) {} + bool operator()(const size_t a, const size_t b) const + { + return vec(a) < vec(b); + } + const T & vec; + }; + + // For use with functions like std::sort + template struct IndexDimLessThan + { + IndexDimLessThan(const T & mat,const int & dim, const int & j) : + mat(mat), + dim(dim), + j(j) + {} + bool operator()(const size_t a, const size_t b) const + { + if(dim == 1) + { + return mat(a,j) < mat(b,j); + }else + { + return mat(j,a) < mat(j,b); + } + } + const T & mat; + const int & dim; + const int & j; + }; + + // For use with functions like std::sort + template struct IndexRowLessThan + { + IndexRowLessThan(const T & mat) : mat ( mat) {} + bool operator()(const size_t a, const size_t b) const + { + const int cols = mat.cols(); + // Lexicographical order + for(int j = 0;j mat(b,j)) + { + return false; + } else if(mat(a,j) < mat(b,j)) + { + return true; + } + } + // equality is false + return false; + } + const T & mat; + }; + + // For use with functions like std::sort + template struct IndexRowEquals + { + IndexRowEquals(const T & mat) : mat ( mat) {} + bool operator()(const size_t a, const size_t b) const + { + const int cols = mat.cols(); + // Lexicographical order + for(int j = 0;j +// This function is not intended to be a permanent function of libigl. Rather +// it is a "drop-in" workaround for documented bug in Eigen: +// http://eigen.tuxfamily.org/bz/show_bug.cgi?id=1383 +// +// Replace: +// +// Eigen::VectorXi::LinSpaced(size,low,high); +// +// With: +// +// igl::LinSpaced(size,low,high); +// +// Specifcally, this version will _always_ return an empty vector if size==0, +// regardless of the values for low and high. If size != 0, then this simply +// returns the result of Eigen::Derived::LinSpaced. +// +// Until this bug is fixed, we should also avoid calls to the member function +// `.setLinSpaced`. This means replacing: +// +// a.setLinSpaced(size,low,high); +// +// with +// +// a = igl::LinSpaced(size,low,high); +// +namespace igl +{ + template + //inline typename Eigen::DenseBase< Derived >::RandomAccessLinSpacedReturnType + inline Derived LinSpaced( + typename Derived::Index size, + const typename Derived::Scalar & low, + const typename Derived::Scalar & high); +} + +// Implementation + +template +//inline typename Eigen::DenseBase< Derived >::RandomAccessLinSpacedReturnType +inline Derived +igl::LinSpaced( + typename Derived::Index size, + const typename Derived::Scalar & low, + const typename Derived::Scalar & high) +{ + if(size == 0) + { + // Force empty vector with correct "RandomAccessLinSpacedReturnType" type. + return Derived::LinSpaced(0,0,1); + }else if(high < low) + { + return low-Derived::LinSpaced(size,low-low,low-high).array(); + }else{ + return Derived::LinSpaced(size,low,high); + } +} + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/MappingEnergyType.h b/src/external/libigl-2.3.0/include/igl/MappingEnergyType.h new file mode 100644 index 000000000..1eeeb778b --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/MappingEnergyType.h @@ -0,0 +1,27 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2018 Zhongshi Jiang +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_MAPPINGENERGYTYPE_H +#define IGL_MAPPINGENERGYTYPE_H +namespace igl +{ + // Energy Types used for Parameterization/Mapping. + // Refer to SLIM [Rabinovich et al. 2017] for more details + // Todo: Integrate with ARAPEnergyType + + enum MappingEnergyType + { + ARAP = 0, + LOG_ARAP = 1, + SYMMETRIC_DIRICHLET = 2, + CONFORMAL = 3, + EXP_CONFORMAL = 4, + EXP_SYMMETRIC_DIRICHLET = 5, + NUM_SLIM_ENERGY_TYPES = 6 + }; +} +#endif diff --git a/src/external/libigl-2.3.0/include/igl/MeshBooleanType.h b/src/external/libigl-2.3.0/include/igl/MeshBooleanType.h new file mode 100644 index 000000000..2eb293624 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/MeshBooleanType.h @@ -0,0 +1,23 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_MESH_BOOLEAN_TYPE_H +#define IGL_MESH_BOOLEAN_TYPE_H +namespace igl +{ + enum MeshBooleanType + { + MESH_BOOLEAN_TYPE_UNION = 0, + MESH_BOOLEAN_TYPE_INTERSECT = 1, + MESH_BOOLEAN_TYPE_MINUS = 2, + MESH_BOOLEAN_TYPE_XOR = 3, + MESH_BOOLEAN_TYPE_RESOLVE = 4, + NUM_MESH_BOOLEAN_TYPES = 5 + }; +}; + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/MshLoader.cpp b/src/external/libigl-2.3.0/include/igl/MshLoader.cpp new file mode 100644 index 000000000..0939e3bb6 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/MshLoader.cpp @@ -0,0 +1,497 @@ +// based on MSH reader from PyMesh + +// Copyright (c) 2015 Qingnan Zhou +// Copyright (C) 2020 Vladimir Fonov +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "MshLoader.h" + +#include +#include +#include +#include + +#include + +namespace igl { + // helper function + void inline _msh_eat_white_space(std::ifstream& fin) { + char next = fin.peek(); + while (next == '\n' || next == ' ' || next == '\t' || next == '\r') { + fin.get(); + next = fin.peek(); + } + } +} + +IGL_INLINE igl::MshLoader::MshLoader(const std::string &filename) { + std::ifstream fin(filename, std::ios::in | std::ios::binary); + + if (!fin.is_open()) { + std::stringstream err_msg; + err_msg << "failed to open file \"" << filename << "\""; + throw std::ios_base::failure(err_msg.str()); + } + // Parse header + std::string buf; + double version; + int type; + fin >> buf; + if (buf != "$MeshFormat") { throw std::runtime_error("Unexpected .msh format"); } + + fin >> version >> type >> m_data_size; + m_binary = (type == 1); + if(version>2.2 || version<2.0) + { + // probably unsupported version + std::stringstream err_msg; + err_msg << "Error: Unsupported file version:" << version << std::endl; + throw std::runtime_error(err_msg.str()); + + } + // Some sanity check. + if (m_data_size != 8) { + std::stringstream err_msg; + err_msg << "Error: data size must be 8 bytes." << std::endl; + throw std::runtime_error(err_msg.str()); + } + if (sizeof(int) != 4) { + std::stringstream err_msg; + err_msg << "Error: code must be compiled with int size 4 bytes." << std::endl; + throw std::runtime_error(err_msg.str()); + } + + // Read in extra info from binary header. + if (m_binary) { + int one; + igl::_msh_eat_white_space(fin); + fin.read(reinterpret_cast(&one), sizeof(int)); + if (one != 1) { + std::stringstream err_msg; + err_msg << "Binary msh file " << filename + << " is saved with different endianness than this machine." + << std::endl; + throw std::runtime_error(err_msg.str()); + } + } + + fin >> buf; + if (buf != "$EndMeshFormat") + { + std::stringstream err_msg; + err_msg << "Unexpected contents in the file header." << std::endl; + throw std::runtime_error(err_msg.str()); + } + + while (!fin.eof()) { + buf.clear(); + fin >> buf; + if (buf == "$Nodes") { + parse_nodes(fin); + fin >> buf; + if (buf != "$EndNodes") { throw std::runtime_error("Unexpected tag"); } + } else if (buf == "$Elements") { + parse_elements(fin); + fin >> buf; + if (buf != "$EndElements") { throw std::runtime_error("Unexpected tag"); } + } else if (buf == "$NodeData") { + parse_node_field(fin); + fin >> buf; + if (buf != "$EndNodeData") { throw std::runtime_error("Unexpected tag"); } + } else if (buf == "$ElementData") { + parse_element_field(fin); + fin >> buf; + if (buf != "$EndElementData") { throw std::runtime_error("Unexpected tag"); } + } else if (fin.eof()) { + break; + } else { + parse_unknown_field(fin, buf); + } + } + fin.close(); +} + +IGL_INLINE void igl::MshLoader::parse_nodes(std::ifstream& fin) { + size_t num_nodes; + fin >> num_nodes; + m_nodes.resize(num_nodes*3); + + if (m_binary) { + size_t stride = (4+3*m_data_size); + size_t num_bytes = stride * num_nodes; + char* data = new char[num_bytes]; + igl::_msh_eat_white_space(fin); + fin.read(data, num_bytes); + + for (size_t i=0; i> node_idx; + node_idx -= 1; + // here it's 3D node explicitly + fin >> m_nodes[node_idx*3] + >> m_nodes[node_idx*3+1] + >> m_nodes[node_idx*3+2]; + } + } +} + +IGL_INLINE void igl::MshLoader::parse_elements(std::ifstream& fin) { + m_elements_tags.resize(2); //hardcoded to have 2 tags + size_t num_elements; + fin >> num_elements; + + size_t nodes_per_element; + + if (m_binary) { + igl::_msh_eat_white_space(fin); + int elem_read = 0; + while (elem_read < num_elements) { + // Parse element header. + int elem_type, num_elems, num_tags; + fin.read((char*)&elem_type, sizeof(int)); + fin.read((char*)&num_elems, sizeof(int)); + fin.read((char*)&num_tags, sizeof(int)); + nodes_per_element = num_nodes_per_elem_type(elem_type); + + // store node info + for (size_t i=0; i> elem_num >> elem_type >> num_tags; + + // read tags. + for (size_t j=0; j> tag; + if(j<2) m_elements_tags[j].push_back(tag); + } + for (size_t j=num_tags; j<2; j++) + m_elements_tags[j].push_back(-1); // fill up tags if less then 2 + + nodes_per_element = num_nodes_per_elem_type(elem_type); + m_elements_types.push_back(elem_type); + m_elements_lengths.push_back(nodes_per_element); + + elem_num -= 1; + m_elements_ids.push_back(elem_num); + m_elements_nodes_idx.push_back(m_elements.size()); + // Parse node idx. + for (size_t j=0; j> idx; + m_elements.push_back(idx-1); // msh index starts from 1. + } + } + } + // debug + assert(m_elements_types.size() == m_elements_ids.size()); + assert(m_elements_tags[0].size() == m_elements_ids.size()); + assert(m_elements_tags[1].size() == m_elements_ids.size()); + assert(m_elements_lengths.size() == m_elements_ids.size()); +} + +IGL_INLINE void igl::MshLoader::parse_node_field( std::ifstream& fin ) { + size_t num_string_tags; + size_t num_real_tags; + size_t num_int_tags; + + fin >> num_string_tags; + std::vector str_tags(num_string_tags); + + for (size_t i=0; i> str_tags[i]; + } + } + + fin >> num_real_tags; + std::vector real_tags(num_real_tags); + for (size_t i=0; i> real_tags[i]; + + fin >> num_int_tags; + std::vector int_tags(num_int_tags); + for (size_t i=0; i> int_tags[i]; + + if (num_string_tags <= 0 || num_int_tags <= 2) { + throw std::runtime_error("Unexpected number of field tags"); + } + std::string fieldname = str_tags[0]; + int num_components = int_tags[1]; + int num_entries = int_tags[2]; + + std::vector field( num_entries*num_components ); + + if (m_binary) { + size_t num_bytes = (num_components * m_data_size + 4) * num_entries; + char* data = new char[num_bytes]; + igl::_msh_eat_white_space(fin); + fin.read(data, num_bytes); + for (size_t i=0; i=num_entries) throw std::runtime_error("Index too big"); + size_t base_idx = i*(4+num_components*m_data_size) + 4; + // TODO: make this work when m_data_size != sizeof(double) ? + memcpy(&field[node_idx*num_components], &data[base_idx], num_components*m_data_size); + } + delete [] data; + } else { + int node_idx; + for (size_t i=0; i> node_idx; + node_idx -= 1; + for (size_t j=0; j> field[node_idx*num_components+j]; + } + } + } + + m_node_fields_names.push_back(fieldname); + m_node_fields.push_back(field); + m_node_fields_components.push_back(num_components); +} + +IGL_INLINE void igl::MshLoader::parse_element_field(std::ifstream& fin) { + size_t num_string_tags; + size_t num_real_tags; + size_t num_int_tags; + + fin >> num_string_tags; + std::vector str_tags(num_string_tags); + for (size_t i=0; i> str_tags[i]; + } + } + + fin >> num_real_tags; + std::vector real_tags(num_real_tags); + for (size_t i=0; i> real_tags[i]; + + fin >> num_int_tags; + std::vector int_tags(num_int_tags); + for (size_t i=0; i> int_tags[i]; + + if (num_string_tags <= 0 || num_int_tags <= 2) { + throw std::runtime_error("Invalid file format"); + } + std::string fieldname = str_tags[0]; + int num_components = int_tags[1]; + int num_entries = int_tags[2]; + std::vector field(num_entries*num_components); + + if (m_binary) { + size_t num_bytes = (num_components * m_data_size + 4) * num_entries; + char* data = new char[num_bytes]; + igl::_msh_eat_white_space(fin); + fin.read(data, num_bytes); + for (int i=0; i> elem_idx; + elem_idx -= 1; + for (size_t j=0; j> field[elem_idx*num_components+j]; + } + } + } + m_element_fields_names.push_back(fieldname); + m_element_fields.push_back(field); + m_element_fields_components.push_back(num_components); +} + +IGL_INLINE void igl::MshLoader::parse_unknown_field(std::ifstream& fin, + const std::string& fieldname) { + std::cerr << "Warning: \"" << fieldname << "\" not supported yet. Ignored." << std::endl; + std::string endmark = fieldname.substr(0,1) + "End" + + fieldname.substr(1,fieldname.size()-1); + + std::string buf(""); + while (buf != endmark && !fin.eof()) { + fin >> buf; + } +} + +IGL_INLINE int igl::MshLoader::num_nodes_per_elem_type(int elem_type) { + int nodes_per_element = 0; + switch (elem_type) { + case ELEMENT_LINE: // 2-node line + nodes_per_element = 2; + break; + case ELEMENT_TRI: + nodes_per_element = 3; // 3-node triangle + break; + case ELEMENT_QUAD: + nodes_per_element = 4; // 5-node quad + break; + case ELEMENT_TET: + nodes_per_element = 4; // 4-node tetrahedra + break; + case ELEMENT_HEX: // 8-node hexahedron + nodes_per_element = 8; + break; + case ELEMENT_PRISM: // 6-node prism + nodes_per_element = 6; + break; + case ELEMENT_LINE_2ND_ORDER: + nodes_per_element = 3; + break; + case ELEMENT_TRI_2ND_ORDER: + nodes_per_element = 6; + break; + case ELEMENT_QUAD_2ND_ORDER: + nodes_per_element = 9; + break; + case ELEMENT_TET_2ND_ORDER: + nodes_per_element = 10; + break; + case ELEMENT_HEX_2ND_ORDER: + nodes_per_element = 27; + break; + case ELEMENT_PRISM_2ND_ORDER: + nodes_per_element = 18; + break; + case ELEMENT_PYRAMID_2ND_ORDER: + nodes_per_element = 14; + break; + case ELEMENT_POINT: // 1-node point + nodes_per_element = 1; + break; + default: + std::stringstream err_msg; + err_msg << "Element type (" << elem_type << ") is not supported yet." + << std::endl; + throw std::runtime_error(err_msg.str()); + } + return nodes_per_element; +} + + +IGL_INLINE bool igl::MshLoader::is_element_map_identity() const +{ + for(int i=0;i( + msh_struct( m_elements_tags[tag_column][i], + m_elements_types[i]), i) + ); + } + + // identify unique structures + std::vector _unique_structs; + std::unique_copy(std::begin(m_structure_index), + std::end(m_structure_index), + std::back_inserter(_unique_structs), + [](const StructIndex::value_type &c1, const StructIndex::value_type &c2) + { return c1.first == c2.first; }); + + std::for_each( _unique_structs.begin(), _unique_structs.end(), + [this](const StructIndex::value_type &n){ this->m_structures.push_back(n.first); }); + + for(auto t = m_structures.begin(); t != m_structures.end(); ++t) + { + // identify all elements corresponding to this tag + auto structure_range = m_structure_index.equal_range( *t ); + int cnt=0; + + for(auto i=structure_range.first; i!=structure_range.second; i++) + cnt++; + + m_structure_length.insert( std::pair( *t, cnt)); + } +} diff --git a/src/external/libigl-2.3.0/include/igl/MshLoader.h b/src/external/libigl-2.3.0/include/igl/MshLoader.h new file mode 100644 index 000000000..67ef46932 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/MshLoader.h @@ -0,0 +1,190 @@ +// based on MSH reader from PyMesh + +// Copyright (c) 2015 Qingnan Zhou +// Copyright (C) 2020 Vladimir Fonov +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_MSH_LOADER_H +#define IGL_MSH_LOADER_H +#include "igl_inline.h" + +#include +#include +#include +#include +#include + +namespace igl { + +// Class for loading information from .msh file +// depends only on c++stl library +class MshLoader { + public: + + struct msh_struct { + int tag,el_type; + msh_struct(int _tag=0,int _type=0): + tag(_tag),el_type(_type){} + bool operator== (const msh_struct& a) const { + return this->tag==a.tag && + this->el_type==a.el_type; + } + + bool operator< (const msh_struct& a) const { + return (this->tag*100+this->el_type) < + (a.tag*100+a.el_type); + } + }; + + typedef double Float; + + typedef std::vector IndexVector; + typedef std::vector IntVector; + typedef std::vector FloatVector; + typedef std::vector FloatField; + typedef std::vector IntField; + typedef std::vector FieldNames; + typedef std::multimap StructIndex; + typedef std::vector StructVector; + + enum {ELEMENT_LINE=1, ELEMENT_TRI=2, ELEMENT_QUAD=3, + ELEMENT_TET=4, ELEMENT_HEX=5, ELEMENT_PRISM=6, + ELEMENT_PYRAMID=7, + // 2nd order elements + ELEMENT_LINE_2ND_ORDER=8, ELEMENT_TRI_2ND_ORDER=9, + ELEMENT_QUAD_2ND_ORDER=10,ELEMENT_TET_2ND_ORDER=11, + ELEMENT_HEX_2ND_ORDER=12, ELEMENT_PRISM_2ND_ORDER=13, + ELEMENT_PYRAMID_2ND_ORDER=14, + // other elements + ELEMENT_POINT=15 }; + public: + MshLoader(const std::string &filename); + + public: + + // get nodes , x,y,z sequentially + const FloatVector& get_nodes() const { return m_nodes; } + // get elements , identifying nodes that create an element + // variable length per element + const IndexVector& get_elements() const { return m_elements; } + + // get element types + const IntVector& get_elements_types() const { return m_elements_types; } + // get element lengths + const IntVector& get_elements_lengths() const { return m_elements_lengths; } + // get element tags ( physical (0) and elementary (1) ) + const IntField& get_elements_tags() const { return m_elements_tags; } + // get element IDs + const IntVector& get_elements_ids() const { return m_elements_ids; } + + // get reverse index from node to element + const IndexVector& get_elements_nodes_idx() const { return m_elements_nodes_idx; } + + // get fields assigned per node, all fields and components sequentially + const FloatField& get_node_fields() const { return m_node_fields;} + // get node field names, + const FieldNames& get_node_fields_names() const { return m_node_fields_names;} + // get number of node field components + const IntVector& get_node_fields_components() const {return m_node_fields_components;} + + int get_node_field_components(size_t c) const + { + return m_node_fields_components[c]; + } + + // get fields assigned per element, all fields and components sequentially + const FloatField& get_element_fields() const { return m_element_fields;} + // get element field names + const FieldNames& get_element_fields_names() const { return m_element_fields_names;} + // get number of element field components + const IntVector& get_element_fields_components() const {return m_element_fields_components;} + + int get_element_field_components(size_t c) const { + return m_element_fields_components[c]; + } + // check if field is present at node level + bool is_node_field(const std::string& fieldname) const { + return (std::find(std::begin(m_node_fields_names), + std::end(m_node_fields_names), + fieldname) != std::end(m_node_fields_names) ); + } + // check if field is present at element level + bool is_element_field(const std::string& fieldname) const { + return (std::find(std::begin(m_element_fields_names), + std::end(m_element_fields_names), + fieldname) != std::end(m_node_fields_names) ); + } + + // check if all elements have ids assigned sequentially + bool is_element_map_identity() const ; + + // create tag index + // tag_column: ( physical (0) or elementary (1) ) specifying which tag to use + void index_structures(int tag_column); + + // get tag index, call index_structure_tags first + const StructIndex& get_structure_index() const + { + return m_structure_index; + } + + // get size of a structure identified by tag and element type + const StructIndex& get_structure_length() const + { + return m_structure_length; + } + + //! get list of structures + const StructVector& get_structures() const + { + return m_structures; + } + + public: + // helper function, calculate number of nodes associated with an element + static int num_nodes_per_elem_type(int elem_type); + + private: + void parse_nodes(std::ifstream& fin); + void parse_elements(std::ifstream& fin); + void parse_node_field(std::ifstream& fin); + void parse_element_field(std::ifstream& fin); + void parse_unknown_field(std::ifstream& fin, + const std::string& fieldname); + + private: + bool m_binary; + size_t m_data_size; + + FloatVector m_nodes; // len x 3 vector + + IndexVector m_elements; // linear array for nodes corresponding to each element + IndexVector m_elements_nodes_idx; // element indexes + + IntVector m_elements_ids; // element id's + IntVector m_elements_types; // Element types + IntVector m_elements_lengths; // Element lengths + IntField m_elements_tags; // Element tags, currently 2xtags per element + + FloatField m_node_fields; // Float field defined at each node + IntVector m_node_fields_components; // Number of components for node field + FieldNames m_node_fields_names; // Node field name + + FloatField m_element_fields; // Float field defined at each element + IntVector m_element_fields_components; // Number of components for element field + FieldNames m_element_fields_names; // Element field name + + StructIndex m_structure_index; // index tag ids + StructVector m_structures; // unique structures + StructIndex m_structure_length; // length of structures with consistent element type +}; + +} //igl + +#ifndef IGL_STATIC_LIBRARY +# include "MshLoader.cpp" +#endif + +#endif //IGL_MSH_LOADER_H \ No newline at end of file diff --git a/src/external/libigl-2.3.0/include/igl/MshSaver.cpp b/src/external/libigl-2.3.0/include/igl/MshSaver.cpp new file mode 100644 index 000000000..ac941af83 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/MshSaver.cpp @@ -0,0 +1,347 @@ +// based on MSH writer from PyMesh + +// Copyright (c) 2015 Qingnan Zhou +// Copyright (C) 2020 Vladimir Fonov +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "MshSaver.h" + +#include +#include +#include +#include + + +IGL_INLINE igl::MshSaver::MshSaver(const std::string& filename, bool binary) : + m_binary(binary), m_num_nodes(0), m_num_elements(0) { + if (!m_binary) { + fout.open(filename.c_str(), std::fstream::out); + } else { + fout.open(filename.c_str(), std::fstream::binary); + } + if (!fout) { + std::stringstream err_msg; + err_msg << "Error opening " << filename << " to write msh file." << std::endl; + throw std::ios_base::failure(err_msg.str()); + } +} + +IGL_INLINE igl::MshSaver::~MshSaver() { + fout.close(); +} + +IGL_INLINE void igl::MshSaver::save_mesh( + const FloatVector& nodes, + const IndexVector& elements, + const IntVector& element_lengths, + const IntVector& element_types, + const IntVector& element_tags + ) { + + save_header(); + + save_nodes(nodes); + + save_elements(elements, element_lengths, element_types, element_tags ); +} + +IGL_INLINE void igl::MshSaver::save_header() { + if (!m_binary) { + fout << "$MeshFormat" << std::endl; + fout << "2.2 0 " << sizeof(double) << std::endl; + fout << "$EndMeshFormat" << std::endl; + fout.precision(17); + } else { + fout << "$MeshFormat" << std::endl; + fout << "2.2 1 " << sizeof(double) << std::endl; + int one = 1; + fout.write((char*)&one, sizeof(int)); + fout << "\n$EndMeshFormat" << std::endl; + } + fout.flush(); +} + +IGL_INLINE void igl::MshSaver::save_nodes(const FloatVector& nodes) { + // Save nodes. + // 3D hadrcoded + m_num_nodes = nodes.size() / 3; + fout << "$Nodes" << std::endl; + fout << m_num_nodes << std::endl; + if (!m_binary) { + for (size_t i=0; i 0) { + //int elem_type = el_type; + int num_elems = m_num_elements; + //int tags = 0; + if (!m_binary) { + size_t el_ptr=0; + for (size_t i=0;i( elements[el_ptr + e] )+1; + fout.write((const char*)&_elem, sizeof(int)); + } + el_ptr+=elem_len; + } + } + } + } + fout << "$EndElements" << std::endl; + fout.flush(); +} + +IGL_INLINE void igl::MshSaver::save_scalar_field(const std::string& fieldname, const FloatVector& field) { + assert(field.size() == m_num_nodes); + fout << "$NodeData" << std::endl; + fout << "1" << std::endl; // num string tags. + fout << "\"" << fieldname << "\"" << std::endl; + fout << "1" << std::endl; // num real tags. + fout << "0.0" << std::endl; // time value. + fout << "3" << std::endl; // num int tags. + fout << "0" << std::endl; // the time step + fout << "1" << std::endl; // 1-component scalar field. + fout << m_num_nodes << std::endl; // number of nodes + + if (m_binary) { + for (size_t i=0; i +// Copyright (C) 2020 Vladimir Fonov +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_MSH_SAVER_H +#define IGL_MSH_SAVER_H +#include "igl_inline.h" + +#include +#include +#include + +namespace igl { + +// Class for dumping information to .msh file +// depends only on c++stl library +// current implementation works only with 3D information +class MshSaver { + public: + typedef double Float; + + typedef std::vector IndexVector; + typedef std::vector IntVector; + typedef std::vector FloatVector; + typedef std::vector FloatField; + typedef std::vector IntField; + typedef std::vector FieldNames; + + MshSaver(const std::string& filename, bool binary=true); + ~MshSaver(); + + public: + // Only these element types are supported right now + enum {ELEMENT_LINE=1, ELEMENT_TRI=2, ELEMENT_QUAD=3, + ELEMENT_TET=4, ELEMENT_HEX=5, ELEMENT_PRISM=6 }; + + public: + // save mesh geometry + void save_mesh( + const FloatVector& nodes, + const IndexVector& elements, + const IntVector& element_lengths, + const IntVector& element_type, + const IntVector& element_tags ); + + // save additional fields associated with the mesh + + // add node scalar field + void save_scalar_field(const std::string& fieldname, const FloatVector& field); + // add node vectot field + void save_vector_field(const std::string& fieldname, const FloatVector& field); + // add element scalar field + void save_elem_scalar_field(const std::string& fieldname, const FloatVector& field); + // add element vector field + void save_elem_vector_field(const std::string& fieldname, const FloatVector& field); + // add element tensor field + void save_elem_tensor_field(const std::string& fieldname, const FloatVector& field); + + protected: + void save_header(); + void save_nodes(const FloatVector& nodes); + void save_elements(const IndexVector& elements, + const IntVector& element_lengths, + const IntVector& element_type, + const IntVector& element_tags); + + private: + bool m_binary; + size_t m_num_nodes; + size_t m_num_elements; + + std::ofstream fout; +}; +} //igl + +#ifndef IGL_STATIC_LIBRARY +# include "MshSaver.cpp" +#endif + +#endif //MSH_SAVER_H diff --git a/src/external/libigl-2.3.0/include/igl/NormalType.h b/src/external/libigl-2.3.0/include/igl/NormalType.h new file mode 100644 index 000000000..b74b57b6a --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/NormalType.h @@ -0,0 +1,27 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_NORMALTYPE_H +#define IGL_NORMALTYPE_H + +namespace igl +{ + // PER_VERTEX_NORMALS Normals computed per vertex based on incident faces + // PER_FACE_NORMALS Normals computed per face + // PER_CORNER_NORMALS Normals computed per corner (aka wedge) based on + // incident faces without sharp edge + enum NormalType + { + PER_VERTEX_NORMALS, + PER_FACE_NORMALS, + PER_CORNER_NORMALS + }; +# define NUM_NORMAL_TYPE 3 +} + +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/ONE.h b/src/external/libigl-2.3.0/include/igl/ONE.h new file mode 100644 index 000000000..93c509d4e --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/ONE.h @@ -0,0 +1,22 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_ONE_H +#define IGL_ONE_H +namespace igl +{ + // Often one needs a reference to a dummy variable containing one as its + // value, for example when using AntTweakBar's + // TwSetParam( "3D View", "opened", TW_PARAM_INT32, 1, &INT_ONE); + const char CHAR_ONE = 1; + const int INT_ONE = 1; + const unsigned int UNSIGNED_INT_ONE = 1; + const double DOUBLE_ONE = 1; + const float FLOAT_ONE = 1; +} +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/PI.h b/src/external/libigl-2.3.0/include/igl/PI.h new file mode 100644 index 000000000..520649cc7 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/PI.h @@ -0,0 +1,19 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_PI_H +#define IGL_PI_H +namespace igl +{ + // Use standard mathematical constants' M_PI if available +#ifdef M_PI + constexpr double PI = M_PI; +#else + constexpr double PI = 3.1415926535897932384626433832795; +#endif +} +#endif diff --git a/src/external/libigl-2.3.0/include/igl/REDRUM.h b/src/external/libigl-2.3.0/include/igl/REDRUM.h new file mode 100644 index 000000000..79ab72ffd --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/REDRUM.h @@ -0,0 +1,55 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_REDRUM_H +#define IGL_REDRUM_H + +// Q: These should probably be inside the igl namespace. What's the correct +// way to do that? +// A: I guess the right way is to not use a macro but a proper function with +// streams as input and output. + +// ANSI color codes for formatting iostream style output + +#ifdef IGL_REDRUM_NOOP + +// Bold Red, etc. +#define NORUM(X) X +#define REDRUM(X) X +#define GREENRUM(X) X +#define YELLOWRUM(X) X +#define BLUERUM(X) X +#define MAGENTARUM(X) X +#define CYANRUM(X) X +// Regular Red, etc. +#define REDGIN(X) X +#define GREENGIN(X) X +#define YELLOWGIN(X) X +#define BLUEGIN(X) X +#define MAGENTAGIN(X) X +#define CYANGIN(X) X + +#else + +// Bold Red, etc. +#define NORUM(X) ""< +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_STR_H +#define IGL_STR_H +// http://stackoverflow.com/a/2433143/148668 +#include +#include +// Suppose you have a function: +// void func(std::string c); +// Then you can write: +// func(STR("foo"<<1<<"bar")); +#define STR(X) static_cast(std::ostringstream().flush() << X).str() +#endif diff --git a/src/external/libigl-2.3.0/include/igl/Singular_Value_Decomposition_Givens_QR_Factorization_Kernel.hpp b/src/external/libigl-2.3.0/include/igl/Singular_Value_Decomposition_Givens_QR_Factorization_Kernel.hpp new file mode 100644 index 000000000..2207285aa --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/Singular_Value_Decomposition_Givens_QR_Factorization_Kernel.hpp @@ -0,0 +1,128 @@ +//##################################################################### +// Copyright (c) 2010-2011, Eftychios Sifakis. +// +// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or +// other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +// BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +// SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +//##################################################################### + +//########################################################### +// Compute the Givens half-angle, construct the Givens quaternion and the rotation sine/cosine (for the full angle) +//########################################################### + +#ifdef _WIN32 + #undef max + #undef min +#endif + +ENABLE_SCALAR_IMPLEMENTATION(Ssh.f=SANPIVOT.f*SANPIVOT.f;) ENABLE_SSE_IMPLEMENTATION(Vsh=_mm_mul_ps(VANPIVOT,VANPIVOT);) ENABLE_AVX_IMPLEMENTATION(Vsh=_mm256_mul_ps(VANPIVOT,VANPIVOT);) +ENABLE_SCALAR_IMPLEMENTATION(Ssh.ui=(Ssh.f>=Ssmall_number.f)?0xffffffff:0;) ENABLE_SSE_IMPLEMENTATION(Vsh=_mm_cmpge_ps(Vsh,Vsmall_number);) ENABLE_AVX_IMPLEMENTATION(Vsh=_mm256_cmp_ps(Vsh,Vsmall_number, _CMP_GE_OS);) //ENABLE_AVX_IMPLEMENTATION(Vsh=_mm256_cmpge_ps(Vsh,Vsmall_number);) +ENABLE_SCALAR_IMPLEMENTATION(Ssh.ui=Ssh.ui&SANPIVOT.ui;) ENABLE_SSE_IMPLEMENTATION(Vsh=_mm_and_ps(Vsh,VANPIVOT);) ENABLE_AVX_IMPLEMENTATION(Vsh=_mm256_and_ps(Vsh,VANPIVOT);) + +ENABLE_SCALAR_IMPLEMENTATION(Stmp5.f=0.;) ENABLE_SSE_IMPLEMENTATION(Vtmp5=_mm_xor_ps(Vtmp5,Vtmp5);) ENABLE_AVX_IMPLEMENTATION(Vtmp5=_mm256_xor_ps(Vtmp5,Vtmp5);) +ENABLE_SCALAR_IMPLEMENTATION(Sch.f=Stmp5.f-SAPIVOT.f;) ENABLE_SSE_IMPLEMENTATION(Vch=_mm_sub_ps(Vtmp5,VAPIVOT);) ENABLE_AVX_IMPLEMENTATION(Vch=_mm256_sub_ps(Vtmp5,VAPIVOT);) +ENABLE_SCALAR_IMPLEMENTATION(Sch.f=std::max(Sch.f,SAPIVOT.f);) ENABLE_SSE_IMPLEMENTATION(Vch=_mm_max_ps(Vch,VAPIVOT);) ENABLE_AVX_IMPLEMENTATION(Vch=_mm256_max_ps(Vch,VAPIVOT);) +ENABLE_SCALAR_IMPLEMENTATION(Sch.f=std::max(Sch.f,Ssmall_number.f);) ENABLE_SSE_IMPLEMENTATION(Vch=_mm_max_ps(Vch,Vsmall_number);) ENABLE_AVX_IMPLEMENTATION(Vch=_mm256_max_ps(Vch,Vsmall_number);) +ENABLE_SCALAR_IMPLEMENTATION(Stmp5.ui=(SAPIVOT.f>=Stmp5.f)?0xffffffff:0;) ENABLE_SSE_IMPLEMENTATION(Vtmp5=_mm_cmpge_ps(VAPIVOT,Vtmp5);) ENABLE_AVX_IMPLEMENTATION(Vtmp5=_mm256_cmp_ps(VAPIVOT,Vtmp5, _CMP_GE_OS);) //ENABLE_AVX_IMPLEMENTATION(Vtmp5=_mm256_cmpge_ps(VAPIVOT,Vtmp5);) + +ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Sch.f*Sch.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Vch,Vch);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Vch,Vch);) +ENABLE_SCALAR_IMPLEMENTATION(Stmp2.f=Ssh.f*Ssh.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp2=_mm_mul_ps(Vsh,Vsh);) ENABLE_AVX_IMPLEMENTATION(Vtmp2=_mm256_mul_ps(Vsh,Vsh);) +ENABLE_SCALAR_IMPLEMENTATION(Stmp2.f=Stmp1.f+Stmp2.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp2=_mm_add_ps(Vtmp1,Vtmp2);) ENABLE_AVX_IMPLEMENTATION(Vtmp2=_mm256_add_ps(Vtmp1,Vtmp2);) +ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=rsqrt(Stmp2.f);) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_rsqrt_ps(Vtmp2);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_rsqrt_ps(Vtmp2);) + +ENABLE_SCALAR_IMPLEMENTATION(Stmp4.f=Stmp1.f*Sone_half.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp4=_mm_mul_ps(Vtmp1,Vone_half);) ENABLE_AVX_IMPLEMENTATION(Vtmp4=_mm256_mul_ps(Vtmp1,Vone_half);) +ENABLE_SCALAR_IMPLEMENTATION(Stmp3.f=Stmp1.f*Stmp4.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp3=_mm_mul_ps(Vtmp1,Vtmp4);) ENABLE_AVX_IMPLEMENTATION(Vtmp3=_mm256_mul_ps(Vtmp1,Vtmp4);) +ENABLE_SCALAR_IMPLEMENTATION(Stmp3.f=Stmp1.f*Stmp3.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp3=_mm_mul_ps(Vtmp1,Vtmp3);) ENABLE_AVX_IMPLEMENTATION(Vtmp3=_mm256_mul_ps(Vtmp1,Vtmp3);) +ENABLE_SCALAR_IMPLEMENTATION(Stmp3.f=Stmp2.f*Stmp3.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp3=_mm_mul_ps(Vtmp2,Vtmp3);) ENABLE_AVX_IMPLEMENTATION(Vtmp3=_mm256_mul_ps(Vtmp2,Vtmp3);) +ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Stmp1.f+Stmp4.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_add_ps(Vtmp1,Vtmp4);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_add_ps(Vtmp1,Vtmp4);) +ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Stmp1.f-Stmp3.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_sub_ps(Vtmp1,Vtmp3);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_sub_ps(Vtmp1,Vtmp3);) +ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Stmp1.f*Stmp2.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Vtmp1,Vtmp2);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Vtmp1,Vtmp2);) + +ENABLE_SCALAR_IMPLEMENTATION(Sch.f=Sch.f+Stmp1.f;) ENABLE_SSE_IMPLEMENTATION(Vch=_mm_add_ps(Vch,Vtmp1);) ENABLE_AVX_IMPLEMENTATION(Vch=_mm256_add_ps(Vch,Vtmp1);) + +ENABLE_SCALAR_IMPLEMENTATION(Stmp1.ui=~Stmp5.ui&Ssh.ui;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_andnot_ps(Vtmp5,Vsh);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=Vch;) +ENABLE_SCALAR_IMPLEMENTATION(Stmp2.ui=~Stmp5.ui&Sch.ui;) ENABLE_SSE_IMPLEMENTATION(Vtmp2=_mm_andnot_ps(Vtmp5,Vch);) ENABLE_AVX_IMPLEMENTATION(Vch=_mm256_blendv_ps(Vsh,Vch,Vtmp5);) +ENABLE_SCALAR_IMPLEMENTATION(Sch.ui=Stmp5.ui&Sch.ui;) ENABLE_SSE_IMPLEMENTATION(Vch=_mm_and_ps(Vtmp5,Vch);) ENABLE_AVX_IMPLEMENTATION(Vsh=_mm256_blendv_ps(Vtmp1,Vsh,Vtmp5);) +ENABLE_SCALAR_IMPLEMENTATION(Ssh.ui=Stmp5.ui&Ssh.ui;) ENABLE_SSE_IMPLEMENTATION(Vsh=_mm_and_ps(Vtmp5,Vsh);) +ENABLE_SCALAR_IMPLEMENTATION(Sch.ui=Sch.ui|Stmp1.ui;) ENABLE_SSE_IMPLEMENTATION(Vch=_mm_or_ps(Vch,Vtmp1);) +ENABLE_SCALAR_IMPLEMENTATION(Ssh.ui=Ssh.ui|Stmp2.ui;) ENABLE_SSE_IMPLEMENTATION(Vsh=_mm_or_ps(Vsh,Vtmp2);) + +ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Sch.f*Sch.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Vch,Vch);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Vch,Vch);) +ENABLE_SCALAR_IMPLEMENTATION(Stmp2.f=Ssh.f*Ssh.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp2=_mm_mul_ps(Vsh,Vsh);) ENABLE_AVX_IMPLEMENTATION(Vtmp2=_mm256_mul_ps(Vsh,Vsh);) +ENABLE_SCALAR_IMPLEMENTATION(Stmp2.f=Stmp1.f+Stmp2.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp2=_mm_add_ps(Vtmp1,Vtmp2);) ENABLE_AVX_IMPLEMENTATION(Vtmp2=_mm256_add_ps(Vtmp1,Vtmp2);) +ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=rsqrt(Stmp2.f);) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_rsqrt_ps(Vtmp2);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_rsqrt_ps(Vtmp2);) + +ENABLE_SCALAR_IMPLEMENTATION(Stmp4.f=Stmp1.f*Sone_half.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp4=_mm_mul_ps(Vtmp1,Vone_half);) ENABLE_AVX_IMPLEMENTATION(Vtmp4=_mm256_mul_ps(Vtmp1,Vone_half);) +ENABLE_SCALAR_IMPLEMENTATION(Stmp3.f=Stmp1.f*Stmp4.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp3=_mm_mul_ps(Vtmp1,Vtmp4);) ENABLE_AVX_IMPLEMENTATION(Vtmp3=_mm256_mul_ps(Vtmp1,Vtmp4);) +ENABLE_SCALAR_IMPLEMENTATION(Stmp3.f=Stmp1.f*Stmp3.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp3=_mm_mul_ps(Vtmp1,Vtmp3);) ENABLE_AVX_IMPLEMENTATION(Vtmp3=_mm256_mul_ps(Vtmp1,Vtmp3);) +ENABLE_SCALAR_IMPLEMENTATION(Stmp3.f=Stmp2.f*Stmp3.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp3=_mm_mul_ps(Vtmp2,Vtmp3);) ENABLE_AVX_IMPLEMENTATION(Vtmp3=_mm256_mul_ps(Vtmp2,Vtmp3);) +ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Stmp1.f+Stmp4.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_add_ps(Vtmp1,Vtmp4);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_add_ps(Vtmp1,Vtmp4);) +ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Stmp1.f-Stmp3.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_sub_ps(Vtmp1,Vtmp3);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_sub_ps(Vtmp1,Vtmp3);) + +ENABLE_SCALAR_IMPLEMENTATION(Sch.f=Sch.f*Stmp1.f;) ENABLE_SSE_IMPLEMENTATION(Vch=_mm_mul_ps(Vch,Vtmp1);) ENABLE_AVX_IMPLEMENTATION(Vch=_mm256_mul_ps(Vch,Vtmp1);) +ENABLE_SCALAR_IMPLEMENTATION(Ssh.f=Ssh.f*Stmp1.f;) ENABLE_SSE_IMPLEMENTATION(Vsh=_mm_mul_ps(Vsh,Vtmp1);) ENABLE_AVX_IMPLEMENTATION(Vsh=_mm256_mul_ps(Vsh,Vtmp1);) + +ENABLE_SCALAR_IMPLEMENTATION(Sc.f=Sch.f*Sch.f;) ENABLE_SSE_IMPLEMENTATION(Vc=_mm_mul_ps(Vch,Vch);) ENABLE_AVX_IMPLEMENTATION(Vc=_mm256_mul_ps(Vch,Vch);)ENABLE_SCALAR_IMPLEMENTATION(Ss.f=Ssh.f*Ssh.f;) ENABLE_SSE_IMPLEMENTATION(Vs=_mm_mul_ps(Vsh,Vsh);) ENABLE_AVX_IMPLEMENTATION(Vs=_mm256_mul_ps(Vsh,Vsh);) +ENABLE_SCALAR_IMPLEMENTATION(Sc.f=Sc.f-Ss.f;) ENABLE_SSE_IMPLEMENTATION(Vc=_mm_sub_ps(Vc,Vs);) ENABLE_AVX_IMPLEMENTATION(Vc=_mm256_sub_ps(Vc,Vs);) +ENABLE_SCALAR_IMPLEMENTATION(Ss.f=Ssh.f*Sch.f;) ENABLE_SSE_IMPLEMENTATION(Vs=_mm_mul_ps(Vsh,Vch);) ENABLE_AVX_IMPLEMENTATION(Vs=_mm256_mul_ps(Vsh,Vch);) +ENABLE_SCALAR_IMPLEMENTATION(Ss.f=Ss.f+Ss.f;) ENABLE_SSE_IMPLEMENTATION(Vs=_mm_add_ps(Vs,Vs);) ENABLE_AVX_IMPLEMENTATION(Vs=_mm256_add_ps(Vs,Vs);) + +//########################################################### +// Rotate matrix A +//########################################################### + +ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Ss.f*SA11.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Vs,VA11);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Vs,VA11);) +ENABLE_SCALAR_IMPLEMENTATION(Stmp2.f=Ss.f*SA21.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp2=_mm_mul_ps(Vs,VA21);) ENABLE_AVX_IMPLEMENTATION(Vtmp2=_mm256_mul_ps(Vs,VA21);) +ENABLE_SCALAR_IMPLEMENTATION(SA11.f=Sc.f*SA11.f;) ENABLE_SSE_IMPLEMENTATION(VA11=_mm_mul_ps(Vc,VA11);) ENABLE_AVX_IMPLEMENTATION(VA11=_mm256_mul_ps(Vc,VA11);) +ENABLE_SCALAR_IMPLEMENTATION(SA21.f=Sc.f*SA21.f;) ENABLE_SSE_IMPLEMENTATION(VA21=_mm_mul_ps(Vc,VA21);) ENABLE_AVX_IMPLEMENTATION(VA21=_mm256_mul_ps(Vc,VA21);) +ENABLE_SCALAR_IMPLEMENTATION(SA11.f=SA11.f+Stmp2.f;) ENABLE_SSE_IMPLEMENTATION(VA11=_mm_add_ps(VA11,Vtmp2);) ENABLE_AVX_IMPLEMENTATION(VA11=_mm256_add_ps(VA11,Vtmp2);) +ENABLE_SCALAR_IMPLEMENTATION(SA21.f=SA21.f-Stmp1.f;) ENABLE_SSE_IMPLEMENTATION(VA21=_mm_sub_ps(VA21,Vtmp1);) ENABLE_AVX_IMPLEMENTATION(VA21=_mm256_sub_ps(VA21,Vtmp1);) + +ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Ss.f*SA12.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Vs,VA12);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Vs,VA12);) +ENABLE_SCALAR_IMPLEMENTATION(Stmp2.f=Ss.f*SA22.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp2=_mm_mul_ps(Vs,VA22);) ENABLE_AVX_IMPLEMENTATION(Vtmp2=_mm256_mul_ps(Vs,VA22);) +ENABLE_SCALAR_IMPLEMENTATION(SA12.f=Sc.f*SA12.f;) ENABLE_SSE_IMPLEMENTATION(VA12=_mm_mul_ps(Vc,VA12);) ENABLE_AVX_IMPLEMENTATION(VA12=_mm256_mul_ps(Vc,VA12);) +ENABLE_SCALAR_IMPLEMENTATION(SA22.f=Sc.f*SA22.f;) ENABLE_SSE_IMPLEMENTATION(VA22=_mm_mul_ps(Vc,VA22);) ENABLE_AVX_IMPLEMENTATION(VA22=_mm256_mul_ps(Vc,VA22);) +ENABLE_SCALAR_IMPLEMENTATION(SA12.f=SA12.f+Stmp2.f;) ENABLE_SSE_IMPLEMENTATION(VA12=_mm_add_ps(VA12,Vtmp2);) ENABLE_AVX_IMPLEMENTATION(VA12=_mm256_add_ps(VA12,Vtmp2);) +ENABLE_SCALAR_IMPLEMENTATION(SA22.f=SA22.f-Stmp1.f;) ENABLE_SSE_IMPLEMENTATION(VA22=_mm_sub_ps(VA22,Vtmp1);) ENABLE_AVX_IMPLEMENTATION(VA22=_mm256_sub_ps(VA22,Vtmp1);) + +ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Ss.f*SA13.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Vs,VA13);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Vs,VA13);) +ENABLE_SCALAR_IMPLEMENTATION(Stmp2.f=Ss.f*SA23.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp2=_mm_mul_ps(Vs,VA23);) ENABLE_AVX_IMPLEMENTATION(Vtmp2=_mm256_mul_ps(Vs,VA23);) +ENABLE_SCALAR_IMPLEMENTATION(SA13.f=Sc.f*SA13.f;) ENABLE_SSE_IMPLEMENTATION(VA13=_mm_mul_ps(Vc,VA13);) ENABLE_AVX_IMPLEMENTATION(VA13=_mm256_mul_ps(Vc,VA13);) +ENABLE_SCALAR_IMPLEMENTATION(SA23.f=Sc.f*SA23.f;) ENABLE_SSE_IMPLEMENTATION(VA23=_mm_mul_ps(Vc,VA23);) ENABLE_AVX_IMPLEMENTATION(VA23=_mm256_mul_ps(Vc,VA23);) +ENABLE_SCALAR_IMPLEMENTATION(SA13.f=SA13.f+Stmp2.f;) ENABLE_SSE_IMPLEMENTATION(VA13=_mm_add_ps(VA13,Vtmp2);) ENABLE_AVX_IMPLEMENTATION(VA13=_mm256_add_ps(VA13,Vtmp2);) +ENABLE_SCALAR_IMPLEMENTATION(SA23.f=SA23.f-Stmp1.f;) ENABLE_SSE_IMPLEMENTATION(VA23=_mm_sub_ps(VA23,Vtmp1);) ENABLE_AVX_IMPLEMENTATION(VA23=_mm256_sub_ps(VA23,Vtmp1);) + +//########################################################### +// Update matrix U +//########################################################### + +#ifdef COMPUTE_U_AS_MATRIX +ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Ss.f*SU11.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Vs,VU11);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Vs,VU11);) +ENABLE_SCALAR_IMPLEMENTATION(Stmp2.f=Ss.f*SU12.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp2=_mm_mul_ps(Vs,VU12);) ENABLE_AVX_IMPLEMENTATION(Vtmp2=_mm256_mul_ps(Vs,VU12);) +ENABLE_SCALAR_IMPLEMENTATION(SU11.f=Sc.f*SU11.f;) ENABLE_SSE_IMPLEMENTATION(VU11=_mm_mul_ps(Vc,VU11);) ENABLE_AVX_IMPLEMENTATION(VU11=_mm256_mul_ps(Vc,VU11);) +ENABLE_SCALAR_IMPLEMENTATION(SU12.f=Sc.f*SU12.f;) ENABLE_SSE_IMPLEMENTATION(VU12=_mm_mul_ps(Vc,VU12);) ENABLE_AVX_IMPLEMENTATION(VU12=_mm256_mul_ps(Vc,VU12);) +ENABLE_SCALAR_IMPLEMENTATION(SU11.f=SU11.f+Stmp2.f;) ENABLE_SSE_IMPLEMENTATION(VU11=_mm_add_ps(VU11,Vtmp2);) ENABLE_AVX_IMPLEMENTATION(VU11=_mm256_add_ps(VU11,Vtmp2);) +ENABLE_SCALAR_IMPLEMENTATION(SU12.f=SU12.f-Stmp1.f;) ENABLE_SSE_IMPLEMENTATION(VU12=_mm_sub_ps(VU12,Vtmp1);) ENABLE_AVX_IMPLEMENTATION(VU12=_mm256_sub_ps(VU12,Vtmp1);) + +ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Ss.f*SU21.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Vs,VU21);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Vs,VU21);) +ENABLE_SCALAR_IMPLEMENTATION(Stmp2.f=Ss.f*SU22.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp2=_mm_mul_ps(Vs,VU22);) ENABLE_AVX_IMPLEMENTATION(Vtmp2=_mm256_mul_ps(Vs,VU22);) +ENABLE_SCALAR_IMPLEMENTATION(SU21.f=Sc.f*SU21.f;) ENABLE_SSE_IMPLEMENTATION(VU21=_mm_mul_ps(Vc,VU21);) ENABLE_AVX_IMPLEMENTATION(VU21=_mm256_mul_ps(Vc,VU21);) +ENABLE_SCALAR_IMPLEMENTATION(SU22.f=Sc.f*SU22.f;) ENABLE_SSE_IMPLEMENTATION(VU22=_mm_mul_ps(Vc,VU22);) ENABLE_AVX_IMPLEMENTATION(VU22=_mm256_mul_ps(Vc,VU22);) +ENABLE_SCALAR_IMPLEMENTATION(SU21.f=SU21.f+Stmp2.f;) ENABLE_SSE_IMPLEMENTATION(VU21=_mm_add_ps(VU21,Vtmp2);) ENABLE_AVX_IMPLEMENTATION(VU21=_mm256_add_ps(VU21,Vtmp2);) +ENABLE_SCALAR_IMPLEMENTATION(SU22.f=SU22.f-Stmp1.f;) ENABLE_SSE_IMPLEMENTATION(VU22=_mm_sub_ps(VU22,Vtmp1);) ENABLE_AVX_IMPLEMENTATION(VU22=_mm256_sub_ps(VU22,Vtmp1);) + +ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Ss.f*SU31.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Vs,VU31);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Vs,VU31);) +ENABLE_SCALAR_IMPLEMENTATION(Stmp2.f=Ss.f*SU32.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp2=_mm_mul_ps(Vs,VU32);) ENABLE_AVX_IMPLEMENTATION(Vtmp2=_mm256_mul_ps(Vs,VU32);) +ENABLE_SCALAR_IMPLEMENTATION(SU31.f=Sc.f*SU31.f;) ENABLE_SSE_IMPLEMENTATION(VU31=_mm_mul_ps(Vc,VU31);) ENABLE_AVX_IMPLEMENTATION(VU31=_mm256_mul_ps(Vc,VU31);) +ENABLE_SCALAR_IMPLEMENTATION(SU32.f=Sc.f*SU32.f;) ENABLE_SSE_IMPLEMENTATION(VU32=_mm_mul_ps(Vc,VU32);) ENABLE_AVX_IMPLEMENTATION(VU32=_mm256_mul_ps(Vc,VU32);) +ENABLE_SCALAR_IMPLEMENTATION(SU31.f=SU31.f+Stmp2.f;) ENABLE_SSE_IMPLEMENTATION(VU31=_mm_add_ps(VU31,Vtmp2);) ENABLE_AVX_IMPLEMENTATION(VU31=_mm256_add_ps(VU31,Vtmp2);) +ENABLE_SCALAR_IMPLEMENTATION(SU32.f=SU32.f-Stmp1.f;) ENABLE_SSE_IMPLEMENTATION(VU32=_mm_sub_ps(VU32,Vtmp1);) ENABLE_AVX_IMPLEMENTATION(VU32=_mm256_sub_ps(VU32,Vtmp1);) +#endif diff --git a/src/external/libigl-2.3.0/include/igl/Singular_Value_Decomposition_Jacobi_Conjugation_Kernel.hpp b/src/external/libigl-2.3.0/include/igl/Singular_Value_Decomposition_Jacobi_Conjugation_Kernel.hpp new file mode 100644 index 000000000..70b437131 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/Singular_Value_Decomposition_Jacobi_Conjugation_Kernel.hpp @@ -0,0 +1,118 @@ +//##################################################################### +// Copyright (c) 2010-2011, Eftychios Sifakis. +// +// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or +// other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +// BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +// SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +//##################################################################### + +//########################################################### +// Compute the Givens angle (and half-angle) +//########################################################### + +ENABLE_SCALAR_IMPLEMENTATION(Ssh.f=SS21.f*Sone_half.f;) ENABLE_SSE_IMPLEMENTATION(Vsh=_mm_mul_ps(VS21,Vone_half);) ENABLE_AVX_IMPLEMENTATION(Vsh=_mm256_mul_ps(VS21,Vone_half);) +ENABLE_SCALAR_IMPLEMENTATION(Stmp5.f=SS11.f-SS22.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp5=_mm_sub_ps(VS11,VS22);) ENABLE_AVX_IMPLEMENTATION(Vtmp5=_mm256_sub_ps(VS11,VS22);) + +ENABLE_SCALAR_IMPLEMENTATION(Stmp2.f=Ssh.f*Ssh.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp2=_mm_mul_ps(Vsh,Vsh);) ENABLE_AVX_IMPLEMENTATION(Vtmp2=_mm256_mul_ps(Vsh,Vsh);) +ENABLE_SCALAR_IMPLEMENTATION(Stmp1.ui=(Stmp2.f>=Stiny_number.f)?0xffffffff:0;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_cmpge_ps(Vtmp2,Vtiny_number);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_cmp_ps(Vtmp2,Vtiny_number, _CMP_GE_OS);) //ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_cmpge_ps(Vtmp2,Vtiny_number);) +ENABLE_SCALAR_IMPLEMENTATION(Ssh.ui=Stmp1.ui&Ssh.ui;) ENABLE_SSE_IMPLEMENTATION(Vsh=_mm_and_ps(Vtmp1,Vsh);) ENABLE_AVX_IMPLEMENTATION(Vsh=_mm256_and_ps(Vtmp1,Vsh);) +ENABLE_SCALAR_IMPLEMENTATION(Sch.ui=Stmp1.ui&Stmp5.ui;) ENABLE_SSE_IMPLEMENTATION(Vch=_mm_and_ps(Vtmp1,Vtmp5);) ENABLE_AVX_IMPLEMENTATION(Vch=_mm256_blendv_ps(Vone,Vtmp5,Vtmp1);) +ENABLE_SCALAR_IMPLEMENTATION(Stmp2.ui=~Stmp1.ui&Sone.ui;) ENABLE_SSE_IMPLEMENTATION(Vtmp2=_mm_andnot_ps(Vtmp1,Vone);) +ENABLE_SCALAR_IMPLEMENTATION(Sch.ui=Sch.ui|Stmp2.ui;) ENABLE_SSE_IMPLEMENTATION(Vch=_mm_or_ps(Vch,Vtmp2);) + +ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Ssh.f*Ssh.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Vsh,Vsh);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Vsh,Vsh);) +ENABLE_SCALAR_IMPLEMENTATION(Stmp2.f=Sch.f*Sch.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp2=_mm_mul_ps(Vch,Vch);) ENABLE_AVX_IMPLEMENTATION(Vtmp2=_mm256_mul_ps(Vch,Vch);) +ENABLE_SCALAR_IMPLEMENTATION(Stmp3.f=Stmp1.f+Stmp2.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp3=_mm_add_ps(Vtmp1,Vtmp2);) ENABLE_AVX_IMPLEMENTATION(Vtmp3=_mm256_add_ps(Vtmp1,Vtmp2);) +ENABLE_SCALAR_IMPLEMENTATION(Stmp4.f=rsqrt(Stmp3.f);) ENABLE_SSE_IMPLEMENTATION(Vtmp4=_mm_rsqrt_ps(Vtmp3);) ENABLE_AVX_IMPLEMENTATION(Vtmp4=_mm256_rsqrt_ps(Vtmp3);) + +#ifdef USE_ACCURATE_RSQRT_IN_JACOBI_CONJUGATION +ENABLE_SCALAR_IMPLEMENTATION(Ss.f=Stmp4.f*Sone_half.f;) ENABLE_SSE_IMPLEMENTATION(Vs=_mm_mul_ps(Vtmp4,Vone_half);) ENABLE_AVX_IMPLEMENTATION(Vs=_mm256_mul_ps(Vtmp4,Vone_half);) +ENABLE_SCALAR_IMPLEMENTATION(Sc.f=Stmp4.f*Ss.f;) ENABLE_SSE_IMPLEMENTATION(Vc=_mm_mul_ps(Vtmp4,Vs);) ENABLE_AVX_IMPLEMENTATION(Vc=_mm256_mul_ps(Vtmp4,Vs);) +ENABLE_SCALAR_IMPLEMENTATION(Sc.f=Stmp4.f*Sc.f;) ENABLE_SSE_IMPLEMENTATION(Vc=_mm_mul_ps(Vtmp4,Vc);) ENABLE_AVX_IMPLEMENTATION(Vc=_mm256_mul_ps(Vtmp4,Vc);) +ENABLE_SCALAR_IMPLEMENTATION(Sc.f=Stmp3.f*Sc.f;) ENABLE_SSE_IMPLEMENTATION(Vc=_mm_mul_ps(Vtmp3,Vc);) ENABLE_AVX_IMPLEMENTATION(Vc=_mm256_mul_ps(Vtmp3,Vc);) +ENABLE_SCALAR_IMPLEMENTATION(Stmp4.f=Stmp4.f+Ss.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp4=_mm_add_ps(Vtmp4,Vs);) ENABLE_AVX_IMPLEMENTATION(Vtmp4=_mm256_add_ps(Vtmp4,Vs);) +ENABLE_SCALAR_IMPLEMENTATION(Stmp4.f=Stmp4.f-Sc.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp4=_mm_sub_ps(Vtmp4,Vc);) ENABLE_AVX_IMPLEMENTATION(Vtmp4=_mm256_sub_ps(Vtmp4,Vc);) +#endif + +ENABLE_SCALAR_IMPLEMENTATION(Ssh.f=Stmp4.f*Ssh.f;) ENABLE_SSE_IMPLEMENTATION(Vsh=_mm_mul_ps(Vtmp4,Vsh);) ENABLE_AVX_IMPLEMENTATION(Vsh=_mm256_mul_ps(Vtmp4,Vsh);) +ENABLE_SCALAR_IMPLEMENTATION(Sch.f=Stmp4.f*Sch.f;) ENABLE_SSE_IMPLEMENTATION(Vch=_mm_mul_ps(Vtmp4,Vch);) ENABLE_AVX_IMPLEMENTATION(Vch=_mm256_mul_ps(Vtmp4,Vch);) + +ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Sfour_gamma_squared.f*Stmp1.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Vfour_gamma_squared,Vtmp1);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Vfour_gamma_squared,Vtmp1);) +ENABLE_SCALAR_IMPLEMENTATION(Stmp1.ui=(Stmp2.f<=Stmp1.f)?0xffffffff:0;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_cmple_ps(Vtmp2,Vtmp1);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_cmp_ps(Vtmp2,Vtmp1, _CMP_LE_OS);) //ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_cmple_ps(Vtmp2,Vtmp1);) + +ENABLE_SCALAR_IMPLEMENTATION(Stmp2.ui=Ssine_pi_over_eight.ui&Stmp1.ui;) ENABLE_SSE_IMPLEMENTATION(Vtmp2=_mm_and_ps(Vsine_pi_over_eight,Vtmp1);) ENABLE_AVX_IMPLEMENTATION(Vsh=_mm256_blendv_ps(Vsh,Vsine_pi_over_eight,Vtmp1);) +ENABLE_SCALAR_IMPLEMENTATION(Ssh.ui=~Stmp1.ui&Ssh.ui;) ENABLE_SSE_IMPLEMENTATION(Vsh=_mm_andnot_ps(Vtmp1,Vsh);) +ENABLE_SCALAR_IMPLEMENTATION(Ssh.ui=Ssh.ui|Stmp2.ui;) ENABLE_SSE_IMPLEMENTATION(Vsh=_mm_or_ps(Vsh,Vtmp2);) +ENABLE_SCALAR_IMPLEMENTATION(Stmp2.ui=Scosine_pi_over_eight.ui&Stmp1.ui;) ENABLE_SSE_IMPLEMENTATION(Vtmp2=_mm_and_ps(Vcosine_pi_over_eight,Vtmp1);) ENABLE_AVX_IMPLEMENTATION(Vch=_mm256_blendv_ps(Vch,Vcosine_pi_over_eight,Vtmp1);) +ENABLE_SCALAR_IMPLEMENTATION(Sch.ui=~Stmp1.ui&Sch.ui;) ENABLE_SSE_IMPLEMENTATION(Vch=_mm_andnot_ps(Vtmp1,Vch);) +ENABLE_SCALAR_IMPLEMENTATION(Sch.ui=Sch.ui|Stmp2.ui;) ENABLE_SSE_IMPLEMENTATION(Vch=_mm_or_ps(Vch,Vtmp2);) + +ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Ssh.f*Ssh.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Vsh,Vsh);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Vsh,Vsh);) +ENABLE_SCALAR_IMPLEMENTATION(Stmp2.f=Sch.f*Sch.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp2=_mm_mul_ps(Vch,Vch);) ENABLE_AVX_IMPLEMENTATION(Vtmp2=_mm256_mul_ps(Vch,Vch);) +ENABLE_SCALAR_IMPLEMENTATION(Sc.f=Stmp2.f-Stmp1.f;) ENABLE_SSE_IMPLEMENTATION(Vc=_mm_sub_ps(Vtmp2,Vtmp1);) ENABLE_AVX_IMPLEMENTATION(Vc=_mm256_sub_ps(Vtmp2,Vtmp1);) +ENABLE_SCALAR_IMPLEMENTATION(Ss.f=Sch.f*Ssh.f;) ENABLE_SSE_IMPLEMENTATION(Vs=_mm_mul_ps(Vch,Vsh);) ENABLE_AVX_IMPLEMENTATION(Vs=_mm256_mul_ps(Vch,Vsh);) +ENABLE_SCALAR_IMPLEMENTATION(Ss.f=Ss.f+Ss.f;) ENABLE_SSE_IMPLEMENTATION(Vs=_mm_add_ps(Vs,Vs);) ENABLE_AVX_IMPLEMENTATION(Vs=_mm256_add_ps(Vs,Vs);) + +//########################################################### +// Perform the actual Givens conjugation +//########################################################### + +#ifndef USE_ACCURATE_RSQRT_IN_JACOBI_CONJUGATION +ENABLE_SCALAR_IMPLEMENTATION(Stmp3.f=Stmp1.f+Stmp2.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp3=_mm_add_ps(Vtmp1,Vtmp2);) ENABLE_AVX_IMPLEMENTATION(Vtmp3=_mm256_add_ps(Vtmp1,Vtmp2);) +ENABLE_SCALAR_IMPLEMENTATION(SS33.f=SS33.f*Stmp3.f;) ENABLE_SSE_IMPLEMENTATION(VS33=_mm_mul_ps(VS33,Vtmp3);) ENABLE_AVX_IMPLEMENTATION(VS33=_mm256_mul_ps(VS33,Vtmp3);) +ENABLE_SCALAR_IMPLEMENTATION(SS31.f=SS31.f*Stmp3.f;) ENABLE_SSE_IMPLEMENTATION(VS31=_mm_mul_ps(VS31,Vtmp3);) ENABLE_AVX_IMPLEMENTATION(VS31=_mm256_mul_ps(VS31,Vtmp3);) +ENABLE_SCALAR_IMPLEMENTATION(SS32.f=SS32.f*Stmp3.f;) ENABLE_SSE_IMPLEMENTATION(VS32=_mm_mul_ps(VS32,Vtmp3);) ENABLE_AVX_IMPLEMENTATION(VS32=_mm256_mul_ps(VS32,Vtmp3);) +ENABLE_SCALAR_IMPLEMENTATION(SS33.f=SS33.f*Stmp3.f;) ENABLE_SSE_IMPLEMENTATION(VS33=_mm_mul_ps(VS33,Vtmp3);) ENABLE_AVX_IMPLEMENTATION(VS33=_mm256_mul_ps(VS33,Vtmp3);) +#endif + +ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Ss.f*SS31.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Vs,VS31);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Vs,VS31);) +ENABLE_SCALAR_IMPLEMENTATION(Stmp2.f=Ss.f*SS32.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp2=_mm_mul_ps(Vs,VS32);) ENABLE_AVX_IMPLEMENTATION(Vtmp2=_mm256_mul_ps(Vs,VS32);) +ENABLE_SCALAR_IMPLEMENTATION(SS31.f=Sc.f*SS31.f;) ENABLE_SSE_IMPLEMENTATION(VS31=_mm_mul_ps(Vc,VS31);) ENABLE_AVX_IMPLEMENTATION(VS31=_mm256_mul_ps(Vc,VS31);) +ENABLE_SCALAR_IMPLEMENTATION(SS32.f=Sc.f*SS32.f;) ENABLE_SSE_IMPLEMENTATION(VS32=_mm_mul_ps(Vc,VS32);) ENABLE_AVX_IMPLEMENTATION(VS32=_mm256_mul_ps(Vc,VS32);) +ENABLE_SCALAR_IMPLEMENTATION(SS31.f=Stmp2.f+SS31.f;) ENABLE_SSE_IMPLEMENTATION(VS31=_mm_add_ps(Vtmp2,VS31);) ENABLE_AVX_IMPLEMENTATION(VS31=_mm256_add_ps(Vtmp2,VS31);) +ENABLE_SCALAR_IMPLEMENTATION(SS32.f=SS32.f-Stmp1.f;) ENABLE_SSE_IMPLEMENTATION(VS32=_mm_sub_ps(VS32,Vtmp1);) ENABLE_AVX_IMPLEMENTATION(VS32=_mm256_sub_ps(VS32,Vtmp1);) + +ENABLE_SCALAR_IMPLEMENTATION(Stmp2.f=Ss.f*Ss.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp2=_mm_mul_ps(Vs,Vs);) ENABLE_AVX_IMPLEMENTATION(Vtmp2=_mm256_mul_ps(Vs,Vs);) +ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=SS22.f*Stmp2.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(VS22,Vtmp2);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(VS22,Vtmp2);) +ENABLE_SCALAR_IMPLEMENTATION(Stmp3.f=SS11.f*Stmp2.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp3=_mm_mul_ps(VS11,Vtmp2);) ENABLE_AVX_IMPLEMENTATION(Vtmp3=_mm256_mul_ps(VS11,Vtmp2);) +ENABLE_SCALAR_IMPLEMENTATION(Stmp4.f=Sc.f*Sc.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp4=_mm_mul_ps(Vc,Vc);) ENABLE_AVX_IMPLEMENTATION(Vtmp4=_mm256_mul_ps(Vc,Vc);) +ENABLE_SCALAR_IMPLEMENTATION(SS11.f=SS11.f*Stmp4.f;) ENABLE_SSE_IMPLEMENTATION(VS11=_mm_mul_ps(VS11,Vtmp4);) ENABLE_AVX_IMPLEMENTATION(VS11=_mm256_mul_ps(VS11,Vtmp4);) +ENABLE_SCALAR_IMPLEMENTATION(SS22.f=SS22.f*Stmp4.f;) ENABLE_SSE_IMPLEMENTATION(VS22=_mm_mul_ps(VS22,Vtmp4);) ENABLE_AVX_IMPLEMENTATION(VS22=_mm256_mul_ps(VS22,Vtmp4);) +ENABLE_SCALAR_IMPLEMENTATION(SS11.f=SS11.f+Stmp1.f;) ENABLE_SSE_IMPLEMENTATION(VS11=_mm_add_ps(VS11,Vtmp1);) ENABLE_AVX_IMPLEMENTATION(VS11=_mm256_add_ps(VS11,Vtmp1);) +ENABLE_SCALAR_IMPLEMENTATION(SS22.f=SS22.f+Stmp3.f;) ENABLE_SSE_IMPLEMENTATION(VS22=_mm_add_ps(VS22,Vtmp3);) ENABLE_AVX_IMPLEMENTATION(VS22=_mm256_add_ps(VS22,Vtmp3);) +ENABLE_SCALAR_IMPLEMENTATION(Stmp4.f=Stmp4.f-Stmp2.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp4=_mm_sub_ps(Vtmp4,Vtmp2);) ENABLE_AVX_IMPLEMENTATION(Vtmp4=_mm256_sub_ps(Vtmp4,Vtmp2);) +ENABLE_SCALAR_IMPLEMENTATION(Stmp2.f=SS21.f+SS21.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp2=_mm_add_ps(VS21,VS21);) ENABLE_AVX_IMPLEMENTATION(Vtmp2=_mm256_add_ps(VS21,VS21);) +ENABLE_SCALAR_IMPLEMENTATION(SS21.f=SS21.f*Stmp4.f;) ENABLE_SSE_IMPLEMENTATION(VS21=_mm_mul_ps(VS21,Vtmp4);) ENABLE_AVX_IMPLEMENTATION(VS21=_mm256_mul_ps(VS21,Vtmp4);) +ENABLE_SCALAR_IMPLEMENTATION(Stmp4.f=Sc.f*Ss.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp4=_mm_mul_ps(Vc,Vs);) ENABLE_AVX_IMPLEMENTATION(Vtmp4=_mm256_mul_ps(Vc,Vs);) +ENABLE_SCALAR_IMPLEMENTATION(Stmp2.f=Stmp2.f*Stmp4.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp2=_mm_mul_ps(Vtmp2,Vtmp4);) ENABLE_AVX_IMPLEMENTATION(Vtmp2=_mm256_mul_ps(Vtmp2,Vtmp4);) +ENABLE_SCALAR_IMPLEMENTATION(Stmp5.f=Stmp5.f*Stmp4.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp5=_mm_mul_ps(Vtmp5,Vtmp4);) ENABLE_AVX_IMPLEMENTATION(Vtmp5=_mm256_mul_ps(Vtmp5,Vtmp4);) +ENABLE_SCALAR_IMPLEMENTATION(SS11.f=SS11.f+Stmp2.f;) ENABLE_SSE_IMPLEMENTATION(VS11=_mm_add_ps(VS11,Vtmp2);) ENABLE_AVX_IMPLEMENTATION(VS11=_mm256_add_ps(VS11,Vtmp2);) +ENABLE_SCALAR_IMPLEMENTATION(SS21.f=SS21.f-Stmp5.f;) ENABLE_SSE_IMPLEMENTATION(VS21=_mm_sub_ps(VS21,Vtmp5);) ENABLE_AVX_IMPLEMENTATION(VS21=_mm256_sub_ps(VS21,Vtmp5);) +ENABLE_SCALAR_IMPLEMENTATION(SS22.f=SS22.f-Stmp2.f;) ENABLE_SSE_IMPLEMENTATION(VS22=_mm_sub_ps(VS22,Vtmp2);) ENABLE_AVX_IMPLEMENTATION(VS22=_mm256_sub_ps(VS22,Vtmp2);) + +//########################################################### +// Compute the cumulative rotation, in quaternion form +//########################################################### + +ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Ssh.f*Sqvvx.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Vsh,Vqvvx);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Vsh,Vqvvx);) +ENABLE_SCALAR_IMPLEMENTATION(Stmp2.f=Ssh.f*Sqvvy.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp2=_mm_mul_ps(Vsh,Vqvvy);) ENABLE_AVX_IMPLEMENTATION(Vtmp2=_mm256_mul_ps(Vsh,Vqvvy);) +ENABLE_SCALAR_IMPLEMENTATION(Stmp3.f=Ssh.f*Sqvvz.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp3=_mm_mul_ps(Vsh,Vqvvz);) ENABLE_AVX_IMPLEMENTATION(Vtmp3=_mm256_mul_ps(Vsh,Vqvvz);) +ENABLE_SCALAR_IMPLEMENTATION(Ssh.f=Ssh.f*Sqvs.f;) ENABLE_SSE_IMPLEMENTATION(Vsh=_mm_mul_ps(Vsh,Vqvs);) ENABLE_AVX_IMPLEMENTATION(Vsh=_mm256_mul_ps(Vsh,Vqvs);) + +ENABLE_SCALAR_IMPLEMENTATION(Sqvs.f=Sch.f*Sqvs.f;) ENABLE_SSE_IMPLEMENTATION(Vqvs=_mm_mul_ps(Vch,Vqvs);) ENABLE_AVX_IMPLEMENTATION(Vqvs=_mm256_mul_ps(Vch,Vqvs);) +ENABLE_SCALAR_IMPLEMENTATION(Sqvvx.f=Sch.f*Sqvvx.f;) ENABLE_SSE_IMPLEMENTATION(Vqvvx=_mm_mul_ps(Vch,Vqvvx);) ENABLE_AVX_IMPLEMENTATION(Vqvvx=_mm256_mul_ps(Vch,Vqvvx);) +ENABLE_SCALAR_IMPLEMENTATION(Sqvvy.f=Sch.f*Sqvvy.f;) ENABLE_SSE_IMPLEMENTATION(Vqvvy=_mm_mul_ps(Vch,Vqvvy);) ENABLE_AVX_IMPLEMENTATION(Vqvvy=_mm256_mul_ps(Vch,Vqvvy);) +ENABLE_SCALAR_IMPLEMENTATION(Sqvvz.f=Sch.f*Sqvvz.f;) ENABLE_SSE_IMPLEMENTATION(Vqvvz=_mm_mul_ps(Vch,Vqvvz);) ENABLE_AVX_IMPLEMENTATION(Vqvvz=_mm256_mul_ps(Vch,Vqvvz);) + +ENABLE_SCALAR_IMPLEMENTATION(SQVVZ.f=SQVVZ.f+Ssh.f;) ENABLE_SSE_IMPLEMENTATION(VQVVZ=_mm_add_ps(VQVVZ,Vsh);) ENABLE_AVX_IMPLEMENTATION(VQVVZ=_mm256_add_ps(VQVVZ,Vsh);) +ENABLE_SCALAR_IMPLEMENTATION(Sqvs.f=Sqvs.f-STMP3.f;) ENABLE_SSE_IMPLEMENTATION(Vqvs=_mm_sub_ps(Vqvs,VTMP3);) ENABLE_AVX_IMPLEMENTATION(Vqvs=_mm256_sub_ps(Vqvs,VTMP3);) +ENABLE_SCALAR_IMPLEMENTATION(SQVVX.f=SQVVX.f+STMP2.f;) ENABLE_SSE_IMPLEMENTATION(VQVVX=_mm_add_ps(VQVVX,VTMP2);) ENABLE_AVX_IMPLEMENTATION(VQVVX=_mm256_add_ps(VQVVX,VTMP2);) +ENABLE_SCALAR_IMPLEMENTATION(SQVVY.f=SQVVY.f-STMP1.f;) ENABLE_SSE_IMPLEMENTATION(VQVVY=_mm_sub_ps(VQVVY,VTMP1);) ENABLE_AVX_IMPLEMENTATION(VQVVY=_mm256_sub_ps(VQVVY,VTMP1);) diff --git a/src/external/libigl-2.3.0/include/igl/Singular_Value_Decomposition_Kernel_Declarations.hpp b/src/external/libigl-2.3.0/include/igl/Singular_Value_Decomposition_Kernel_Declarations.hpp new file mode 100644 index 000000000..0c3b3ff87 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/Singular_Value_Decomposition_Kernel_Declarations.hpp @@ -0,0 +1,137 @@ +//##################################################################### +// Copyright (c) 2010-2011, Eftychios Sifakis. +// +// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or +// other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +// BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +// SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +//##################################################################### + +//########################################################### +// Local variable declarations +//########################################################### + +#ifdef PRINT_DEBUGGING_OUTPUT + +#ifdef USE_SSE_IMPLEMENTATION + float buf[4]; + float A11,A21,A31,A12,A22,A32,A13,A23,A33; + float S11,S21,S31,S22,S32,S33; +#ifdef COMPUTE_V_AS_QUATERNION + float QVS,QVVX,QVVY,QVVZ; +#endif +#ifdef COMPUTE_V_AS_MATRIX + float V11,V21,V31,V12,V22,V32,V13,V23,V33; +#endif +#ifdef COMPUTE_U_AS_QUATERNION + float QUS,QUVX,QUVY,QUVZ; +#endif +#ifdef COMPUTE_U_AS_MATRIX + float U11,U21,U31,U12,U22,U32,U13,U23,U33; +#endif +#endif + +#ifdef USE_AVX_IMPLEMENTATION + float buf[8]; + float A11,A21,A31,A12,A22,A32,A13,A23,A33; + float S11,S21,S31,S22,S32,S33; +#ifdef COMPUTE_V_AS_QUATERNION + float QVS,QVVX,QVVY,QVVZ; +#endif +#ifdef COMPUTE_V_AS_MATRIX + float V11,V21,V31,V12,V22,V32,V13,V23,V33; +#endif +#ifdef COMPUTE_U_AS_QUATERNION + float QUS,QUVX,QUVY,QUVZ; +#endif +#ifdef COMPUTE_U_AS_MATRIX + float U11,U21,U31,U12,U22,U32,U13,U23,U33; +#endif +#endif + +#endif + +const float Four_Gamma_Squared=sqrt(8.)+3.; +const float Sine_Pi_Over_Eight=.5*sqrt(2.-sqrt(2.)); +const float Cosine_Pi_Over_Eight=.5*sqrt(2.+sqrt(2.)); + +ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sfour_gamma_squared;) ENABLE_SSE_IMPLEMENTATION(__m128 Vfour_gamma_squared;) ENABLE_AVX_IMPLEMENTATION(__m256 Vfour_gamma_squared;) +ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Ssine_pi_over_eight;) ENABLE_SSE_IMPLEMENTATION(__m128 Vsine_pi_over_eight;) ENABLE_AVX_IMPLEMENTATION(__m256 Vsine_pi_over_eight;) +ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Scosine_pi_over_eight;) ENABLE_SSE_IMPLEMENTATION(__m128 Vcosine_pi_over_eight;) ENABLE_AVX_IMPLEMENTATION(__m256 Vcosine_pi_over_eight;) +ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sone_half;) ENABLE_SSE_IMPLEMENTATION(__m128 Vone_half;) ENABLE_AVX_IMPLEMENTATION(__m256 Vone_half;) +ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sone;) ENABLE_SSE_IMPLEMENTATION(__m128 Vone;) ENABLE_AVX_IMPLEMENTATION(__m256 Vone;) +ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Stiny_number;) ENABLE_SSE_IMPLEMENTATION(__m128 Vtiny_number;) ENABLE_AVX_IMPLEMENTATION(__m256 Vtiny_number;) +ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Ssmall_number;) ENABLE_SSE_IMPLEMENTATION(__m128 Vsmall_number;) ENABLE_AVX_IMPLEMENTATION(__m256 Vsmall_number;) + +ENABLE_SCALAR_IMPLEMENTATION(Sfour_gamma_squared.f=Four_Gamma_Squared;) ENABLE_SSE_IMPLEMENTATION(Vfour_gamma_squared=_mm_set1_ps(Four_Gamma_Squared);) ENABLE_AVX_IMPLEMENTATION(Vfour_gamma_squared=_mm256_set1_ps(Four_Gamma_Squared);) +ENABLE_SCALAR_IMPLEMENTATION(Ssine_pi_over_eight.f=Sine_Pi_Over_Eight;) ENABLE_SSE_IMPLEMENTATION(Vsine_pi_over_eight=_mm_set1_ps(Sine_Pi_Over_Eight);) ENABLE_AVX_IMPLEMENTATION(Vsine_pi_over_eight=_mm256_set1_ps(Sine_Pi_Over_Eight);) +ENABLE_SCALAR_IMPLEMENTATION(Scosine_pi_over_eight.f=Cosine_Pi_Over_Eight;) ENABLE_SSE_IMPLEMENTATION(Vcosine_pi_over_eight=_mm_set1_ps(Cosine_Pi_Over_Eight);) ENABLE_AVX_IMPLEMENTATION(Vcosine_pi_over_eight=_mm256_set1_ps(Cosine_Pi_Over_Eight);) +ENABLE_SCALAR_IMPLEMENTATION(Sone_half.f=.5;) ENABLE_SSE_IMPLEMENTATION(Vone_half=_mm_set1_ps(.5);) ENABLE_AVX_IMPLEMENTATION(Vone_half=_mm256_set1_ps(.5);) +ENABLE_SCALAR_IMPLEMENTATION(Sone.f=1.;) ENABLE_SSE_IMPLEMENTATION(Vone=_mm_set1_ps(1.);) ENABLE_AVX_IMPLEMENTATION(Vone=_mm256_set1_ps(1.);) +ENABLE_SCALAR_IMPLEMENTATION(Stiny_number.f=1.e-20;) ENABLE_SSE_IMPLEMENTATION(Vtiny_number=_mm_set1_ps(1.e-20);) ENABLE_AVX_IMPLEMENTATION(Vtiny_number=_mm256_set1_ps(1.e-20);) +ENABLE_SCALAR_IMPLEMENTATION(Ssmall_number.f=1.e-12;) ENABLE_SSE_IMPLEMENTATION(Vsmall_number=_mm_set1_ps(1.e-12);) ENABLE_AVX_IMPLEMENTATION(Vsmall_number=_mm256_set1_ps(1.e-12);) + +ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sa11;) ENABLE_SSE_IMPLEMENTATION(__m128 Va11;) ENABLE_AVX_IMPLEMENTATION(__m256 Va11;) +ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sa21;) ENABLE_SSE_IMPLEMENTATION(__m128 Va21;) ENABLE_AVX_IMPLEMENTATION(__m256 Va21;) +ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sa31;) ENABLE_SSE_IMPLEMENTATION(__m128 Va31;) ENABLE_AVX_IMPLEMENTATION(__m256 Va31;) +ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sa12;) ENABLE_SSE_IMPLEMENTATION(__m128 Va12;) ENABLE_AVX_IMPLEMENTATION(__m256 Va12;) +ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sa22;) ENABLE_SSE_IMPLEMENTATION(__m128 Va22;) ENABLE_AVX_IMPLEMENTATION(__m256 Va22;) +ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sa32;) ENABLE_SSE_IMPLEMENTATION(__m128 Va32;) ENABLE_AVX_IMPLEMENTATION(__m256 Va32;) +ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sa13;) ENABLE_SSE_IMPLEMENTATION(__m128 Va13;) ENABLE_AVX_IMPLEMENTATION(__m256 Va13;) +ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sa23;) ENABLE_SSE_IMPLEMENTATION(__m128 Va23;) ENABLE_AVX_IMPLEMENTATION(__m256 Va23;) +ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sa33;) ENABLE_SSE_IMPLEMENTATION(__m128 Va33;) ENABLE_AVX_IMPLEMENTATION(__m256 Va33;) + +#ifdef COMPUTE_V_AS_MATRIX +ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sv11;) ENABLE_SSE_IMPLEMENTATION(__m128 Vv11;) ENABLE_AVX_IMPLEMENTATION(__m256 Vv11;) +ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sv21;) ENABLE_SSE_IMPLEMENTATION(__m128 Vv21;) ENABLE_AVX_IMPLEMENTATION(__m256 Vv21;) +ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sv31;) ENABLE_SSE_IMPLEMENTATION(__m128 Vv31;) ENABLE_AVX_IMPLEMENTATION(__m256 Vv31;) +ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sv12;) ENABLE_SSE_IMPLEMENTATION(__m128 Vv12;) ENABLE_AVX_IMPLEMENTATION(__m256 Vv12;) +ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sv22;) ENABLE_SSE_IMPLEMENTATION(__m128 Vv22;) ENABLE_AVX_IMPLEMENTATION(__m256 Vv22;) +ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sv32;) ENABLE_SSE_IMPLEMENTATION(__m128 Vv32;) ENABLE_AVX_IMPLEMENTATION(__m256 Vv32;) +ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sv13;) ENABLE_SSE_IMPLEMENTATION(__m128 Vv13;) ENABLE_AVX_IMPLEMENTATION(__m256 Vv13;) +ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sv23;) ENABLE_SSE_IMPLEMENTATION(__m128 Vv23;) ENABLE_AVX_IMPLEMENTATION(__m256 Vv23;) +ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sv33;) ENABLE_SSE_IMPLEMENTATION(__m128 Vv33;) ENABLE_AVX_IMPLEMENTATION(__m256 Vv33;) +#endif + +#ifdef COMPUTE_V_AS_QUATERNION +ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sqvs;) ENABLE_SSE_IMPLEMENTATION(__m128 Vqvs;) ENABLE_AVX_IMPLEMENTATION(__m256 Vqvs;) +ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sqvvx;) ENABLE_SSE_IMPLEMENTATION(__m128 Vqvvx;) ENABLE_AVX_IMPLEMENTATION(__m256 Vqvvx;) +ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sqvvy;) ENABLE_SSE_IMPLEMENTATION(__m128 Vqvvy;) ENABLE_AVX_IMPLEMENTATION(__m256 Vqvvy;) +ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sqvvz;) ENABLE_SSE_IMPLEMENTATION(__m128 Vqvvz;) ENABLE_AVX_IMPLEMENTATION(__m256 Vqvvz;) +#endif + +#ifdef COMPUTE_U_AS_MATRIX +ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Su11;) ENABLE_SSE_IMPLEMENTATION(__m128 Vu11;) ENABLE_AVX_IMPLEMENTATION(__m256 Vu11;) +ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Su21;) ENABLE_SSE_IMPLEMENTATION(__m128 Vu21;) ENABLE_AVX_IMPLEMENTATION(__m256 Vu21;) +ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Su31;) ENABLE_SSE_IMPLEMENTATION(__m128 Vu31;) ENABLE_AVX_IMPLEMENTATION(__m256 Vu31;) +ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Su12;) ENABLE_SSE_IMPLEMENTATION(__m128 Vu12;) ENABLE_AVX_IMPLEMENTATION(__m256 Vu12;) +ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Su22;) ENABLE_SSE_IMPLEMENTATION(__m128 Vu22;) ENABLE_AVX_IMPLEMENTATION(__m256 Vu22;) +ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Su32;) ENABLE_SSE_IMPLEMENTATION(__m128 Vu32;) ENABLE_AVX_IMPLEMENTATION(__m256 Vu32;) +ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Su13;) ENABLE_SSE_IMPLEMENTATION(__m128 Vu13;) ENABLE_AVX_IMPLEMENTATION(__m256 Vu13;) +ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Su23;) ENABLE_SSE_IMPLEMENTATION(__m128 Vu23;) ENABLE_AVX_IMPLEMENTATION(__m256 Vu23;) +ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Su33;) ENABLE_SSE_IMPLEMENTATION(__m128 Vu33;) ENABLE_AVX_IMPLEMENTATION(__m256 Vu33;) +#endif + +#ifdef COMPUTE_U_AS_QUATERNION +ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Squs;) ENABLE_SSE_IMPLEMENTATION(__m128 Vqus;) ENABLE_AVX_IMPLEMENTATION(__m256 Vqus;) +ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Squvx;) ENABLE_SSE_IMPLEMENTATION(__m128 Vquvx;) ENABLE_AVX_IMPLEMENTATION(__m256 Vquvx;) +ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Squvy;) ENABLE_SSE_IMPLEMENTATION(__m128 Vquvy;) ENABLE_AVX_IMPLEMENTATION(__m256 Vquvy;) +ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Squvz;) ENABLE_SSE_IMPLEMENTATION(__m128 Vquvz;) ENABLE_AVX_IMPLEMENTATION(__m256 Vquvz;) +#endif + +ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sc;) ENABLE_SSE_IMPLEMENTATION(__m128 Vc;) ENABLE_AVX_IMPLEMENTATION(__m256 Vc;) +ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Ss;) ENABLE_SSE_IMPLEMENTATION(__m128 Vs;) ENABLE_AVX_IMPLEMENTATION(__m256 Vs;) +ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sch;) ENABLE_SSE_IMPLEMENTATION(__m128 Vch;) ENABLE_AVX_IMPLEMENTATION(__m256 Vch;) +ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Ssh;) ENABLE_SSE_IMPLEMENTATION(__m128 Vsh;) ENABLE_AVX_IMPLEMENTATION(__m256 Vsh;) +ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Stmp1;) ENABLE_SSE_IMPLEMENTATION(__m128 Vtmp1;) ENABLE_AVX_IMPLEMENTATION(__m256 Vtmp1;) +ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Stmp2;) ENABLE_SSE_IMPLEMENTATION(__m128 Vtmp2;) ENABLE_AVX_IMPLEMENTATION(__m256 Vtmp2;) +ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Stmp3;) ENABLE_SSE_IMPLEMENTATION(__m128 Vtmp3;) ENABLE_AVX_IMPLEMENTATION(__m256 Vtmp3;) +ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Stmp4;) ENABLE_SSE_IMPLEMENTATION(__m128 Vtmp4;) ENABLE_AVX_IMPLEMENTATION(__m256 Vtmp4;) +ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Stmp5;) ENABLE_SSE_IMPLEMENTATION(__m128 Vtmp5;) ENABLE_AVX_IMPLEMENTATION(__m256 Vtmp5;) diff --git a/src/external/libigl-2.3.0/include/igl/Singular_Value_Decomposition_Main_Kernel_Body.hpp b/src/external/libigl-2.3.0/include/igl/Singular_Value_Decomposition_Main_Kernel_Body.hpp new file mode 100644 index 000000000..e8898a8aa --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/Singular_Value_Decomposition_Main_Kernel_Body.hpp @@ -0,0 +1,1277 @@ +//##################################################################### +// Copyright (c) 2010-2011, Eftychios Sifakis. +// +// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or +// other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +// BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +// SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +//##################################################################### + +#ifdef __INTEL_COMPILER +#pragma warning( disable : 592 ) +#endif + +// #define USE_ACCURATE_RSQRT_IN_JACOBI_CONJUGATION +// #define PERFORM_STRICT_QUATERNION_RENORMALIZATION + +{ // Begin block : Scope of qV (if not maintained) + +#ifndef COMPUTE_V_AS_QUATERNION + ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sqvs;) ENABLE_SSE_IMPLEMENTATION(__m128 Vqvs;) ENABLE_AVX_IMPLEMENTATION(__m256 Vqvs;) + ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sqvvx;) ENABLE_SSE_IMPLEMENTATION(__m128 Vqvvx;) ENABLE_AVX_IMPLEMENTATION(__m256 Vqvvx;) + ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sqvvy;) ENABLE_SSE_IMPLEMENTATION(__m128 Vqvvy;) ENABLE_AVX_IMPLEMENTATION(__m256 Vqvvy;) + ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sqvvz;) ENABLE_SSE_IMPLEMENTATION(__m128 Vqvvz;) ENABLE_AVX_IMPLEMENTATION(__m256 Vqvvz;) +#endif + +{ // Begin block : Symmetric eigenanalysis + + ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Ss11;) ENABLE_SSE_IMPLEMENTATION(__m128 Vs11;) ENABLE_AVX_IMPLEMENTATION(__m256 Vs11;) + ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Ss21;) ENABLE_SSE_IMPLEMENTATION(__m128 Vs21;) ENABLE_AVX_IMPLEMENTATION(__m256 Vs21;) + ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Ss31;) ENABLE_SSE_IMPLEMENTATION(__m128 Vs31;) ENABLE_AVX_IMPLEMENTATION(__m256 Vs31;) + ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Ss22;) ENABLE_SSE_IMPLEMENTATION(__m128 Vs22;) ENABLE_AVX_IMPLEMENTATION(__m256 Vs22;) + ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Ss32;) ENABLE_SSE_IMPLEMENTATION(__m128 Vs32;) ENABLE_AVX_IMPLEMENTATION(__m256 Vs32;) + ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Ss33;) ENABLE_SSE_IMPLEMENTATION(__m128 Vs33;) ENABLE_AVX_IMPLEMENTATION(__m256 Vs33;) + + ENABLE_SCALAR_IMPLEMENTATION(Sqvs.f=1.;) ENABLE_SSE_IMPLEMENTATION(Vqvs=Vone;) ENABLE_AVX_IMPLEMENTATION(Vqvs=Vone;) + ENABLE_SCALAR_IMPLEMENTATION(Sqvvx.f=0.;) ENABLE_SSE_IMPLEMENTATION(Vqvvx=_mm_xor_ps(Vqvvx,Vqvvx);) ENABLE_AVX_IMPLEMENTATION(Vqvvx=_mm256_xor_ps(Vqvvx,Vqvvx);) + ENABLE_SCALAR_IMPLEMENTATION(Sqvvy.f=0.;) ENABLE_SSE_IMPLEMENTATION(Vqvvy=_mm_xor_ps(Vqvvy,Vqvvy);) ENABLE_AVX_IMPLEMENTATION(Vqvvy=_mm256_xor_ps(Vqvvy,Vqvvy);) + ENABLE_SCALAR_IMPLEMENTATION(Sqvvz.f=0.;) ENABLE_SSE_IMPLEMENTATION(Vqvvz=_mm_xor_ps(Vqvvz,Vqvvz);) ENABLE_AVX_IMPLEMENTATION(Vqvvz=_mm256_xor_ps(Vqvvz,Vqvvz);) + + //########################################################### + // Compute normal equations matrix + //########################################################### + + ENABLE_SCALAR_IMPLEMENTATION(Ss11.f=Sa11.f*Sa11.f;) ENABLE_SSE_IMPLEMENTATION(Vs11=_mm_mul_ps(Va11,Va11);) ENABLE_AVX_IMPLEMENTATION(Vs11=_mm256_mul_ps(Va11,Va11);) + ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Sa21.f*Sa21.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Va21,Va21);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Va21,Va21);) + ENABLE_SCALAR_IMPLEMENTATION(Ss11.f=Stmp1.f+Ss11.f;) ENABLE_SSE_IMPLEMENTATION(Vs11=_mm_add_ps(Vtmp1,Vs11);) ENABLE_AVX_IMPLEMENTATION(Vs11=_mm256_add_ps(Vtmp1,Vs11);) + ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Sa31.f*Sa31.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Va31,Va31);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Va31,Va31);) + ENABLE_SCALAR_IMPLEMENTATION(Ss11.f=Stmp1.f+Ss11.f;) ENABLE_SSE_IMPLEMENTATION(Vs11=_mm_add_ps(Vtmp1,Vs11);) ENABLE_AVX_IMPLEMENTATION(Vs11=_mm256_add_ps(Vtmp1,Vs11);) + + ENABLE_SCALAR_IMPLEMENTATION(Ss21.f=Sa12.f*Sa11.f;) ENABLE_SSE_IMPLEMENTATION(Vs21=_mm_mul_ps(Va12,Va11);) ENABLE_AVX_IMPLEMENTATION(Vs21=_mm256_mul_ps(Va12,Va11);) + ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Sa22.f*Sa21.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Va22,Va21);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Va22,Va21);) + ENABLE_SCALAR_IMPLEMENTATION(Ss21.f=Stmp1.f+Ss21.f;) ENABLE_SSE_IMPLEMENTATION(Vs21=_mm_add_ps(Vtmp1,Vs21);) ENABLE_AVX_IMPLEMENTATION(Vs21=_mm256_add_ps(Vtmp1,Vs21);) + ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Sa32.f*Sa31.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Va32,Va31);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Va32,Va31);) + ENABLE_SCALAR_IMPLEMENTATION(Ss21.f=Stmp1.f+Ss21.f;) ENABLE_SSE_IMPLEMENTATION(Vs21=_mm_add_ps(Vtmp1,Vs21);) ENABLE_AVX_IMPLEMENTATION(Vs21=_mm256_add_ps(Vtmp1,Vs21);) + + ENABLE_SCALAR_IMPLEMENTATION(Ss31.f=Sa13.f*Sa11.f;) ENABLE_SSE_IMPLEMENTATION(Vs31=_mm_mul_ps(Va13,Va11);) ENABLE_AVX_IMPLEMENTATION(Vs31=_mm256_mul_ps(Va13,Va11);) + ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Sa23.f*Sa21.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Va23,Va21);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Va23,Va21);) + ENABLE_SCALAR_IMPLEMENTATION(Ss31.f=Stmp1.f+Ss31.f;) ENABLE_SSE_IMPLEMENTATION(Vs31=_mm_add_ps(Vtmp1,Vs31);) ENABLE_AVX_IMPLEMENTATION(Vs31=_mm256_add_ps(Vtmp1,Vs31);) + ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Sa33.f*Sa31.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Va33,Va31);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Va33,Va31);) + ENABLE_SCALAR_IMPLEMENTATION(Ss31.f=Stmp1.f+Ss31.f;) ENABLE_SSE_IMPLEMENTATION(Vs31=_mm_add_ps(Vtmp1,Vs31);) ENABLE_AVX_IMPLEMENTATION(Vs31=_mm256_add_ps(Vtmp1,Vs31);) + + ENABLE_SCALAR_IMPLEMENTATION(Ss22.f=Sa12.f*Sa12.f;) ENABLE_SSE_IMPLEMENTATION(Vs22=_mm_mul_ps(Va12,Va12);) ENABLE_AVX_IMPLEMENTATION(Vs22=_mm256_mul_ps(Va12,Va12);) + ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Sa22.f*Sa22.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Va22,Va22);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Va22,Va22);) + ENABLE_SCALAR_IMPLEMENTATION(Ss22.f=Stmp1.f+Ss22.f;) ENABLE_SSE_IMPLEMENTATION(Vs22=_mm_add_ps(Vtmp1,Vs22);) ENABLE_AVX_IMPLEMENTATION(Vs22=_mm256_add_ps(Vtmp1,Vs22);) + ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Sa32.f*Sa32.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Va32,Va32);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Va32,Va32);) + ENABLE_SCALAR_IMPLEMENTATION(Ss22.f=Stmp1.f+Ss22.f;) ENABLE_SSE_IMPLEMENTATION(Vs22=_mm_add_ps(Vtmp1,Vs22);) ENABLE_AVX_IMPLEMENTATION(Vs22=_mm256_add_ps(Vtmp1,Vs22);) + + ENABLE_SCALAR_IMPLEMENTATION(Ss32.f=Sa13.f*Sa12.f;) ENABLE_SSE_IMPLEMENTATION(Vs32=_mm_mul_ps(Va13,Va12);) ENABLE_AVX_IMPLEMENTATION(Vs32=_mm256_mul_ps(Va13,Va12);) + ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Sa23.f*Sa22.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Va23,Va22);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Va23,Va22);) + ENABLE_SCALAR_IMPLEMENTATION(Ss32.f=Stmp1.f+Ss32.f;) ENABLE_SSE_IMPLEMENTATION(Vs32=_mm_add_ps(Vtmp1,Vs32);) ENABLE_AVX_IMPLEMENTATION(Vs32=_mm256_add_ps(Vtmp1,Vs32);) + ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Sa33.f*Sa32.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Va33,Va32);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Va33,Va32);) + ENABLE_SCALAR_IMPLEMENTATION(Ss32.f=Stmp1.f+Ss32.f;) ENABLE_SSE_IMPLEMENTATION(Vs32=_mm_add_ps(Vtmp1,Vs32);) ENABLE_AVX_IMPLEMENTATION(Vs32=_mm256_add_ps(Vtmp1,Vs32);) + + ENABLE_SCALAR_IMPLEMENTATION(Ss33.f=Sa13.f*Sa13.f;) ENABLE_SSE_IMPLEMENTATION(Vs33=_mm_mul_ps(Va13,Va13);) ENABLE_AVX_IMPLEMENTATION(Vs33=_mm256_mul_ps(Va13,Va13);) + ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Sa23.f*Sa23.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Va23,Va23);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Va23,Va23);) + ENABLE_SCALAR_IMPLEMENTATION(Ss33.f=Stmp1.f+Ss33.f;) ENABLE_SSE_IMPLEMENTATION(Vs33=_mm_add_ps(Vtmp1,Vs33);) ENABLE_AVX_IMPLEMENTATION(Vs33=_mm256_add_ps(Vtmp1,Vs33);) + ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Sa33.f*Sa33.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Va33,Va33);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Va33,Va33);) + ENABLE_SCALAR_IMPLEMENTATION(Ss33.f=Stmp1.f+Ss33.f;) ENABLE_SSE_IMPLEMENTATION(Vs33=_mm_add_ps(Vtmp1,Vs33);) ENABLE_AVX_IMPLEMENTATION(Vs33=_mm256_add_ps(Vtmp1,Vs33);) + + //########################################################### + // Solve symmetric eigenproblem using Jacobi iteration + //########################################################### + + for(int sweep=1;sweep<=4;sweep++){ + + // First Jacobi conjugation + +#define SS11 Ss11 +#define SS21 Ss21 +#define SS31 Ss31 +#define SS22 Ss22 +#define SS32 Ss32 +#define SS33 Ss33 +#define SQVVX Sqvvx +#define SQVVY Sqvvy +#define SQVVZ Sqvvz +#define STMP1 Stmp1 +#define STMP2 Stmp2 +#define STMP3 Stmp3 + +#define VS11 Vs11 +#define VS21 Vs21 +#define VS31 Vs31 +#define VS22 Vs22 +#define VS32 Vs32 +#define VS33 Vs33 +#define VQVVX Vqvvx +#define VQVVY Vqvvy +#define VQVVZ Vqvvz +#define VTMP1 Vtmp1 +#define VTMP2 Vtmp2 +#define VTMP3 Vtmp3 + +#include "Singular_Value_Decomposition_Jacobi_Conjugation_Kernel.hpp" + +#undef SS11 +#undef SS21 +#undef SS31 +#undef SS22 +#undef SS32 +#undef SS33 +#undef SQVVX +#undef SQVVY +#undef SQVVZ +#undef STMP1 +#undef STMP2 +#undef STMP3 + +#undef VS11 +#undef VS21 +#undef VS31 +#undef VS22 +#undef VS32 +#undef VS33 +#undef VQVVX +#undef VQVVY +#undef VQVVZ +#undef VTMP1 +#undef VTMP2 +#undef VTMP3 + + // Second Jacobi conjugation + +#define SS11 Ss22 +#define SS21 Ss32 +#define SS31 Ss21 +#define SS22 Ss33 +#define SS32 Ss31 +#define SS33 Ss11 +#define SQVVX Sqvvy +#define SQVVY Sqvvz +#define SQVVZ Sqvvx +#define STMP1 Stmp2 +#define STMP2 Stmp3 +#define STMP3 Stmp1 + +#define VS11 Vs22 +#define VS21 Vs32 +#define VS31 Vs21 +#define VS22 Vs33 +#define VS32 Vs31 +#define VS33 Vs11 +#define VQVVX Vqvvy +#define VQVVY Vqvvz +#define VQVVZ Vqvvx +#define VTMP1 Vtmp2 +#define VTMP2 Vtmp3 +#define VTMP3 Vtmp1 + +#include "Singular_Value_Decomposition_Jacobi_Conjugation_Kernel.hpp" + +#undef SS11 +#undef SS21 +#undef SS31 +#undef SS22 +#undef SS32 +#undef SS33 +#undef SQVVX +#undef SQVVY +#undef SQVVZ +#undef STMP1 +#undef STMP2 +#undef STMP3 + +#undef VS11 +#undef VS21 +#undef VS31 +#undef VS22 +#undef VS32 +#undef VS33 +#undef VQVVX +#undef VQVVY +#undef VQVVZ +#undef VTMP1 +#undef VTMP2 +#undef VTMP3 + + // Third Jacobi conjugation + +#define SS11 Ss33 +#define SS21 Ss31 +#define SS31 Ss32 +#define SS22 Ss11 +#define SS32 Ss21 +#define SS33 Ss22 +#define SQVVX Sqvvz +#define SQVVY Sqvvx +#define SQVVZ Sqvvy +#define STMP1 Stmp3 +#define STMP2 Stmp1 +#define STMP3 Stmp2 + +#define VS11 Vs33 +#define VS21 Vs31 +#define VS31 Vs32 +#define VS22 Vs11 +#define VS32 Vs21 +#define VS33 Vs22 +#define VQVVX Vqvvz +#define VQVVY Vqvvx +#define VQVVZ Vqvvy +#define VTMP1 Vtmp3 +#define VTMP2 Vtmp1 +#define VTMP3 Vtmp2 + +#include "Singular_Value_Decomposition_Jacobi_Conjugation_Kernel.hpp" + +#undef SS11 +#undef SS21 +#undef SS31 +#undef SS22 +#undef SS32 +#undef SS33 +#undef SQVVX +#undef SQVVY +#undef SQVVZ +#undef STMP1 +#undef STMP2 +#undef STMP3 + +#undef VS11 +#undef VS21 +#undef VS31 +#undef VS22 +#undef VS32 +#undef VS33 +#undef VQVVX +#undef VQVVY +#undef VQVVZ +#undef VTMP1 +#undef VTMP2 +#undef VTMP3 + } + +#ifdef PRINT_DEBUGGING_OUTPUT +#ifdef USE_SCALAR_IMPLEMENTATION + std::cout<<"Scalar S ="< +#include +#endif + +// Prevent warnings +#ifdef ENABLE_SCALAR_IMPLEMENTATION +# undef ENABLE_SCALAR_IMPLEMENTATION +#endif +#ifdef ENABLE_SSE_IMPLEMENTATION +# undef ENABLE_SSE_IMPLEMENTATION +#endif +#ifdef ENABLE_AVX_IMPLEMENTATION +# undef ENABLE_AVX_IMPLEMENTATION +#endif + +#ifdef USE_SCALAR_IMPLEMENTATION +#define ENABLE_SCALAR_IMPLEMENTATION(X) X +#else +#define ENABLE_SCALAR_IMPLEMENTATION(X) +#endif + +#ifdef USE_SSE_IMPLEMENTATION +#define ENABLE_SSE_IMPLEMENTATION(X) X +#else +#define ENABLE_SSE_IMPLEMENTATION(X) +#endif + +#ifdef USE_AVX_IMPLEMENTATION +#include +#define ENABLE_AVX_IMPLEMENTATION(X) X +#else +// Stefan: removed include. Why does it import MMX instructions, shouldn't this be under the #ifdef USE_SSE_IMPLEMENTATION above? +//#include +#define ENABLE_AVX_IMPLEMENTATION(X) +#endif + +#ifdef USE_SCALAR_IMPLEMENTATION +// Alec: Why is this using sse intrinsics if it's supposed to be the scalar +// implementation? +#ifdef __SSE__ +#include +// Changed to inline +inline float rsqrt(const float f) +{ + float buf[4]; + buf[0]=f; + __m128 v=_mm_loadu_ps(buf); + v=_mm_rsqrt_ss(v); + _mm_storeu_ps(buf,v); + return buf[0]; +} +#else +#include +inline float rsqrt(const float f) +{ + return 1./sqrtf(f); +} +#endif +#endif + + diff --git a/src/external/libigl-2.3.0/include/igl/SolverStatus.h b/src/external/libigl-2.3.0/include/igl/SolverStatus.h new file mode 100644 index 000000000..d9151f5c0 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/SolverStatus.h @@ -0,0 +1,23 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_SOLVER_STATUS_H +#define IGL_SOLVER_STATUS_H +namespace igl +{ + enum SolverStatus + { + // Good + SOLVER_STATUS_CONVERGED = 0, + // OK + SOLVER_STATUS_MAX_ITER = 1, + // Bad + SOLVER_STATUS_ERROR = 2, + NUM_SOLVER_STATUSES = 3, + }; +}; +#endif diff --git a/src/external/libigl-2.3.0/include/igl/SortableRow.h b/src/external/libigl-2.3.0/include/igl/SortableRow.h new file mode 100644 index 000000000..2a6d8c3e8 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/SortableRow.h @@ -0,0 +1,66 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_SORTABLE_ROW_H +#define IGL_SORTABLE_ROW_H + +// Simple class to contain a rowvector which allows rowwise sorting and +// reordering +#include + +namespace igl +{ + // Templates: + // T should be a matrix that implements .size(), and operator(int i) + template + class SortableRow + { + public: + T data; + public: + SortableRow():data(){}; + SortableRow(const T & data):data(data){}; + bool operator<(const SortableRow & that) const + { + // Lexicographical + int minc = (this->data.size() < that.data.size()? + this->data.size() : that.data.size()); + // loop over columns + for(int i = 0;idata(i) == that.data(i)) + { + continue; + } + return this->data(i) < that.data(i); + } + // All characters the same, comes done to length + return this->data.size()data.size() != that.data.size()) + { + return false; + } + for(int i = 0;idata.size();i++) + { + if(this->data(i) != that.data(i)) + { + return false; + } + } + return true; + }; + bool operator!=(const SortableRow & that) const + { + return !(*this == that); + }; + }; +} + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/Timer.h b/src/external/libigl-2.3.0/include/igl/Timer.h new file mode 100644 index 000000000..ac9e55e6b --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/Timer.h @@ -0,0 +1,179 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +// High Resolution Timer. +// +// Resolution on Mac (clock tick) +// Resolution on Linux (1 us not tested) +// Resolution on Windows (clock tick not tested) + +#ifndef IGL_TIMER_H +#define IGL_TIMER_H + +#ifdef WIN32 // Windows system specific +#include +#elif __APPLE__ // Unix based system specific +#include // for mach_absolute_time +#else +#include +#endif +#include + +namespace igl +{ + class Timer + { + public: + // default constructor + Timer(): + stopped(0), +#ifdef WIN32 + frequency(), + startCount(), + endCount() +#elif __APPLE__ + startCount(0), + endCount(0) +#else + startCount(), + endCount() +#endif + { +#ifdef WIN32 + QueryPerformanceFrequency(&frequency); + startCount.QuadPart = 0; + endCount.QuadPart = 0; +#elif __APPLE__ + startCount = 0; + endCount = 0; +#else + startCount.tv_sec = startCount.tv_usec = 0; + endCount.tv_sec = endCount.tv_usec = 0; +#endif + + stopped = 0; + } + // default destructor + ~Timer() + { + + } + +#ifdef __APPLE__ + //Raw mach_absolute_times going in, difference in seconds out + double subtractTimes( uint64_t endTime, uint64_t startTime ) + { + uint64_t difference = endTime - startTime; + static double conversion = 0.0; + + if( conversion == 0.0 ) + { + mach_timebase_info_data_t info; + kern_return_t err = mach_timebase_info( &info ); + + //Convert the timebase into seconds + if( err == 0 ) + conversion = 1e-9 * (double) info.numer / (double) info.denom; + } + + return conversion * (double) difference; + } +#endif + + // start timer + void start() + { + stopped = 0; // reset stop flag +#ifdef WIN32 + QueryPerformanceCounter(&startCount); +#elif __APPLE__ + startCount = mach_absolute_time(); +#else + gettimeofday(&startCount, NULL); +#endif + + } + + // stop the timer + void stop() + { + stopped = 1; // set timer stopped flag + +#ifdef WIN32 + QueryPerformanceCounter(&endCount); +#elif __APPLE__ + endCount = mach_absolute_time(); +#else + gettimeofday(&endCount, NULL); +#endif + + } + // get elapsed time in second + double getElapsedTime() + { + return this->getElapsedTimeInSec(); + } + // get elapsed time in second (same as getElapsedTime) + double getElapsedTimeInSec() + { + return this->getElapsedTimeInMicroSec() * 0.000001; + } + + // get elapsed time in milli-second + double getElapsedTimeInMilliSec() + { + return this->getElapsedTimeInMicroSec() * 0.001; + } + // get elapsed time in micro-second + double getElapsedTimeInMicroSec() + { + double startTimeInMicroSec = 0; + double endTimeInMicroSec = 0; + +#ifdef WIN32 + if(!stopped) + QueryPerformanceCounter(&endCount); + + startTimeInMicroSec = + startCount.QuadPart * (1000000.0 / frequency.QuadPart); + endTimeInMicroSec = endCount.QuadPart * (1000000.0 / frequency.QuadPart); +#elif __APPLE__ + if (!stopped) + endCount = mach_absolute_time(); + + return subtractTimes(endCount,startCount)/1e-6; +#else + if(!stopped) + gettimeofday(&endCount, NULL); + + startTimeInMicroSec = + (startCount.tv_sec * 1000000.0) + startCount.tv_usec; + endTimeInMicroSec = (endCount.tv_sec * 1000000.0) + endCount.tv_usec; +#endif + + return endTimeInMicroSec - startTimeInMicroSec; + } + + private: + // stop flag + int stopped; +#ifdef WIN32 + // ticks per second + LARGE_INTEGER frequency; + LARGE_INTEGER startCount; + LARGE_INTEGER endCount; +#elif __APPLE__ + uint64_t startCount; + uint64_t endCount; +#else + timeval startCount; + timeval endCount; +#endif + }; +} +#endif // TIMER_H_DEF + diff --git a/src/external/libigl-2.3.0/include/igl/Viewport.h b/src/external/libigl-2.3.0/include/igl/Viewport.h new file mode 100644 index 000000000..717d3f97b --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/Viewport.h @@ -0,0 +1,69 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_VIEWPORT_H +#define IGL_VIEWPORT_H + +namespace igl +{ + // Simple Viewport class for an opengl context. Handles reshaping and mouse. + struct Viewport + { + int x,y,width,height; + // Constructors + Viewport( + const int x=0, + const int y=0, + const int width=0, + const int height=0): + x(x), + y(y), + width(width), + height(height) + { + }; + virtual ~Viewport(){} + void reshape( + const int x, + const int y, + const int width, + const int height) + { + this->x = x; + this->y = y; + this->width = width; + this->height = height; + }; + // Given mouse_x,mouse_y on the entire window return mouse_x, mouse_y in + // this viewport. + // + // Inputs: + // my mouse y-coordinate + // wh window height + // Returns y-coordinate in viewport + int mouse_y(const int my,const int wh) + { + return my - (wh - height - y); + } + // Inputs: + // mx mouse x-coordinate + // Returns x-coordinate in viewport + int mouse_x(const int mx) + { + return mx - x; + } + // Returns whether point (mx,my) is in extend of Viewport + bool inside(const int mx, const int my) const + { + return + mx >= x && my >= y && + mx < x+width && my < y+height; + } + }; +} + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/WindingNumberAABB.h b/src/external/libigl-2.3.0/include/igl/WindingNumberAABB.h new file mode 100644 index 000000000..d7f761ba0 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/WindingNumberAABB.h @@ -0,0 +1,389 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +// # MUTUAL DEPENDENCY ISSUE FOR HEADER ONLY VERSION +// MUST INCLUDE winding_number.h first before guard: +#include "winding_number.h" + +#ifndef IGL_WINDINGNUMBERAABB_H +#define IGL_WINDINGNUMBERAABB_H +#include "WindingNumberTree.h" + +namespace igl +{ + template < + typename Point, + typename DerivedV, + typename DerivedF > + class WindingNumberAABB : public WindingNumberTree + { + protected: + Point min_corner; + Point max_corner; + typename DerivedV::Scalar total_positive_area; + public: + enum SplitMethod + { + CENTER_ON_LONGEST_AXIS = 0, + MEDIAN_ON_LONGEST_AXIS = 1, + NUM_SPLIT_METHODS = 2 + } split_method; + public: + inline WindingNumberAABB(): + total_positive_area(std::numeric_limits::infinity()), + split_method(MEDIAN_ON_LONGEST_AXIS) + {} + inline WindingNumberAABB( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F); + inline WindingNumberAABB( + const WindingNumberTree & parent, + const Eigen::MatrixBase & F); + // Initialize some things + inline void set_mesh( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F); + inline void init(); + inline bool inside(const Point & p) const; + inline virtual void grow(); + // Compute min and max corners + inline void compute_min_max_corners(); + inline typename DerivedV::Scalar max_abs_winding_number(const Point & p) const; + inline typename DerivedV::Scalar max_simple_abs_winding_number(const Point & p) const; + }; +} + +// Implementation + +#include "winding_number.h" + +#include "barycenter.h" +#include "median.h" +#include "doublearea.h" +#include "per_face_normals.h" + +#include +#include +#include + +// Minimum number of faces in a hierarchy element (this is probably dependent +// on speed of machine and compiler optimization) +#ifndef WindingNumberAABB_MIN_F +# define WindingNumberAABB_MIN_F 100 +#endif + +template +inline void igl::WindingNumberAABB::set_mesh( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F) +{ + igl::WindingNumberTree::set_mesh(V,F); + init(); +} + +template +inline void igl::WindingNumberAABB::init() +{ + using namespace Eigen; + assert(max_corner.size() == 3); + assert(min_corner.size() == 3); + compute_min_max_corners(); + Eigen::Matrix dblA; + doublearea(this->getV(),this->getF(),dblA); + total_positive_area = dblA.sum()/2.0; +} + +template +inline igl::WindingNumberAABB::WindingNumberAABB( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F): + WindingNumberTree(V,F), + min_corner(), + max_corner(), + total_positive_area( + std::numeric_limits::infinity()), + split_method(MEDIAN_ON_LONGEST_AXIS) +{ + init(); +} + +template +inline igl::WindingNumberAABB::WindingNumberAABB( + const WindingNumberTree & parent, + const Eigen::MatrixBase & F): + WindingNumberTree(parent,F), + min_corner(), + max_corner(), + total_positive_area( + std::numeric_limits::infinity()), + split_method(MEDIAN_ON_LONGEST_AXIS) +{ + init(); +} + +template +inline void igl::WindingNumberAABB::grow() +{ + using namespace std; + using namespace Eigen; + // Clear anything that already exists + this->delete_children(); + + //cout<<"cap.rows(): "<getcap().rows()<getF().rows()<getF().rows() <= (WindingNumberAABB_MIN_F>0?WindingNumberAABB_MIN_F:0) || + (this->getcap().rows() - 2) >= this->getF().rows()) + { + // Don't grow + return; + } + + // Compute longest direction + int max_d = -1; + typename DerivedV::Scalar max_len = + -numeric_limits::infinity(); + for(int d = 0;d max_len ) + { + max_len = (max_corner[d] - min_corner[d]); + max_d = d; + } + } + // Compute facet barycenters + Eigen::Matrix BC; + barycenter(this->getV(),this->getF(),BC); + + + // Blerg, why is selecting rows so difficult + + typename DerivedV::Scalar split_value; + // Split in longest direction + switch(split_method) + { + case MEDIAN_ON_LONGEST_AXIS: + // Determine median + median(BC.col(max_d),split_value); + break; + default: + assert(false); + case CENTER_ON_LONGEST_AXIS: + split_value = 0.5*(max_corner[max_d] + min_corner[max_d]); + break; + } + //cout<<"c: "<<0.5*(max_corner[max_d] + min_corner[max_d])<<" "<< + // "m: "< id( this->getF().rows()); + for(int i = 0;igetF().rows();i++) + { + if(BC(i,max_d) <= split_value) + { + id[i] = 0; //left + }else + { + id[i] = 1; //right + } + } + + const int lefts = (int) count(id.begin(),id.end(),0); + const int rights = (int) count(id.begin(),id.end(),1); + if(lefts == 0 || rights == 0) + { + // badly balanced base case (could try to recut) + return; + } + assert(lefts+rights == this->getF().rows()); + DerivedF leftF(lefts, this->getF().cols()); + DerivedF rightF(rights,this->getF().cols()); + int left_i = 0; + int right_i = 0; + for(int i = 0;igetF().rows();i++) + { + if(id[i] == 0) + { + leftF.row(left_i++) = this->getF().row(i); + }else if(id[i] == 1) + { + rightF.row(right_i++) = this->getF().row(i); + }else + { + assert(false); + } + } + assert(right_i == rightF.rows()); + assert(left_i == leftF.rows()); + // Finally actually grow children and Recursively grow + WindingNumberAABB * leftWindingNumberAABB = + new WindingNumberAABB(*this,leftF); + leftWindingNumberAABB->grow(); + this->children.push_back(leftWindingNumberAABB); + WindingNumberAABB * rightWindingNumberAABB = + new WindingNumberAABB(*this,rightF); + rightWindingNumberAABB->grow(); + this->children.push_back(rightWindingNumberAABB); +} + +template +inline bool igl::WindingNumberAABB::inside(const Point & p) const +{ + assert(p.size() == max_corner.size()); + assert(p.size() == min_corner.size()); + for(int i = 0;i= max_corner(i)) + // **MUST** be conservative + if( p(i) < min_corner(i) || p(i) > max_corner(i)) + { + return false; + } + } + return true; +} + +template +inline void igl::WindingNumberAABB::compute_min_max_corners() +{ + using namespace std; + // initialize corners + for(int d = 0;d::infinity(); + max_corner[d] = -numeric_limits::infinity(); + } + + this->center = Point(0,0,0); + // Loop over facets + for(int i = 0;igetF().rows();i++) + { + for(int j = 0;jgetF().cols();j++) + { + for(int d = 0;dgetV()(this->getF()(i,j),d) < min_corner[d] ? + this->getV()(this->getF()(i,j),d) : min_corner[d]; + max_corner[d] = + this->getV()(this->getF()(i,j),d) > max_corner[d] ? + this->getV()(this->getF()(i,j),d) : max_corner[d]; + } + // This is biased toward vertices incident on more than one face, but + // perhaps that's good + this->center += this->getV().row(this->getF()(i,j)); + } + } + // Average + this->center.array() /= this->getF().size(); + + //cout<<"min_corner: "<min_corner.transpose()<center.transpose()<max_corner.transpose()<max_corner + this->min_corner)*0.5).transpose()<radius = (max_corner-min_corner).norm()/2.0; +} + +template +inline typename DerivedV::Scalar +igl::WindingNumberAABB::max_abs_winding_number(const Point & p) const +{ + using namespace std; + // Only valid if not inside + if(inside(p)) + { + return numeric_limits::infinity(); + } + // Q: we know the total positive area so what's the most this could project + // to? Remember it could be layered in the same direction. + return numeric_limits::infinity(); +} + +template +inline typename DerivedV::Scalar + igl::WindingNumberAABB::max_simple_abs_winding_number( + const Point & p) const +{ + using namespace std; + using namespace Eigen; + // Only valid if not inside + if(inside(p)) + { + return numeric_limits::infinity(); + } + // Max simple is the same as sum of positive winding number contributions of + // bounding box + + // begin precomputation + //MatrixXd BV((int)pow(2,3),3); + typedef + Eigen::Matrix + MatrixXS; + typedef + Eigen::Matrix + MatrixXF; + MatrixXS BV((int)(1<<3),3); + BV << + min_corner[0],min_corner[1],min_corner[2], + min_corner[0],min_corner[1],max_corner[2], + min_corner[0],max_corner[1],min_corner[2], + min_corner[0],max_corner[1],max_corner[2], + max_corner[0],min_corner[1],min_corner[2], + max_corner[0],min_corner[1],max_corner[2], + max_corner[0],max_corner[1],min_corner[2], + max_corner[0],max_corner[1],max_corner[2]; + MatrixXF BF(2*2*3,3); + BF << + 0,6,4, + 0,2,6, + 0,3,2, + 0,1,3, + 2,7,6, + 2,3,7, + 4,6,7, + 4,7,5, + 0,4,5, + 0,5,1, + 1,5,7, + 1,7,3; + MatrixXS BFN; + per_face_normals(BV,BF,BFN); + // end of precomputation + + // Only keep those with positive dot products + MatrixXF PBF(BF.rows(),BF.cols()); + int pbfi = 0; + Point p2c = 0.5*(min_corner+max_corner)-p; + for(int i = 0;i 0) + { + PBF.row(pbfi++) = BF.row(i); + } + } + PBF.conservativeResize(pbfi,PBF.cols()); + return igl::winding_number(BV,PBF,p); +} + +// This is a bullshit template because AABB annoyingly needs templates for bad +// combinations of 3D V with DIM=2 AABB +// +// _Define_ as a no-op rather than monkeying around with the proper code above +namespace igl +{ + template <> inline igl::WindingNumberAABB,Eigen::Matrix,Eigen::Matrix>::WindingNumberAABB(const Eigen::MatrixBase> & V, const Eigen::MatrixBase> & F){}; + template <> inline void igl::WindingNumberAABB,Eigen::Matrix,Eigen::Matrix>::grow(){}; + template <> inline void igl::WindingNumberAABB,Eigen::Matrix,Eigen::Matrix>::init(){}; + +} + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/WindingNumberMethod.h b/src/external/libigl-2.3.0/include/igl/WindingNumberMethod.h new file mode 100644 index 000000000..3bb9062b1 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/WindingNumberMethod.h @@ -0,0 +1,23 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_WINDINGNUMBERMETHOD_H +#define IGL_WINDINGNUMBERMETHOD_H +namespace igl +{ + // EXACT_WINDING_NUMBER_METHOD exact hierarchical evaluation + // APPROX_SIMPLE_WINDING_NUMBER_METHOD poor approximation + // APPROX_CACHE_WINDING_NUMBER_METHOD another poor approximation + enum WindingNumberMethod + { + EXACT_WINDING_NUMBER_METHOD = 0, + APPROX_SIMPLE_WINDING_NUMBER_METHOD = 1, + APPROX_CACHE_WINDING_NUMBER_METHOD = 2, + NUM_WINDING_NUMBER_METHODS = 3 + }; +} +#endif diff --git a/src/external/libigl-2.3.0/include/igl/WindingNumberTree.h b/src/external/libigl-2.3.0/include/igl/WindingNumberTree.h new file mode 100644 index 000000000..91d084e6c --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/WindingNumberTree.h @@ -0,0 +1,501 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_WINDINGNUMBERTREE_H +#define IGL_WINDINGNUMBERTREE_H +#include +#include +#include +#include "WindingNumberMethod.h" + +namespace igl +{ + // Space partitioning tree for computing winding number hierarchically. + // + // Templates: + // Point type for points in space, e.g. Eigen::Vector3d + template < + typename Point, + typename DerivedV, + typename DerivedF > + class WindingNumberTree + { + public: + // Method to use (see enum above) + //static double min_max_w; + static std::map< + std::pair, + typename DerivedV::Scalar> + cached; + // This is only need to fill in references, it should never actually be touched + // and shouldn't cause race conditions. (This is a hack, but I think it's "safe") + static DerivedV dummyV; + protected: + WindingNumberMethod method; + const WindingNumberTree * parent; + std::list children; + typedef + Eigen::Matrix + MatrixXS; + typedef + Eigen::Matrix + MatrixXF; + //// List of boundary edges (recall edges are vertices in 2d) + //const Eigen::MatrixXi boundary; + // Base mesh vertices + DerivedV & V; + // Base mesh vertices with duplicates removed + MatrixXS SV; + // Facets in this bounding volume + MatrixXF F; + // Tessellated boundary curve + MatrixXF cap; + // Upper Bound on radius of enclosing ball + typename DerivedV::Scalar radius; + // (Approximate) center (of mass) + Point center; + public: + inline WindingNumberTree(); + // For root + inline WindingNumberTree( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F); + // For chilluns + inline WindingNumberTree( + const WindingNumberTree & parent, + const Eigen::MatrixBase & F); + inline virtual ~WindingNumberTree(); + inline void delete_children(); + inline virtual void set_mesh( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F); + // Set method + inline void set_method( const WindingNumberMethod & m); + public: + inline const DerivedV & getV() const; + inline const MatrixXF & getF() const; + inline const MatrixXF & getcap() const; + // Grow the Tree recursively + inline virtual void grow(); + // Determine whether a given point is inside the bounding + // + // Inputs: + // p query point + // Returns true if the point p is inside this bounding volume + inline virtual bool inside(const Point & p) const; + // Compute the (partial) winding number of a given point p + // According to method + // + // Inputs: + // p query point + // Returns winding number + inline typename DerivedV::Scalar winding_number(const Point & p) const; + // Same as above, but always computes winding number using exact method + // (sum over every facet) + inline typename DerivedV::Scalar winding_number_all(const Point & p) const; + // Same as above, but always computes using sum over tessllated boundary + inline typename DerivedV::Scalar winding_number_boundary(const Point & p) const; + //// Same as winding_number above, but if max_simple_abs_winding_number is + //// less than some threshold min_max_w just return 0 (colloquially the "fast + //// multipole method) + //// + //// + //// Inputs: + //// p query point + //// min_max_w minimum max simple w to be processed + //// Returns approximate winding number + //double winding_number_approx_simple( + // const Point & p, + // const double min_max_w); + // Print contents of Tree + // + // Optional input: + // tab tab to show depth + inline void print(const char * tab=""); + // Determine max absolute winding number + // + // Inputs: + // p query point + // Returns max winding number of + inline virtual typename DerivedV::Scalar max_abs_winding_number(const Point & p) const; + // Same as above, but stronger assumptions on (V,F). Assumes (V,F) is a + // simple polyhedron + inline virtual typename DerivedV::Scalar max_simple_abs_winding_number(const Point & p) const; + // Compute or read cached winding number for point p with respect to mesh + // in bounding box, recursing according to approximation criteria + // + // Inputs: + // p query point + // that WindingNumberTree containing mesh w.r.t. which we're computing w.n. + // Returns cached winding number + inline virtual typename DerivedV::Scalar cached_winding_number(const WindingNumberTree & that, const Point & p) const; + }; +} + +// Implementation + +#include "WindingNumberTree.h" +#include "winding_number.h" +#include "triangle_fan.h" +#include "exterior_edges.h" + +#include +#include + +#include +#include + +//template +//WindingNumberMethod WindingNumberTree::method = EXACT_WINDING_NUMBER_METHOD; +//template +//double WindingNumberTree::min_max_w = 0; +template +std::map< std::pair*,const igl::WindingNumberTree*>, typename DerivedV::Scalar> + igl::WindingNumberTree::cached; + +template +inline igl::WindingNumberTree::WindingNumberTree(): + method(EXACT_WINDING_NUMBER_METHOD), + parent(NULL), + V(dummyV), + SV(), + F(), + cap(), + radius(std::numeric_limits::infinity()), + center(0,0,0) +{ +} + +template +inline igl::WindingNumberTree::WindingNumberTree( + const Eigen::MatrixBase & _V, + const Eigen::MatrixBase & _F): + method(EXACT_WINDING_NUMBER_METHOD), + parent(NULL), + V(dummyV), + SV(), + F(), + cap(), + radius(std::numeric_limits::infinity()), + center(0,0,0) +{ + set_mesh(_V,_F); +} + +template +inline void igl::WindingNumberTree::set_mesh( + const Eigen::MatrixBase & _V, + const Eigen::MatrixBase & _F) +{ + using namespace std; + // Remove any exactly duplicate vertices + // Q: Can this ever increase the complexity of the boundary? + // Q: Would we gain even more by remove almost exactly duplicate vertices? + MatrixXF SF,SVI,SVJ; + igl::remove_duplicate_vertices(_V,_F,0.0,SV,SVI,SVJ,F); + triangle_fan(igl::exterior_edges(F),cap); + V = SV; +} + +template +inline igl::WindingNumberTree::WindingNumberTree( + const igl::WindingNumberTree & parent, + const Eigen::MatrixBase & _F): + method(parent.method), + parent(&parent), + V(parent.V), + SV(), + F(_F), + cap(triangle_fan(igl::exterior_edges(_F))) +{ +} + +template +inline igl::WindingNumberTree::~WindingNumberTree() +{ + delete_children(); +} + +template +inline void igl::WindingNumberTree::delete_children() +{ + using namespace std; + // Delete children + typename list* >::iterator cit = children.begin(); + while(cit != children.end()) + { + // clear the memory of this item + delete (* cit); + // erase from list, returns next element in iterator + cit = children.erase(cit); + } +} + +template +inline void igl::WindingNumberTree::set_method(const WindingNumberMethod & m) +{ + this->method = m; + for(auto child : children) + { + child->set_method(m); + } +} + +template +inline const DerivedV & igl::WindingNumberTree::getV() const +{ + return V; +} + +template +inline const typename igl::WindingNumberTree::MatrixXF& + igl::WindingNumberTree::getF() const +{ + return F; +} + +template +inline const typename igl::WindingNumberTree::MatrixXF& + igl::WindingNumberTree::getcap() const +{ + return cap; +} + +template +inline void igl::WindingNumberTree::grow() +{ + // Don't grow + return; +} + +template +inline bool igl::WindingNumberTree::inside(const Point & /*p*/) const +{ + return true; +} + +template +inline typename DerivedV::Scalar +igl::WindingNumberTree::winding_number(const Point & p) const +{ + using namespace std; + //cout<<"+"<0) + { + // Recurse on each child and accumulate + typename DerivedV::Scalar sum = 0; + for( + typename list* >::const_iterator cit = children.begin(); + cit != children.end(); + cit++) + { + switch(method) + { + case EXACT_WINDING_NUMBER_METHOD: + sum += (*cit)->winding_number(p); + break; + case APPROX_SIMPLE_WINDING_NUMBER_METHOD: + case APPROX_CACHE_WINDING_NUMBER_METHOD: + //if((*cit)->max_simple_abs_winding_number(p) > min_max_w) + //{ + sum += (*cit)->winding_number(p); + //} + break; + default: + assert(false); + break; + } + } + return sum; + }else + { + return winding_number_all(p); + } + }else{ + // Otherwise we can just consider boundary + // Q: If we using the "multipole" method should we also subdivide the + // boundary case? + if((cap.rows() - 2) < F.rows()) + { + switch(method) + { + case EXACT_WINDING_NUMBER_METHOD: + return winding_number_boundary(p); + case APPROX_SIMPLE_WINDING_NUMBER_METHOD: + { + typename DerivedV::Scalar dist = (p-center).norm(); + // Radius is already an overestimate of inside + if(dist>1.0*radius) + { + return 0; + }else + { + return winding_number_boundary(p); + } + } + case APPROX_CACHE_WINDING_NUMBER_METHOD: + { + return parent->cached_winding_number(*this,p); + } + default: assert(false);break; + } + }else + { + // doesn't pay off to use boundary + return winding_number_all(p); + } + } + return 0; +} + +template +inline typename DerivedV::Scalar + igl::WindingNumberTree::winding_number_all(const Point & p) const +{ + return igl::winding_number(V,F,p); +} + +template +inline typename DerivedV::Scalar +igl::WindingNumberTree::winding_number_boundary(const Point & p) const +{ + using namespace Eigen; + using namespace std; + return igl::winding_number(V,cap,p); +} + +//template +//inline double igl::WindingNumberTree::winding_number_approx_simple( +// const Point & p, +// const double min_max_w) +//{ +// using namespace std; +// if(max_simple_abs_winding_number(p) > min_max_w) +// { +// return winding_number(p); +// }else +// { +// cout<<"Skipped! "< +inline void igl::WindingNumberTree::print(const char * tab) +{ + using namespace std; + // Print all facets + cout<* >::iterator cit = children.begin(); + cit != children.end(); + cit++) + { + cout<<","<print((string(tab)+"").c_str()); + } +} + +template +inline typename DerivedV::Scalar +igl::WindingNumberTree::max_abs_winding_number(const Point & /*p*/) const +{ + return std::numeric_limits::infinity(); +} + +template +inline typename DerivedV::Scalar +igl::WindingNumberTree::max_simple_abs_winding_number( + const Point & /*p*/) const +{ + using namespace std; + return numeric_limits::infinity(); +} + +template +inline typename DerivedV::Scalar +igl::WindingNumberTree::cached_winding_number( + const igl::WindingNumberTree & that, + const Point & p) const +{ + using namespace std; + // Simple metric for `is_far` + // + // this that + // -------- + // ----- / | \ . + // / r \ / R \ . + // | p ! | | ! | + // \_____/ \ / + // \________/ + // + // + // a = angle formed by trapazoid formed by raising sides with lengths r and R + // at respective centers. + // + // a = atan2(R-r,d), where d is the distance between centers + + // That should be bigger (what about parent? what about sister?) + bool is_far = this->radiusradius, + (that.center - this->center).norm()); + assert(a>0); + is_far = (a this_that(this,&that); + // Need to compute it for first time? + if(cached.count(this_that)==0) + { + cached[this_that] = + that.winding_number_boundary(this->center); + } + return cached[this_that]; + }else if(children.size() == 0) + { + // not far and hierarchy ended too soon: can't use cache + return that.winding_number_boundary(p); + }else + { + for( + typename list* >::const_iterator cit = children.begin(); + cit != children.end(); + cit++) + { + if((*cit)->inside(p)) + { + return (*cit)->cached_winding_number(that,p); + } + } + // Not inside any children? This can totally happen because bounding boxes + // are set to bound contained facets. So sibilings may overlap and their + // union may not contain their parent (though, their union is certainly a + // subset of their parent). + assert(false); + } + return 0; +} + +// Explicit instantiation of static variable +template < + typename Point, + typename DerivedV, + typename DerivedF > +DerivedV igl::WindingNumberTree::dummyV; + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/ZERO.h b/src/external/libigl-2.3.0/include/igl/ZERO.h new file mode 100644 index 000000000..bd2829905 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/ZERO.h @@ -0,0 +1,21 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_ZERO_H +#define IGL_ZERO_H +namespace igl +{ + // Often one needs a reference to a dummy variable containing zero as its + // value, for example when using AntTweakBar's + // TwSetParam( "3D View", "opened", TW_PARAM_INT32, 1, &INT_ZERO); + const char CHAR_ZERO = 0; + const int INT_ZERO = 0; + const unsigned int UNSIGNED_INT_ZERO = 0; + const double DOUBLE_ZERO = 0; + const float FLOAT_ZERO = 0; +} +#endif diff --git a/src/external/libigl-2.3.0/include/igl/accumarray.cpp b/src/external/libigl-2.3.0/include/igl/accumarray.cpp new file mode 100644 index 000000000..28d42cc71 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/accumarray.cpp @@ -0,0 +1,52 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2018 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "accumarray.h" +#include + +template < + typename DerivedS, + typename DerivedV, + typename DerivedA + > +void igl::accumarray( + const Eigen::MatrixBase & S, + const Eigen::MatrixBase & V, + Eigen::PlainObjectBase & A) +{ + assert(V.size() == S.size() && "S and V should be same size"); + if(S.size() == 0) { A.resize(0,1); return; } + A.setZero(S.maxCoeff()+1,1); + for(int s = 0;s +void igl::accumarray( + const Eigen::MatrixBase & S, + const typename DerivedA::Scalar V, + Eigen::PlainObjectBase & A) +{ + if(S.size() == 0) { A.resize(0,1); return; } + A.setZero(S.maxCoeff()+1,1); + for(int s = 0;s, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::Matrix::Scalar, Eigen::PlainObjectBase >&); +template void igl::accumarray, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/accumarray.h b/src/external/libigl-2.3.0/include/igl/accumarray.h new file mode 100644 index 000000000..1afbddb76 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/accumarray.h @@ -0,0 +1,50 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2018 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef ACCUMARRY_H +#define ACCUMARRY_H +#include "igl_inline.h" +#include +namespace igl +{ + // ACCUMARRY Like Matlab's accumarray. Accumulate values in V using subscripts + // in S. + // + // Inputs: + // S #S list of subscripts + // V #V list of values + // Outputs: + // A max(subs)+1 list of accumulated values + template < + typename DerivedS, + typename DerivedV, + typename DerivedA + > + void accumarray( + const Eigen::MatrixBase & S, + const Eigen::MatrixBase & V, + Eigen::PlainObjectBase & A); + // Inputs: + // S #S list of subscripts + // V single value used for all + // Outputs: + // A max(subs)+1 list of accumulated values + template < + typename DerivedS, + typename DerivedA + > + void accumarray( + const Eigen::MatrixBase & S, + const typename DerivedA::Scalar V, + Eigen::PlainObjectBase & A); +} + +#ifndef IGL_STATIC_LIBRARY +# include "accumarray.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/active_set.cpp b/src/external/libigl-2.3.0/include/igl/active_set.cpp new file mode 100644 index 000000000..b7112e8b1 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/active_set.cpp @@ -0,0 +1,370 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "active_set.h" +#include "min_quad_with_fixed.h" +#include "slice.h" +#include "slice_into.h" +#include "cat.h" +//#include "matlab_format.h" + +#include +#include +#include + +template < + typename AT, + typename DerivedB, + typename Derivedknown, + typename DerivedY, + typename AeqT, + typename DerivedBeq, + typename AieqT, + typename DerivedBieq, + typename Derivedlx, + typename Derivedux, + typename DerivedZ + > +IGL_INLINE igl::SolverStatus igl::active_set( + const Eigen::SparseMatrix& A, + const Eigen::PlainObjectBase & B, + const Eigen::PlainObjectBase & known, + const Eigen::PlainObjectBase & Y, + const Eigen::SparseMatrix& Aeq, + const Eigen::PlainObjectBase & Beq, + const Eigen::SparseMatrix& Aieq, + const Eigen::PlainObjectBase & Bieq, + const Eigen::PlainObjectBase & p_lx, + const Eigen::PlainObjectBase & p_ux, + const igl::active_set_params & params, + Eigen::PlainObjectBase & Z + ) +{ +//#define ACTIVE_SET_CPP_DEBUG +#if defined(ACTIVE_SET_CPP_DEBUG) && !defined(_MSC_VER) +# warning "ACTIVE_SET_CPP_DEBUG" +#endif + using namespace Eigen; + using namespace std; + SolverStatus ret = SOLVER_STATUS_ERROR; + const int n = A.rows(); + assert(n == A.cols() && "A must be square"); + // Discard const qualifiers + //if(B.size() == 0) + //{ + // B = DerivedB::Zero(n,1); + //} + assert(n == B.rows() && "B.rows() must match A.rows()"); + assert(B.cols() == 1 && "B must be a column vector"); + assert(Y.cols() == 1 && "Y must be a column vector"); + assert((Aeq.size() == 0 && Beq.size() == 0) || Aeq.cols() == n); + assert((Aeq.size() == 0 && Beq.size() == 0) || Aeq.rows() == Beq.rows()); + assert((Aeq.size() == 0 && Beq.size() == 0) || Beq.cols() == 1); + assert((Aieq.size() == 0 && Bieq.size() == 0) || Aieq.cols() == n); + assert((Aieq.size() == 0 && Bieq.size() == 0) || Aieq.rows() == Bieq.rows()); + assert((Aieq.size() == 0 && Bieq.size() == 0) || Bieq.cols() == 1); + Eigen::Matrix lx; + Eigen::Matrix ux; + if(p_lx.size() == 0) + { + lx = Derivedlx::Constant( + n,1,-numeric_limits::max()); + }else + { + lx = p_lx; + } + if(p_ux.size() == 0) + { + ux = Derivedux::Constant( + n,1,numeric_limits::max()); + }else + { + ux = p_ux; + } + assert(lx.rows() == n && "lx must have n rows"); + assert(ux.rows() == n && "ux must have n rows"); + assert(ux.cols() == 1 && "lx must be a column vector"); + assert(lx.cols() == 1 && "ux must be a column vector"); + assert((ux.array()-lx.array()).minCoeff() > 0 && "ux(i) must be > lx(i)"); + if(Z.size() != 0) + { + // Initial guess should have correct size + assert(Z.rows() == n && "Z must have n rows"); + assert(Z.cols() == 1 && "Z must be a column vector"); + } + assert(known.cols() == 1 && "known must be a column vector"); + // Number of knowns + const int nk = known.size(); + + // Initialize active sets + typedef int BOOL; +#define TRUE 1 +#define FALSE 0 + Matrix as_lx = Matrix::Constant(n,1,FALSE); + Matrix as_ux = Matrix::Constant(n,1,FALSE); + Matrix as_ieq = Matrix::Constant(Aieq.rows(),1,FALSE); + + // Keep track of previous Z for comparison + DerivedZ old_Z; + old_Z = DerivedZ::Constant( + n,1,numeric_limits::max()); + + int iter = 0; + while(true) + { +#ifdef ACTIVE_SET_CPP_DEBUG + cout<<"Iteration: "< 0) + { + for(int z = 0;z < n;z++) + { + if(Z(z) < lx(z)) + { + new_as_lx += (as_lx(z)?0:1); + //new_as_lx++; + as_lx(z) = TRUE; + } + if(Z(z) > ux(z)) + { + new_as_ux += (as_ux(z)?0:1); + //new_as_ux++; + as_ux(z) = TRUE; + } + } + if(Aieq.rows() > 0) + { + DerivedZ AieqZ; + AieqZ = Aieq*Z; + for(int a = 0;a Bieq(a)) + { + new_as_ieq += (as_ieq(a)?0:1); + as_ieq(a) = TRUE; + } + } + } +#ifdef ACTIVE_SET_CPP_DEBUG + cout<<" new_as_lx: "< as_ieq_list(as_ieq_count,1); + // Gather active constraints and resp. rhss + DerivedBeq Beq_i; + Beq_i.resize(Beq.rows()+as_ieq_count,1); + Beq_i.head(Beq.rows()) = Beq; + { + int k =0; + for(int a=0;a Aeq_i,Aieq_i; + slice(Aieq,as_ieq_list,1,Aieq_i); + // Append to equality constraints + cat(1,Aeq,Aieq_i,Aeq_i); + + + min_quad_with_fixed_data data; +#ifndef NDEBUG + { + // NO DUPES! + Matrix fixed = Matrix::Constant(n,1,FALSE); + for(int k = 0;k 0 && Aeq_i.rows() > Aeq.rows()) + { + cerr<<" *Are you sure rows of [Aeq;Aieq] are linearly independent?*"<< + endl; + } + ret = SOLVER_STATUS_ERROR; + break; + } +#ifdef ACTIVE_SET_CPP_DEBUG + cout<<" min_quad_with_fixed_solve"< Ak; + // Slow + slice(A,known_i,1,Ak); + DerivedB Bk; + slice(B,known_i,Bk); + MatrixXd Lambda_known_i = -(0.5*Ak*Z + 0.5*Bk); + // reverse the lambda values for lx + Lambda_known_i.block(nk,0,as_lx_count,1) = + (-1*Lambda_known_i.block(nk,0,as_lx_count,1)).eval(); + + // Extract Lagrange multipliers for Aieq_i (always at back of sol) + VectorXd Lambda_Aieq_i(Aieq_i.rows(),1); + for(int l = 0;l0 && iter>=params.max_iter) + { + ret = SOLVER_STATUS_MAX_ITER; + break; + } + + } + + return ret; +} + + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +template igl::SolverStatus igl::active_set, Eigen::Matrix, Eigen::Matrix, double, Eigen::Matrix, double, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::SparseMatrix const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::SparseMatrix const&, Eigen::PlainObjectBase > const&, Eigen::SparseMatrix const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, igl::active_set_params const&, Eigen::PlainObjectBase >&); +template igl::SolverStatus igl::active_set, Eigen::Matrix, Eigen::Matrix, double, Eigen::Matrix, double, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::SparseMatrix const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::SparseMatrix const&, Eigen::PlainObjectBase > const&, Eigen::SparseMatrix const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, igl::active_set_params const&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/active_set.h b/src/external/libigl-2.3.0/include/igl/active_set.h new file mode 100644 index 000000000..9f2676344 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/active_set.h @@ -0,0 +1,111 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_ACTIVE_SET_H +#define IGL_ACTIVE_SET_H + +#include "igl_inline.h" +#include "SolverStatus.h" +#include +#include + +namespace igl +{ + struct active_set_params; + // Known Bugs: rows of [Aeq;Aieq] **must** be linearly independent. Should be + // using QR decomposition otherwise: + // https://v8doc.sas.com/sashtml/ormp/chap5/sect32.htm + // + // ACTIVE_SET Minimize quadratic energy + // + // 0.5*Z'*A*Z + Z'*B + C with constraints + // + // that Z(known) = Y, optionally also subject to the constraints Aeq*Z = Beq, + // and further optionally subject to the linear inequality constraints that + // Aieq*Z <= Bieq and constant inequality constraints lx <= x <= ux + // + // Inputs: + // A n by n matrix of quadratic coefficients + // B n by 1 column of linear coefficients + // known list of indices to known rows in Z + // Y list of fixed values corresponding to known rows in Z + // Aeq meq by n list of linear equality constraint coefficients + // Beq meq by 1 list of linear equality constraint constant values + // Aieq mieq by n list of linear inequality constraint coefficients + // Bieq mieq by 1 list of linear inequality constraint constant values + // lx n by 1 list of lower bounds [] implies -Inf + // ux n by 1 list of upper bounds [] implies Inf + // params struct of additional parameters (see below) + // Z if not empty, is taken to be an n by 1 list of initial guess values + // (see output) + // Outputs: + // Z n by 1 list of solution values + // Returns true on success, false on error + // + // Benchmark: For a harmonic solve on a mesh with 325K facets, matlab 2.2 + // secs, igl/min_quad_with_fixed.h 7.1 secs + // + template < + typename AT, + typename DerivedB, + typename Derivedknown, + typename DerivedY, + typename AeqT, + typename DerivedBeq, + typename AieqT, + typename DerivedBieq, + typename Derivedlx, + typename Derivedux, + typename DerivedZ + > + IGL_INLINE igl::SolverStatus active_set( + const Eigen::SparseMatrix& A, + const Eigen::PlainObjectBase & B, + const Eigen::PlainObjectBase & known, + const Eigen::PlainObjectBase & Y, + const Eigen::SparseMatrix& Aeq, + const Eigen::PlainObjectBase & Beq, + const Eigen::SparseMatrix& Aieq, + const Eigen::PlainObjectBase & Bieq, + const Eigen::PlainObjectBase & lx, + const Eigen::PlainObjectBase & ux, + const igl::active_set_params & params, + Eigen::PlainObjectBase & Z + ); +}; + +#include "EPS.h" +struct igl::active_set_params +{ + // Input parameters for active_set: + // Auu_pd whether Auu is positive definite {false} + // max_iter Maximum number of iterations (0 = Infinity, {100}) + // inactive_threshold Threshold on Lagrange multiplier values to determine + // whether to keep constraints active {EPS} + // constraint_threshold Threshold on whether constraints are violated (0 + // is perfect) {EPS} + // solution_diff_threshold Threshold on the squared norm of the difference + // between two consecutive solutions {EPS} + bool Auu_pd; + int max_iter; + double inactive_threshold; + double constraint_threshold; + double solution_diff_threshold; + active_set_params(): + Auu_pd(false), + max_iter(100), + inactive_threshold(igl::DOUBLE_EPS), + constraint_threshold(igl::DOUBLE_EPS), + solution_diff_threshold(igl::DOUBLE_EPS) + {}; +}; + +#ifndef IGL_STATIC_LIBRARY +# include "active_set.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/adjacency_list.cpp b/src/external/libigl-2.3.0/include/igl/adjacency_list.cpp new file mode 100644 index 000000000..fa6579e3b --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/adjacency_list.cpp @@ -0,0 +1,180 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "adjacency_list.h" + +#include "verbose.h" +#include + +template +IGL_INLINE void igl::adjacency_list( + const Eigen::MatrixBase & F, + std::vector >& A, + bool sorted) +{ + A.clear(); + A.resize(F.maxCoeff()+1); + + // Loop over faces + for(int i = 0;i d + int s = F(i,j); + int d = F(i,(j+1)%F.cols()); + A.at(s).push_back(d); + A.at(d).push_back(s); + } + } + + // Remove duplicates + for(int i=0; i<(int)A.size();++i) + { + std::sort(A[i].begin(), A[i].end()); + A[i].erase(std::unique(A[i].begin(), A[i].end()), A[i].end()); + } + + // If needed, sort every VV + if (sorted) + { + // Loop over faces + + // for every vertex v store a set of ordered edges not incident to v that belongs to triangle incident on v. + std::vector > > SR; + SR.resize(A.size()); + + for(int i = 0;i d + int s = F(i,j); + int d = F(i,(j+1)%F.cols()); + // Get index of opposing vertex v + int v = F(i,(j+2)%F.cols()); + + std::vector e(2); + e[0] = d; + e[1] = v; + SR[s].push_back(e); + } + } + + for(int v=0; v<(int)SR.size();++v) + { + std::vector& vv = A.at(v); + std::vector >& sr = SR[v]; + + std::vector > pn = sr; + + // Compute previous/next for every element in sr + for(int i=0;i<(int)sr.size();++i) + { + int a = sr[i][0]; + int b = sr[i][1]; + + // search for previous + int p = -1; + for(int j=0;j<(int)sr.size();++j) + if(sr[j][1] == a) + p = j; + pn[i][0] = p; + + // search for next + int n = -1; + for(int j=0;j<(int)sr.size();++j) + if(sr[j][0] == b) + n = j; + pn[i][1] = n; + + } + + // assume manifoldness (look for beginning of a single chain) + int c = 0; + for(int j=0; j<=(int)sr.size();++j) + if (pn[c][0] != -1) + c = pn[c][0]; + + if (pn[c][0] == -1) // border case + { + // finally produce the new vv relation + for(int j=0; j<(int)sr.size();++j) + { + vv[j] = sr[c][0]; + if (pn[c][1] != -1) + c = pn[c][1]; + } + vv.back() = sr[c][1]; + } + else + { + // finally produce the new vv relation + for(int j=0; j<(int)sr.size();++j) + { + vv[j] = sr[c][0]; + + c = pn[c][1]; + } + } + } + } +} + +template +IGL_INLINE void igl::adjacency_list( + const std::vector > & F, + std::vector >& A) +{ + A.clear(); + + // Find maxCoeff + Index maxCoeff = 0; + for(const auto &vec : F) + { + for(int coeff : vec) + { + maxCoeff = std::max(coeff, maxCoeff); + } + } + A.resize(maxCoeff + 1); + + // Loop over faces + for(int i = 0;i d + int s = F[i][j]; + int d = F[i][(j+1)%F[i].size()]; + A.at(s).push_back(d); + A.at(d).push_back(s); + } + } + + // Remove duplicates + for(int i=0; i<(int)A.size();++i) + { + std::sort(A[i].begin(), A[i].end()); + A[i].erase(std::unique(A[i].begin(), A[i].end()), A[i].end()); + } + +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::adjacency_list, int>(Eigen::MatrixBase > const&, std::vector >, std::allocator > > >&, bool); +// generated by autoexplicit.sh +template void igl::adjacency_list, int>(Eigen::MatrixBase > const&, std::vector >, std::allocator > > >&, bool); +template void igl::adjacency_list, int>(Eigen::MatrixBase > const&, std::vector >, std::allocator > > >&, bool); +template void igl::adjacency_list, unsigned int>(class Eigen::MatrixBase > const &, class std::vector >, class std::allocator > > > &, bool); +template void igl::adjacency_list(std::vector >, std::allocator > > > const&, std::vector >, std::allocator > > >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/adjacency_list.h b/src/external/libigl-2.3.0/include/igl/adjacency_list.h new file mode 100644 index 000000000..e9040da8b --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/adjacency_list.h @@ -0,0 +1,51 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_ADJACENCY_LIST_H +#define IGL_ADJACENCY_LIST_H +#include "igl_inline.h" + +#include +#include +#include +namespace igl +{ + // Constructs the graph adjacency list of a given mesh (V,F) + // Templates: + // T should be a eigen sparse matrix primitive type like int or double + // Inputs: + // F #F by dim list of mesh faces (must be triangles) + // sorted flag that indicates if the list should be sorted counter-clockwise + // Outputs: + // A vector > containing at row i the adjacent vertices of vertex i + // + // Example: + // // Mesh in (V,F) + // vector > A; + // adjacency_list(F,A); + // + // See also: edges, cotmatrix, diag + template + IGL_INLINE void adjacency_list( + const Eigen::MatrixBase & F, + std::vector >& A, + bool sorted = false); + + // Variant that accepts polygonal faces. + // Each element of F is a set of indices of a polygonal face. + template + IGL_INLINE void adjacency_list( + const std::vector > & F, + std::vector >& A); + +} + +#ifndef IGL_STATIC_LIBRARY +# include "adjacency_list.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/adjacency_matrix.cpp b/src/external/libigl-2.3.0/include/igl/adjacency_matrix.cpp new file mode 100644 index 000000000..3b4fae32b --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/adjacency_matrix.cpp @@ -0,0 +1,125 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "adjacency_matrix.h" + +#include "verbose.h" + +#include + +template +IGL_INLINE void igl::adjacency_matrix( + const Eigen::MatrixBase & F, + Eigen::SparseMatrix& A) +{ + using namespace std; + using namespace Eigen; + typedef typename DerivedF::Scalar Index; + + typedef Triplet IJV; + vector ijv; + ijv.reserve(F.size()*2); + // Loop over **simplex** (i.e., **not quad**) + for(int i = 0;i d + Index s = F(i,j); + Index d = F(i,k); + ijv.push_back(IJV(s,d,1)); + ijv.push_back(IJV(d,s,1)); + } + } + + const Index n = F.maxCoeff()+1; + A.resize(n,n); + switch(F.cols()) + { + case 3: + A.reserve(6*(F.maxCoeff()+1)); + break; + case 4: + A.reserve(26*(F.maxCoeff()+1)); + break; + } + A.setFromTriplets(ijv.begin(),ijv.end()); + + // Force all non-zeros to be one + + // Iterate over outside + for(int k=0; k::InnerIterator it (A,k); it; ++it) + { + assert(it.value() != 0); + A.coeffRef(it.row(),it.col()) = 1; + } + } +} + +template +IGL_INLINE void igl::adjacency_matrix( + const Eigen::MatrixBase & I, + const Eigen::MatrixBase & C, + Eigen::SparseMatrix& A) +{ + using namespace std; + using namespace Eigen; + + typedef Triplet IJV; + vector ijv; + ijv.reserve(C(C.size()-1)*2); + typedef typename DerivedI::Scalar Index; + const Index n = I.maxCoeff()+1; + { + // loop over polygons + for(Index p = 0;p::InnerIterator it (A,k); it; ++it) + { + assert(it.value() != 0); + A.coeffRef(it.row(),it.col()) = 1; + } + } +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +template void igl::adjacency_matrix, Eigen::Matrix, int>(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::SparseMatrix& ); +// generated by autoexplicit.sh +template void igl::adjacency_matrix, bool>(Eigen::MatrixBase > const&, Eigen::SparseMatrix&); +template void igl::adjacency_matrix, double>(Eigen::MatrixBase > const&, Eigen::SparseMatrix&); +template void igl::adjacency_matrix, int>(Eigen::MatrixBase > const&, Eigen::SparseMatrix&); +template void igl::adjacency_matrix, int>(Eigen::MatrixBase > const&, Eigen::SparseMatrix&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/adjacency_matrix.h b/src/external/libigl-2.3.0/include/igl/adjacency_matrix.h new file mode 100644 index 000000000..79aa976e4 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/adjacency_matrix.h @@ -0,0 +1,66 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_ADJACENCY_MATRIX_H +#define IGL_ADJACENCY_MATRIX_H +#include "igl_inline.h" + +#define EIGEN_YES_I_KNOW_SPARSE_MODULE_IS_NOT_STABLE_YET +#include +#include + +namespace igl +{ + // Constructs the graph adjacency matrix of a given mesh (V,F) + // Templates: + // T should be a eigen sparse matrix primitive type like int or double + // Inputs: + // F #F by dim list of mesh simplices + // Outputs: + // A max(F)+1 by max(F)+1 adjacency matrix, each row i corresponding to V(i,:) + // + // Example: + // // Mesh in (V,F) + // Eigen::SparseMatrix A; + // adjacency_matrix(F,A); + // // sum each row + // SparseVector Asum; + // sum(A,1,Asum); + // // Convert row sums into diagonal of sparse matrix + // SparseMatrix Adiag; + // diag(Asum,Adiag); + // // Build uniform laplacian + // SparseMatrix U; + // U = A-Adiag; + // + // See also: edges, cotmatrix, diag + template + IGL_INLINE void adjacency_matrix( + const Eigen::MatrixBase & F, + Eigen::SparseMatrix& A); + // Constructs an vertex adjacency for a polygon mesh. + // + // Inputs: + // I #I vectorized list of polygon corner indices into rows of some matrix V + // C #polygons+1 list of cumulative polygon sizes so that C(i+1)-C(i) = + // size of the ith polygon, and so I(C(i)) through I(C(i+1)-1) are the + // indices of the ith polygon + // Outputs: + // A max(I)+1 by max(I)+1 adjacency matrix, each row i corresponding to V(i,:) + // + template + IGL_INLINE void adjacency_matrix( + const Eigen::MatrixBase & I, + const Eigen::MatrixBase & C, + Eigen::SparseMatrix& A); +} + +#ifndef IGL_STATIC_LIBRARY +# include "adjacency_matrix.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/all.cpp b/src/external/libigl-2.3.0/include/igl/all.cpp new file mode 100644 index 000000000..35245eacb --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/all.cpp @@ -0,0 +1,26 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "all.h" +#include "redux.h" + + +template +IGL_INLINE void igl::all( + const Eigen::SparseMatrix & A, + const int dim, + Eigen::PlainObjectBase& B) +{ + typedef typename DerivedB::Scalar Scalar; + igl::redux(A,dim,[](Scalar a, Scalar b){ return a && b!=0;},B); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +#endif + + diff --git a/src/external/libigl-2.3.0/include/igl/all.h b/src/external/libigl-2.3.0/include/igl/all.h new file mode 100644 index 000000000..6e84fdd52 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/all.h @@ -0,0 +1,36 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_ALL_H +#define IGL_ALL_H +#include "igl_inline.h" +#include +#include +namespace igl +{ + // For Dense matrices use: A.rowwise().all() or A.colwise().all() + // + // Inputs: + // A m by n sparse matrix + // dim dimension along which to check for all (1 or 2) + // Output: + // B n-long vector (if dim == 1) + // or + // B m-long vector (if dim == 2) + // + template + IGL_INLINE void all( + const Eigen::SparseMatrix & A, + const int dim, + Eigen::PlainObjectBase& B); +} +#ifndef IGL_STATIC_LIBRARY +# include "all.cpp" +#endif +#endif + + diff --git a/src/external/libigl-2.3.0/include/igl/all_pairs_distances.cpp b/src/external/libigl-2.3.0/include/igl/all_pairs_distances.cpp new file mode 100644 index 000000000..608cf9b85 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/all_pairs_distances.cpp @@ -0,0 +1,39 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "all_pairs_distances.h" +#include + +template +IGL_INLINE void igl::all_pairs_distances( + const Mat & V, + const Mat & U, + const bool squared, + Mat & D) +{ + // dimension should be the same + assert(V.cols() == U.cols()); + // resize output + D.resize(V.rows(),U.rows()); + for(int i = 0;i >(Eigen::Matrix const&, Eigen::Matrix const&, bool, Eigen::Matrix&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/all_pairs_distances.h b/src/external/libigl-2.3.0/include/igl/all_pairs_distances.h new file mode 100644 index 000000000..9acc1b730 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/all_pairs_distances.h @@ -0,0 +1,41 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_ALL_PAIRS_DISTANCES_H +#define IGL_ALL_PAIRS_DISTANCES_H +#include "igl_inline.h" + +namespace igl +{ + // ALL_PAIRS_DISTANCES compute distances between each point i in V and point j + // in U + // + // D = all_pairs_distances(V,U) + // + // Templates: + // Mat matrix class like MatrixXd + // Inputs: + // V #V by dim list of points + // U #U by dim list of points + // squared whether to return squared distances + // Outputs: + // D #V by #U matrix of distances, where D(i,j) gives the distance or + // squareed distance between V(i,:) and U(j,:) + // + template + IGL_INLINE void all_pairs_distances( + const Mat & V, + const Mat & U, + const bool squared, + Mat & D); +} + +#ifndef IGL_STATIC_LIBRARY +# include "all_pairs_distances.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/ambient_occlusion.cpp b/src/external/libigl-2.3.0/include/igl/ambient_occlusion.cpp new file mode 100644 index 000000000..8b72319e0 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/ambient_occlusion.cpp @@ -0,0 +1,139 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "ambient_occlusion.h" +#include "random_dir.h" +#include "ray_mesh_intersect.h" +#include "EPS.h" +#include "Hit.h" +#include "parallel_for.h" +#include +#include +#include + +template < + typename DerivedP, + typename DerivedN, + typename DerivedS > +IGL_INLINE void igl::ambient_occlusion( + const std::function< + bool( + const Eigen::Vector3f&, + const Eigen::Vector3f&) + > & shoot_ray, + const Eigen::MatrixBase & P, + const Eigen::MatrixBase & N, + const int num_samples, + Eigen::PlainObjectBase & S) +{ + using namespace Eigen; + const int n = P.rows(); + // Resize output + S.resize(n,1); + // Embree seems to be parallel when constructing but not when tracing rays + const MatrixXf D = random_dir_stratified(num_samples).cast(); + + const auto & inner = [&P,&N,&num_samples,&D,&S,&shoot_ray](const int p) + { + const Vector3f origin = P.row(p).template cast(); + const Vector3f normal = N.row(p).template cast(); + int num_hits = 0; + for(int s = 0;s +IGL_INLINE void igl::ambient_occlusion( + const igl::AABB & aabb, + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const Eigen::MatrixBase & P, + const Eigen::MatrixBase & N, + const int num_samples, + Eigen::PlainObjectBase & S) +{ + const auto & shoot_ray = [&aabb,&V,&F]( + const Eigen::Vector3f& _s, + const Eigen::Vector3f& dir)->bool + { + Eigen::Vector3f s = _s+1e-4*dir; + igl::Hit hit; + return aabb.intersect_ray( + V, + F, + s .cast().eval(), + dir.cast().eval(), + hit); + }; + return ambient_occlusion(shoot_ray,P,N,num_samples,S); + +} + +template < + typename DerivedV, + typename DerivedF, + typename DerivedP, + typename DerivedN, + typename DerivedS > +IGL_INLINE void igl::ambient_occlusion( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const Eigen::MatrixBase & P, + const Eigen::MatrixBase & N, + const int num_samples, + Eigen::PlainObjectBase & S) +{ + if(F.rows() < 100) + { + // Super naive + const auto & shoot_ray = [&V,&F]( + const Eigen::Vector3f& _s, + const Eigen::Vector3f& dir)->bool + { + Eigen::Vector3f s = _s+1e-4*dir; + igl::Hit hit; + return ray_mesh_intersect(s,dir,V,F,hit); + }; + return ambient_occlusion(shoot_ray,P,N,num_samples,S); + } + AABB aabb; + aabb.init(V,F); + return ambient_occlusion(aabb,V,F,P,N,num_samples,S); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::ambient_occlusion, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, int, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::ambient_occlusion, Eigen::Matrix, Eigen::Matrix >(std::function const&, Eigen::Matrix const&)> const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, int, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::ambient_occlusion, Eigen::Matrix, Eigen::Matrix >(std::function const&, Eigen::Matrix const&)> const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, int, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::ambient_occlusion, Eigen::Matrix, Eigen::Matrix >(std::function const&, Eigen::Matrix const&)> const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, int, Eigen::PlainObjectBase >&); +template void igl::ambient_occlusion, Eigen::Matrix, Eigen::Matrix >(std::function const&, Eigen::Matrix const&)> const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, int, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/ambient_occlusion.h b/src/external/libigl-2.3.0/include/igl/ambient_occlusion.h new file mode 100644 index 000000000..5e67ff598 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/ambient_occlusion.h @@ -0,0 +1,80 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_AMBIENT_OCCLUSION_H +#define IGL_AMBIENT_OCCLUSION_H +#include "igl_inline.h" +#include "AABB.h" +#include +#include +namespace igl +{ + // Compute ambient occlusion per given point + // + // Inputs: + // shoot_ray function handle that outputs hits of a given ray against a + // mesh (embedded in function handles as captured variable/data) + // P #P by 3 list of origin points + // N #P by 3 list of origin normals + // Outputs: + // S #P list of ambient occlusion values between 1 (fully occluded) and + // 0 (not occluded) + // + template < + typename DerivedP, + typename DerivedN, + typename DerivedS > + IGL_INLINE void ambient_occlusion( + const std::function< + bool( + const Eigen::Vector3f&, + const Eigen::Vector3f&) + > & shoot_ray, + const Eigen::MatrixBase & P, + const Eigen::MatrixBase & N, + const int num_samples, + Eigen::PlainObjectBase & S); + // Inputs: + // AABB axis-aligned bounding box hierarchy around (V,F) + template < + typename DerivedV, + int DIM, + typename DerivedF, + typename DerivedP, + typename DerivedN, + typename DerivedS > + IGL_INLINE void ambient_occlusion( + const igl::AABB & aabb, + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const Eigen::MatrixBase & P, + const Eigen::MatrixBase & N, + const int num_samples, + Eigen::PlainObjectBase & S); + // Inputs: + // V #V by 3 list of mesh vertex positions + // F #F by 3 list of mesh face indices into V + template < + typename DerivedV, + typename DerivedF, + typename DerivedP, + typename DerivedN, + typename DerivedS > + IGL_INLINE void ambient_occlusion( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const Eigen::MatrixBase & P, + const Eigen::MatrixBase & N, + const int num_samples, + Eigen::PlainObjectBase & S); + +}; +#ifndef IGL_STATIC_LIBRARY +# include "ambient_occlusion.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/angular_distance.cpp b/src/external/libigl-2.3.0/include/igl/angular_distance.cpp new file mode 100644 index 000000000..803c290c9 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/angular_distance.cpp @@ -0,0 +1,20 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "angular_distance.h" +#include +#include +IGL_INLINE double igl::angular_distance( + const Eigen::Quaterniond & A, + const Eigen::Quaterniond & B) +{ + assert(fabs(A.norm()-1) +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_ANGULAR_DISTANCE_H +#define IGL_ANGULAR_DISTANCE_H +#include "igl_inline.h" +#include +namespace igl +{ + // The "angular distance" between two unit quaternions is the angle of the + // smallest rotation (treated as an Axis and Angle) that takes A to B. + // + // Inputs: + // A unit quaternion + // B unit quaternion + // Returns angular distance + IGL_INLINE double angular_distance( + const Eigen::Quaterniond & A, + const Eigen::Quaterniond & B); +} + +#ifndef IGL_STATIC_LIBRARY +#include "angular_distance.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/any.cpp b/src/external/libigl-2.3.0/include/igl/any.cpp new file mode 100644 index 000000000..0488c8ffb --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/any.cpp @@ -0,0 +1,26 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "any.h" +#include "redux.h" + + +template +IGL_INLINE void igl::any( + const Eigen::SparseMatrix & A, + const int dim, + Eigen::PlainObjectBase& B) +{ + typedef typename DerivedB::Scalar Scalar; + igl::redux(A,dim,[](Scalar a, Scalar b){ return a || b!=0;},B); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::any >(Eigen::SparseMatrix const&, int, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/any.h b/src/external/libigl-2.3.0/include/igl/any.h new file mode 100644 index 000000000..08a80e4cb --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/any.h @@ -0,0 +1,35 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_ANY_H +#define IGL_ANY_H +#include "igl_inline.h" +#include +#include +namespace igl +{ + // For Dense matrices use: A.rowwise().any() or A.colwise().any() + // + // Inputs: + // A m by n sparse matrix + // dim dimension along which to check for any (1 or 2) + // Output: + // B n-long vector (if dim == 1) + // or + // B m-long vector (if dim == 2) + // + template + IGL_INLINE void any( + const Eigen::SparseMatrix & A, + const int dim, + Eigen::PlainObjectBase& B); +} +#ifndef IGL_STATIC_LIBRARY +# include "any.cpp" +#endif +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/any_of.cpp b/src/external/libigl-2.3.0/include/igl/any_of.cpp new file mode 100644 index 000000000..9defd0339 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/any_of.cpp @@ -0,0 +1,20 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "any_of.h" +#include +template +IGL_INLINE bool igl::any_of(const Mat & S) +{ + return std::any_of(S.data(),S.data()+S.size(),[](bool s){return s;}); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +template bool igl::any_of >(Eigen::Matrix const&); +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/any_of.h b/src/external/libigl-2.3.0/include/igl/any_of.h new file mode 100644 index 000000000..95ec1d373 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/any_of.h @@ -0,0 +1,26 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_ANY_OF_H +#define IGL_ANY_OF_H +#include "igl_inline.h" +namespace igl +{ + // Wrapper for STL `any_of` for matrix types + // + // Inputs: + // S matrix + // Returns whether any entries are true + // + // Seems that Eigen (now) implements this for `Eigen::Array` + template + IGL_INLINE bool any_of(const Mat & S); +} +#ifndef IGL_STATIC_LIBRARY +# include "any_of.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/arap.cpp b/src/external/libigl-2.3.0/include/igl/arap.cpp new file mode 100644 index 000000000..dc5af4cf6 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/arap.cpp @@ -0,0 +1,312 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "arap.h" +#include "colon.h" +#include "cotmatrix.h" +#include "massmatrix.h" +#include "group_sum_matrix.h" +#include "covariance_scatter_matrix.h" +#include "speye.h" +#include "mode.h" +#include "project_isometrically_to_plane.h" +#include "slice.h" +#include "arap_rhs.h" +#include "repdiag.h" +#include "columnize.h" +#include "fit_rotations.h" +#include +#include + +template < + typename DerivedV, + typename DerivedF, + typename Derivedb> +IGL_INLINE bool igl::arap_precomputation( + const Eigen::PlainObjectBase & V, + const Eigen::PlainObjectBase & F, + const int dim, + const Eigen::PlainObjectBase & b, + ARAPData & data) +{ + using namespace std; + using namespace Eigen; + typedef typename DerivedV::Scalar Scalar; + // number of vertices + const int n = V.rows(); + data.n = n; + assert((b.size() == 0 || b.maxCoeff() < n) && "b out of bounds"); + assert((b.size() == 0 || b.minCoeff() >=0) && "b out of bounds"); + // remember b + data.b = b; + //assert(F.cols() == 3 && "For now only triangles"); + // dimension + //const int dim = V.cols(); + assert((dim == 3 || dim ==2) && "dim should be 2 or 3"); + data.dim = dim; + //assert(dim == 3 && "Only 3d supported"); + // Defaults + data.f_ext = MatrixXd::Zero(n,data.dim); + + assert(data.dim <= V.cols() && "solve dim should be <= embedding"); + bool flat = (V.cols() - data.dim)==1; + + DerivedV plane_V; + DerivedF plane_F; + typedef SparseMatrix SparseMatrixS; + SparseMatrixS ref_map,ref_map_dim; + if(flat) + { + project_isometrically_to_plane(V,F,plane_V,plane_F,ref_map); + repdiag(ref_map,dim,ref_map_dim); + } + const PlainObjectBase& ref_V = (flat?plane_V:V); + const PlainObjectBase& ref_F = (flat?plane_F:F); + SparseMatrixS L; + cotmatrix(V,F,L); + + ARAPEnergyType eff_energy = data.energy; + if(eff_energy == ARAP_ENERGY_TYPE_DEFAULT) + { + switch(F.cols()) + { + case 3: + if(data.dim == 3) + { + eff_energy = ARAP_ENERGY_TYPE_SPOKES_AND_RIMS; + }else + { + eff_energy = ARAP_ENERGY_TYPE_ELEMENTS; + } + break; + case 4: + eff_energy = ARAP_ENERGY_TYPE_ELEMENTS; + break; + default: + assert(false); + } + } + + + // Get covariance scatter matrix, when applied collects the covariance + // matrices used to fit rotations to during optimization + covariance_scatter_matrix(ref_V,ref_F,eff_energy,data.CSM); + if(flat) + { + data.CSM = (data.CSM * ref_map_dim.transpose()).eval(); + } + assert(data.CSM.cols() == V.rows()*data.dim); + + // Get group sum scatter matrix, when applied sums all entries of the same + // group according to G + SparseMatrix G_sum; + if(data.G.size() == 0) + { + if(eff_energy == ARAP_ENERGY_TYPE_ELEMENTS) + { + speye(F.rows(),G_sum); + }else + { + speye(n,G_sum); + } + }else + { + // groups are defined per vertex, convert to per face using mode + if(eff_energy == ARAP_ENERGY_TYPE_ELEMENTS) + { + Eigen::Matrix GG; + MatrixXi GF(F.rows(),F.cols()); + for(int j = 0;j GFj; + slice(data.G,F.col(j),GFj); + GF.col(j) = GFj; + } + mode(GF,2,GG); + data.G=GG; + } + //printf("group_sum_matrix()\n"); + group_sum_matrix(data.G,G_sum); + } + SparseMatrix G_sum_dim; + repdiag(G_sum,data.dim,G_sum_dim); + assert(G_sum_dim.cols() == data.CSM.rows()); + data.CSM = (G_sum_dim * data.CSM).eval(); + + + arap_rhs(ref_V,ref_F,data.dim,eff_energy,data.K); + if(flat) + { + data.K = (ref_map_dim * data.K).eval(); + } + assert(data.K.rows() == data.n*data.dim); + + SparseMatrix Q = (-L).eval(); + + if(data.with_dynamics) + { + const double h = data.h; + assert(h != 0); + SparseMatrix M; + massmatrix(V,F,MASSMATRIX_TYPE_DEFAULT,data.M); + const double dw = (1./data.ym)*(h*h); + SparseMatrix DQ = dw * 1./(h*h)*data.M; + Q += DQ; + // Dummy external forces + data.f_ext = MatrixXd::Zero(n,data.dim); + data.vel = MatrixXd::Zero(n,data.dim); + } + + return min_quad_with_fixed_precompute( + Q,b,SparseMatrix(),true,data.solver_data); +} + +template < + typename Derivedbc, + typename DerivedU> +IGL_INLINE bool igl::arap_solve( + const Eigen::PlainObjectBase & bc, + ARAPData & data, + Eigen::PlainObjectBase & U) +{ + using namespace Eigen; + using namespace std; + assert(data.b.size() == bc.rows()); + if(bc.size() > 0) + { + assert(bc.cols() == data.dim && "bc.cols() match data.dim"); + } + const int n = data.n; + int iter = 0; + if(U.size() == 0) + { + // terrible initial guess.. should at least copy input mesh +#ifndef NDEBUG + cerr<<"arap_solve: Using terrible initial guess for U. Try U = V."<0) + { + bcc = bc.col(c); + } + min_quad_with_fixed_solve( + data.solver_data, + Bc,bcc,Beq, + Uc); + U.col(c) = Uc; + } + + iter++; + } + if(data.with_dynamics) + { + // Keep track of velocity for next time + data.vel = (U-U0)/data.h; + } + + return true; +} + +#ifdef IGL_STATIC_LIBRARY +template bool igl::arap_solve, Eigen::Matrix >(Eigen::PlainObjectBase > const&, igl::ARAPData&, Eigen::PlainObjectBase >&); +template bool igl::arap_precomputation, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, int, Eigen::PlainObjectBase > const&, igl::ARAPData&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/arap.h b/src/external/libigl-2.3.0/include/igl/arap.h new file mode 100644 index 000000000..b2210e64f --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/arap.h @@ -0,0 +1,104 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_ARAP_H +#define IGL_ARAP_H +#include "igl_inline.h" +#include "min_quad_with_fixed.h" +#include "ARAPEnergyType.h" +#include +#include + +namespace igl +{ + struct ARAPData + { + // n #V + // G #V list of group indices (1 to k) for each vertex, such that vertex i + // is assigned to group G(i) + // energy type of energy to use + // with_dynamics whether using dynamics (need to call arap_precomputation + // after changing) + // f_ext #V by dim list of external forces + // vel #V by dim list of velocities + // h dynamics time step + // ym ~Young's modulus smaller is softer, larger is more rigid/stiff + // max_iter maximum inner iterations + // K rhs pre-multiplier + // M mass matrix + // solver_data quadratic solver data + // b list of boundary indices into V + // dim dimension being used for solving + int n; + Eigen::VectorXi G; + ARAPEnergyType energy; + bool with_dynamics; + Eigen::MatrixXd f_ext,vel; + double h; + double ym; + int max_iter; + Eigen::SparseMatrix K,M; + Eigen::SparseMatrix CSM; + min_quad_with_fixed_data solver_data; + Eigen::VectorXi b; + int dim; + ARAPData(): + n(0), + G(), + energy(ARAP_ENERGY_TYPE_DEFAULT), + with_dynamics(false), + f_ext(), + h(1), + ym(1), + max_iter(10), + K(), + CSM(), + solver_data(), + b(), + dim(-1) // force this to be set by _precomputation + { + }; + }; + + // Compute necessary information to start using an ARAP deformation + // + // Inputs: + // V #V by dim list of mesh positions + // F #F by simplex-size list of triangle|tet indices into V + // dim dimension being used at solve time. For deformation usually dim = + // V.cols(), for surface parameterization V.cols() = 3 and dim = 2 + // b #b list of "boundary" fixed vertex indices into V + // Outputs: + // data struct containing necessary precomputation + template < + typename DerivedV, + typename DerivedF, + typename Derivedb> + IGL_INLINE bool arap_precomputation( + const Eigen::PlainObjectBase & V, + const Eigen::PlainObjectBase & F, + const int dim, + const Eigen::PlainObjectBase & b, + ARAPData & data); + // Inputs: + // bc #b by dim list of boundary conditions + // data struct containing necessary precomputation and parameters + // U #V by dim initial guess + template < + typename Derivedbc, + typename DerivedU> + IGL_INLINE bool arap_solve( + const Eigen::PlainObjectBase & bc, + ARAPData & data, + Eigen::PlainObjectBase & U); +}; + +#ifndef IGL_STATIC_LIBRARY +#include "arap.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/arap_dof.cpp b/src/external/libigl-2.3.0/include/igl/arap_dof.cpp new file mode 100644 index 000000000..eaf2ea71f --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/arap_dof.cpp @@ -0,0 +1,884 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "arap_dof.h" + +#include "cotmatrix.h" +#include "massmatrix.h" +#include "speye.h" +#include "repdiag.h" +#include "repmat.h" +#include "slice.h" +#include "colon.h" +#include "is_sparse.h" +#include "mode.h" +#include "is_symmetric.h" +#include "group_sum_matrix.h" +#include "arap_rhs.h" +#include "covariance_scatter_matrix.h" +#include "fit_rotations.h" + +#include "verbose.h" +#include "print_ijv.h" + +#include "get_seconds_hires.h" +//#include "MKLEigenInterface.h" +#include "kkt_inverse.h" +#include "get_seconds.h" +#include "columnize.h" + +// defined if no early exit is supported, i.e., always take a fixed number of iterations +#define IGL_ARAP_DOF_FIXED_ITERATIONS_COUNT + +// A careful derivation of this implementation is given in the corresponding +// matlab function arap_dof.m +template +IGL_INLINE bool igl::arap_dof_precomputation( + const Eigen::MatrixXd & V, + const Eigen::MatrixXi & F, + const LbsMatrixType & M, + const Eigen::Matrix & G, + ArapDOFData & data) +{ + using namespace Eigen; + typedef Matrix MatrixXS; + // number of mesh (domain) vertices + int n = V.rows(); + // cache problem size + data.n = n; + // dimension of mesh + data.dim = V.cols(); + assert(data.dim == M.rows()/n); + assert(data.dim*n == M.rows()); + if(data.dim == 3) + { + // Check if z-coordinate is all zeros + if(V.col(2).minCoeff() == 0 && V.col(2).maxCoeff() == 0) + { + data.effective_dim = 2; + } + }else + { + data.effective_dim = data.dim; + } + // Number of handles + data.m = M.cols()/data.dim/(data.dim+1); + assert(data.m*data.dim*(data.dim+1) == M.cols()); + //assert(m == C.rows()); + + //printf("n=%d; dim=%d; m=%d;\n",n,data.dim,data.m); + + // Build cotangent laplacian + SparseMatrix Lcot; + //printf("cotmatrix()\n"); + cotmatrix(V,F,Lcot); + // Discrete laplacian (should be minus matlab version) + SparseMatrix Lapl = -2.0*Lcot; +#ifdef EXTREME_VERBOSE + cout<<"LaplIJV=["< G_sum; + if(G.size() == 0) + { + speye(n,G_sum); + }else + { + // groups are defined per vertex, convert to per face using mode + Eigen::Matrix GG; + if(data.energy == ARAP_ENERGY_TYPE_ELEMENTS) + { + MatrixXi GF(F.rows(),F.cols()); + for(int j = 0;j GFj; + slice(G,F.col(j),GFj); + GF.col(j) = GFj; + } + mode(GF,2,GG); + }else + { + GG=G; + } + //printf("group_sum_matrix()\n"); + group_sum_matrix(GG,G_sum); + } + +#ifdef EXTREME_VERBOSE + cout<<"G_sumIJV=["< CSM; + //printf("covariance_scatter_matrix()\n"); + covariance_scatter_matrix(V,F,data.energy,CSM); +#ifdef EXTREME_VERBOSE + cout<<"CSMIJV=["< G_sum_dim; + repdiag(G_sum,data.dim,G_sum_dim); + CSM = (G_sum_dim * CSM).eval(); +#ifdef EXTREME_VERBOSE + cout<<"CSMIJV=["< span_n(n); + for(int i = 0;i span_mlbs_cols(M.cols()); + for(int i = 0;i CSMj; + //printf("CSM_M(): slice\n"); + slice( + CSM, + colon(j*k,(j+1)*k-1), + colon(j*n,(j+1)*n-1), + CSMj); + assert(CSMj.rows() == k); + assert(CSMj.cols() == n); + LbsMatrixType CSMjM_i = CSMj * M_i; + if(is_sparse(CSMjM_i)) + { + // Convert to full + //printf("CSM_M(): full\n"); + MatrixXd CSMjM_ifull(CSMjM_i); +// printf("CSM_M[%d]: %d %d\n",i,data.CSM_M[i].rows(),data.CSM_M[i].cols()); +// printf("CSM_M[%d].block(%d*%d=%d,0,%d,%d): %d %d\n",i,j,k,CSMjM_i.rows(),CSMjM_i.cols(), +// data.CSM_M[i].block(j*k,0,CSMjM_i.rows(),CSMjM_i.cols()).rows(), +// data.CSM_M[i].block(j*k,0,CSMjM_i.rows(),CSMjM_i.cols()).cols()); +// printf("CSM_MjMi: %d %d\n",i,CSMjM_i.rows(),CSMjM_i.cols()); +// printf("CSM_MjM_ifull: %d %d\n",i,CSMjM_ifull.rows(),CSMjM_ifull.cols()); + data.CSM_M[i].block(j*k,0,CSMjM_i.rows(),CSMjM_i.cols()) = CSMjM_ifull; + }else + { + data.CSM_M[i].block(j*k,0,CSMjM_i.rows(),CSMjM_i.cols()) = CSMjM_i; + } + } +#ifdef EXTREME_VERBOSE + cout<<"CSM_Mi=["< K; + arap_rhs(V,F,V.cols(),data.energy,K); +//#ifdef EXTREME_VERBOSE +// cout<<"KIJV=["< G_sumT = G_sum.transpose(); + SparseMatrix G_sumT_dim_dim; + repdiag(G_sumT,data.dim*data.dim,G_sumT_dim_dim); + LbsMatrixType MT = M.transpose(); + // If this is a bottle neck then consider reordering matrix multiplication + data.M_KG = -4.0 * (MT * (K * G_sumT_dim_dim)); +//#ifdef EXTREME_VERBOSE +// cout<<"data.M_KGIJV=["< A; + repdiag(Lapl,data.dim,A); + data.Q = MT * (A * M); +//#ifdef EXTREME_VERBOSE +// cout<<"QIJV=["< Mass; + //printf("massmatrix()\n"); + massmatrix(V,F,(F.cols()>3?MASSMATRIX_TYPE_BARYCENTRIC:MASSMATRIX_TYPE_VORONOI),Mass); + //cout<<"MIJV=["< Mass_rep; + repdiag(Mass,data.dim,Mass_rep); + + // Multiply either side by weights matrix (should be dense) + data.Mass_tilde = MT * Mass_rep * M; + MatrixXd ones(data.dim*data.n,data.dim); + for(int i = 0;i + inline static SSCALAR maxBlokErr(const Eigen::Matrix3f &blok) + { + SSCALAR mD; + SSCALAR value = blok(0,0); + SSCALAR diff1 = fabs(blok(1,1) - value); + SSCALAR diff2 = fabs(blok(2,2) - value); + if (diff1 > diff2) mD = diff1; + else mD = diff2; + + for (int v=0; v<3; v++) + { + for (int w=0; w<3; w++) + { + if (v == w) + { + continue; + } + if (mD < fabs(blok(v, w))) + { + mD = fabs(blok(v, w)); + } + } + } + + return mD; + } + + // converts CSM_M_SSCALAR[0], CSM_M_SSCALAR[1], CSM_M_SSCALAR[2] into one + // "condensed" matrix CSM while checking we're not losing any information by + // this process; specifically, returns maximal difference from scaled 3x3 + // identity blocks, which should be pretty small number + template + static typename MatrixXS::Scalar condense_CSM( + const std::vector &CSM_M_SSCALAR, + int numBones, + int dim, + MatrixXS &CSM) + { + const int numRows = CSM_M_SSCALAR[0].rows(); + assert(CSM_M_SSCALAR[0].cols() == dim*(dim+1)*numBones); + assert(CSM_M_SSCALAR[1].cols() == dim*(dim+1)*numBones); + assert(CSM_M_SSCALAR[2].cols() == dim*(dim+1)*numBones); + assert(CSM_M_SSCALAR[1].rows() == numRows); + assert(CSM_M_SSCALAR[2].rows() == numRows); + + const int numCols = (dim + 1)*numBones; + CSM.resize(numRows, numCols); + + typedef typename MatrixXS::Scalar SSCALAR; + SSCALAR maxDiff = 0.0f; + + for (int r=0; r(blok); + if (mD > maxDiff) maxDiff = mD; + + // use the first value: + CSM(r, coord*numBones + b) = blok(0,0); + } + } + } + + return maxDiff; + } + + // splits x_0, ... , x_dim coordinates in column vector 'L' into a numBones*(dimp1) x dim matrix 'Lsep'; + // assumes 'Lsep' has already been preallocated + // + // is this the same as uncolumnize? no. + template + static void splitColumns( + const MatL &L, + int numBones, + int dim, + int dimp1, + MatLsep &Lsep) + { + assert(L.cols() == 1); + assert(L.rows() == dim*(dimp1)*numBones); + + assert(Lsep.rows() == (dimp1)*numBones && Lsep.cols() == dim); + + for (int b=0; b + static void mergeColumns(const MatrixXS &Lsep, int numBones, int dim, int dimp1, MatrixXS &L) + { + assert(L.cols() == 1); + assert(L.rows() == dim*(dimp1)*numBones); + + assert(Lsep.rows() == (dimp1)*numBones && Lsep.cols() == dim); + + for (int b=0; b + static typename MatrixXS::Scalar condense_Solve1(MatrixXS &Solve1, int numBones, int numGroups, int dim, MatrixXS &CSolve1) + { + assert(Solve1.rows() == dim*(dim + 1)*numBones); + assert(Solve1.cols() == dim*dim*numGroups); + + typedef typename MatrixXS::Scalar SSCALAR; + SSCALAR maxDiff = 0.0f; + + CSolve1.resize((dim + 1)*numBones, dim*numGroups); + for (int rowCoord=0; rowCoord(blok); + if (mD > maxDiff) maxDiff = mD; + + CSolve1(rowCoord*numBones + b, colCoord*numGroups + g) = blok(0,0); + } + } + } + } + + return maxDiff; + } +} + +template +IGL_INLINE bool igl::arap_dof_recomputation( + const Eigen::Matrix & fixed_dim, + const Eigen::SparseMatrix & A_eq, + ArapDOFData & data) +{ + using namespace Eigen; + typedef Matrix MatrixXS; + + LbsMatrixType * Q; + LbsMatrixType Qdyn; + if(data.with_dynamics) + { + // multiply by 1/timestep and to quadratic coefficients matrix + // Might be missing a 0.5 here + LbsMatrixType Q_copy = data.Q; + Qdyn = Q_copy + (1.0/(data.h*data.h))*data.Mass_tilde; + Q = &Qdyn; + + // This may/should be superfluous + //printf("is_symmetric()\n"); + if(!is_symmetric(*Q)) + { + //printf("Fixing symmetry...\n"); + // "Fix" symmetry + LbsMatrixType QT = (*Q).transpose(); + LbsMatrixType Q_copy = *Q; + *Q = 0.5*(Q_copy+QT); + // Check that ^^^ this really worked. It doesn't always + //assert(is_symmetric(*Q)); + } + }else + { + Q = &data.Q; + } + + assert((int)data.CSM_M.size() == data.dim); + assert(A_eq.cols() == data.m*data.dim*(data.dim+1)); + data.fixed_dim = fixed_dim; + + if(fixed_dim.size() > 0) + { + assert(fixed_dim.maxCoeff() < data.m*data.dim*(data.dim+1)); + assert(fixed_dim.minCoeff() >= 0); + } + +#ifdef EXTREME_VERBOSE + cout<<"data.fixed_dim=["<(), + M_Solve.block(0, fsRows, fsRows, fsCols2).template cast(); + + if(data.with_dynamics) + { + printf( + "---------------------------------------------------------------------\n" + "\n\n\nWITH DYNAMICS recomputation\n\n\n" + "---------------------------------------------------------------------\n" + ); + // Also need to save Π1 before it gets multiplied by Ktilde (aka M_KG) + data.Pi_1 = M_Solve.block(0, 0, fsRows, fsRows).template cast(); + } + + // Precompute condensed matrices, + // first CSM: + std::vector CSM_M_SSCALAR; + CSM_M_SSCALAR.resize(data.dim); + for (int i=0; i(); + SSCALAR maxErr1 = condense_CSM(CSM_M_SSCALAR, data.m, data.dim, data.CSM); + verbose("condense_CSM maxErr = %.15f (this should be close to zero)\n", maxErr1); + assert(fabs(maxErr1) < 1e-5); + + // and then solveBlock1: + // number of groups + const int k = data.CSM_M[0].rows()/data.dim; + MatrixXS SolveBlock1 = data.M_FullSolve.block(0, 0, data.M_FullSolve.rows(), data.dim * data.dim * k); + SSCALAR maxErr2 = condense_Solve1(SolveBlock1, data.m, k, data.dim, data.CSolveBlock1); + verbose("condense_Solve1 maxErr = %.15f (this should be close to zero)\n", maxErr2); + assert(fabs(maxErr2) < 1e-5); + + return true; +} + +template +IGL_INLINE bool igl::arap_dof_update( + const ArapDOFData & data, + const Eigen::Matrix & B_eq, + const Eigen::MatrixXd & L0, + const int max_iters, + const double +#ifdef IGL_ARAP_DOF_FIXED_ITERATIONS_COUNT + tol, +#else + /*tol*/, +#endif + Eigen::MatrixXd & L + ) +{ + using namespace Eigen; + typedef Matrix MatrixXS; +#ifdef ARAP_GLOBAL_TIMING + double timer_start = get_seconds_hires(); +#endif + + // number of dimensions + assert((int)data.CSM_M.size() == data.dim); + assert((int)L0.size() == (data.m)*data.dim*(data.dim+1)); + assert(max_iters >= 0); + assert(tol >= 0); + + // timing variables + double + sec_start, + sec_covGather, + sec_fitRotations, + //sec_rhs, + sec_prepMult, + sec_solve, sec_end; + + assert(L0.cols() == 1); +#ifdef EXTREME_VERBOSE + cout<<"dim="<(); + + int iters = 0; +#ifndef IGL_ARAP_DOF_FIXED_ITERATIONS_COUNT + double max_diff = tol+1; +#endif + + MatrixXS S(k*data.dim,data.dim); + MatrixXS R(data.dim,data.dim*k); + Eigen::Matrix Rcol(data.dim * data.dim * k); + Matrix B_eq_SSCALAR = B_eq.cast(); + Matrix B_eq_fix_SSCALAR; + Matrix L0SSCALAR = L0.cast(); + slice(L0SSCALAR, data.fixed_dim, B_eq_fix_SSCALAR); + //MatrixXS rhsFull(Rcol.rows() + B_eq.rows() + B_eq_fix_SSCALAR.rows(), 1); + + MatrixXS Lsep(data.m*(data.dim + 1), 3); + const MatrixXS L_part2 = + data.M_FullSolve.block(0, Rcol.rows(), data.M_FullSolve.rows(), B_eq_SSCALAR.rows()) * B_eq_SSCALAR; + const MatrixXS L_part3 = + data.M_FullSolve.block(0, Rcol.rows() + B_eq_SSCALAR.rows(), data.M_FullSolve.rows(), B_eq_fix_SSCALAR.rows()) * B_eq_fix_SSCALAR; + MatrixXS L_part2and3 = L_part2 + L_part3; + + // preallocate workspace variables: + MatrixXS Rxyz(k*data.dim, data.dim); + MatrixXS L_part1xyz((data.dim + 1) * data.m, data.dim); + MatrixXS L_part1(data.dim * (data.dim + 1) * data.m, 1); + +#ifdef ARAP_GLOBAL_TIMING + double timer_prepFinished = get_seconds_hires(); +#endif + +#ifdef IGL_ARAP_DOF_FIXED_ITERATIONS_COUNT + while(iters < max_iters) +#else + while(iters < max_iters && max_diff > tol) +#endif + { + if(data.print_timings) + { + sec_start = get_seconds_hires(); + } + +#ifndef IGL_ARAP_DOF_FIXED_ITERATIONS_COUNT + L_prev = L_SSCALAR; +#endif + /////////////////////////////////////////////////////////////////////////// + // Local step: Fix positions, fit rotations + /////////////////////////////////////////////////////////////////////////// + + // Gather covariance matrices + + splitColumns(L_SSCALAR, data.m, data.dim, data.dim + 1, Lsep); + + S = data.CSM * Lsep; + // interestingly, this doesn't seem to be so slow, but + //MKL is still 2x faster (probably due to AVX) + //#ifdef IGL_ARAP_DOF_DOUBLE_PRECISION_SOLVE + // MKL_matMatMult_double(S, data.CSM, Lsep); + //#else + // MKL_matMatMult_single(S, data.CSM, Lsep); + //#endif + + if(data.print_timings) + { + sec_covGather = get_seconds_hires(); + } + +#ifdef EXTREME_VERBOSE + cout<<"S=["<(); + + MatrixXd temp_g = data.fgrav*(data.grav_mag*data.grav_dir); + + assert(data.fext.rows() == temp_g.rows()); + assert(data.fext.cols() == temp_g.cols()); + MatrixXd temp2 = data.Mass_tilde * temp_d + temp_g + data.fext.template cast(); + MatrixXS temp2_f = temp2.template cast(); + L_part1_dyn = data.Pi_1 * temp2_f; + L_part1.array() = L_part1.array() + L_part1_dyn.array(); + } + + //L_SSCALAR = L_part1 + L_part2and3; + assert(L_SSCALAR.rows() == L_part1.rows() && L_SSCALAR.rows() == L_part2and3.rows()); + for (int i=0; i(); + assert(L.cols() == 1); + +#ifdef ARAP_GLOBAL_TIMING + double timer_finito = get_seconds_hires(); + printf( + "ARAP preparation = %f, " + "all %i iterations = %f [ms]\n", + (timer_prepFinished - timer_start)*1000.0, + max_iters, + (timer_finito - timer_prepFinished)*1000.0); +#endif + + return true; +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +template bool igl::arap_dof_update, double>(ArapDOFData, double> const&, Eigen::Matrix const&, Eigen::Matrix const&, int, double, Eigen::Matrix&); +template bool igl::arap_dof_recomputation, double>(Eigen::Matrix const&, Eigen::SparseMatrix const&, ArapDOFData, double>&); +template bool igl::arap_dof_precomputation, double>(Eigen::Matrix const&, Eigen::Matrix const&, Eigen::Matrix const&, Eigen::Matrix const&, ArapDOFData, double>&); +template bool igl::arap_dof_update, float>(igl::ArapDOFData, float> const&, Eigen::Matrix const&, Eigen::Matrix const&, int, double, Eigen::Matrix&); +template bool igl::arap_dof_recomputation, float>(Eigen::Matrix const&, Eigen::SparseMatrix const&, igl::ArapDOFData, float>&); +template bool igl::arap_dof_precomputation, float>(Eigen::Matrix const&, Eigen::Matrix const&, Eigen::Matrix const&, Eigen::Matrix const&, igl::ArapDOFData, float>&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/arap_dof.h b/src/external/libigl-2.3.0/include/igl/arap_dof.h new file mode 100644 index 000000000..f3647a3a1 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/arap_dof.h @@ -0,0 +1,244 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_ARAP_ENERGY_TYPE_DOF_H +#define IGL_ARAP_ENERGY_TYPE_DOF_H +#include "igl_inline.h" + +#include +#include +#include "ARAPEnergyType.h" +#include + +namespace igl +{ + // Caller example: + // + // Once: + // arap_dof_precomputation(...) + // + // Each frame: + // while(not satisfied) + // arap_dof_update(...) + // end + + template + struct ArapDOFData; + + /////////////////////////////////////////////////////////////////////////// + // + // Arap DOF precomputation consists of two parts the computation. The first is + // that which depends solely on the mesh (V,F), the linear blend skinning + // weights (M) and the groups G. Then there's the part that depends on the + // previous precomputation and the list of free and fixed vertices. + // + /////////////////////////////////////////////////////////////////////////// + + + // The code and variables differ from the description in Section 3 of "Fast + // Automatic Skinning Transformations" by [Jacobson et al. 2012] + // + // Here is a useful conversion table: + // + // [article] [code] + // S = \tilde{K} T S = CSM * Lsep + // S --> R S --> R --shuffled--> Rxyz + // Gamma_solve RT = Pi_1 \tilde{K} RT L_part1xyz = CSolveBlock1 * Rxyz + // Pi_1 \tilde{K} CSolveBlock1 + // Peq = [T_full; P_pos] + // T_full B_eq_fix <--- L0 + // P_pos B_eq + // Pi_2 * P_eq = Lpart2and3 = Lpart2 + Lpart3 + // Pi_2_left T_full + Lpart3 = M_fullsolve(right) * B_eq_fix + // Pi_2_right P_pos Lpart2 = M_fullsolve(left) * B_eq + // T = [Pi_1 Pi_2] [\tilde{K}TRT P_eq] L = Lpart1 + Lpart2and3 + // + + // Precomputes the system we are going to optimize. This consists of building + // constructor matrices (to compute covariance matrices from transformations + // and to build the poisson solve right hand side from rotation matrix entries) + // and also prefactoring the poisson system. + // + // Inputs: + // V #V by dim list of vertex positions + // F #F by {3|4} list of face indices + // M #V * dim by #handles * dim * (dim+1) matrix such that + // new_V(:) = LBS(V,W,A) = reshape(M * A,size(V)), where A is a column + // vectors formed by the entries in each handle's dim by dim+1 + // transformation matrix. Specifcally, A = + // reshape(permute(Astack,[3 1 2]),n*dim*(dim+1),1) + // or A = [Lxx;Lyx;Lxy;Lyy;tx;ty], and likewise for other dim + // if Astack(:,:,i) is the dim by (dim+1) transformation at handle i + // handles are ordered according to P then BE (point handles before bone + // handles) + // G #V list of group indices (1 to k) for each vertex, such that vertex i + // is assigned to group G(i) + // Outputs: + // data structure containing all necessary precomputation for calling + // arap_dof_update + // Returns true on success, false on error + // + // See also: lbs_matrix_column + template + IGL_INLINE bool arap_dof_precomputation( + const Eigen::MatrixXd & V, + const Eigen::MatrixXi & F, + const LbsMatrixType & M, + const Eigen::Matrix & G, + ArapDOFData & data); + + // Should always be called after arap_dof_precomputation, but may be called in + // between successive calls to arap_dof_update, recomputes precomputation + // given that there are only changes in free and fixed + // + // Inputs: + // fixed_dim list of transformation element indices for fixed (or partailly + // fixed) handles: not necessarily the complement of 'free' + // NOTE: the constraints for fixed transformations still need to be + // present in A_eq + // A_eq dim*#constraint_points by m*dim*(dim+1) matrix of linear equality + // constraint coefficients. Each row corresponds to a linear constraint, + // so that A_eq * L = Beq says that the linear transformation entries in + // the column L should produce the user supplied positional constraints + // for each handle in Beq. The row A_eq(i*dim+d) corresponds to the + // constrain on coordinate d of position i + // Outputs: + // data structure containing all necessary precomputation for calling + // arap_dof_update + // Returns true on success, false on error + // + // See also: lbs_matrix_column + template + IGL_INLINE bool arap_dof_recomputation( + const Eigen::Matrix & fixed_dim, + const Eigen::SparseMatrix & A_eq, + ArapDOFData & data); + + // Optimizes the transformations attached to each weight function based on + // precomputed system. + // + // Inputs: + // data precomputation data struct output from arap_dof_precomputation + // Beq dim*#constraint_points constraint values. + // L0 #handles * dim * dim+1 list of initial guess transformation entries, + // also holds fixed transformation entries for fixed handles + // max_iters maximum number of iterations + // tol stopping criteria parameter. If variables (linear transformation + // matrix entries) change by less than 'tol' the optimization terminates, + // 0.75 (weak tolerance) + // 0.0 (extreme tolerance) + // Outputs: + // L #handles * dim * dim+1 list of final optimized transformation entries, + // allowed to be the same as L + template + IGL_INLINE bool arap_dof_update( + const ArapDOFData & data, + const Eigen::Matrix & B_eq, + const Eigen::MatrixXd & L0, + const int max_iters, + const double tol, + Eigen::MatrixXd & L + ); + + // Structure that contains fields for all precomputed data or data that needs + // to be remembered at update + template + struct ArapDOFData + { + typedef Eigen::Matrix MatrixXS; + // Type of arap energy we're solving + igl::ARAPEnergyType energy; + //// LU decomposition precomptation data; note: not used by araf_dop_update + //// any more, replaced by M_FullSolve + //igl::min_quad_with_fixed_data lu_data; + // List of indices of fixed transformation entries + Eigen::Matrix fixed_dim; + // List of precomputed covariance scatter matrices multiplied by lbs + // matrices + //std::vector > CSM_M; + std::vector CSM_M; + LbsMatrixType M_KG; + // Number of mesh vertices + int n; + // Number of weight functions + int m; + // Number of dimensions + int dim; + // Effective dimensions + int effective_dim; + // List of indices into C of positional constraints + Eigen::Matrix interpolated; + std::vector free_mask; + // Full quadratic coefficients matrix before lagrangian (should be dense) + LbsMatrixType Q; + + + //// Solve matrix for the global step + //Eigen::MatrixXd M_Solve; // TODO: remove from here + + // Full solve matrix that contains also conversion from rotations to the right hand side, + // i.e., solves Poisson transformations just from rotations and positional constraints + MatrixXS M_FullSolve; + + // Precomputed condensed matrices (3x3 commutators folded to 1x1): + MatrixXS CSM; + MatrixXS CSolveBlock1; + + // Print timings at each update + bool print_timings; + + // Dynamics + bool with_dynamics; + // I'm hiding the extra dynamics stuff in this struct, which sort of defeats + // the purpose of this function-based coding style... + + // Time step + double h; + + // L0 #handles * dim * dim+1 list of transformation entries from + // previous solve + MatrixXS L0; + //// Lm1 #handles * dim * dim+1 list of transformation entries from + //// previous-previous solve + //MatrixXS Lm1; + // "Velocity" + MatrixXS Lvel0; + + // #V by dim matrix of external forces + // fext + MatrixXS fext; + + // Mass_tilde: MT * Mass * M + LbsMatrixType Mass_tilde; + + // Force due to gravity (premultiplier) + Eigen::MatrixXd fgrav; + // Direction of gravity + Eigen::Vector3d grav_dir; + // Magnitude of gravity + double grav_mag; + + // Π1 from the paper + MatrixXS Pi_1; + + // Default values + ArapDOFData(): + energy(igl::ARAP_ENERGY_TYPE_SPOKES), + with_dynamics(false), + h(1), + grav_dir(0,-1,0), + grav_mag(0) + { + } + }; +} + +#ifndef IGL_STATIC_LIBRARY +# include "arap_dof.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/arap_linear_block.cpp b/src/external/libigl-2.3.0/include/igl/arap_linear_block.cpp new file mode 100644 index 000000000..7501721b6 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/arap_linear_block.cpp @@ -0,0 +1,259 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "arap_linear_block.h" +#include "verbose.h" +#include "cotmatrix_entries.h" +#include + +template +IGL_INLINE void igl::arap_linear_block( + const MatV & V, + const MatF & F, + const int d, + const igl::ARAPEnergyType energy, + MatK & Kd) +{ + switch(energy) + { + case ARAP_ENERGY_TYPE_SPOKES: + return igl::arap_linear_block_spokes(V,F,d,Kd); + break; + case ARAP_ENERGY_TYPE_SPOKES_AND_RIMS: + return igl::arap_linear_block_spokes_and_rims(V,F,d,Kd); + break; + case ARAP_ENERGY_TYPE_ELEMENTS: + return igl::arap_linear_block_elements(V,F,d,Kd); + break; + default: + verbose("Unsupported energy type: %d\n",energy); + assert(false); + } +} + + +template +IGL_INLINE void igl::arap_linear_block_spokes( + const MatV & V, + const MatF & F, + const int d, + MatK & Kd) +{ + typedef typename MatK::Scalar Scalar; + + using namespace std; + using namespace Eigen; + // simplex size (3: triangles, 4: tetrahedra) + int simplex_size = F.cols(); + // Number of elements + int m = F.rows(); + // Temporary output + Matrix edges; + Kd.resize(V.rows(), V.rows()); + vector > Kd_IJV; + if(simplex_size == 3) + { + // triangles + Kd.reserve(7*V.rows()); + Kd_IJV.reserve(7*V.rows()); + edges.resize(3,2); + edges << + 1,2, + 2,0, + 0,1; + }else if(simplex_size == 4) + { + // tets + Kd.reserve(17*V.rows()); + Kd_IJV.reserve(17*V.rows()); + edges.resize(6,2); + edges << + 1,2, + 2,0, + 0,1, + 3,0, + 3,1, + 3,2; + } + // gather cotangent weights + Matrix C; + cotmatrix_entries(V,F,C); + // should have weights for each edge + assert(C.cols() == edges.rows()); + // loop over elements + for(int i = 0;i(source,dest,v)); + Kd_IJV.push_back(Triplet(dest,source,-v)); + Kd_IJV.push_back(Triplet(source,source,v)); + Kd_IJV.push_back(Triplet(dest,dest,-v)); + } + } + Kd.setFromTriplets(Kd_IJV.begin(),Kd_IJV.end()); + Kd.makeCompressed(); +} + +template +IGL_INLINE void igl::arap_linear_block_spokes_and_rims( + const MatV & V, + const MatF & F, + const int d, + MatK & Kd) +{ + typedef typename MatK::Scalar Scalar; + + using namespace std; + using namespace Eigen; + // simplex size (3: triangles, 4: tetrahedra) + int simplex_size = F.cols(); + // Number of elements + int m = F.rows(); + // Temporary output + Kd.resize(V.rows(), V.rows()); + vector > Kd_IJV; + Matrix edges; + if(simplex_size == 3) + { + // triangles + Kd.reserve(7*V.rows()); + Kd_IJV.reserve(7*V.rows()); + edges.resize(3,2); + edges << + 1,2, + 2,0, + 0,1; + }else if(simplex_size == 4) + { + // tets + Kd.reserve(17*V.rows()); + Kd_IJV.reserve(17*V.rows()); + edges.resize(6,2); + edges << + 1,2, + 2,0, + 0,1, + 3,0, + 3,1, + 3,2; + // Not implemented yet for tets + assert(false); + } + // gather cotangent weights + Matrix C; + cotmatrix_entries(V,F,C); + // should have weights for each edge + assert(C.cols() == edges.rows()); + // loop over elements + for(int i = 0;i(Rs,Rd,v)); + Kd_IJV.push_back(Triplet(Rd,Rs,-v)); + }else if(Rd == source) + { + Kd_IJV.push_back(Triplet(Rd,Rs,v)); + }else if(Rs == dest) + { + Kd_IJV.push_back(Triplet(Rs,Rd,-v)); + } + } + Kd_IJV.push_back(Triplet(source,source,v)); + Kd_IJV.push_back(Triplet(dest,dest,-v)); + } + } + Kd.setFromTriplets(Kd_IJV.begin(),Kd_IJV.end()); + Kd.makeCompressed(); +} + +template +IGL_INLINE void igl::arap_linear_block_elements( + const MatV & V, + const MatF & F, + const int d, + MatK & Kd) +{ + typedef typename MatK::Scalar Scalar; + using namespace std; + using namespace Eigen; + // simplex size (3: triangles, 4: tetrahedra) + int simplex_size = F.cols(); + // Number of elements + int m = F.rows(); + // Temporary output + Kd.resize(V.rows(), F.rows()); + vector > Kd_IJV; + Matrix edges; + if(simplex_size == 3) + { + // triangles + Kd.reserve(7*V.rows()); + Kd_IJV.reserve(7*V.rows()); + edges.resize(3,2); + edges << + 1,2, + 2,0, + 0,1; + }else if(simplex_size == 4) + { + // tets + Kd.reserve(17*V.rows()); + Kd_IJV.reserve(17*V.rows()); + edges.resize(6,2); + edges << + 1,2, + 2,0, + 0,1, + 3,0, + 3,1, + 3,2; + } + // gather cotangent weights + Matrix C; + cotmatrix_entries(V,F,C); + // should have weights for each edge + assert(C.cols() == edges.rows()); + // loop over elements + for(int i = 0;i(source,i,v)); + Kd_IJV.push_back(Triplet(dest,i,-v)); + } + } + Kd.setFromTriplets(Kd_IJV.begin(),Kd_IJV.end()); + Kd.makeCompressed(); +} + + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +template void igl::arap_linear_block >, Eigen::MatrixBase >, Eigen::SparseMatrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, int, igl::ARAPEnergyType, Eigen::SparseMatrix&); +template void igl::arap_linear_block, Eigen::Matrix, Eigen::SparseMatrix >(Eigen::Matrix const&, Eigen::Matrix const&, int, igl::ARAPEnergyType, Eigen::SparseMatrix&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/arap_linear_block.h b/src/external/libigl-2.3.0/include/igl/arap_linear_block.h new file mode 100644 index 000000000..9983550aa --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/arap_linear_block.h @@ -0,0 +1,78 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_ARAP_LINEAR_BLOCK_H +#define IGL_ARAP_LINEAR_BLOCK_H +#include "igl_inline.h" + +#include +#include + +namespace igl +{ + // ARAP_LINEAR_BLOCK constructs a block of the matrix which constructs the + // linear terms of a given arap energy. When treating rotations as knowns + // (arranged in a column) then this constructs Kd of K such that the linear + // portion of the energy is as a column: + // K * R = [Kx Z ... Ky Z ... + // Z Kx ... Z Ky ... + // ... ] + // These blocks are also used to build the "covariance scatter matrices". + // Here we want to build a scatter matrix that multiplies against positions + // (treated as known) producing covariance matrices to fit each rotation. + // Notice that in the case of the RHS of the poisson solve the rotations are + // known and the positions unknown, and vice versa for rotation fitting. + // These linear block just relate the rotations to the positions, linearly in + // each. + // + // Templates: + // MatV vertex position matrix, e.g. Eigen::MatrixXd + // MatF face index matrix, e.g. Eigen::MatrixXd + // Scalar e.g. double + // Inputs: + // V #V by dim list of initial domain positions + // F #F by #simplex size list of triangle indices into V + // d coordinate of linear constructor to build + // energy ARAPEnergyType enum value defining which energy is being used. + // See ARAPEnergyType.h for valid options and explanations. + // Outputs: + // Kd #V by #V/#F block of the linear constructor matrix corresponding to + // coordinate d + // + template + IGL_INLINE void arap_linear_block( + const MatV & V, + const MatF & F, + const int d, + const igl::ARAPEnergyType energy, + MatK & Kd); + // Helper functions for each energy type + template + IGL_INLINE void arap_linear_block_spokes( + const MatV & V, + const MatF & F, + const int d, + MatK & Kd); + template + IGL_INLINE void arap_linear_block_spokes_and_rims( + const MatV & V, + const MatF & F, + const int d, + MatK & Kd); + template + IGL_INLINE void arap_linear_block_elements( + const MatV & V, + const MatF & F, + const int d, + MatK & Kd); +} + +#ifndef IGL_STATIC_LIBRARY +# include "arap_linear_block.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/arap_rhs.cpp b/src/external/libigl-2.3.0/include/igl/arap_rhs.cpp new file mode 100644 index 000000000..0a794e5f0 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/arap_rhs.cpp @@ -0,0 +1,95 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "arap_rhs.h" +#include "arap_linear_block.h" +#include "verbose.h" +#include "repdiag.h" +#include "cat.h" +#include + +template +IGL_INLINE void igl::arap_rhs( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const int dim, + const igl::ARAPEnergyType energy, + Eigen::SparseCompressedBase& K) +{ + using namespace std; + using namespace Eigen; + // Number of dimensions + int Vdim = V.cols(); + //// Number of mesh vertices + //int n = V.rows(); + //// Number of mesh elements + //int m = F.rows(); + //// number of rotations + //int nr; + switch(energy) + { + case ARAP_ENERGY_TYPE_SPOKES: + //nr = n; + break; + case ARAP_ENERGY_TYPE_SPOKES_AND_RIMS: + //nr = n; + break; + case ARAP_ENERGY_TYPE_ELEMENTS: + //nr = m; + break; + default: + fprintf( + stderr, + "arap_rhs.h: Error: Unsupported arap energy %d\n", + energy); + return; + } + + DerivedK KX,KY,KZ; + arap_linear_block(V,F,0,energy,KX); + arap_linear_block(V,F,1,energy,KY); + if(Vdim == 2) + { + K = cat(2,repdiag(KX,dim),repdiag(KY,dim)); + }else if(Vdim == 3) + { + arap_linear_block(V,F,2,energy,KZ); + if(dim == 3) + { + K = cat(2,cat(2,repdiag(KX,dim),repdiag(KY,dim)),repdiag(KZ,dim)); + }else if(dim ==2) + { + DerivedK ZZ(KX.rows()*2,KX.cols()); + K = cat(2,cat(2, + cat(2,repdiag(KX,dim),ZZ), + cat(2,repdiag(KY,dim),ZZ)), + cat(2,repdiag(KZ,dim),ZZ)); + }else + { + assert(false); + fprintf( + stderr, + "arap_rhs.h: Error: Unsupported dimension %d\n", + dim); + } + }else + { + assert(false); + fprintf( + stderr, + "arap_rhs.h: Error: Unsupported dimension %d\n", + Vdim); + return; + } + +} + + + +#ifdef IGL_STATIC_LIBRARY +template void igl::arap_rhs(const Eigen::MatrixBase & V, const Eigen::MatrixBase & F,const int dim, const igl::ARAPEnergyType energy,Eigen::SparseCompressedBase>& K); +#endif \ No newline at end of file diff --git a/src/external/libigl-2.3.0/include/igl/arap_rhs.h b/src/external/libigl-2.3.0/include/igl/arap_rhs.h new file mode 100644 index 000000000..2d456f6bc --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/arap_rhs.h @@ -0,0 +1,43 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_ARAP_RHS_H +#define IGL_ARAP_RHS_H +#include "igl_inline.h" + +#include +#include +#include + +namespace igl +{ + // ARAP_RHS build right-hand side constructor of global poisson solve for + // various Arap energies + // Inputs: + // V #V by Vdim list of initial domain positions + // F #F by 3 list of triangle indices into V + // dim dimension being used at solve time. For deformation usually dim = + // V.cols(), for surface parameterization V.cols() = 3 and dim = 2 + // energy igl::ARAPEnergyType enum value defining which energy is being + // used. See igl::ARAPEnergyType.h for valid options and explanations. + // Outputs: + // K #V*dim by #(F|V)*dim*dim matrix such that: + // b = K * reshape(permute(R,[3 1 2]),size(V|F,1)*size(V,2)*size(V,2),1); + // + // See also: arap_linear_block + template + IGL_INLINE void arap_rhs( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const int dim, + const igl::ARAPEnergyType energy, + Eigen::SparseCompressedBase& K); +} +#ifndef IGL_STATIC_LIBRARY +#include "arap_rhs.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/average_from_edges_onto_vertices.cpp b/src/external/libigl-2.3.0/include/igl/average_from_edges_onto_vertices.cpp new file mode 100644 index 000000000..12c54c58b --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/average_from_edges_onto_vertices.cpp @@ -0,0 +1,68 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2020 Oded Stein +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "average_from_edges_onto_vertices.h" + +template +IGL_INLINE void +igl::average_from_edges_onto_vertices( + const Eigen::MatrixBase &F, + const Eigen::MatrixBase &E, + const Eigen::MatrixBase &oE, + const Eigen::MatrixBase &uE, + Eigen::PlainObjectBase &uV) +{ + using Scalar = typename DeriveduE::Scalar; + using VecX = Eigen::Matrix; + using Int = typename DerivedF::Scalar; + + assert(E.rows()==F.rows() && "E does not match dimensions of F."); + assert(oE.rows()==F.rows() && "oE does not match dimensions of F."); + assert(E.cols()==3 && F.cols()==3 && oE.cols()==3 && + "This method is for triangle meshes."); + + const Int n = F.maxCoeff()+1; + + VecX edgesPerVertex(n); + edgesPerVertex.setZero(); + uV.resize(n,1); + uV.setZero(); + + for(Eigen::Index i=0; i0) { + uV(i) /= valence; + } + } +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +template void igl::average_from_edges_onto_vertices, Eigen::Matrix, Eigen::Matrix, Eigen::PartialReduxExpr, Eigen::internal::member_norm, 1>, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase, Eigen::internal::member_norm, 1> > const&, Eigen::PlainObjectBase >&); +template void igl::average_from_edges_onto_vertices, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::average_from_edges_onto_vertices, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/average_from_edges_onto_vertices.h b/src/external/libigl-2.3.0/include/igl/average_from_edges_onto_vertices.h new file mode 100644 index 000000000..fb290f8b5 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/average_from_edges_onto_vertices.h @@ -0,0 +1,39 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2020 Oded Stein +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_AVERAGE_FROM_EDGES_ONTO_VERTICES_H +#define IGL_AVERAGE_FROM_EDGES_ONTO_VERTICES_H +#include "igl_inline.h" + +#include +namespace igl +{ + // Move a scalar field defined on edges to vertices by averaging + // + // Input: + // F: triangle mesh connectivity + // E, oE: mapping from halfedges to edges and orientation as generated by + // orient_halfedges + // uE: scalar field defined on edges, one per edge + // + // Output: + // uV: scalar field defined on vertices + template + IGL_INLINE void average_from_edges_onto_vertices( + const Eigen::MatrixBase &F, + const Eigen::MatrixBase &E, + const Eigen::MatrixBase &oE, + const Eigen::MatrixBase &uE, + Eigen::PlainObjectBase &uV); +} + +#ifndef IGL_STATIC_LIBRARY +# include "average_from_edges_onto_vertices.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/average_onto_faces.cpp b/src/external/libigl-2.3.0/include/igl/average_onto_faces.cpp new file mode 100644 index 000000000..b62c5e81a --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/average_onto_faces.cpp @@ -0,0 +1,27 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "average_onto_faces.h" + +template +IGL_INLINE void igl::average_onto_faces( + const Eigen::MatrixBase & F, + const Eigen::MatrixBase & S, + Eigen::PlainObjectBase & SF) +{ + SF.setConstant(F.rows(),S.cols(),0); + for (int i = 0; i , Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/average_onto_faces.h b/src/external/libigl-2.3.0/include/igl/average_onto_faces.h new file mode 100644 index 000000000..6fc358b79 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/average_onto_faces.h @@ -0,0 +1,34 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_AVERAGE_ONTO_FACES_H +#define IGL_AVERAGE_ONTO_FACES_H +#include "igl_inline.h" + +#include +namespace igl +{ + // average_onto_vertices + // Move a scalar field defined on faces to vertices by averaging + // + // Input: + // F #F by ss list of simples/faces + // S #V by dim list of per-vertex values + // Output: + // SF #F by dim list of per-face values + template + IGL_INLINE void average_onto_faces( + const Eigen::MatrixBase & F, + const Eigen::MatrixBase & S, + Eigen::PlainObjectBase & SF); +} + +#ifndef IGL_STATIC_LIBRARY +# include "average_onto_faces.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/average_onto_vertices.cpp b/src/external/libigl-2.3.0/include/igl/average_onto_vertices.cpp new file mode 100644 index 000000000..599460570 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/average_onto_vertices.cpp @@ -0,0 +1,33 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "average_onto_vertices.h" + +template +IGL_INLINE void igl::average_onto_vertices(const Eigen::MatrixBase &V, + const Eigen::MatrixBase &F, + const Eigen::MatrixBase &S, + Eigen::PlainObjectBase &SV) +{ + SV = DerivedS::Zero(V.rows(),S.cols()); + Eigen::Matrix COUNT(V.rows()); + COUNT.setZero(); + for (int i = 0; i +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_AVERAGE_ONTO_VERTICES_H +#define IGL_AVERAGE_ONTO_VERTICES_H +#include "igl_inline.h" + +#include +namespace igl +{ + // average_onto_vertices + // Move a scalar field defined on faces to vertices by averaging + // + // Input: + // V,F: mesh + // S: scalar field defined on faces, Fx1 + // + // Output: + // SV: scalar field defined on vertices + template + IGL_INLINE void average_onto_vertices(const Eigen::MatrixBase &V, + const Eigen::MatrixBase &F, + const Eigen::MatrixBase &S, + Eigen::PlainObjectBase &SV); +} + +#ifndef IGL_STATIC_LIBRARY +# include "average_onto_vertices.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/avg_edge_length.cpp b/src/external/libigl-2.3.0/include/igl/avg_edge_length.cpp new file mode 100644 index 000000000..b06d9ce5e --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/avg_edge_length.cpp @@ -0,0 +1,39 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "avg_edge_length.h" +#include "edges.h" + +#include + +template +IGL_INLINE double igl::avg_edge_length( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F) +{ + typedef typename DerivedF::Scalar Index; + Eigen::Matrix E; + + igl::edges(F, E); + + double avg = 0; + + for (unsigned i=0;i, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&); +template double igl::avg_edge_length, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&); +// generated by autoexplicit.sh +#endif diff --git a/src/external/libigl-2.3.0/include/igl/avg_edge_length.h b/src/external/libigl-2.3.0/include/igl/avg_edge_length.h new file mode 100644 index 000000000..3c224bfa4 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/avg_edge_length.h @@ -0,0 +1,41 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_AVERAGEEDGELENGTH_H +#define IGL_AVERAGEEDGELENGTH_H + +#include "igl_inline.h" +#include +#include +#include + +namespace igl +{ + // Compute the average edge length for the given triangle mesh + // Templates: + // DerivedV derived from vertex positions matrix type: i.e. MatrixXd + // DerivedF derived from face indices matrix type: i.e. MatrixXi + // DerivedL derived from edge lengths matrix type: i.e. MatrixXd + // Inputs: + // V eigen matrix #V by 3 + // F #F by simplex-size list of mesh faces (must be simplex) + // Outputs: + // l average edge length + // + // See also: adjacency_matrix + template + IGL_INLINE double avg_edge_length( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F); + +} + +#ifndef IGL_STATIC_LIBRARY +# include "avg_edge_length.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/axis_angle_to_quat.cpp b/src/external/libigl-2.3.0/include/igl/axis_angle_to_quat.cpp new file mode 100644 index 000000000..009d0522c --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/axis_angle_to_quat.cpp @@ -0,0 +1,42 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "axis_angle_to_quat.h" +#include "EPS.h" +#include + +// http://www.antisphere.com/Wiki/tools:anttweakbar +template +IGL_INLINE void igl::axis_angle_to_quat( + const Q_type *axis, + const Q_type angle, + Q_type *out) +{ + Q_type n = axis[0]*axis[0] + axis[1]*axis[1] + axis[2]*axis[2]; + if( fabs(n)>igl::EPS()) + { + Q_type f = 0.5*angle; + out[3] = cos(f); + f = sin(f)/sqrt(n); + out[0] = axis[0]*f; + out[1] = axis[1]*f; + out[2] = axis[2]*f; + } + else + { + out[3] = 1.0; + out[0] = out[1] = out[2] = 0.0; + } +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::axis_angle_to_quat(double const*, double, double*); +// generated by autoexplicit.sh +template void igl::axis_angle_to_quat(float const*, float, float*); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/axis_angle_to_quat.h b/src/external/libigl-2.3.0/include/igl/axis_angle_to_quat.h new file mode 100644 index 000000000..6533b1bec --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/axis_angle_to_quat.h @@ -0,0 +1,33 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_AXIS_ANGLE_TO_QUAT_H +#define IGL_AXIS_ANGLE_TO_QUAT_H +#include "igl_inline.h" + +namespace igl +{ + // Convert axis angle representation of a rotation to a quaternion + // A Quaternion, q, is defined here as an arrays of four scalars (x,y,z,w), + // such that q = x*i + y*j + z*k + w + // Inputs: + // axis 3d vector + // angle scalar + // Outputs: + // quaternion + template + IGL_INLINE void axis_angle_to_quat( + const Q_type *axis, + const Q_type angle, + Q_type *out); +} + +#ifndef IGL_STATIC_LIBRARY +# include "axis_angle_to_quat.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/barycenter.cpp b/src/external/libigl-2.3.0/include/igl/barycenter.cpp new file mode 100644 index 000000000..55ac5e18b --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/barycenter.cpp @@ -0,0 +1,56 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "barycenter.h" + +template < + typename DerivedV, + typename DerivedF, + typename DerivedBC> +IGL_INLINE void igl::barycenter( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + Eigen::PlainObjectBase & BC) +{ + BC.setZero(F.rows(),V.cols()); + // Loop over faces + for(int i = 0;i, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::barycenter, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::barycenter, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::barycenter, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::barycenter, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::barycenter, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::barycenter, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::barycenter, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::barycenter, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::barycenter, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::barycenter, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::barycenter, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::barycenter, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::barycenter, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::barycenter, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::barycenter, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::barycenter, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::barycenter, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::barycenter, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/barycenter.h b/src/external/libigl-2.3.0/include/igl/barycenter.h new file mode 100644 index 000000000..ef78e94a6 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/barycenter.h @@ -0,0 +1,36 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_BARYCENTER_H +#define IGL_BARYCENTER_H +#include "igl_inline.h" +#include +namespace igl +{ + // Computes the barycenter of every simplex + // + // Inputs: + // V #V x dim matrix of vertex coordinates + // F #F x simplex_size matrix of indices of simplex corners into V + // Output: + // BC #F x dim matrix of 3d vertices + // + template < + typename DerivedV, + typename DerivedF, + typename DerivedBC> + IGL_INLINE void barycenter( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + Eigen::PlainObjectBase & BC); +} + +#ifndef IGL_STATIC_LIBRARY +# include "barycenter.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/barycentric_coordinates.cpp b/src/external/libigl-2.3.0/include/igl/barycentric_coordinates.cpp new file mode 100644 index 000000000..998a737bf --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/barycentric_coordinates.cpp @@ -0,0 +1,113 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "barycentric_coordinates.h" +#include "volume.h" + +template < + typename DerivedP, + typename DerivedA, + typename DerivedB, + typename DerivedC, + typename DerivedD, + typename DerivedL> +IGL_INLINE void igl::barycentric_coordinates( + const Eigen::MatrixBase & P, + const Eigen::MatrixBase & A, + const Eigen::MatrixBase & B, + const Eigen::MatrixBase & C, + const Eigen::MatrixBase & D, + Eigen::PlainObjectBase & L) +{ + using namespace Eigen; + assert(P.cols() == 3 && "query must be in 3d"); + assert(A.cols() == 3 && "corners must be in 3d"); + assert(B.cols() == 3 && "corners must be in 3d"); + assert(C.cols() == 3 && "corners must be in 3d"); + assert(D.cols() == 3 && "corners must be in 3d"); + assert(P.rows() == A.rows() && "Must have same number of queries as corners"); + assert(A.rows() == B.rows() && "Corners must be same size"); + assert(A.rows() == C.rows() && "Corners must be same size"); + assert(A.rows() == D.rows() && "Corners must be same size"); + typedef Matrix + VectorXS; + // Total volume + VectorXS vol,LA,LB,LC,LD; + volume(B,D,C,P,LA); + volume(A,C,D,P,LB); + volume(A,D,B,P,LC); + volume(A,B,C,P,LD); + volume(A,B,C,D,vol); + L.resize(P.rows(),4); + L< +IGL_INLINE void igl::barycentric_coordinates( + const Eigen::MatrixBase & P, + const Eigen::MatrixBase & A, + const Eigen::MatrixBase & B, + const Eigen::MatrixBase & C, + Eigen::PlainObjectBase & L) +{ + using namespace Eigen; +#ifndef NDEBUG + const int DIM = P.cols(); + assert(A.cols() == DIM && "corners must be in same dimension as query"); + assert(B.cols() == DIM && "corners must be in same dimension as query"); + assert(C.cols() == DIM && "corners must be in same dimension as query"); + assert(P.rows() == A.rows() && "Must have same number of queries as corners"); + assert(A.rows() == B.rows() && "Corners must be same size"); + assert(A.rows() == C.rows() && "Corners must be same size"); +#endif + + // http://gamedev.stackexchange.com/a/23745 + typedef + Eigen::Array< + typename DerivedP::Scalar, + DerivedP::RowsAtCompileTime, + DerivedP::ColsAtCompileTime> + ArrayS; + typedef + Eigen::Array< + typename DerivedP::Scalar, + DerivedP::RowsAtCompileTime, + 1> + VectorS; + + const ArrayS v0 = B.array() - A.array(); + const ArrayS v1 = C.array() - A.array(); + const ArrayS v2 = P.array() - A.array(); + VectorS d00 = (v0*v0).rowwise().sum(); + VectorS d01 = (v0*v1).rowwise().sum(); + VectorS d11 = (v1*v1).rowwise().sum(); + VectorS d20 = (v2*v0).rowwise().sum(); + VectorS d21 = (v2*v1).rowwise().sum(); + VectorS denom = d00 * d11 - d01 * d01; + L.resize(P.rows(),3); + L.col(1) = (d11 * d20 - d01 * d21) / denom; + L.col(2) = (d00 * d21 - d01 * d20) / denom; + L.col(0) = 1.0f -(L.col(1) + L.col(2)).array(); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +template void igl::barycentric_coordinates, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::barycentric_coordinates, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::barycentric_coordinates, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::barycentric_coordinates, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::barycentric_coordinates, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::barycentric_coordinates, Eigen::Block const, 1, -1, false>, Eigen::Block const, 1, -1, false>, Eigen::Block const, 1, -1, false>, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase const, 1, -1, false> > const&, Eigen::MatrixBase const, 1, -1, false> > const&, Eigen::MatrixBase const, 1, -1, false> > const&, Eigen::PlainObjectBase >&); +template void igl::barycentric_coordinates, Eigen::Block const, 1, -1, false>, Eigen::Block const, 1, -1, false>, Eigen::Block const, 1, -1, false>, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase const, 1, -1, false> > const&, Eigen::MatrixBase const, 1, -1, false> > const&, Eigen::MatrixBase const, 1, -1, false> > const&, Eigen::PlainObjectBase >&); +template void igl::barycentric_coordinates, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/barycentric_coordinates.h b/src/external/libigl-2.3.0/include/igl/barycentric_coordinates.h new file mode 100644 index 000000000..ec08669f2 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/barycentric_coordinates.h @@ -0,0 +1,68 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_BARYCENTRIC_COORDINATES_H +#define IGL_BARYCENTRIC_COORDINATES_H +#include "igl_inline.h" +#include +namespace igl +{ + // Compute barycentric coordinates in a tet + // + // Inputs: + // P #P by 3 Query points in 3d + // A #P by 3 Tet corners in 3d + // B #P by 3 Tet corners in 3d + // C #P by 3 Tet corners in 3d + // D #P by 3 Tet corners in 3d + // Outputs: + // L #P by 4 list of barycentric coordinates + // + template < + typename DerivedP, + typename DerivedA, + typename DerivedB, + typename DerivedC, + typename DerivedD, + typename DerivedL> + IGL_INLINE void barycentric_coordinates( + const Eigen::MatrixBase & P, + const Eigen::MatrixBase & A, + const Eigen::MatrixBase & B, + const Eigen::MatrixBase & C, + const Eigen::MatrixBase & D, + Eigen::PlainObjectBase & L); + // Compute barycentric coordinates in a triangle + // + // Inputs: + // P #P by dim Query points + // A #P by dim Triangle corners + // B #P by dim Triangle corners + // C #P by dim Triangle corners + // Outputs: + // L #P by 3 list of barycentric coordinates + // + template < + typename DerivedP, + typename DerivedA, + typename DerivedB, + typename DerivedC, + typename DerivedL> + IGL_INLINE void barycentric_coordinates( + const Eigen::MatrixBase & P, + const Eigen::MatrixBase & A, + const Eigen::MatrixBase & B, + const Eigen::MatrixBase & C, + Eigen::PlainObjectBase & L); + +} + +#ifndef IGL_STATIC_LIBRARY +# include "barycentric_coordinates.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/barycentric_interpolation.cpp b/src/external/libigl-2.3.0/include/igl/barycentric_interpolation.cpp new file mode 100644 index 000000000..0e1c63e98 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/barycentric_interpolation.cpp @@ -0,0 +1,42 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2020 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "barycentric_interpolation.h" +#include "parallel_for.h" + +template < + typename DerivedD, + typename DerivedF, + typename DerivedB, + typename DerivedI, + typename DerivedX> +IGL_INLINE void igl::barycentric_interpolation( + const Eigen::MatrixBase & D, + const Eigen::MatrixBase & F, + const Eigen::MatrixBase & B, + const Eigen::MatrixBase & I, + Eigen::PlainObjectBase & X) +{ + assert(B.rows() == I.size()); + assert(F.cols() == B.cols()); + X.setZero(B.rows(),D.cols()); + // should use parallel_for + //for(int i = 0;i, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/barycentric_interpolation.h b/src/external/libigl-2.3.0/include/igl/barycentric_interpolation.h new file mode 100644 index 000000000..3255c6eb8 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/barycentric_interpolation.h @@ -0,0 +1,42 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2020 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_BARYCENTRIC_INTERPOLATION_H +#define IGL_BARYCENTRIC_INTERPOLATION_H +#include "igl_inline.h" +#include +namespace igl +{ + // Interpolate data on a triangle mesh using barycentric coordinates + // + // Inputs: + // D #D by dim list of per-vertex data + // F #F by 3 list of triangle indices + // B #X by 3 list of barycentric corodinates + // I #X list of triangle indices + // Outputs: + // X #X by dim list of interpolated data + template < + typename DerivedD, + typename DerivedF, + typename DerivedB, + typename DerivedI, + typename DerivedX> + IGL_INLINE void barycentric_interpolation( + const Eigen::MatrixBase & D, + const Eigen::MatrixBase & F, + const Eigen::MatrixBase & B, + const Eigen::MatrixBase & I, + Eigen::PlainObjectBase & X); +} + +#ifndef IGL_STATIC_LIBRARY +# include "barycentric_interpolation.cpp" +#endif + +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/basename.cpp b/src/external/libigl-2.3.0/include/igl/basename.cpp new file mode 100644 index 000000000..ae4fb118e --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/basename.cpp @@ -0,0 +1,38 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "basename.h" + +#include + +IGL_INLINE std::string igl::basename(const std::string & path) +{ + if(path == "") + { + return std::string(""); + } + // http://stackoverflow.com/questions/5077693/dirnamephp-similar-function-in-c + std::string::const_reverse_iterator last_slash = + std::find( + path.rbegin(), + path.rend(), '/'); + if( last_slash == path.rend() ) + { + // No slashes found + return path; + }else if(1 == (last_slash.base() - path.begin())) + { + // Slash is first char + return std::string(path.begin()+1,path.end()); + }else if(path.end() == last_slash.base() ) + { + // Slash is last char + std::string redo = std::string(path.begin(),path.end()-1); + return igl::basename(redo); + } + return std::string(last_slash.base(),path.end()); +} diff --git a/src/external/libigl-2.3.0/include/igl/basename.h b/src/external/libigl-2.3.0/include/igl/basename.h new file mode 100644 index 000000000..fb333b5c4 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/basename.h @@ -0,0 +1,29 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_BASENAME_H +#define IGL_BASENAME_H +#include "igl_inline.h" + +#include + +namespace igl +{ + // Function like PHP's basename: /etc/sudoers.d --> sudoers.d + // Input: + // path string containing input path + // Returns string containing basename (see php's basename) + // + // See also: dirname, pathinfo + IGL_INLINE std::string basename(const std::string & path); +} + +#ifndef IGL_STATIC_LIBRARY +# include "basename.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/bbw.cpp b/src/external/libigl-2.3.0/include/igl/bbw.cpp new file mode 100644 index 000000000..8193ed223 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/bbw.cpp @@ -0,0 +1,148 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "bbw.h" +#include "min_quad_with_fixed.h" +#include "harmonic.h" +#include "parallel_for.h" +#include +#include +#include +#include + +igl::BBWData::BBWData(): + partition_unity(false), + W0(), + active_set_params(), + verbosity(0) +{ + // We know that the Bilaplacian is positive semi-definite + active_set_params.Auu_pd = true; +} + +void igl::BBWData::print() +{ + using namespace std; + cout<<"partition_unity: "< +IGL_INLINE bool igl::bbw( + const Eigen::PlainObjectBase & V, + const Eigen::PlainObjectBase & Ele, + const Eigen::PlainObjectBase & b, + const Eigen::PlainObjectBase & bc, + igl::BBWData & data, + Eigen::PlainObjectBase & W + ) +{ + using namespace std; + using namespace Eigen; + assert(!data.partition_unity && "partition_unity not implemented yet"); + // number of domain vertices + int n = V.rows(); + // number of handles + int m = bc.cols(); + // Build biharmonic operator + Eigen::SparseMatrix Q; + harmonic(V,Ele,2,Q); + W.derived().resize(n,m); + // No linear terms + VectorXd c = VectorXd::Zero(n); + // No linear constraints + SparseMatrix A(0,n),Aeq(0,n),Aieq(0,n); + VectorXd Beq(0,1),Bieq(0,1); + // Upper and lower box constraints (Constant bounds) + VectorXd ux = VectorXd::Ones(n); + VectorXd lx = VectorXd::Zero(n); + active_set_params eff_params = data.active_set_params; + if(data.verbosity >= 1) + { + cout<<"BBW: max_iter: "<= 1) + { + cout<<"BBW: Computing initial weights for "< mqwf; + min_quad_with_fixed_precompute(Q,b,Aeq,true,mqwf); + min_quad_with_fixed_solve(mqwf,c,bc,Beq,W); + // decrement + eff_params.max_iter--; + bool error = false; + // Loop over handles + std::mutex critical; + const auto & optimize_weight = [&](const int i) + { + // Quicker exit for paralle_for + if(error) + { + return; + } + if(data.verbosity >= 1) + { + std::lock_guard lock(critical); + cout<<"BBW: Computing weight for handle "<, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, igl::BBWData&, Eigen::PlainObjectBase >&); +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/bbw.h b/src/external/libigl-2.3.0/include/igl/bbw.h new file mode 100644 index 000000000..bec20bb98 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/bbw.h @@ -0,0 +1,77 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_BBW_H +#define IGL_BBW_H +#include "igl_inline.h" + +#include +#include + +namespace igl +{ + // Container for BBW computation related data and flags + class BBWData + { + public: + // Enforce partition of unity during optimization (optimize all weight + // simultaneously) + bool partition_unity; + // Initial guess + Eigen::MatrixXd W0; + igl::active_set_params active_set_params; + // Verbosity level + // 0: quiet + // 1: loud + // 2: louder + int verbosity; + public: + IGL_INLINE BBWData(); + // Print current state of object + IGL_INLINE void print(); + }; + + // Compute Bounded Biharmonic Weights on a given domain (V,Ele) with a given + // set of boundary conditions + // + // Templates + // DerivedV derived type of eigen matrix for V (e.g. MatrixXd) + // DerivedF derived type of eigen matrix for F (e.g. MatrixXi) + // Derivedb derived type of eigen matrix for b (e.g. VectorXi) + // Derivedbc derived type of eigen matrix for bc (e.g. MatrixXd) + // DerivedW derived type of eigen matrix for W (e.g. MatrixXd) + // Inputs: + // V #V by dim vertex positions + // Ele #Elements by simplex-size list of element indices + // b #b boundary indices into V + // bc #b by #W list of boundary values + // data object containing options, initial guess --> solution and results + // Outputs: + // W #V by #W list of *unnormalized* weights to normalize use + // igl::normalize_row_sums(W,W); + // Returns true on success, false on failure + template < + typename DerivedV, + typename DerivedEle, + typename Derivedb, + typename Derivedbc, + typename DerivedW> + IGL_INLINE bool bbw( + const Eigen::PlainObjectBase & V, + const Eigen::PlainObjectBase & Ele, + const Eigen::PlainObjectBase & b, + const Eigen::PlainObjectBase & bc, + BBWData & data, + Eigen::PlainObjectBase & W); +} + +#ifndef IGL_STATIC_LIBRARY +# include "bbw.cpp" +#endif + +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/bezier.cpp b/src/external/libigl-2.3.0/include/igl/bezier.cpp new file mode 100644 index 000000000..9cca6cbff --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/bezier.cpp @@ -0,0 +1,74 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2020 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "bezier.h" +#include + +// Adapted from main.c accompanying +// An Algorithm for Automatically Fitting Digitized Curves +// by Philip J. Schneider +// from "Graphics Gems", Academic Press, 1990 +template +IGL_INLINE void igl::bezier( + const Eigen::MatrixBase & V, + const typename DerivedV::Scalar t, + Eigen::PlainObjectBase & P) +{ + // working local copy + DerivedV Vtemp = V; + int degree = Vtemp.rows()-1; + /* Triangle computation */ + for (int i = 1; i <= degree; i++) + { + for (int j = 0; j <= degree-i; j++) + { + Vtemp.row(j) = ((1.0 - t) * Vtemp.row(j) + t * Vtemp.row(j+1)).eval(); + } + } + P = Vtemp.row(0); +} + +template +IGL_INLINE void igl::bezier( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & T, + Eigen::PlainObjectBase & P) +{ + P.resize(T.size(),V.cols()); + for(int i = 0;i Pi; + bezier(V,T(i),Pi); + P.row(i) = Pi; + } +} + +template +IGL_INLINE void igl::bezier( + const std::vector & spline, + const Eigen::MatrixBase & T, + Eigen::PlainObjectBase & P) +{ + if(spline.size() == 0) return; + const int m = T.rows(); + const int dim = spline[0].cols(); + P.resize(m*spline.size(),dim); + for(int c = 0;c, Eigen::Matrix, Eigen::Matrix >(std::vector, std::allocator > > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::bezier, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::bezier, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::Matrix::Scalar, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/bezier.h b/src/external/libigl-2.3.0/include/igl/bezier.h new file mode 100644 index 000000000..4e0dbbbb2 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/bezier.h @@ -0,0 +1,51 @@ +#ifndef BEZIER_H +#define BEZIER_H +#include "igl_inline.h" +#include +#include +namespace igl +{ + // Evaluate a polynomial Bezier Curve. + // + // Inputs: + // V #V by dim list of Bezier control points + // t evaluation parameter within [0,1] + // Outputs: + // P 1 by dim output point + template + IGL_INLINE void bezier( + const Eigen::MatrixBase & V, + const typename DerivedV::Scalar t, + Eigen::PlainObjectBase & P); + // Evaluate a polynomial Bezier Curve. + // + // Inputs: + // V #V by dim list of Bezier control points + // T #T evaluation parameters within [0,1] + // Outputs: + // P #T by dim output points + template + IGL_INLINE void bezier( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & T, + Eigen::PlainObjectBase & P); + // Evaluate a polynomial Bezier spline with a fixed parameter set for each + // sub-curve + // + // Inputs: + // spline #curves list of lists of Bezier control points + // T #T evaluation parameters within [0,1] to use for each spline + // Outputs: + // P #curves*#T by dim output points + template + IGL_INLINE void bezier( + const std::vector & spline, + const Eigen::MatrixBase & T, + Eigen::PlainObjectBase & P); +} + +#ifndef IGL_STATIC_LIBRARY +# include "bezier.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/bfs.cpp b/src/external/libigl-2.3.0/include/igl/bfs.cpp new file mode 100644 index 000000000..076c8a40b --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/bfs.cpp @@ -0,0 +1,93 @@ +#include "bfs.h" +#include "list_to_matrix.h" +#include +#include + +template < + typename AType, + typename DerivedD, + typename DerivedP> +IGL_INLINE void igl::bfs( + const AType & A, + const size_t s, + Eigen::PlainObjectBase & D, + Eigen::PlainObjectBase & P) +{ + std::vector vD; + std::vector vP; + bfs(A,s,vD,vP); + list_to_matrix(vD,D); + list_to_matrix(vP,P); +} + +template < + typename AType, + typename DType, + typename PType> +IGL_INLINE void igl::bfs( + const std::vector > & A, + const size_t s, + std::vector & D, + std::vector & P) +{ + // number of nodes + int N = s+1; + for(const auto & Ai : A) for(const auto & a : Ai) N = std::max(N,a+1); + std::vector seen(N,false); + P.resize(N,-1); + std::queue > Q; + Q.push({s,-1}); + while(!Q.empty()) + { + const int f = Q.front().first; + const int p = Q.front().second; + Q.pop(); + if(seen[f]) + { + continue; + } + D.push_back(f); + P[f] = p; + seen[f] = true; + for(const auto & n : A[f]) Q.push({n,f}); + } +} + + +template < + typename AType, + typename DType, + typename PType> +IGL_INLINE void igl::bfs( + const Eigen::SparseCompressedBase & A, + const size_t s, + std::vector & D, + std::vector & P) +{ + // number of nodes + int N = A.rows(); + assert(A.rows() == A.cols()); + std::vector seen(N,false); + P.resize(N,-1); + std::queue > Q; + Q.push({s,-1}); + while(!Q.empty()) + { + const int f = Q.front().first; + const int p = Q.front().second; + Q.pop(); + if(seen[f]) + { + continue; + } + D.push_back(f); + P[f] = p; + seen[f] = true; + for(typename AType::InnerIterator it (A,f); it; ++it) + { + if(it.value()) Q.push({it.index(),f}); + } + } + +} + diff --git a/src/external/libigl-2.3.0/include/igl/bfs.h b/src/external/libigl-2.3.0/include/igl/bfs.h new file mode 100644 index 000000000..e1c761b38 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/bfs.h @@ -0,0 +1,54 @@ +#ifndef IGL_BFS_H +#define IGL_BFS_H +#include "igl_inline.h" +#include +#include +#include +namespace igl +{ + // Traverse a **directed** graph represented by an adjacency list using + // breadth first search + // + // Inputs: + // A #V list of adjacency lists or #V by #V adjacency matrix + // s starting node (index into A) + // Outputs: + // D #V list of indices into rows of A in the order in which graph nodes + // are discovered. + // P #V list of indices into rows of A of predecessor in resulting + // spanning tree {-1 indicates root/not discovered), order corresponds to + // V **not** D. + template < + typename AType, + typename DerivedD, + typename DerivedP> + IGL_INLINE void bfs( + const AType & A, + const size_t s, + Eigen::PlainObjectBase & D, + Eigen::PlainObjectBase & P); + + template < + typename AType, + typename DType, + typename PType> + IGL_INLINE void bfs( + const std::vector > & A, + const size_t s, + std::vector & D, + std::vector & P); + template < + typename AType, + typename DType, + typename PType> + IGL_INLINE void bfs( + const Eigen::SparseCompressedBase & A, + const size_t s, + std::vector & D, + std::vector & P); +} +#ifndef IGL_STATIC_LIBRARY +# include "bfs.cpp" +#endif +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/bfs_orient.cpp b/src/external/libigl-2.3.0/include/igl/bfs_orient.cpp new file mode 100644 index 000000000..2a8c6f083 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/bfs_orient.cpp @@ -0,0 +1,100 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "bfs_orient.h" +#include "orientable_patches.h" +#include +#include + +template +IGL_INLINE void igl::bfs_orient( + const Eigen::MatrixBase & F, + Eigen::PlainObjectBase & FF, + Eigen::PlainObjectBase & C) +{ + using namespace Eigen; + using namespace std; + SparseMatrix A; + orientable_patches(F,C,A); + + // number of faces + const int m = F.rows(); + // number of patches + const int num_cc = C.maxCoeff()+1; + VectorXi seen = VectorXi::Zero(m); + + // Edge sets + const int ES[3][2] = {{1,2},{2,0},{0,1}}; + + if(((void*)&FF) != ((void*)&F)) + { + FF = F; + } + // loop over patches +#pragma omp parallel for + for(int c = 0;c Q; + // find first member of patch c + for(int f = 0;f 0) + { + continue; + } + seen(f)++; + // loop over neighbors of f + for(typename SparseMatrix::InnerIterator it (A,f); it; ++it) + { + // might be some lingering zeros, and skip self-adjacency + if(it.value() != 0 && it.row() != f) + { + const int n = it.row(); + assert(n != f); + // loop over edges of f + for(int efi = 0;efi<3;efi++) + { + // efi'th edge of face f + Vector2i ef(FF(f,ES[efi][0]),FF(f,ES[efi][1])); + // loop over edges of n + for(int eni = 0;eni<3;eni++) + { + // eni'th edge of face n + Vector2i en(FF(n,ES[eni][0]),FF(n,ES[eni][1])); + // Match (half-edges go same direction) + if(ef(0) == en(0) && ef(1) == en(1)) + { + // flip face n + FF.row(n) = FF.row(n).reverse().eval(); + } + } + } + // add neighbor to queue + Q.push(n); + } + } + } + } + + // make sure flip is OK if &FF = &F +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +template void igl::bfs_orient, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/bfs_orient.h b/src/external/libigl-2.3.0/include/igl/bfs_orient.h new file mode 100644 index 000000000..6c08592ca --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/bfs_orient.h @@ -0,0 +1,36 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_BFS_ORIENT_H +#define IGL_BFS_ORIENT_H +#include +#include + +namespace igl +{ + // Consistently orient faces in orientable patches using BFS + // + // F = bfs_orient(F,V); + // + // Inputs: + // F #F by 3 list of faces + // Outputs: + // FF #F by 3 list of faces (OK if same as F) + // C #F list of component ids + // + // + template + IGL_INLINE void bfs_orient( + const Eigen::MatrixBase & F, + Eigen::PlainObjectBase & FF, + Eigen::PlainObjectBase & C); +} +#ifndef IGL_STATIC_LIBRARY +# include "bfs_orient.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/biharmonic_coordinates.cpp b/src/external/libigl-2.3.0/include/igl/biharmonic_coordinates.cpp new file mode 100644 index 000000000..e3b3a3a6a --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/biharmonic_coordinates.cpp @@ -0,0 +1,207 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "biharmonic_coordinates.h" +#include "cotmatrix.h" +#include "sum.h" +#include "massmatrix.h" +#include "min_quad_with_fixed.h" +#include "crouzeix_raviart_massmatrix.h" +#include "crouzeix_raviart_cotmatrix.h" +#include "normal_derivative.h" +#include "on_boundary.h" +#include + +template < + typename DerivedV, + typename DerivedT, + typename SType, + typename DerivedW> +IGL_INLINE bool igl::biharmonic_coordinates( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & T, + const std::vector > & S, + Eigen::PlainObjectBase & W) +{ + return biharmonic_coordinates(V,T,S,2,W); +} + +template < + typename DerivedV, + typename DerivedT, + typename SType, + typename DerivedW> +IGL_INLINE bool igl::biharmonic_coordinates( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & T, + const std::vector > & S, + const int k, + Eigen::PlainObjectBase & W) +{ + using namespace Eigen; + using namespace std; + + typedef typename DerivedV::Scalar Scalar; + typedef typename DerivedT::Scalar Integer; + + // This is not the most efficient way to build A, but follows "Linear + // Subspace Design for Real-Time Shape Deformation" [Wang et al. 2015]. + SparseMatrix A; + { + DiagonalMatrix Minv; + SparseMatrix L, K; + Array C; + { + Array I; + on_boundary(T,I,C); + } +#ifdef false + // Version described in paper is "wrong" + // http://www.cs.toronto.edu/~jacobson/images/error-in-linear-subspace-design-for-real-time-shape-deformation-2017-wang-et-al.pdf + SparseMatrix N, Z, M; + normal_derivative(V,T,N); + { + std::vector> ZIJV; + for(int t =0;t)M.diagonal()).array().abs().maxCoeff(); + Minv = + ((Matrix)M.diagonal().array().inverse()).asDiagonal(); +#else + Eigen::SparseMatrix M; + Eigen::Matrix E; + Eigen::Matrix EMAP; + crouzeix_raviart_massmatrix(V,T,M,E,EMAP); + crouzeix_raviart_cotmatrix(V,T,E,EMAP,L); + // Ad #E by #V facet-vertex incidence matrix + Eigen::SparseMatrix Ad(E.rows(),V.rows()); + { + std::vector> AIJV(E.size()); + for(int e = 0;e(e, E(e, c), 1); + } + } + Ad.setFromTriplets(AIJV.begin(),AIJV.end()); + } + // Degrees + Eigen::Matrix De; + sum(Ad,2,De); + Eigen::DiagonalMatrix De_diag = + De.array().inverse().matrix().asDiagonal(); + K = L*(De_diag*Ad); + // normalize + M /= ((Matrix)M.diagonal()).array().abs().maxCoeff(); + Minv = ((Matrix)M.diagonal().array().inverse()).asDiagonal(); + // kill boundary edges + for(int f = 0;f & h){return h.size()==1;}); + // number of region handles + const size_t r = S.size()-mp; + // Vertices in region handles + size_t mr = 0; + for(const auto & h : S) + { + if(h.size() > 1) + { + mr += h.size(); + } + } + const size_t dim = T.cols()-1; + // Might as well be dense... I think... + Matrix J = Matrix::Zero(mp+mr,mp+r*(dim+1)); + Matrix b(mp+mr); + Matrix H(mp+r*(dim+1),dim); + { + int v = 0; + int c = 0; + for(int h = 0;h= dim+1); + for(int p = 0;p::Zero(A.rows()).eval(),b,J,SparseMatrix(),Matrix(),true,W); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +template bool igl::biharmonic_coordinates, Eigen::Matrix, int, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, std::vector >, std::allocator > > > const&, int, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/biharmonic_coordinates.h b/src/external/libigl-2.3.0/include/igl/biharmonic_coordinates.h new file mode 100644 index 000000000..583eee386 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/biharmonic_coordinates.h @@ -0,0 +1,90 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_BIHARMONIC_COORDINATES_H +#define IGL_BIHARMONIC_COORDINATES_H +#include "igl_inline.h" +#include +#include +namespace igl +{ + // Compute "discrete biharmonic generalized barycentric coordinates" as + // described in "Linear Subspace Design for Real-Time Shape Deformation" + // [Wang et al. 2015]. Not to be confused with "Bounded Biharmonic Weights + // for Real-Time Deformation" [Jacobson et al. 2011] or "Biharmonic + // Coordinates" (2D complex barycentric coordinates) [Weber et al. 2012]. + // These weights minimize a discrete version of the squared Laplacian energy + // subject to positional interpolation constraints at selected vertices + // (point handles) and transformation interpolation constraints at regions + // (region handles). + // + // Templates: + // HType should be a simple index type e.g. `int`,`size_t` + // Inputs: + // V #V by dim list of mesh vertex positions + // T #T by dim+1 list of / triangle indices into V if dim=2 + // \ tetrahedron indices into V if dim=3 + // S #point-handles+#region-handles list of lists of selected vertices for + // each handle. Point handles should have singleton lists and region + // handles should have lists of size at least dim+1 (and these points + // should be in general position). + // Outputs: + // W #V by #points-handles+(#region-handles * dim+1) matrix of weights so + // that columns correspond to each handles generalized barycentric + // coordinates (for point-handles) or animation space weights (for region + // handles). + // returns true only on success + // + // Example: + // + // MatrixXd W; + // igl::biharmonic_coordinates(V,F,S,W); + // const size_t dim = T.cols()-1; + // MatrixXd H(W.cols(),dim); + // { + // int c = 0; + // for(int h = 0;h + IGL_INLINE bool biharmonic_coordinates( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & T, + const std::vector > & S, + Eigen::PlainObjectBase & W); + // k 2-->biharmonic, 3-->triharmonic + template < + typename DerivedV, + typename DerivedT, + typename SType, + typename DerivedW> + IGL_INLINE bool biharmonic_coordinates( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & T, + const std::vector > & S, + const int k, + Eigen::PlainObjectBase & W); + +}; +# ifndef IGL_STATIC_LIBRARY +# include "biharmonic_coordinates.cpp" +# endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/bijective_composite_harmonic_mapping.cpp b/src/external/libigl-2.3.0/include/igl/bijective_composite_harmonic_mapping.cpp new file mode 100644 index 000000000..733618219 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/bijective_composite_harmonic_mapping.cpp @@ -0,0 +1,115 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2017 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "bijective_composite_harmonic_mapping.h" + +#include "slice.h" +#include "doublearea.h" +#include "harmonic.h" +//#include "matlab/MatlabWorkspace.h" +#include + +template < + typename DerivedV, + typename DerivedF, + typename Derivedb, + typename Derivedbc, + typename DerivedU> +IGL_INLINE bool igl::bijective_composite_harmonic_mapping( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const Eigen::MatrixBase & b, + const Eigen::MatrixBase & bc, + Eigen::PlainObjectBase & U) +{ + return bijective_composite_harmonic_mapping(V,F,b,bc,1,200,20,true,U); +} + +template < + typename DerivedV, + typename DerivedF, + typename Derivedb, + typename Derivedbc, + typename DerivedU> +IGL_INLINE bool igl::bijective_composite_harmonic_mapping( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const Eigen::MatrixBase & b, + const Eigen::MatrixBase & bc, + const int min_steps, + const int max_steps, + const int num_inner_iters, + const bool test_for_flips, + Eigen::PlainObjectBase & U) +{ + typedef typename Derivedbc::Scalar Scalar; + assert(V.cols() == 2 && bc.cols() == 2 && "Input should be 2D"); + assert(F.cols() == 3 && "F should contain triangles"); + int tries = 0; + int nsteps = min_steps; + Eigen::Matrix bc0; + slice(V,b,1,bc0); + + // It's difficult to check for flips "robustly" in the sense that the input + // mesh might not have positive/consistent sign to begin with. + + while(nsteps<=max_steps) + { + U = V; + int flipped = 0; + int nans = 0; + int step = 0; + for(;step<=nsteps;step++) + { + const Scalar t = ((Scalar)step)/((Scalar)nsteps); + // linearly interpolate boundary conditions + // TODO: replace this with something that guarantees a homotopic "morph" + // of the boundary conditions. Something like "Homotopic Morphing of + // Planar Curves" [Dym et al. 2015] but also handling multiple connected + // components. + Eigen::Matrix bct = bc0 + t * (bc - bc0); + // Compute dsicrete harmonic map using metric of previous step + for(int iter = 0;iter(U), F, b, bct, 1, U); + igl::slice(U,b,1,bct); + nans = (U.array() != U.array()).count(); + if(test_for_flips) + { + Eigen::Matrix A; + doublearea(U,F,A); + flipped = (A.array() < 0 ).count(); + //std::cout<<" "< 0 || nans>0) break; + } + if(flipped == 0 && nans == 0) + { + return step == nsteps+1; + } + nsteps *= 2; + } + //std::cout<<"failed to finish in "<, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template bool igl::bijective_composite_harmonic_mapping, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, int, int, int, bool, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/bijective_composite_harmonic_mapping.h b/src/external/libigl-2.3.0/include/igl/bijective_composite_harmonic_mapping.h new file mode 100644 index 000000000..f055e5293 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/bijective_composite_harmonic_mapping.h @@ -0,0 +1,79 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2017 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_BIJECTIVE_COMPOSITE_HARMONIC_MAPPING_H +#define IGL_BIJECTIVE_COMPOSITE_HARMONIC_MAPPING_H +#include "igl_inline.h" +#include + +namespace igl +{ + // Compute a planar mapping of a triangulated polygon (V,F) subjected to + // boundary conditions (b,bc). The mapping should be bijective in the sense + // that no triangles' areas become negative (this assumes they started + // positive). This mapping is computed by "composing" harmonic mappings + // between incremental morphs of the boundary conditions. This is a bit like + // a discrete version of "Bijective Composite Mean Value Mappings" [Schneider + // et al. 2013] but with a discrete harmonic map (cf. harmonic coordinates) + // instead of mean value coordinates. This is inspired by "Embedding a + // triangular graph within a given boundary" [Xu et al. 2011]. + // + // Inputs: + // V #V by 2 list of triangle mesh vertex positions + // F #F by 3 list of triangle indices into V + // b #b list of boundary indices into V + // bc #b by 2 list of boundary conditions corresponding to b + // Outputs: + // U #V by 2 list of output mesh vertex locations + // Returns true if and only if U contains a successful bijectie mapping + // + // + template < + typename DerivedV, + typename DerivedF, + typename Derivedb, + typename Derivedbc, + typename DerivedU> + IGL_INLINE bool bijective_composite_harmonic_mapping( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const Eigen::MatrixBase & b, + const Eigen::MatrixBase & bc, + Eigen::PlainObjectBase & U); + // + // Inputs: + // min_steps minimum number of steps to take from V(b,:) to bc + // max_steps minimum number of steps to take from V(b,:) to bc (if + // max_steps == min_steps then no further number of steps will be tried) + // num_inner_iters number of iterations of harmonic solves to run after + // for each morph step (to try to push flips back in) + // test_for_flips whether to check if flips occurred (and trigger more + // steps). if test_for_flips = false then this function always returns + // true + // + template < + typename DerivedV, + typename DerivedF, + typename Derivedb, + typename Derivedbc, + typename DerivedU> + IGL_INLINE bool bijective_composite_harmonic_mapping( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const Eigen::MatrixBase & b, + const Eigen::MatrixBase & bc, + const int min_steps, + const int max_steps, + const int num_inner_iters, + const bool test_for_flips, + Eigen::PlainObjectBase & U); +} + +#ifndef IGL_STATIC_LIBRARY +# include "bijective_composite_harmonic_mapping.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/blkdiag.cpp b/src/external/libigl-2.3.0/include/igl/blkdiag.cpp new file mode 100644 index 000000000..a53ea8595 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/blkdiag.cpp @@ -0,0 +1,71 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2020 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "blkdiag.h" + +template +IGL_INLINE void igl::blkdiag( + const std::vector> & L, + Eigen::SparseMatrix & Y) +{ + int nr = 0; + int nc = 0; + int nnz = 0; + for(const auto & A : L) + { + nr += A.rows(); + nc += A.cols(); + } + Y.resize(nr,nc); + { + int i = 0; + int j = 0; + for(const auto & A : L) + { + for(int k = 0;k::InnerIterator it(A,k);it;++it) + { + Y.insert(i+it.row(),j+k) = it.value(); + } + } + i += A.rows(); + j += A.cols(); + } + } +} + +template +IGL_INLINE void igl::blkdiag( + const std::vector & L, + Eigen::PlainObjectBase & Y) +{ + int nr = 0; + int nc = 0; + for(const auto & A : L) + { + nr += A.rows(); + nc += A.cols(); + } + Y.setZero(nr,nc); + { + int i = 0; + int j = 0; + for(const auto & A : L) + { + Y.block(i,j,A.rows(),A.cols()) = A; + i += A.rows(); + j += A.cols(); + } + } +} + +#ifdef IGL_STATIC_LIBRARY +// explicit template instantiations +template void igl::blkdiag >(std::vector, std::allocator > > const&, Eigen::PlainObjectBase >&); +template void igl::blkdiag(std::vector, std::allocator > > const&, Eigen::SparseMatrix&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/blkdiag.h b/src/external/libigl-2.3.0/include/igl/blkdiag.h new file mode 100644 index 000000000..bc0ee190e --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/blkdiag.h @@ -0,0 +1,40 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2020 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_BLKDIAG_H +#define IGL_BLKDIAG_H +#include "igl_inline.h" +#include +#include +#include + +namespace igl +{ + // Given a list of matrices place them along the diagonal as blocks of the + // output matrix. Like matlab's blkdiag. + // + // Inputs: + // L list of matrices {A,B, ...} + // Outputs: + // Y A.rows()+B.rows()+... by A.cols()+B.cols()+... block diagonal + // + // See also: cat, repdiag + template + IGL_INLINE void blkdiag( + const std::vector> & L, + Eigen::SparseMatrix & Y); + template + IGL_INLINE void blkdiag( + const std::vector & L, + Eigen::PlainObjectBase & Y); +} + +#ifndef IGL_STATIC_LIBRARY +# include "blkdiag.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/blue_noise.cpp b/src/external/libigl-2.3.0/include/igl/blue_noise.cpp new file mode 100644 index 000000000..ac447feb4 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/blue_noise.cpp @@ -0,0 +1,372 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2020 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "blue_noise.h" +#include "doublearea.h" +#include "random_points_on_mesh.h" +#include "slice.h" +#include "sortrows.h" +#include "PI.h" +#include "get_seconds.h" +#include +#include +#include + +namespace igl +{ + // It is very important that we use 64bit keys to avoid out of bounds (easy to + // get to happen with dense samplings (e.g., r = 0.0005*bbd) + typedef int64_t BlueNoiseKeyType; +} + +// Helper functions +namespace igl +{ + // Should probably find and replace with less generic name + // + // Map 3D subscripts (x,y,z) to unique index (return value) + // + // Inputs: + // w side length of w×w×w integer cube lattice + // x subscript along x direction + // y subscript along y direction + // z subscript along z direction + // Returns index value + // + inline BlueNoiseKeyType blue_noise_key( + const BlueNoiseKeyType w, // pass by copy --> int64_t so that multiplication is OK + const BlueNoiseKeyType x, // pass by copy --> int64_t so that multiplication is OK + const BlueNoiseKeyType y, // pass by copy --> int64_t so that multiplication is OK + const BlueNoiseKeyType z) // pass by copy --> int64_t so that multiplication is OK + { + return x+w*(y+w*z); + } + // Determine if a query candidate at position X.row(i) is too close to already + // selected sites (stored in S). + // + // Inputs: + // X #X by 3 list of raw candidate positions + // Xs #Xs by 3 list of corresponding integer cell subscripts + // i index of candidate in question + // S map from cell index to index into X of selected candidate (or -1 if + // cell is currently empty) + // rr Poisson disk radius squared + // w side length of w×w×w integer cube lattice (into which Xs subscripts) + template < + typename DerivedX, + typename DerivedXs> + inline bool blue_noise_far_enough( + const Eigen::MatrixBase & X, + const Eigen::MatrixBase & Xs, + const std::unordered_map & S, + const double & rr, + const int & w, + const int i) + { + const int xi = Xs(i,0); + const int yi = Xs(i,1); + const int zi = Xs(i,2); + BlueNoiseKeyType k = blue_noise_key(w,xi,yi,zi); + int g = 2; // ceil(r/s) + for(int x = std::max(xi-g,0);x<=std::min(xi+g,w-1);x++) + for(int y = std::max(yi-g,0);y<=std::min(yi+g,w-1);y++) + for(int z = std::max(zi-g,0);z<=std::min(zi+g,w-1);z++) + { + if(x!=xi || y!=yi || z!=zi) + { + const BlueNoiseKeyType nk = blue_noise_key(w,x,y,z); + // have already selected from this cell + const auto Siter = S.find(nk); + if(Siter !=S.end() && Siter->second >= 0) + { + const int ni = Siter->second; + // too close + if( (X.row(i)-X.row(ni)).squaredNorm() < rr) + { + return false; + } + } + } + } + return true; + } + // Try to activate a candidate in a given cell + // + // Inputs: + // X #X by 3 list of raw candidate positions + // Xs #Xs by 3 list of corresponding integer cell subscripts + // rr Poisson disk radius squared + // w side length of w×w×w integer cube lattice (into which Xs subscripts) + // nk index of cell in which we'd like to activate a candidate + // M map from cell index to list of candidates + // S map from cell index to index into X of selected candidate (or -1 if + // cell is currently empty) + // active list of indices into X of active candidates + // Outputs: + // M visited candidates deemed too close to already selected points are + // removed + // S updated to reflect activated point (if successful) + // active updated to reflect activated point (if successful) + // Returns true iff activation was successful + template < + typename DerivedX, + typename DerivedXs> + inline bool activate( + const Eigen::MatrixBase & X, + const Eigen::MatrixBase & Xs, + const double & rr, + const int & i, + const int & w, + const BlueNoiseKeyType & nk, + std::unordered_map > & M, + std::unordered_map & S, + std::vector & active) + { + assert(M.count(nk)); + auto & Mvec = M.find(nk)->second; + auto miter = Mvec.begin(); + while(miter != Mvec.end()) + { + const int mi = *miter; + // mi is our candidate sample. Is it far enough from all existing + // samples? + if(i>=0 && (X.row(i)-X.row(mi)).squaredNorm() > 4.*rr) + { + // too far skip (reject) + miter++; + } else if(blue_noise_far_enough(X,Xs,S,rr,w,mi)) + { + active.push_back(mi); + S.find(nk)->second = mi; + //printf(" found %d\n",mi); + return true; + }else + { + // remove forever (instead of incrementing we swap and eat from the + // back) + //std::swap(*miter,Mvec.back()); + *miter = Mvec.back(); + bool was_last = (std::next(miter) == Mvec.end()); + Mvec.pop_back(); + if (was_last) { + // popping from the vector can invalidate the iterator, if it was + // pointing to the last element that was popped. Alternatively, + // one could use indices directly... + miter = Mvec.end(); + } + } + } + return false; + } + + template < + typename DerivedX, + typename DerivedXs> + inline bool step( + const Eigen::MatrixBase & X, + const Eigen::MatrixBase & Xs, + const double & rr, + const int & w, + std::unordered_map > & M, + std::unordered_map & S, + std::vector & active, + std::vector & collected + ) + { + //considered.clear(); + if(active.size() == 0) return false; + // random entry + const int e = rand() % active.size(); + const int i = active[e]; + //printf("%d\n",i); + const int xi = Xs(i,0); + const int yi = Xs(i,1); + const int zi = Xs(i,2); + //printf("%d %d %d - %g %g %g\n",xi,yi,zi,X(i,0),X(i,1),X(i,2)); + // cell indices of neighbors + int g = 4; + std::vector N;N.reserve((1+g*1)^3-1); + for(int x = std::max(xi-g,0);x<=std::min(xi+g,w-1);x++) + for(int y = std::max(yi-g,0);y<=std::min(yi+g,w-1);y++) + for(int z = std::max(zi-g,0);z<=std::min(zi+g,w-1);z++) + { + if(x!=xi || y!=yi || z!=zi) + { + //printf(" %d %d %d\n",x,y,z); + const BlueNoiseKeyType nk = blue_noise_key(w,x,y,z); + // haven't yet selected from this cell? + const auto Siter = S.find(nk); + if(Siter !=S.end() && Siter->second < 0) + { + assert(M.find(nk) != M.end()); + N.emplace_back(nk); + } + } + } + //printf(" --------\n"); + // randomize order: this might be a little paranoid... + std::random_shuffle(std::begin(N), std::end(N)); + bool found = false; + for(const BlueNoiseKeyType & nk : N) + { + assert(M.find(nk) != M.end()); + if(activate(X,Xs,rr,i,w,nk,M,S,active)) + { + found = true; + break; + } + } + if(!found) + { + // remove i from active list + // https://stackoverflow.com/a/60765833/148668 + collected.push_back(i); + //printf(" before: "); for(const int j : active) { printf("%d ",j); } printf("\n"); + std::swap(active[e], active.back()); + //printf(" after : "); for(const int j : active) { printf("%d ",j); } printf("\n"); + active.pop_back(); + //printf(" removed %d\n",i); + } + //printf(" active: "); for(const int j : active) { printf("%d ",j); } printf("\n"); + return true; + } +} + +template < + typename DerivedV, + typename DerivedF, + typename DerivedB, + typename DerivedFI, + typename DerivedP> +IGL_INLINE void igl::blue_noise( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const typename DerivedV::Scalar r, + Eigen::PlainObjectBase & B, + Eigen::PlainObjectBase & FI, + Eigen::PlainObjectBase & P) +{ + typedef typename DerivedV::Scalar Scalar; + typedef Eigen::Matrix VectorXS; + // float+RowMajor is faster... + typedef Eigen::Matrix MatrixX3S; + assert(V.cols() == 3 && "Only 3D embeddings allowed"); + // minimum radius + const Scalar min_r = r; + // cell size based on 3D distance + // It works reasonably well (but is probably biased to use s=2*r/√3 here and + // g=1 in the outer loop below. + // + // One thing to try would be to store a list in S (rather than a single point) + // or equivalently a mask over M and just use M as a generic spatial hash + // (with arbitrary size) and then tune its size (being careful to make g a + // function of r and s; and removing the `if S=-1 checks`) + const Scalar s = r/sqrt(3.0); + + const double area = + [&](){Eigen::VectorXd A;igl::doublearea(V,F,A);return A.array().sum()/2;}(); + // Circle packing in the plane has igl::PI*sqrt(3)/6 efficiency + const double expected_number_of_points = + area * (igl::PI * sqrt(3.0) / 6.0) / (igl::PI * min_r * min_r / 4.0); + + // Make a uniform random sampling with 30*expected_number_of_points. + const int nx = 30.0*expected_number_of_points; + MatrixX3S X,XB; + Eigen::VectorXi XFI; + igl::random_points_on_mesh(nx,V,F,XB,XFI,X); + + // Rescale so that s = 1 + Eigen::Matrix Xs = + ((X.rowwise()-X.colwise().minCoeff())/s).template cast(); + const int w = Xs.maxCoeff()+1; + { + Eigen::VectorXi I; + igl::sortrows(decltype(Xs)(Xs),true,Xs,I); + igl::slice(decltype(X)(X),I,1,X); + // These two could be spun off in their own thread. + igl::slice(decltype(XB)(XB),I,1,XB); + igl::slice(decltype(XFI)(XFI),I,1,XFI); + } + // Initialization + std::unordered_map > M; + std::unordered_map S; + // attempted to seed + std::unordered_map A; + // Q: Too many? + // A: Seems to help though. + M.reserve(Xs.rows()); + S.reserve(Xs.rows()); + for(int i = 0;isecond.push_back(i); + } + S.emplace(k,-1); + A.emplace(k,false); + } + + std::vector active; + // precompute r² + // Q: is this necessary? + const double rr = r*r; + std::vector collected; + collected.reserve(2.0*expected_number_of_points); + + auto Mouter = M.begin(); + // Just take the first point as the initial seed + const auto initialize = [&]()->bool + { + while(true) + { + if(Mouter == M.end()) + { + return false; + } + const BlueNoiseKeyType k = Mouter->first; + // Haven't placed in this cell yet + if(S[k]<0) + { + if(activate(X,Xs,rr,-1,w,k,M,S,active)) return true; + } + Mouter++; + } + assert(false && "should not be reachable."); + }; + + // important if mesh contains many connected components + while(initialize()) + { + while(active.size()>0) + { + step(X,Xs,rr,w,M,S,active,collected); + } + } + { + const int n = collected.size(); + P.resize(n,3); + B.resize(n,3); + FI.resize(n); + for(int i = 0;i(); + B.row(i) = XB.row(c).template cast(); + FI(i) = XFI(c); + } + } +} + +#ifdef IGL_STATIC_LIBRARY +template void igl::blue_noise, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::Matrix::Scalar, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::blue_noise, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::Matrix::Scalar, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/blue_noise.h b/src/external/libigl-2.3.0/include/igl/blue_noise.h new file mode 100644 index 000000000..45f3bfcc3 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/blue_noise.h @@ -0,0 +1,49 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2020 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_BLUE_NOISE_H +#define IGL_BLUE_NOISE_H +#include "igl_inline.h" +#include +namespace igl +{ + // "Fast Poisson Disk Sampling in Arbitrary Dimensions" [Bridson 2007] + // + // For very dense samplings this is faster than (up to 2x) cyCodeBase's + // implementation of "Sample Elimination for Generating Poisson Disk Sample + // Sets" [Yuksel 2015]. YMMV + // + // Inputs: + // V #V by dim list of mesh vertex positions + // F #F by 3 list of mesh triangle indices into rows of V + // r Poisson disk radius (evaluated according to Euclidean distance on V) + // Outputs: + // B #P by 3 list of barycentric coordinates, ith row are coordinates of + // ith sampled point in face FI(i) + // FI #P list of indices into F + // P #P by dim list of sample positions. + // See also: random_points_on_mesh + template < + typename DerivedV, + typename DerivedF, + typename DerivedB, + typename DerivedFI, + typename DerivedP> + IGL_INLINE void blue_noise( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const typename DerivedV::Scalar r, + Eigen::PlainObjectBase & B, + Eigen::PlainObjectBase & FI, + Eigen::PlainObjectBase & P); +} + +#ifndef IGL_STATIC_LIBRARY +# include "blue_noise.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/bone_parents.cpp b/src/external/libigl-2.3.0/include/igl/bone_parents.cpp new file mode 100644 index 000000000..8434683e7 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/bone_parents.cpp @@ -0,0 +1,32 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "bone_parents.h" + +template +IGL_INLINE void igl::bone_parents( + const Eigen::MatrixBase& BE, + Eigen::PlainObjectBase& P) +{ + P.resize(BE.rows(),1); + // Stupid O(n²) version + for(int e = 0;e, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/bone_parents.h b/src/external/libigl-2.3.0/include/igl/bone_parents.h new file mode 100644 index 000000000..ccad3f919 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/bone_parents.h @@ -0,0 +1,32 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_BONE_PARENTS_H +#define IGL_BONE_PARENTS_H +#include "igl_inline.h" +#include +namespace igl +{ + // BONE_PARENTS Recover "parent" bones from directed graph representation. + // + // Inputs: + // BE #BE by 2 list of directed bone edges + // Outputs: + // P #BE by 1 list of parent indices into BE, -1 means root. + // + template + IGL_INLINE void bone_parents( + const Eigen::MatrixBase& BE, + Eigen::PlainObjectBase& P); +} + +#ifndef IGL_STATIC_LIBRARY +# include "bone_parents.cpp" +#endif + +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/boundary_conditions.cpp b/src/external/libigl-2.3.0/include/igl/boundary_conditions.cpp new file mode 100644 index 000000000..f7146cd70 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/boundary_conditions.cpp @@ -0,0 +1,192 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "boundary_conditions.h" + +#include "verbose.h" +#include "EPS.h" +#include "project_to_line.h" + +#include +#include +#include + +IGL_INLINE bool igl::boundary_conditions( + const Eigen::MatrixXd & V , + const Eigen::MatrixXi & /*Ele*/, + const Eigen::MatrixXd & C , + const Eigen::VectorXi & P , + const Eigen::MatrixXi & BE , + const Eigen::MatrixXi & CE , + Eigen::VectorXi & b , + Eigen::MatrixXd & bc ) +{ + using namespace Eigen; + using namespace std; + + if(P.size()+BE.rows() == 0) + { + verbose("^%s: Error: no handles found\n",__FUNCTION__); + return false; + } + + vector bci; + vector bcj; + vector bcv; + + // loop over points + for(int p = 0;p FLOAT_EPS) + { + verbose("^%s: Error: handle %d does not receive 0 weight\n",__FUNCTION__,i); + return false; + } + if(max_c< (1-FLOAT_EPS)) + { + verbose("^%s: Error: handle %d does not receive 1 weight\n",__FUNCTION__,i); + return false; + } + } + + return true; +} diff --git a/src/external/libigl-2.3.0/include/igl/boundary_conditions.h b/src/external/libigl-2.3.0/include/igl/boundary_conditions.h new file mode 100644 index 000000000..643dbe7c1 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/boundary_conditions.h @@ -0,0 +1,55 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_BOUNDARY_CONDITIONS_H +#define IGL_BOUNDARY_CONDITIONS_H +#include "igl_inline.h" +#include + +namespace igl +{ + + // Compute boundary conditions for automatic weights computation. This + // function expects that the given mesh (V,Ele) has sufficient samples + // (vertices) exactly at point handle locations and exactly along bone and + // cage edges. + // + // Inputs: + // V #V by dim list of domain vertices + // Ele #Ele by simplex-size list of simplex indices + // C #C by dim list of handle positions + // P #P by 1 list of point handle indices into C + // BE #BE by 2 list of bone edge indices into C + // CE #CE by 2 list of cage edge indices into *P* + // Outputs: + // b #b list of boundary indices (indices into V of vertices which have + // known, fixed values) + // bc #b by #weights list of known/fixed values for boundary vertices + // (notice the #b != #weights in general because #b will include all the + // intermediary samples along each bone, etc.. The ordering of the + // weights corresponds to [P;BE] + // Returns false if boundary conditions are suspicious: + // P and BE are empty + // bc is empty + // some column of bc doesn't have a 0 (assuming bc has >1 columns) + // some column of bc doesn't have a 1 (assuming bc has >1 columns) + IGL_INLINE bool boundary_conditions( + const Eigen::MatrixXd & V, + const Eigen::MatrixXi & Ele, + const Eigen::MatrixXd & C, + const Eigen::VectorXi & P, + const Eigen::MatrixXi & BE, + const Eigen::MatrixXi & CE, + Eigen::VectorXi & b, + Eigen::MatrixXd & bc); +} + +#ifndef IGL_STATIC_LIBRARY +# include "boundary_conditions.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/boundary_facets.cpp b/src/external/libigl-2.3.0/include/igl/boundary_facets.cpp new file mode 100644 index 000000000..232a303d8 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/boundary_facets.cpp @@ -0,0 +1,222 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "boundary_facets.h" +#include "face_occurrences.h" +#include "list_to_matrix.h" +#include "matrix_to_list.h" +#include "sort.h" +#include "unique_rows.h" +#include "accumarray.h" +#include "slice_mask.h" + +#include + +#include +#include + +template < + typename DerivedT, + typename DerivedF, + typename DerivedJ, + typename DerivedK> +IGL_INLINE void igl::boundary_facets( + const Eigen::MatrixBase& T, + Eigen::PlainObjectBase& F, + Eigen::PlainObjectBase& J, + Eigen::PlainObjectBase& K) +{ + const int simplex_size = T.cols(); + // Handle boring base case + if(T.rows() == 0) + { + F.resize(0,simplex_size-1); + J.resize(0,1); + K.resize(0,1); + return; + } + // Get a list of all facets + DerivedF allF(T.rows()*simplex_size,simplex_size-1); + // Gather faces (e.g., loop over tets) + for(int i = 0; i< (int)T.rows();i++) + { + switch(simplex_size) + { + case 4: + // get face in correct order + allF(i*simplex_size+0,0) = T(i,1); + allF(i*simplex_size+0,1) = T(i,3); + allF(i*simplex_size+0,2) = T(i,2); + // get face in correct order + allF(i*simplex_size+1,0) = T(i,0); + allF(i*simplex_size+1,1) = T(i,2); + allF(i*simplex_size+1,2) = T(i,3); + // get face in correct order + allF(i*simplex_size+2,0) = T(i,0); + allF(i*simplex_size+2,1) = T(i,3); + allF(i*simplex_size+2,2) = T(i,1); + // get face in correct order + allF(i*simplex_size+3,0) = T(i,0); + allF(i*simplex_size+3,1) = T(i,1); + allF(i*simplex_size+3,2) = T(i,2); + break; + case 3: + allF(i*simplex_size+0,0) = T(i,1); + allF(i*simplex_size+0,1) = T(i,2); + allF(i*simplex_size+1,0) = T(i,2); + allF(i*simplex_size+1,1) = T(i,0); + allF(i*simplex_size+2,0) = T(i,0); + allF(i*simplex_size+2,1) = T(i,1); + break; + } + } + DerivedF sortedF; + igl::sort(allF,2,true,sortedF); + Eigen::VectorXi m,n; + { + DerivedF _1; + igl::unique_rows(sortedF,_1,m,n); + } + Eigen::VectorXi C; + igl::accumarray(n,1,C); + const int ones = (C.array()==1).count(); + // Resize output to fit number of non-twos + F.resize(ones, allF.cols()); + J.resize(F.rows(),1); + K.resize(F.rows(),1); + int k = 0; + for(int c = 0;c< (int)C.size();c++) + { + if(C(c) == 1) + { + const int i = m(c); + assert(k<(int)F.rows()); + F.row(k) = allF.row(i); + J(k) = i/simplex_size; + K(k) = i%simplex_size; + k++; + } + } + assert(k==(int)F.rows()); +} + +template +IGL_INLINE void igl::boundary_facets( + const Eigen::MatrixBase& T, + Eigen::PlainObjectBase& F) +{ + Eigen::VectorXi J,K; + return boundary_facets(T,F,J,K); +} + +template +Ret igl::boundary_facets( + const Eigen::MatrixBase& T) +{ + Ret F; + igl::boundary_facets(T,F); + return F; +} + +template +IGL_INLINE void igl::boundary_facets( + const std::vector > & T, + std::vector > & F) +{ + // Kept for legacy reasons. Could probably just delete. + using namespace std; + + if(T.size() == 0) + { + F.clear(); + return; + } + + int simplex_size = T[0].size(); + // Get a list of all faces + vector > allF( + T.size()*simplex_size, + vector(simplex_size-1)); + + // Gather faces, loop over tets + for(int i = 0; i< (int)T.size();i++) + { + assert((int)T[i].size() == simplex_size); + switch(simplex_size) + { + case 4: + // get face in correct order + allF[i*simplex_size+0][0] = T[i][1]; + allF[i*simplex_size+0][1] = T[i][3]; + allF[i*simplex_size+0][2] = T[i][2]; + // get face in correct order + allF[i*simplex_size+1][0] = T[i][0]; + allF[i*simplex_size+1][1] = T[i][2]; + allF[i*simplex_size+1][2] = T[i][3]; + // get face in correct order + allF[i*simplex_size+2][0] = T[i][0]; + allF[i*simplex_size+2][1] = T[i][3]; + allF[i*simplex_size+2][2] = T[i][1]; + // get face in correct order + allF[i*simplex_size+3][0] = T[i][0]; + allF[i*simplex_size+3][1] = T[i][1]; + allF[i*simplex_size+3][2] = T[i][2]; + break; + case 3: + allF[i*simplex_size+0][0] = T[i][1]; + allF[i*simplex_size+0][1] = T[i][2]; + allF[i*simplex_size+1][0] = T[i][2]; + allF[i*simplex_size+1][1] = T[i][0]; + allF[i*simplex_size+2][0] = T[i][0]; + allF[i*simplex_size+2][1] = T[i][1]; + break; + } + } + + // Counts + vector C; + face_occurrences(allF,C); + + // Q: Why not just count the number of ones? + // A: because we are including non-manifold edges as boundary edges + int twos = (int) count(C.begin(),C.end(),2); + //int ones = (int) count(C.begin(),C.end(),1); + // Resize output to fit number of ones + F.resize(allF.size() - twos); + //F.resize(ones); + int k = 0; + for(int i = 0;i< (int)allF.size();i++) + { + if(C[i] != 2) + { + assert(k<(int)F.size()); + F[k] = allF[i]; + k++; + } + } + assert(k==(int)F.size()); + //if(k != F.size()) + //{ + // printf("%d =? %d\n",k,F.size()); + //} + +} + + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::boundary_facets, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::boundary_facets, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::boundary_facets, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::boundary_facets(std::vector >, std::allocator > > > const&, std::vector >, std::allocator > > >&); +//template Eigen::MatrixBase > igl::boundary_facets(Eigen::PlainObjectBase > const&); +template Eigen::Matrix igl::boundary_facets, Eigen::Matrix >(Eigen::MatrixBase > const&); +template void igl::boundary_facets, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/boundary_facets.h b/src/external/libigl-2.3.0/include/igl/boundary_facets.h new file mode 100644 index 000000000..9258db69b --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/boundary_facets.h @@ -0,0 +1,57 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_BOUNDARY_FACETS_H +#define IGL_BOUNDARY_FACETS_H +#include "igl_inline.h" + +#include + +#include + +namespace igl +{ + // BOUNDARY_FACETS Determine boundary faces (edges) of tetrahedra (triangles) + // stored in T (analogous to qptoolbox's `outline` and `boundary_faces`). + // + // Input: + // T tetrahedron (triangle) index list, m by 4 (3), where m is the number of tetrahedra + // Output: + // F list of boundary faces, n by 3 (2), where n is the number of boundary faces + // J list of indices into T, n by 1 + // K list of indices revealing across from which vertex is this facet + // + // + template < + typename DerivedT, + typename DerivedF, + typename DerivedJ, + typename DerivedK> + IGL_INLINE void boundary_facets( + const Eigen::MatrixBase& T, + Eigen::PlainObjectBase& F, + Eigen::PlainObjectBase& J, + Eigen::PlainObjectBase& K); + template + IGL_INLINE void boundary_facets( + const Eigen::MatrixBase& T, + Eigen::PlainObjectBase& F); + // Same as above but returns F + template + Ret boundary_facets( + const Eigen::MatrixBase& T); + template + IGL_INLINE void boundary_facets( + const std::vector > & T, + std::vector > & F); +} + +#ifndef IGL_STATIC_LIBRARY +# include "boundary_facets.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/boundary_loop.cpp b/src/external/libigl-2.3.0/include/igl/boundary_loop.cpp new file mode 100644 index 000000000..537a23d1c --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/boundary_loop.cpp @@ -0,0 +1,154 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Stefan Brugger +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "boundary_loop.h" +#include "slice.h" +#include "triangle_triangle_adjacency.h" +#include "vertex_triangle_adjacency.h" +#include "is_border_vertex.h" +#include + +template +IGL_INLINE void igl::boundary_loop( + const Eigen::MatrixBase & F, + std::vector >& L) +{ + using namespace std; + using namespace Eigen; + + if(F.rows() == 0) + return; + + VectorXd Vdummy(F.maxCoeff()+1,1); + Eigen::Matrix TT,TTi; + vector > VF, VFi; + triangle_triangle_adjacency(F,TT,TTi); + vertex_triangle_adjacency(Vdummy,F,VF,VFi); + + vector unvisited = is_border_vertex(F); + set unseen; + for (size_t i = 0; i < unvisited.size(); ++i) + { + if (unvisited[i]) + unseen.insert(unseen.end(),i); + } + + while (!unseen.empty()) + { + vector l; + + // Get first vertex of loop + int start = *unseen.begin(); + unseen.erase(unseen.begin()); + unvisited[start] = false; + l.push_back(start); + + bool done = false; + while (!done) + { + // Find next vertex + bool newBndEdge = false; + int v = l[l.size()-1]; + int next; + for (int i = 0; i < (int)VF[v].size() && !newBndEdge; i++) + { + int fid = VF[v][i]; + + if (TT.row(fid).minCoeff() < 0.) // Face contains boundary edge + { + int vLoc = -1; + if (F(fid,0) == v) vLoc = 0; + if (F(fid,1) == v) vLoc = 1; + if (F(fid,2) == v) vLoc = 2; + + int vNext = F(fid,(vLoc + 1) % F.cols()); + + newBndEdge = false; + if (unvisited[vNext] && TT(fid,vLoc) < 0) + { + next = vNext; + newBndEdge = true; + } + } + } + + if (newBndEdge) + { + l.push_back(next); + unseen.erase(next); + unvisited[next] = false; + } + else + done = true; + } + L.push_back(l); + } +} + +template +IGL_INLINE void igl::boundary_loop( + const Eigen::MatrixBase& F, + std::vector& L) +{ + using namespace Eigen; + using namespace std; + + if(F.rows() == 0) + return; + + vector > Lall; + boundary_loop(F,Lall); + + int idxMax = -1; + size_t maxLen = 0; + for (size_t i = 0; i < Lall.size(); ++i) + { + if (Lall[i].size() > maxLen) + { + maxLen = Lall[i].size(); + idxMax = i; + } + } + + //Check for meshes without boundary + if (idxMax == -1) + { + L.clear(); + return; + } + + L.resize(Lall[idxMax].size()); + for (size_t i = 0; i < Lall[idxMax].size(); ++i) + { + L[i] = Lall[idxMax][i]; + } +} + +template +IGL_INLINE void igl::boundary_loop( + const Eigen::MatrixBase& F, + Eigen::PlainObjectBase& L) +{ + using namespace Eigen; + using namespace std; + + if(F.rows() == 0) + return; + + vector Lvec; + boundary_loop(F,Lvec); + + L.resize(Lvec.size(), 1); + for (size_t i = 0; i < Lvec.size(); ++i) + L(i) = Lvec[i]; +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +template void igl::boundary_loop, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::boundary_loop, int>(Eigen::MatrixBase > const&, std::vector >, std::allocator > > >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/boundary_loop.h b/src/external/libigl-2.3.0/include/igl/boundary_loop.h new file mode 100644 index 000000000..f60ff7098 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/boundary_loop.h @@ -0,0 +1,66 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Stefan Brugger +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_BOUNDARY_LOOP_H +#define IGL_BOUNDARY_LOOP_H +#include "igl_inline.h" + +#include +#include + +namespace igl +{ + // Compute list of ordered boundary loops for a manifold mesh. + // + // Templates: + // Index index type + // Inputs: + // F #V by dim list of mesh faces + // Outputs: + // L list of loops where L[i] = ordered list of boundary vertices in loop i + // + template + IGL_INLINE void boundary_loop( + const Eigen::MatrixBase& F, + std::vector >& L); + + + // Compute ordered boundary loops for a manifold mesh and return the + // longest loop in terms of vertices. + // + // Templates: + // Index index type + // Inputs: + // F #V by dim list of mesh faces + // Outputs: + // L ordered list of boundary vertices of longest boundary loop + // + template + IGL_INLINE void boundary_loop( + const Eigen::MatrixBase& F, + std::vector& L); + + // Compute ordered boundary loops for a manifold mesh and return the + // longest loop in terms of vertices. + // + // Templates: + // Index index type + // Inputs: + // F #V by dim list of mesh faces + // Outputs: + // L ordered list of boundary vertices of longest boundary loop + // + template + IGL_INLINE void boundary_loop( + const Eigen::MatrixBase& F, + Eigen::PlainObjectBase& L); +} + +#ifndef IGL_STATIC_LIBRARY +# include "boundary_loop.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/bounding_box.cpp b/src/external/libigl-2.3.0/include/igl/bounding_box.cpp new file mode 100644 index 000000000..4777d2511 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/bounding_box.cpp @@ -0,0 +1,105 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "bounding_box.h" +#include + +template +IGL_INLINE void igl::bounding_box( + const Eigen::MatrixBase& V, + Eigen::PlainObjectBase& BV, + Eigen::PlainObjectBase& BF) +{ + return bounding_box(V,0.,BV,BF); +} + +template +IGL_INLINE void igl::bounding_box( + const Eigen::MatrixBase& V, + const typename DerivedV::Scalar pad, + Eigen::PlainObjectBase& BV, + Eigen::PlainObjectBase& BF) +{ + using namespace std; + + const int dim = V.cols(); + const auto & minV = V.colwise().minCoeff().array()-pad; + const auto & maxV = V.colwise().maxCoeff().array()+pad; + // 2^n vertices + BV.resize((1ull< combos = + [&BV,&minV,&maxV,&combos]( + const int dim, + const int i, + int * X, + const int pre_index) + { + for(X[i] = 0;X[i]<2;X[i]++) + { + int index = pre_index*2+X[i]; + if((i+1), Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::bounding_box, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::bounding_box, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::Matrix::Scalar, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::bounding_box, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::bounding_box, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::bounding_box, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/bounding_box.h b/src/external/libigl-2.3.0/include/igl/bounding_box.h new file mode 100644 index 000000000..7e053d2cc --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/bounding_box.h @@ -0,0 +1,39 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_BOUNDING_BOX_H +#define IGL_BOUNDING_BOX_H +#include "igl_inline.h" +#include +namespace igl +{ + // Build a triangle mesh of the bounding box of a given list of vertices + // + // Inputs: + // V #V by dim list of rest domain positions + // Outputs: + // BV 2^dim by dim list of bounding box corners positions + // BF #BF by dim list of simplex facets + template + IGL_INLINE void bounding_box( + const Eigen::MatrixBase& V, + Eigen::PlainObjectBase& BV, + Eigen::PlainObjectBase& BF); + template + IGL_INLINE void bounding_box( + const Eigen::MatrixBase& V, + const typename DerivedV::Scalar pad, + Eigen::PlainObjectBase& BV, + Eigen::PlainObjectBase& BF); +} + +#ifndef IGL_STATIC_LIBRARY +# include "bounding_box.cpp" +#endif + +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/bounding_box_diagonal.cpp b/src/external/libigl-2.3.0/include/igl/bounding_box_diagonal.cpp new file mode 100644 index 000000000..1023abb50 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/bounding_box_diagonal.cpp @@ -0,0 +1,26 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "bounding_box_diagonal.h" +#include "mat_max.h" +#include "mat_min.h" +#include + +IGL_INLINE double igl::bounding_box_diagonal( + const Eigen::MatrixXd & V) +{ + using namespace Eigen; + VectorXd maxV,minV; + VectorXi maxVI,minVI; + mat_max(V,1,maxV,maxVI); + mat_min(V,1,minV,minVI); + return sqrt((maxV-minV).array().square().sum()); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +#endif diff --git a/src/external/libigl-2.3.0/include/igl/bounding_box_diagonal.h b/src/external/libigl-2.3.0/include/igl/bounding_box_diagonal.h new file mode 100644 index 000000000..f11821d0d --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/bounding_box_diagonal.h @@ -0,0 +1,27 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_BOUNDING_BOX_DIAGONAL_H +#define IGL_BOUNDING_BOX_DIAGONAL_H +#include "igl_inline.h" +#include +namespace igl +{ + // Compute the length of the diagonal of a given meshes axis-aligned bounding + // box + // + // Inputs: + // V #V by 3 list of vertex/point positions + // Returns length of bounding box diagonal + IGL_INLINE double bounding_box_diagonal( const Eigen::MatrixXd & V); +} + +#ifndef IGL_STATIC_LIBRARY +# include "bounding_box_diagonal.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/canonical_quaternions.cpp b/src/external/libigl-2.3.0/include/igl/canonical_quaternions.cpp new file mode 100644 index 000000000..55d68da86 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/canonical_quaternions.cpp @@ -0,0 +1,21 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "canonical_quaternions.h" + +template <> IGL_INLINE float igl::CANONICAL_VIEW_QUAT(int i, int j) +{ + return (float)igl::CANONICAL_VIEW_QUAT_F[i][j]; +} +template <> IGL_INLINE double igl::CANONICAL_VIEW_QUAT(int i, int j) +{ + return (double)igl::CANONICAL_VIEW_QUAT_D[i][j]; +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +#endif diff --git a/src/external/libigl-2.3.0/include/igl/canonical_quaternions.h b/src/external/libigl-2.3.0/include/igl/canonical_quaternions.h new file mode 100644 index 000000000..86d90112d --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/canonical_quaternions.h @@ -0,0 +1,129 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_CANONICAL_QUATERNIONS_H +#define IGL_CANONICAL_QUATERNIONS_H +#include "igl_inline.h" +// Define some canonical quaternions for floats and doubles +// A Quaternion, q, is defined here as an arrays of four scalars (x,y,z,w), +// such that q = x*i + y*j + z*k + w +namespace igl +{ + // Float versions +#define SQRT_2_OVER_2 0.707106781f + // Identity + const float IDENTITY_QUAT_F[4] = {0,0,0,1}; + // The following match the Matlab canonical views + // X point right, Y pointing up and Z point out + const float XY_PLANE_QUAT_F[4] = {0,0,0,1}; + // X points right, Y points *in* and Z points up + const float XZ_PLANE_QUAT_F[4] = {-SQRT_2_OVER_2,0,0,SQRT_2_OVER_2}; + // X points out, Y points right, and Z points up + const float YZ_PLANE_QUAT_F[4] = {-0.5,-0.5,-0.5,0.5}; + const float CANONICAL_VIEW_QUAT_F[][4] = + { + { 0, 0, 0, 1}, // 0 + { 0, 0, SQRT_2_OVER_2, SQRT_2_OVER_2}, // 1 + { 0, 0, 1, 0}, // 2 + { 0, 0, SQRT_2_OVER_2,-SQRT_2_OVER_2}, // 3 + + { 0, -1, 0, 0}, // 4 + {-SQRT_2_OVER_2, SQRT_2_OVER_2, 0, 0}, // 5 + { -1, 0, 0, 0}, // 6 + {-SQRT_2_OVER_2,-SQRT_2_OVER_2, 0, 0}, // 7 + + { -0.5, -0.5, -0.5, 0.5}, // 8 + { 0,-SQRT_2_OVER_2, 0, SQRT_2_OVER_2}, // 9 + { 0.5, -0.5, 0.5, 0.5}, // 10 + { SQRT_2_OVER_2, 0, SQRT_2_OVER_2, 0}, // 11 + + { SQRT_2_OVER_2, 0,-SQRT_2_OVER_2, 0}, // 12 + { 0.5, 0.5, -0.5, 0.5}, // 13 + { 0, SQRT_2_OVER_2, 0, SQRT_2_OVER_2}, // 14 + { -0.5, 0.5, 0.5, 0.5}, // 15 + + { 0, SQRT_2_OVER_2, SQRT_2_OVER_2, 0}, // 16 + { -0.5, 0.5, 0.5, -0.5}, // 17 + {-SQRT_2_OVER_2, 0, 0,-SQRT_2_OVER_2}, // 18 + { -0.5, -0.5, -0.5, -0.5}, // 19 + + {-SQRT_2_OVER_2, 0, 0, SQRT_2_OVER_2}, // 20 + { -0.5, -0.5, 0.5, 0.5}, // 21 + { 0,-SQRT_2_OVER_2, SQRT_2_OVER_2, 0}, // 22 + { 0.5, -0.5, 0.5, -0.5} // 23 + }; +#undef SQRT_2_OVER_2 + // Double versions +#define SQRT_2_OVER_2 0.70710678118654757 + // Identity + const double IDENTITY_QUAT_D[4] = {0,0,0,1}; + // The following match the Matlab canonical views + // X point right, Y pointing up and Z point out + const double XY_PLANE_QUAT_D[4] = {0,0,0,1}; + // X points right, Y points *in* and Z points up + const double XZ_PLANE_QUAT_D[4] = {-SQRT_2_OVER_2,0,0,SQRT_2_OVER_2}; + // X points out, Y points right, and Z points up + const double YZ_PLANE_QUAT_D[4] = {-0.5,-0.5,-0.5,0.5}; + const double CANONICAL_VIEW_QUAT_D[][4] = + { + { 0, 0, 0, 1}, + { 0, 0, SQRT_2_OVER_2, SQRT_2_OVER_2}, + { 0, 0, 1, 0}, + { 0, 0, SQRT_2_OVER_2,-SQRT_2_OVER_2}, + + { 0, -1, 0, 0}, + {-SQRT_2_OVER_2, SQRT_2_OVER_2, 0, 0}, + { -1, 0, 0, 0}, + {-SQRT_2_OVER_2,-SQRT_2_OVER_2, 0, 0}, + + { -0.5, -0.5, -0.5, 0.5}, + { 0,-SQRT_2_OVER_2, 0, SQRT_2_OVER_2}, + { 0.5, -0.5, 0.5, 0.5}, + { SQRT_2_OVER_2, 0, SQRT_2_OVER_2, 0}, + + { SQRT_2_OVER_2, 0,-SQRT_2_OVER_2, 0}, + { 0.5, 0.5, -0.5, 0.5}, + { 0, SQRT_2_OVER_2, 0, SQRT_2_OVER_2}, + { -0.5, 0.5, 0.5, 0.5}, + + { 0, SQRT_2_OVER_2, SQRT_2_OVER_2, 0}, + { -0.5, 0.5, 0.5, -0.5}, + {-SQRT_2_OVER_2, 0, 0,-SQRT_2_OVER_2}, + { -0.5, -0.5, -0.5, -0.5}, + + {-SQRT_2_OVER_2, 0, 0, SQRT_2_OVER_2}, + { -0.5, -0.5, 0.5, 0.5}, + { 0,-SQRT_2_OVER_2, SQRT_2_OVER_2, 0}, + { 0.5, -0.5, 0.5, -0.5} + }; +#undef SQRT_2_OVER_2 +#define NUM_CANONICAL_VIEW_QUAT 24 + + // NOTE: I want to rather be able to return a Q_type[][] but C++ is not + // making it easy. So instead I've written a per-element accessor + + // Return element [i][j] of the corresponding CANONICAL_VIEW_QUAT_* of the + // given templated type + // Inputs: + // i index of quaternion + // j index of coordinate in quaternion i + // Returns values of CANONICAL_VIEW_QUAT_*[i][j] + template + IGL_INLINE Q_type CANONICAL_VIEW_QUAT(int i, int j); + // Template specializations for float and double + template <> + IGL_INLINE float CANONICAL_VIEW_QUAT(int i, int j); + template <> + IGL_INLINE double CANONICAL_VIEW_QUAT(int i, int j); + +} + +#ifndef IGL_STATIC_LIBRARY +# include "canonical_quaternions.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/cat.cpp b/src/external/libigl-2.3.0/include/igl/cat.cpp new file mode 100644 index 000000000..c5bc20671 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/cat.cpp @@ -0,0 +1,340 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "cat.h" + +#include + +// Bug in unsupported/Eigen/SparseExtra needs iostream first +#include +#include + + +// Sparse matrices need to be handled carefully. Because C++ does not +// Template: +// Scalar sparse matrix scalar type, e.g. double +template +IGL_INLINE void igl::cat( + const int dim, + const Eigen::SparseMatrix & A, + const Eigen::SparseMatrix & B, + Eigen::SparseMatrix & C) +{ + + assert(dim == 1 || dim == 2); + using namespace Eigen; + // Special case if B or A is empty + if(A.size() == 0) + { + C = B; + return; + } + if(B.size() == 0) + { + C = A; + return; + } + +#if false + // This **must** be DynamicSparseMatrix, otherwise this implementation is + // insanely slow + DynamicSparseMatrix dyn_C; + if(dim == 1) + { + assert(A.cols() == B.cols()); + dyn_C.resize(A.rows()+B.rows(),A.cols()); + }else if(dim == 2) + { + assert(A.rows() == B.rows()); + dyn_C.resize(A.rows(),A.cols()+B.cols()); + }else + { + fprintf(stderr,"cat.h: Error: Unsupported dimension %d\n",dim); + } + + dyn_C.reserve(A.nonZeros()+B.nonZeros()); + + // Iterate over outside of A + for(int k=0; k::InnerIterator it (A,k); it; ++it) + { + dyn_C.coeffRef(it.row(),it.col()) += it.value(); + } + } + + // Iterate over outside of B + for(int k=0; k::InnerIterator it (B,k); it; ++it) + { + int r = (dim == 1 ? A.rows()+it.row() : it.row()); + int c = (dim == 2 ? A.cols()+it.col() : it.col()); + dyn_C.coeffRef(r,c) += it.value(); + } + } + + C = SparseMatrix(dyn_C); +#elif false + std::vector > CIJV; + CIJV.reserve(A.nonZeros() + B.nonZeros()); + { + // Iterate over outside of A + for(int k=0; k::InnerIterator it (A,k); it; ++it) + { + CIJV.emplace_back(it.row(),it.col(),it.value()); + } + } + // Iterate over outside of B + for(int k=0; k::InnerIterator it (B,k); it; ++it) + { + int r = (dim == 1 ? A.rows()+it.row() : it.row()); + int c = (dim == 2 ? A.cols()+it.col() : it.col()); + CIJV.emplace_back(r,c,it.value()); + } + } + + } + + C = SparseMatrix( + dim == 1 ? A.rows()+B.rows() : A.rows(), + dim == 1 ? A.cols() : A.cols()+B.cols()); + C.reserve(A.nonZeros() + B.nonZeros()); + C.setFromTriplets(CIJV.begin(),CIJV.end()); +#else + C = SparseMatrix( + dim == 1 ? A.rows()+B.rows() : A.rows(), + dim == 1 ? A.cols() : A.cols()+B.cols()); + Eigen::VectorXi per_col = Eigen::VectorXi::Zero(C.cols()); + if(dim == 1) + { + assert(A.outerSize() == B.outerSize()); + for(int k = 0;k::InnerIterator it (A,k); it; ++it) + { + per_col(k)++; + } + for(typename SparseMatrix::InnerIterator it (B,k); it; ++it) + { + per_col(k)++; + } + } + }else + { + for(int k = 0;k::InnerIterator it (A,k); it; ++it) + { + per_col(k)++; + } + } + for(int k = 0;k::InnerIterator it (B,k); it; ++it) + { + per_col(A.cols() + k)++; + } + } + } + C.reserve(per_col); + if(dim == 1) + { + for(int k = 0;k::InnerIterator it (A,k); it; ++it) + { + C.insert(it.row(),k) = it.value(); + } + for(typename SparseMatrix::InnerIterator it (B,k); it; ++it) + { + C.insert(A.rows()+it.row(),k) = it.value(); + } + } + }else + { + for(int k = 0;k::InnerIterator it (A,k); it; ++it) + { + C.insert(it.row(),k) = it.value(); + } + } + for(int k = 0;k::InnerIterator it (B,k); it; ++it) + { + C.insert(it.row(),A.cols()+k) = it.value(); + } + } + } + C.makeCompressed(); + +#endif + +} + +template +IGL_INLINE void igl::cat( + const int dim, + const Eigen::MatrixBase & A, + const Eigen::MatrixBase & B, + MatC & C) +{ + assert(dim == 1 || dim == 2); + // Special case if B or A is empty + if(A.size() == 0) + { + C = B; + return; + } + if(B.size() == 0) + { + C = A; + return; + } + + if(dim == 1) + { + assert(A.cols() == B.cols()); + C.resize(A.rows()+B.rows(),A.cols()); + C << A,B; + }else if(dim == 2) + { + assert(A.rows() == B.rows()); + C.resize(A.rows(),A.cols()+B.cols()); + C << A,B; + }else + { + fprintf(stderr,"cat.h: Error: Unsupported dimension %d\n",dim); + } +} + +template +IGL_INLINE Mat igl::cat(const int dim, const Mat & A, const Mat & B) +{ + assert(dim == 1 || dim == 2); + Mat C; + igl::cat(dim,A,B,C); + return C; +} + +template +IGL_INLINE void igl::cat(const std::vector > & A, Mat & C) +{ + using namespace std; + // Start with empty matrix + C.resize(0,0); + for(const auto & row_vec : A) + { + // Concatenate each row horizontally + // Start with empty matrix + Mat row(0,0); + for(const auto & element : row_vec) + { + row = cat(2,row,element); + } + // Concatenate rows vertically + C = cat(1,C,row); + } +} + +template +IGL_INLINE void igl::cat(const int dim, const std::vector & A, Eigen::PlainObjectBase & C) +{ + assert(dim == 1 || dim == 2); + using namespace Eigen; + + const int num_mat = A.size(); + if(num_mat == 0) + { + C.resize(0,0); + return; + } + + if(dim == 1) + { + const int A_cols = A[0].cols(); + + int tot_rows = 0; + for(const auto & m : A) + { + tot_rows += m.rows(); + } + + C.resize(tot_rows, A_cols); + + int cur_row = 0; + for(int i = 0; i < num_mat; i++) + { + assert(A_cols == A[i].cols()); + C.block(cur_row,0,A[i].rows(),A_cols) = A[i]; + cur_row += A[i].rows(); + } + } + else if(dim == 2) + { + const int A_rows = A[0].rows(); + + int tot_cols = 0; + for(const auto & m : A) + { + tot_cols += m.cols(); + } + + C.resize(A_rows,tot_cols); + + int cur_col = 0; + for(int i = 0; i < num_mat; i++) + { + assert(A_rows == A[i].rows()); + C.block(0,cur_col,A_rows,A[i].cols()) = A[i]; + cur_col += A[i].cols(); + } + } + else + { + fprintf(stderr,"cat.h: Error: Unsupported dimension %d\n",dim); + } +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::cat, Eigen::Matrix >(int, std::vector, std::allocator > > const&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template Eigen::Matrix igl::cat >(int, Eigen::Matrix const&, Eigen::Matrix const&); +// generated by autoexplicit.sh +template Eigen::SparseMatrix igl::cat >(int, Eigen::SparseMatrix const&, Eigen::SparseMatrix const&); +// generated by autoexplicit.sh +template Eigen::Matrix igl::cat >(int, Eigen::Matrix const&, Eigen::Matrix const&); +template void igl::cat, Eigen::Matrix >(int, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::Matrix&); +template Eigen::Matrix igl::cat >(int, Eigen::Matrix const&, Eigen::Matrix const&); +template Eigen::Matrix igl::cat >(int, Eigen::Matrix const&, Eigen::Matrix const&); +template void igl::cat, Eigen::Matrix >(int, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::Matrix&); +template void igl::cat, Eigen::Matrix >(int, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::Matrix&); +template void igl::cat, Eigen::Matrix >(int, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::Matrix&); +template void igl::cat, Eigen::Matrix >(int, std::vector, std::allocator > > const&, Eigen::PlainObjectBase >&); +template void igl::cat, Eigen::Matrix >(int, std::vector, std::allocator > > const&, Eigen::PlainObjectBase >&); +template void igl::cat, Eigen::Matrix >(int, std::vector, std::allocator > > const&, Eigen::PlainObjectBase >&); +template void igl::cat, Eigen::Matrix >(int, std::vector, std::allocator > > const&, Eigen::PlainObjectBase >&); +template void igl::cat, Eigen::Matrix >(int, std::vector, std::allocator > > const&, Eigen::PlainObjectBase >&); +template void igl::cat, Eigen::Matrix >(int, std::vector, std::allocator > > const&, Eigen::PlainObjectBase >&); +template void igl::cat, Eigen::Matrix >(int, std::vector, std::allocator > > const&, Eigen::PlainObjectBase >&); +template void igl::cat, Eigen::Matrix >(int, std::vector, std::allocator > > const&, Eigen::PlainObjectBase >&); +template void igl::cat, Eigen::Matrix >(int, std::vector, std::allocator > > const&, Eigen::PlainObjectBase >&); +template void igl::cat, Eigen::Matrix >(int, std::vector, std::allocator > > const&, Eigen::PlainObjectBase >&); +template void igl::cat, Eigen::Matrix >(int, std::vector, std::allocator > > const&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/cat.h b/src/external/libigl-2.3.0/include/igl/cat.h new file mode 100644 index 000000000..7a2bcff7d --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/cat.h @@ -0,0 +1,82 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_CAT_H +#define IGL_CAT_H +#include "igl_inline.h" + +#define EIGEN_YES_I_KNOW_SPARSE_MODULE_IS_NOT_STABLE_YET +#include +#include +#include + +namespace igl +{ + // If you're using Dense matrices you might be better off using the << operator + + // This is an attempt to act like matlab's cat function. + + // Perform concatenation of a two matrices along a single dimension + // If dim == 1, then C = [A;B]. If dim == 2 then C = [A B] + // + // Template: + // Scalar scalar data type for sparse matrices like double or int + // Mat matrix type for all matrices (e.g. MatrixXd, SparseMatrix) + // MatC matrix type for output matrix (e.g. MatrixXd) needs to support + // resize + // Inputs: + // A first input matrix + // B second input matrix + // dim dimension along which to concatenate, 1 or 2 + // Outputs: + // C output matrix + // + template + IGL_INLINE void cat( + const int dim, + const Eigen::SparseMatrix & A, + const Eigen::SparseMatrix & B, + Eigen::SparseMatrix & C); + template + IGL_INLINE void cat( + const int dim, + const Eigen::MatrixBase & A, + const Eigen::MatrixBase & B, + MatC & C); + // Wrapper that returns C + template + IGL_INLINE Mat cat(const int dim, const Mat & A, const Mat & B); + + // Note: Maybe we can autogenerate a bunch of overloads D = cat(int,A,B,C), + // E = cat(int,A,B,C,D), etc. + + // Concatenate a "matrix" of blocks + // C = [A0;A1;A2;...;An] where Ai = [A[i][0] A[i][1] ... A[i][m]]; + // + // Inputs: + // A a matrix (vector of row vectors) + // Output: + // C + template + IGL_INLINE void cat(const std::vector > & A, Mat & C); + + // Concatenate a std::vector of matrices along the specified dimension + // + // Inputs: + // dim dimension along which to concatenate, 1 or 2 + // A std::vector of eigen matrices. Must have identical # cols if dim == 1 or rows if dim == 2 + // Outputs: + // C output matrix + template + IGL_INLINE void cat(const int dim, const std::vector & A, Eigen::PlainObjectBase & C); +} + +#ifndef IGL_STATIC_LIBRARY +# include "cat.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/ceil.cpp b/src/external/libigl-2.3.0/include/igl/ceil.cpp new file mode 100644 index 000000000..278269ab2 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/ceil.cpp @@ -0,0 +1,33 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "ceil.h" +#include + +template < typename DerivedX, typename DerivedY> +IGL_INLINE void igl::ceil( + const Eigen::PlainObjectBase& X, + Eigen::PlainObjectBase& Y) +{ + using namespace std; + //Y = DerivedY::Zero(m,n); +//#pragma omp parallel for + //for(int i = 0;iScalar{return std::ceil(x);}).template cast(); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +template void igl::ceil, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/ceil.h b/src/external/libigl-2.3.0/include/igl/ceil.h new file mode 100644 index 000000000..b6acee904 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/ceil.h @@ -0,0 +1,30 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_CEIL_H +#define IGL_CEIL_H +#include "igl_inline.h" +#include +namespace igl +{ + // Ceil a given matrix to nearest integers + // + // Inputs: + // X m by n matrix of scalars + // Outputs: + // Y m by n matrix of ceiled integers + template < typename DerivedX, typename DerivedY> + IGL_INLINE void ceil( + const Eigen::PlainObjectBase& X, + Eigen::PlainObjectBase& Y); +} + +#ifndef IGL_STATIC_LIBRARY +# include "ceil.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/centroid.cpp b/src/external/libigl-2.3.0/include/igl/centroid.cpp new file mode 100644 index 000000000..588f0665e --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/centroid.cpp @@ -0,0 +1,72 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "centroid.h" +#include + +template < + typename DerivedV, + typename DerivedF, + typename Derivedc, + typename Derivedvol> +IGL_INLINE void igl::centroid( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + Eigen::PlainObjectBase& cen, + Derivedvol & vol) +{ + using namespace Eigen; + assert(F.cols() == 3 && "F should contain triangles."); + assert(V.cols() == 3 && "V should contain 3d points."); + const int m = F.rows(); + cen.setZero(); + vol = 0; + // loop over faces + for(int f = 0;f RowVector3S; + const RowVector3S & a = V.row(F(f,0)); + const RowVector3S & b = V.row(F(f,1)); + const RowVector3S & c = V.row(F(f,2)); + // un-normalized normal + const RowVector3S & n = (b-a).cross(c-a); + // total volume via divergence theorem: ∫ 1 + vol += n.dot(a)/6.; + // centroid via divergence theorem and midpoint quadrature: ∫ x + cen.array() += (1./24.*n.array()*((a+b).array().square() + (b+c).array().square() + + (c+a).array().square()).array()); + } + cen *= 1./(2.*vol); +} + +template < + typename DerivedV, + typename DerivedF, + typename Derivedc> +IGL_INLINE void igl::centroid( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + Eigen::PlainObjectBase& c) +{ + typename Derivedc::Scalar vol; + return centroid(V,F,c,vol); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::centroid, Eigen::Matrix, Eigen::Matrix, float>(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, float&); +// generated by autoexplicit.sh +template void igl::centroid, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::centroid, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::centroid, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::centroid, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/centroid.h b/src/external/libigl-2.3.0/include/igl/centroid.h new file mode 100644 index 000000000..31fa7ae6b --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/centroid.h @@ -0,0 +1,49 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_CENTROID_H +#define IGL_CENTROID_H +#include "igl_inline.h" +#include +namespace igl +{ + // CENTROID Computes the centroid of a closed mesh using a surface integral. + // + // Inputs: + // V #V by dim list of rest domain positions + // F #F by 3 list of triangle indices into V + // Outputs: + // c dim vector of centroid coordinates + // vol total volume of solid. + // + template < + typename DerivedV, + typename DerivedF, + typename Derivedc, + typename Derivedvol> + IGL_INLINE void centroid( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + Eigen::PlainObjectBase& c, + Derivedvol & vol); + template < + typename DerivedV, + typename DerivedF, + typename Derivedc> + IGL_INLINE void centroid( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + Eigen::PlainObjectBase& c); + +} + +#ifndef IGL_STATIC_LIBRARY +# include "centroid.cpp" +#endif + +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/circulation.cpp b/src/external/libigl-2.3.0/include/igl/circulation.cpp new file mode 100644 index 000000000..b1bee7f0e --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/circulation.cpp @@ -0,0 +1,143 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "circulation.h" +#include "list_to_matrix.h" +#include + +IGL_INLINE std::vector igl::circulation( + const int e, + const bool ccw, + const Eigen::VectorXi & EMAP, + const Eigen::MatrixXi & EF, + const Eigen::MatrixXi & EI) +{ + // prepare output + std::vector N; + N.reserve(6); + const int m = EMAP.size()/3; + assert(m*3 == EMAP.size()); + const auto & step = [&]( + const int e, + const int ff, + int & ne, + int & nf) + { + assert((EF(e,1) == ff || EF(e,0) == ff) && "e should touch ff"); + //const int fside = EF(e,1)==ff?1:0; + const int nside = EF(e,0)==ff?1:0; + const int nv = EI(e,nside); + // get next face + nf = EF(e,nside); + // get next edge + const int dir = ccw?-1:1; + ne = EMAP(nf+m*((nv+dir+3)%3)); + }; + // Always start with first face (ccw in step will be sure to turn right + // direction) + const int f0 = EF(e,0); + int fi = f0; + int ei = e; + while(true) + { + step(ei,fi,ei,fi); + N.push_back(fi); + // back to start? + if(fi == f0) + { + assert(ei == e); + break; + } + } + return N; +} + +IGL_INLINE void igl::circulation( + const int e, + const bool ccw, + const Eigen::VectorXi & EMAP, + const Eigen::MatrixXi & EF, + const Eigen::MatrixXi & EI, + Eigen::VectorXi & vN) +{ + std::vector N = circulation(e,ccw,EMAP,EF,EI); + igl::list_to_matrix(N,vN); +} + +IGL_INLINE void igl::circulation( + const int e, + const bool ccw, + const Eigen::MatrixXi & F, + const Eigen::VectorXi & EMAP, + const Eigen::MatrixXi & EF, + const Eigen::MatrixXi & EI, + /*std::vector & Ne,*/ + std::vector & Nv, + std::vector & Nf) +{ + // + // for e --> (bf) and ccw=true + // + // c---d + // / \ / \ + // a---b-e-f + // \ / \ / + // g---h + // + // // (might start with {bhf} depending on edge) + // Ne = […] -> [fd db dc cb ca ab ag gb gh hb hf fb] + // {upto cylic order} + // Nf = […] -> [{bfd}, {bdc}, {bca}, {bag}, {bgh}, {bhf}] + // Nv = [d c a g h f] + // + // prepare output + //Ne.clear();Ne.reserve(2*10); + Nv.clear();Nv.reserve(10); + Nf.clear();Nf.reserve(10); + const int m = EMAP.size()/3; + assert(m*3 == EMAP.size()); + const auto & step = [&]( + const int e, + const int ff, + int & ne, + //int & re, + int & rv, + int & nf) + { + assert((EF(e,1) == ff || EF(e,0) == ff) && "e should touch ff"); + //const int fside = EF(e,1)==ff?1:0; + const int nside = EF(e,0)==ff?1:0; + const int nv = EI(e,nside); + // get next face + nf = EF(e,nside); + // get next edge + const int dir = ccw?-1:1; + rv = F(nf,nv); + ne = EMAP(nf+m*((nv+dir+3)%3)); + //re = EMAP(nf+m*((nv+2*dir+3)%3)); + }; + // Always start with first face (ccw in step will be sure to turn right + // direction) + const int f0 = EF(e,0); + int fi = f0; + int ei = e; + while(true) + { + int re,rv; + step(ei,fi,ei/*,re*/,rv,fi); + Nf.push_back(fi); + //Ne.push_back(re); + //Ne.push_back(ei); + Nv.push_back(rv); + // back to start? + if(fi == f0) + { + assert(ei == e); + break; + } + } +} diff --git a/src/external/libigl-2.3.0/include/igl/circulation.h b/src/external/libigl-2.3.0/include/igl/circulation.h new file mode 100644 index 000000000..ccd0eeacc --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/circulation.h @@ -0,0 +1,65 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_CIRCULATION_H +#define IGL_CIRCULATION_H +#include "igl_inline.h" +#include +#include + +namespace igl +{ + // Return list of faces around the end point of an edge. Assumes + // data-structures are built from an edge-manifold **closed** mesh. + // + // Inputs: + // e index into E of edge to circulate + // ccw whether to _continue_ in ccw direction of edge (circulate around + // E(e,1)) + // EMAP #F*3 list of indices into E, mapping each directed edge to unique + // unique edge in E + // EF #E by 2 list of edge flaps, EF(e,0)=f means e=(i-->j) is the edge of + // F(f,:) opposite the vth corner, where EI(e,0)=v. Similarly EF(e,1) " + // e=(j->i) + // EI #E by 2 list of edge flap corners (see above). + // Returns list of faces touched by circulation (in cyclically order). + // + // See also: edge_flaps + IGL_INLINE std::vector circulation( + const int e, + const bool ccw, + const Eigen::VectorXi & EMAP, + const Eigen::MatrixXi & EF, + const Eigen::MatrixXi & EI); + // Wrapper with VectorXi output. + IGL_INLINE void circulation( + const int e, + const bool ccw, + const Eigen::VectorXi & EMAP, + const Eigen::MatrixXi & EF, + const Eigen::MatrixXi & EI, + Eigen::VectorXi & vN); + // Outputs: + //// Ne 2*#Nf list of indices into E of "next" rim-spoke-rim-spoke-... + // Nv #Nv list of "next" vertex indices + // Nf #Nf list of face indices + IGL_INLINE void circulation( + const int e, + const bool ccw, + const Eigen::MatrixXi & F, + const Eigen::VectorXi & EMAP, + const Eigen::MatrixXi & EF, + const Eigen::MatrixXi & EI, + /*std::vector & Ne,*/ + std::vector & Nv, + std::vector & Nf); +} + +#ifndef IGL_STATIC_LIBRARY +# include "circulation.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/circumradius.cpp b/src/external/libigl-2.3.0/include/igl/circumradius.cpp new file mode 100644 index 000000000..88fcbf39a --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/circumradius.cpp @@ -0,0 +1,30 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "circumradius.h" +#include "edge_lengths.h" +#include "doublearea.h" +template < + typename DerivedV, + typename DerivedF, + typename DerivedR> +IGL_INLINE void igl::circumradius( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + Eigen::PlainObjectBase & R) +{ + Eigen::Matrix l; + igl::edge_lengths(V,F,l); + DerivedR A; + igl::doublearea(l,0.,A); + // use formula: R=abc/(4*area) to compute the circum radius + R = l.col(0).array() * l.col(1).array() * l.col(2).array() / (2.0*A.array()); +} + +#ifdef IGL_STATIC_LIBRARY +template void igl::circumradius, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/circumradius.h b/src/external/libigl-2.3.0/include/igl/circumradius.h new file mode 100644 index 000000000..e8187cb04 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/circumradius.h @@ -0,0 +1,34 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_CIRCUMRADIUS_H +#define IGL_CIRCUMRADIUS_H +#include "igl_inline.h" +#include +namespace igl +{ + // Compute the circumradius of each triangle in a mesh (V,F) + // + // Inputs: + // V #V by dim list of mesh vertex positions + // F #F by 3 list of triangle indices into V + // Outputs: + // R #F list of circumradius + // + template < + typename DerivedV, + typename DerivedF, + typename DerivedR> + IGL_INLINE void circumradius( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + Eigen::PlainObjectBase & R); +} +#ifndef IGL_STATIC_LIBRARY +# include "circumradius.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/collapse_edge.cpp b/src/external/libigl-2.3.0/include/igl/collapse_edge.cpp new file mode 100644 index 000000000..268a1046a --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/collapse_edge.cpp @@ -0,0 +1,373 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "collapse_edge.h" +#include "circulation.h" +#include "edge_collapse_is_valid.h" +#include "decimate_trivial_callbacks.h" +#include + +IGL_INLINE bool igl::collapse_edge( + const int e, + const Eigen::RowVectorXd & p, + Eigen::MatrixXd & V, + Eigen::MatrixXi & F, + Eigen::MatrixXi & E, + Eigen::VectorXi & EMAP, + Eigen::MatrixXi & EF, + Eigen::MatrixXi & EI, + int & e1, + int & e2, + int & f1, + int & f2) +{ + std::vector /*Nse,*/Nsf,Nsv; + circulation(e, true,F,EMAP,EF,EI,/*Nse,*/Nsv,Nsf); + std::vector /*Nde,*/Ndf,Ndv; + circulation(e, false,F,EMAP,EF,EI,/*Nde,*/Ndv,Ndf); + return collapse_edge( + e,p,Nsv,Nsf,Ndv,Ndf,V,F,E,EMAP,EF,EI,e1,e2,f1,f2); +} + +IGL_INLINE bool igl::collapse_edge( + const int e, + const Eigen::RowVectorXd & p, + /*const*/ std::vector & Nsv, + const std::vector & Nsf, + /*const*/ std::vector & Ndv, + const std::vector & Ndf, + Eigen::MatrixXd & V, + Eigen::MatrixXi & F, + Eigen::MatrixXi & E, + Eigen::VectorXi & EMAP, + Eigen::MatrixXi & EF, + Eigen::MatrixXi & EI, + int & a_e1, + int & a_e2, + int & a_f1, + int & a_f2) +{ + // Assign this to 0 rather than, say, -1 so that deleted elements will get + // draw as degenerate elements at vertex 0 (which should always exist and + // never get collapsed to anything else since it is the smallest index) + using namespace Eigen; + using namespace std; + const int eflip = E(e,0)>E(e,1); + // source and destination + const int s = eflip?E(e,1):E(e,0); + const int d = eflip?E(e,0):E(e,1); + + if(!edge_collapse_is_valid(Nsv,Ndv)) + { + return false; + } + + // OVERLOAD: caller may have just computed this + // + // Important to grab neighbors of d before monkeying with edges + const std::vector & nV2Fd = (!eflip ? Nsf : Ndf); + + // The following implementation strongly relies on s > & Q, + Eigen::VectorXi & EQ, + Eigen::MatrixXd & C) +{ + int e,e1,e2,f1,f2; + decimate_pre_collapse_callback always_try; + decimate_post_collapse_callback never_care; + decimate_trivial_callbacks(always_try,never_care); + return + collapse_edge( + cost_and_placement,always_try,never_care, + V,F,E,EMAP,EF,EI,Q,EQ,C,e,e1,e2,f1,f2); +} + +IGL_INLINE bool igl::collapse_edge( + const decimate_cost_and_placement_callback & cost_and_placement, + const decimate_pre_collapse_callback & pre_collapse, + const decimate_post_collapse_callback & post_collapse, + Eigen::MatrixXd & V, + Eigen::MatrixXi & F, + Eigen::MatrixXi & E, + Eigen::VectorXi & EMAP, + Eigen::MatrixXi & EF, + Eigen::MatrixXi & EI, + igl::min_heap< std::tuple > & Q, + Eigen::VectorXi & EQ, + Eigen::MatrixXd & C) +{ + int e,e1,e2,f1,f2; + return + collapse_edge( + cost_and_placement,pre_collapse,post_collapse, + V,F,E,EMAP,EF,EI,Q,EQ,C,e,e1,e2,f1,f2); +} + + +IGL_INLINE bool igl::collapse_edge( + const decimate_cost_and_placement_callback & cost_and_placement, + const decimate_pre_collapse_callback & pre_collapse, + const decimate_post_collapse_callback & post_collapse, + Eigen::MatrixXd & V, + Eigen::MatrixXi & F, + Eigen::MatrixXi & E, + Eigen::VectorXi & EMAP, + Eigen::MatrixXi & EF, + Eigen::MatrixXi & EI, + igl::min_heap< std::tuple > & Q, + Eigen::VectorXi & EQ, + Eigen::MatrixXd & C, + int & e, + int & e1, + int & e2, + int & f1, + int & f2) +{ + using namespace Eigen; + using namespace igl; + std::tuple p; + while(true) + { + // Check if Q is empty + if(Q.empty()) + { + // no edges to collapse + e = -1; + return false; + } + // pop from Q + p = Q.top(); + if(std::get<0>(p) == std::numeric_limits::infinity()) + { + e = -1; + // min cost edge is infinite cost + return false; + } + Q.pop(); + e = std::get<1>(p); + // Check if matches timestamp + if(std::get<2>(p) == EQ(e)) + { + break; + } + // must be stale or dead. + assert(std::get<2>(p) < EQ(e) || EQ(e) == -1); + // try again. + } + + // Why is this computed up here? + // If we just need original face neighbors of edge, could we gather that more + // directly than gathering face neighbors of each vertex? + std::vector /*Nse,*/Nsf,Nsv; + circulation(e, true,F,EMAP,EF,EI,/*Nse,*/Nsv,Nsf); + std::vector /*Nde,*/Ndf,Ndv; + circulation(e, false,F,EMAP,EF,EI,/*Nde,*/Ndv,Ndf); + + + bool collapsed = true; + if(pre_collapse(V,F,E,EMAP,EF,EI,Q,EQ,C,e)) + { + collapsed = collapse_edge( + e,C.row(e), + Nsv,Nsf,Ndv,Ndf, + V,F,E,EMAP,EF,EI,e1,e2,f1,f2); + }else + { + // Aborted by pre collapse callback + collapsed = false; + } + post_collapse(V,F,E,EMAP,EF,EI,Q,EQ,C,e,e1,e2,f1,f2,collapsed); + if(collapsed) + { + // Erase the two, other collapsed edges by marking their timestamps as -1 + EQ(e1) = -1; + EQ(e2) = -1; + // TODO: visits edges multiple times, ~150% more updates than should + // + // update local neighbors + // loop over original face neighbors + // + // Can't use previous computed Nse and Nde because those refer to EMAP + // before it was changed... + std::vector Nf; + Nf.reserve( Nsf.size() + Ndf.size() ); // preallocate memory + Nf.insert( Nf.end(), Nsf.begin(), Nsf.end() ); + Nf.insert( Nf.end(), Ndf.begin(), Ndf.end() ); + // https://stackoverflow.com/a/1041939/148668 + std::sort( Nf.begin(), Nf.end() ); + Nf.erase( std::unique( Nf.begin(), Nf.end() ), Nf.end() ); + // Collect all edges that must be updated + std::vector Ne; + Ne.reserve(3*Nf.size()); + for(auto & n : Nf) + { + if(F(n,0) != IGL_COLLAPSE_EDGE_NULL || + F(n,1) != IGL_COLLAPSE_EDGE_NULL || + F(n,2) != IGL_COLLAPSE_EDGE_NULL) + { + for(int v = 0;v<3;v++) + { + // get edge id + const int ei = EMAP(v*F.rows()+n); + Ne.push_back(ei); + } + } + } + // Only process edge once + std::sort( Ne.begin(), Ne.end() ); + Ne.erase( std::unique( Ne.begin(), Ne.end() ), Ne.end() ); + for(auto & ei : Ne) + { + // compute cost and potential placement + double cost; + RowVectorXd place; + cost_and_placement(ei,V,F,E,EMAP,EF,EI,cost,place); + // Increment timestamp + EQ(ei)++; + // Replace in queue + Q.emplace(cost,ei,EQ(ei)); + C.row(ei) = place; + } + }else + { + // reinsert with infinite weight (the provided cost function must **not** + // have given this un-collapsable edge inf cost already) + // Increment timestamp + EQ(e)++; + // Replace in queue + Q.emplace(std::numeric_limits::infinity(),e,EQ(e)); + } + return collapsed; +} diff --git a/src/external/libigl-2.3.0/include/igl/collapse_edge.h b/src/external/libigl-2.3.0/include/igl/collapse_edge.h new file mode 100644 index 000000000..bdb76c186 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/collapse_edge.h @@ -0,0 +1,161 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_COLLAPSE_EDGE_H +#define IGL_COLLAPSE_EDGE_H +#include "igl_inline.h" +#include "min_heap.h" +#include "decimate_callback_types.h" +#include +#include +#include +namespace igl +{ + // Assumes (V,F) is a closed manifold mesh (except for previously collapsed + // faces which should be set to: + // [IGL_COLLAPSE_EDGE_NULL IGL_COLLAPSE_EDGE_NULL IGL_COLLAPSE_EDGE_NULL]. + // Collapses exactly two faces and exactly 3 edges from E (e and one side of + // each face gets collapsed to the other). This is implemented in a way that + // it can be repeatedly called until satisfaction and then the garbage in F + // can be collected by removing NULL faces. + // + // Inputs: + // e index into E of edge to try to collapse. E(e,:) = [s d] or [d s] so + // that sj) is the edge of + // F(f,:) opposite the vth corner, where EI(e,0)=v. Similarly EF(e,1) " + // e=(j->i) + // EI #E by 2 list of edge flap corners (see above). + // e1 index into E of edge collpased on left + // e2 index into E of edge collpased on right + // f1 index into F of face collpased on left + // f2 index into F of face collpased on right + // Returns true if edge was collapsed + #define IGL_COLLAPSE_EDGE_NULL 0 + IGL_INLINE bool collapse_edge( + const int e, + const Eigen::RowVectorXd & p, + Eigen::MatrixXd & V, + Eigen::MatrixXi & F, + Eigen::MatrixXi & E, + Eigen::VectorXi & EMAP, + Eigen::MatrixXi & EF, + Eigen::MatrixXi & EI, + int & e1, + int & e2, + int & f1, + int & f2); + // Inputs: + IGL_INLINE bool collapse_edge( + const int e, + const Eigen::RowVectorXd & p, + /*const*/ std::vector & Nsv, + const std::vector & Nsf, + /*const*/ std::vector & Ndv, + const std::vector & Ndf, + Eigen::MatrixXd & V, + Eigen::MatrixXi & F, + Eigen::MatrixXi & E, + Eigen::VectorXi & EMAP, + Eigen::MatrixXi & EF, + Eigen::MatrixXi & EI, + int & e1, + int & e2, + int & f1, + int & f2); + IGL_INLINE bool collapse_edge( + const int e, + const Eigen::RowVectorXd & p, + Eigen::MatrixXd & V, + Eigen::MatrixXi & F, + Eigen::MatrixXi & E, + Eigen::VectorXi & EMAP, + Eigen::MatrixXi & EF, + Eigen::MatrixXi & EI); + // Collapse least-cost edge from a priority queue and update queue + // + // Inputs/Outputs: + // cost_and_placement function computing cost of collapsing an edge and 3d + // position where it should be placed: + // cost_and_placement(V,F,E,EMAP,EF,EI,cost,placement); + // **If the edges is collapsed** then this function will be called on all + // edges of all faces previously incident on the endpoints of the + // collapsed edge. + // Q queue containing pairs of costs and edge indices and insertion "time" + // EQ #E list of "time" of last time pushed into Q + // C #E by dim list of stored placements + IGL_INLINE bool collapse_edge( + const decimate_cost_and_placement_callback & cost_and_placement, + Eigen::MatrixXd & V, + Eigen::MatrixXi & F, + Eigen::MatrixXi & E, + Eigen::VectorXi & EMAP, + Eigen::MatrixXi & EF, + Eigen::MatrixXi & EI, + igl::min_heap< std::tuple > & Q, + Eigen::VectorXi & EQ, + Eigen::MatrixXd & C); + // Inputs: + // pre_collapse callback called with index of edge whose collapse is about + // to be attempted. This function should return whether to **proceed** + // with the collapse: returning true means "yes, try to collapse", + // returning false means "No, consider this edge 'uncollapsable', behave + // as if collapse_edge(e) returned false. + // post_collapse callback called with index of edge whose collapse was + // just attempted and a flag revealing whether this was successful. + IGL_INLINE bool collapse_edge( + const decimate_cost_and_placement_callback & cost_and_placement, + const decimate_pre_collapse_callback & pre_collapse, + const decimate_post_collapse_callback & post_collapse, + Eigen::MatrixXd & V, + Eigen::MatrixXi & F, + Eigen::MatrixXi & E, + Eigen::VectorXi & EMAP, + Eigen::MatrixXi & EF, + Eigen::MatrixXi & EI, + igl::min_heap< std::tuple > & Q, + Eigen::VectorXi & EQ, + Eigen::MatrixXd & C); + // Outputs: + // e index into E of attempted collapsed edge. Set to -1 if Q is empty or + // contains only infinite cost edges. + // e1 index into E of edge collpased on left. + // e2 index into E of edge collpased on right. + // f1 index into F of face collpased on left. + // f2 index into F of face collpased on right. + IGL_INLINE bool collapse_edge( + const decimate_cost_and_placement_callback & cost_and_placement, + const decimate_pre_collapse_callback & pre_collapse, + const decimate_post_collapse_callback & post_collapse, + Eigen::MatrixXd & V, + Eigen::MatrixXi & F, + Eigen::MatrixXi & E, + Eigen::VectorXi & EMAP, + Eigen::MatrixXi & EF, + Eigen::MatrixXi & EI, + igl::min_heap< std::tuple > & Q, + Eigen::VectorXi & EQ, + Eigen::MatrixXd & C, + int & e, + int & e1, + int & e2, + int & f1, + int & f2); +} + +#ifndef IGL_STATIC_LIBRARY +# include "collapse_edge.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/collapse_small_triangles.cpp b/src/external/libigl-2.3.0/include/igl/collapse_small_triangles.cpp new file mode 100644 index 000000000..5177c584f --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/collapse_small_triangles.cpp @@ -0,0 +1,139 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "collapse_small_triangles.h" + +#include "bounding_box_diagonal.h" +#include "doublearea.h" +#include "edge_lengths.h" +#include "colon.h" +#include "faces_first.h" + +#include + +#include + +void igl::collapse_small_triangles( + const Eigen::MatrixXd & V, + const Eigen::MatrixXi & F, + const double eps, + Eigen::MatrixXi & FF) +{ + using namespace Eigen; + using namespace std; + + // Compute bounding box diagonal length + double bbd = bounding_box_diagonal(V); + MatrixXd l; + edge_lengths(V,F,l); + VectorXd dblA; + doublearea(l,0.,dblA); + + // Minimum area tolerance + const double min_dblarea = 2.0*eps*bbd*bbd; + + Eigen::VectorXi FIM = colon(0,V.rows()-1); + int num_edge_collapses = 0; + // Loop over triangles + for(int f = 0;fmaxl) + { + maxli = e; + maxl = l(f,e); + } + } + // Be sure that min and max aren't the same + maxli = (minli==maxli?(minli+1)%3:maxli); + + // Collapse min edge maintaining max edge: i-->j + // Q: Why this direction? + int i = maxli; + int j = ((minli+1)%3 == maxli ? (minli+2)%3: (minli+1)%3); + assert(i != minli); + assert(j != minli); + assert(i != j); + FIM(F(f,i)) = FIM(F(f,j)); + num_edge_collapses++; + } + } + + // Reindex faces + MatrixXi rF = F; + // Loop over triangles + for(int f = 0;f +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_COLLAPSE_SMALL_TRIANGLES_H +#define IGL_COLLAPSE_SMALL_TRIANGLES_H +#include +namespace igl +{ + // Given a triangle mesh (V,F) compute a new mesh (VV,FF) which contains the + // original faces and vertices of (V,F) except any small triangles have been + // removed via collapse. + // + // We are *not* following the rules in "Mesh Optimization" [Hoppe et al] + // Section 4.2. But for our purposes we don't care about this criteria. + // + // Inputs: + // V #V by 3 list of vertex positions + // F #F by 3 list of triangle indices into V + // eps epsilon for smallest allowed area treated as fraction of squared bounding box + // diagonal + // Outputs: + // FF #FF by 3 list of triangle indices into V + // + // + void collapse_small_triangles( + const Eigen::MatrixXd & V, + const Eigen::MatrixXi & F, + const double eps, + Eigen::MatrixXi & FF); +} + +#ifndef IGL_STATIC_LIBRARY +# include "collapse_small_triangles.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/colon.cpp b/src/external/libigl-2.3.0/include/igl/colon.cpp new file mode 100644 index 000000000..d7a5c8497 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/colon.cpp @@ -0,0 +1,69 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "colon.h" +#include "LinSpaced.h" + +#include + +template +IGL_INLINE void igl::colon( + const L low, + const S step, + const H hi, + Eigen::Matrix & I) +{ + const H size = ((hi-low)/step)+1; + I = igl::LinSpaced >(size,low,low+step*(size-1)); +} + +template +IGL_INLINE void igl::colon( + const L low, + const H hi, + Eigen::Matrix & I) +{ + return igl::colon(low,(T)1,hi,I); +} + +template +IGL_INLINE Eigen::Matrix igl::colon( + const L low, + const H hi) +{ + Eigen::Matrix I; + igl::colon(low,hi,I); + return I; +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template Eigen::Matrix igl::colon(int, int); +template Eigen::Matrix igl::colon(int, long); +template Eigen::Matrix igl::colon(int, long long int); +template Eigen::Matrix igl::colon(double, double); +template void igl::colon(int, long, Eigen::Matrix &); +// generated by autoexplicit.sh +template void igl::colon(int, long, int, Eigen::Matrix &); +template void igl::colon(int, int, long, Eigen::Matrix &); +template void igl::colon(int, long, Eigen::Matrix &); +template void igl::colon(int, int, Eigen::Matrix &); +template void igl::colon(int, long long int, Eigen::Matrix &); +template void igl::colon(int, int, int, Eigen::Matrix &); +template void igl::colon(int, long, Eigen::Matrix &); +template void igl::colon(int, double, double, Eigen::Matrix &); +template void igl::colon(double, double, Eigen::Matrix &); +template void igl::colon(double, double, double, Eigen::Matrix &); +template void igl::colon(int, int, Eigen::Matrix &); +template void igl::colon(int, int, Eigen::Matrix &); +#ifdef WIN32 +template void igl::colon(int, __int64, class Eigen::Matrix &); +template void igl::colon(int, long long, class Eigen::Matrix &); +template void igl::colon(int, __int64, class Eigen::Matrix<__int64, -1, 1, 0, -1, 1> &); +#endif +#endif \ No newline at end of file diff --git a/src/external/libigl-2.3.0/include/igl/colon.h b/src/external/libigl-2.3.0/include/igl/colon.h new file mode 100644 index 000000000..1f2b9bf6f --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/colon.h @@ -0,0 +1,65 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_COLON_H +#define IGL_COLON_H +#include "igl_inline.h" +#include +namespace igl +{ + // Note: + // This should be potentially replaced with eigen's LinSpaced() function + // + // If step = 1, it's about 5 times faster to use: + // X = Eigen::VectorXi::LinSpaced(n,0,n-1); + // than + // X = igl::colon(0,n-1); + // + + // Colon operator like matlab's colon operator. Enumerats values between low + // and hi with step step. + // Templates: + // L should be a eigen matrix primitive type like int or double + // S should be a eigen matrix primitive type like int or double + // H should be a eigen matrix primitive type like int or double + // T should be a eigen matrix primitive type like int or double + // Inputs: + // low starting value if step is valid then this is *always* the first + // element of I + // step step difference between sequential elements returned in I, + // remember this will be cast to template T at compile time. If lowhi then step must be negative. + // Otherwise I will be set to empty. + // hi ending value, if (hi-low)%step is zero then this will be the last + // element in I. If step is positive there will be no elements greater + // than hi, vice versa if hi + IGL_INLINE void colon( + const L low, + const S step, + const H hi, + Eigen::Matrix & I); + // Same as above but step == (T)1 + template + IGL_INLINE void colon( + const L low, + const H hi, + Eigen::Matrix & I); + // Return output rather than set in reference + template + IGL_INLINE Eigen::Matrix colon( + const L low, + const H hi); +} + +#ifndef IGL_STATIC_LIBRARY +# include "colon.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/colormap.cpp b/src/external/libigl-2.3.0/include/igl/colormap.cpp new file mode 100644 index 000000000..ff9e433e4 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/colormap.cpp @@ -0,0 +1,1697 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2017 Joe Graus , Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "colormap.h" +#include + +// One of the new matplotlib colormaps by Nathaniel J.Smith, Stefan van der Walt, and (in the case of viridis) Eric Firing. +// Released under the CC0 license / public domain dedication + +namespace igl +{ + +static double turbo_cm[256][3] = { + {0.18995,0.07176,0.23217}, + {0.19483,0.08339,0.26149}, + {0.19956,0.09498,0.29024}, + {0.20415,0.10652,0.31844}, + {0.20860,0.11802,0.34607}, + {0.21291,0.12947,0.37314}, + {0.21708,0.14087,0.39964}, + {0.22111,0.15223,0.42558}, + {0.22500,0.16354,0.45096}, + {0.22875,0.17481,0.47578}, + {0.23236,0.18603,0.50004}, + {0.23582,0.19720,0.52373}, + {0.23915,0.20833,0.54686}, + {0.24234,0.21941,0.56942}, + {0.24539,0.23044,0.59142}, + {0.24830,0.24143,0.61286}, + {0.25107,0.25237,0.63374}, + {0.25369,0.26327,0.65406}, + {0.25618,0.27412,0.67381}, + {0.25853,0.28492,0.69300}, + {0.26074,0.29568,0.71162}, + {0.26280,0.30639,0.72968}, + {0.26473,0.31706,0.74718}, + {0.26652,0.32768,0.76412}, + {0.26816,0.33825,0.78050}, + {0.26967,0.34878,0.79631}, + {0.27103,0.35926,0.81156}, + {0.27226,0.36970,0.82624}, + {0.27334,0.38008,0.84037}, + {0.27429,0.39043,0.85393}, + {0.27509,0.40072,0.86692}, + {0.27576,0.41097,0.87936}, + {0.27628,0.42118,0.89123}, + {0.27667,0.43134,0.90254}, + {0.27691,0.44145,0.91328}, + {0.27701,0.45152,0.92347}, + {0.27698,0.46153,0.93309}, + {0.27680,0.47151,0.94214}, + {0.27648,0.48144,0.95064}, + {0.27603,0.49132,0.95857}, + {0.27543,0.50115,0.96594}, + {0.27469,0.51094,0.97275}, + {0.27381,0.52069,0.97899}, + {0.27273,0.53040,0.98461}, + {0.27106,0.54015,0.98930}, + {0.26878,0.54995,0.99303}, + {0.26592,0.55979,0.99583}, + {0.26252,0.56967,0.99773}, + {0.25862,0.57958,0.99876}, + {0.25425,0.58950,0.99896}, + {0.24946,0.59943,0.99835}, + {0.24427,0.60937,0.99697}, + {0.23874,0.61931,0.99485}, + {0.23288,0.62923,0.99202}, + {0.22676,0.63913,0.98851}, + {0.22039,0.64901,0.98436}, + {0.21382,0.65886,0.97959}, + {0.20708,0.66866,0.97423}, + {0.20021,0.67842,0.96833}, + {0.19326,0.68812,0.96190}, + {0.18625,0.69775,0.95498}, + {0.17923,0.70732,0.94761}, + {0.17223,0.71680,0.93981}, + {0.16529,0.72620,0.93161}, + {0.15844,0.73551,0.92305}, + {0.15173,0.74472,0.91416}, + {0.14519,0.75381,0.90496}, + {0.13886,0.76279,0.89550}, + {0.13278,0.77165,0.88580}, + {0.12698,0.78037,0.87590}, + {0.12151,0.78896,0.86581}, + {0.11639,0.79740,0.85559}, + {0.11167,0.80569,0.84525}, + {0.10738,0.81381,0.83484}, + {0.10357,0.82177,0.82437}, + {0.10026,0.82955,0.81389}, + {0.09750,0.83714,0.80342}, + {0.09532,0.84455,0.79299}, + {0.09377,0.85175,0.78264}, + {0.09287,0.85875,0.77240}, + {0.09267,0.86554,0.76230}, + {0.09320,0.87211,0.75237}, + {0.09451,0.87844,0.74265}, + {0.09662,0.88454,0.73316}, + {0.09958,0.89040,0.72393}, + {0.10342,0.89600,0.71500}, + {0.10815,0.90142,0.70599}, + {0.11374,0.90673,0.69651}, + {0.12014,0.91193,0.68660}, + {0.12733,0.91701,0.67627}, + {0.13526,0.92197,0.66556}, + {0.14391,0.92680,0.65448}, + {0.15323,0.93151,0.64308}, + {0.16319,0.93609,0.63137}, + {0.17377,0.94053,0.61938}, + {0.18491,0.94484,0.60713}, + {0.19659,0.94901,0.59466}, + {0.20877,0.95304,0.58199}, + {0.22142,0.95692,0.56914}, + {0.23449,0.96065,0.55614}, + {0.24797,0.96423,0.54303}, + {0.26180,0.96765,0.52981}, + {0.27597,0.97092,0.51653}, + {0.29042,0.97403,0.50321}, + {0.30513,0.97697,0.48987}, + {0.32006,0.97974,0.47654}, + {0.33517,0.98234,0.46325}, + {0.35043,0.98477,0.45002}, + {0.36581,0.98702,0.43688}, + {0.38127,0.98909,0.42386}, + {0.39678,0.99098,0.41098}, + {0.41229,0.99268,0.39826}, + {0.42778,0.99419,0.38575}, + {0.44321,0.99551,0.37345}, + {0.45854,0.99663,0.36140}, + {0.47375,0.99755,0.34963}, + {0.48879,0.99828,0.33816}, + {0.50362,0.99879,0.32701}, + {0.51822,0.99910,0.31622}, + {0.53255,0.99919,0.30581}, + {0.54658,0.99907,0.29581}, + {0.56026,0.99873,0.28623}, + {0.57357,0.99817,0.27712}, + {0.58646,0.99739,0.26849}, + {0.59891,0.99638,0.26038}, + {0.61088,0.99514,0.25280}, + {0.62233,0.99366,0.24579}, + {0.63323,0.99195,0.23937}, + {0.64362,0.98999,0.23356}, + {0.65394,0.98775,0.22835}, + {0.66428,0.98524,0.22370}, + {0.67462,0.98246,0.21960}, + {0.68494,0.97941,0.21602}, + {0.69525,0.97610,0.21294}, + {0.70553,0.97255,0.21032}, + {0.71577,0.96875,0.20815}, + {0.72596,0.96470,0.20640}, + {0.73610,0.96043,0.20504}, + {0.74617,0.95593,0.20406}, + {0.75617,0.95121,0.20343}, + {0.76608,0.94627,0.20311}, + {0.77591,0.94113,0.20310}, + {0.78563,0.93579,0.20336}, + {0.79524,0.93025,0.20386}, + {0.80473,0.92452,0.20459}, + {0.81410,0.91861,0.20552}, + {0.82333,0.91253,0.20663}, + {0.83241,0.90627,0.20788}, + {0.84133,0.89986,0.20926}, + {0.85010,0.89328,0.21074}, + {0.85868,0.88655,0.21230}, + {0.86709,0.87968,0.21391}, + {0.87530,0.87267,0.21555}, + {0.88331,0.86553,0.21719}, + {0.89112,0.85826,0.21880}, + {0.89870,0.85087,0.22038}, + {0.90605,0.84337,0.22188}, + {0.91317,0.83576,0.22328}, + {0.92004,0.82806,0.22456}, + {0.92666,0.82025,0.22570}, + {0.93301,0.81236,0.22667}, + {0.93909,0.80439,0.22744}, + {0.94489,0.79634,0.22800}, + {0.95039,0.78823,0.22831}, + {0.95560,0.78005,0.22836}, + {0.96049,0.77181,0.22811}, + {0.96507,0.76352,0.22754}, + {0.96931,0.75519,0.22663}, + {0.97323,0.74682,0.22536}, + {0.97679,0.73842,0.22369}, + {0.98000,0.73000,0.22161}, + {0.98289,0.72140,0.21918}, + {0.98549,0.71250,0.21650}, + {0.98781,0.70330,0.21358}, + {0.98986,0.69382,0.21043}, + {0.99163,0.68408,0.20706}, + {0.99314,0.67408,0.20348}, + {0.99438,0.66386,0.19971}, + {0.99535,0.65341,0.19577}, + {0.99607,0.64277,0.19165}, + {0.99654,0.63193,0.18738}, + {0.99675,0.62093,0.18297}, + {0.99672,0.60977,0.17842}, + {0.99644,0.59846,0.17376}, + {0.99593,0.58703,0.16899}, + {0.99517,0.57549,0.16412}, + {0.99419,0.56386,0.15918}, + {0.99297,0.55214,0.15417}, + {0.99153,0.54036,0.14910}, + {0.98987,0.52854,0.14398}, + {0.98799,0.51667,0.13883}, + {0.98590,0.50479,0.13367}, + {0.98360,0.49291,0.12849}, + {0.98108,0.48104,0.12332}, + {0.97837,0.46920,0.11817}, + {0.97545,0.45740,0.11305}, + {0.97234,0.44565,0.10797}, + {0.96904,0.43399,0.10294}, + {0.96555,0.42241,0.09798}, + {0.96187,0.41093,0.09310}, + {0.95801,0.39958,0.08831}, + {0.95398,0.38836,0.08362}, + {0.94977,0.37729,0.07905}, + {0.94538,0.36638,0.07461}, + {0.94084,0.35566,0.07031}, + {0.93612,0.34513,0.06616}, + {0.93125,0.33482,0.06218}, + {0.92623,0.32473,0.05837}, + {0.92105,0.31489,0.05475}, + {0.91572,0.30530,0.05134}, + {0.91024,0.29599,0.04814}, + {0.90463,0.28696,0.04516}, + {0.89888,0.27824,0.04243}, + {0.89298,0.26981,0.03993}, + {0.88691,0.26152,0.03753}, + {0.88066,0.25334,0.03521}, + {0.87422,0.24526,0.03297}, + {0.86760,0.23730,0.03082}, + {0.86079,0.22945,0.02875}, + {0.85380,0.22170,0.02677}, + {0.84662,0.21407,0.02487}, + {0.83926,0.20654,0.02305}, + {0.83172,0.19912,0.02131}, + {0.82399,0.19182,0.01966}, + {0.81608,0.18462,0.01809}, + {0.80799,0.17753,0.01660}, + {0.79971,0.17055,0.01520}, + {0.79125,0.16368,0.01387}, + {0.78260,0.15693,0.01264}, + {0.77377,0.15028,0.01148}, + {0.76476,0.14374,0.01041}, + {0.75556,0.13731,0.00942}, + {0.74617,0.13098,0.00851}, + {0.73661,0.12477,0.00769}, + {0.72686,0.11867,0.00695}, + {0.71692,0.11268,0.00629}, + {0.70680,0.10680,0.00571}, + {0.69650,0.10102,0.00522}, + {0.68602,0.09536,0.00481}, + {0.67535,0.08980,0.00449}, + {0.66449,0.08436,0.00424}, + {0.65345,0.07902,0.00408}, + {0.64223,0.07380,0.00401}, + {0.63082,0.06868,0.00401}, + {0.61923,0.06367,0.00410}, + {0.60746,0.05878,0.00427}, + {0.59550,0.05399,0.00453}, + {0.58336,0.04931,0.00486}, + {0.57103,0.04474,0.00529}, + {0.55852,0.04028,0.00579}, + {0.54583,0.03593,0.00638}, + {0.53295,0.03169,0.00705}, + {0.51989,0.02756,0.00780}, + {0.50664,0.02354,0.00863}, + {0.49321,0.01963,0.00955}, + {0.47960,0.01583,0.01055} +}; + +static double inferno_cm[256][3] = { + { 0.001462, 0.000466, 0.013866 }, + { 0.002267, 0.001270, 0.018570 }, + { 0.003299, 0.002249, 0.024239 }, + { 0.004547, 0.003392, 0.030909 }, + { 0.006006, 0.004692, 0.038558 }, + { 0.007676, 0.006136, 0.046836 }, + { 0.009561, 0.007713, 0.055143 }, + { 0.011663, 0.009417, 0.063460 }, + { 0.013995, 0.011225, 0.071862 }, + { 0.016561, 0.013136, 0.080282 }, + { 0.019373, 0.015133, 0.088767 }, + { 0.022447, 0.017199, 0.097327 }, + { 0.025793, 0.019331, 0.105930 }, + { 0.029432, 0.021503, 0.114621 }, + { 0.033385, 0.023702, 0.123397 }, + { 0.037668, 0.025921, 0.132232 }, + { 0.042253, 0.028139, 0.141141 }, + { 0.046915, 0.030324, 0.150164 }, + { 0.051644, 0.032474, 0.159254 }, + { 0.056449, 0.034569, 0.168414 }, + { 0.061340, 0.036590, 0.177642 }, + { 0.066331, 0.038504, 0.186962 }, + { 0.071429, 0.040294, 0.196354 }, + { 0.076637, 0.041905, 0.205799 }, + { 0.081962, 0.043328, 0.215289 }, + { 0.087411, 0.044556, 0.224813 }, + { 0.092990, 0.045583, 0.234358 }, + { 0.098702, 0.046402, 0.243904 }, + { 0.104551, 0.047008, 0.253430 }, + { 0.110536, 0.047399, 0.262912 }, + { 0.116656, 0.047574, 0.272321 }, + { 0.122908, 0.047536, 0.281624 }, + { 0.129285, 0.047293, 0.290788 }, + { 0.135778, 0.046856, 0.299776 }, + { 0.142378, 0.046242, 0.308553 }, + { 0.149073, 0.045468, 0.317085 }, + { 0.155850, 0.044559, 0.325338 }, + { 0.162689, 0.043554, 0.333277 }, + { 0.169575, 0.042489, 0.340874 }, + { 0.176493, 0.041402, 0.348111 }, + { 0.183429, 0.040329, 0.354971 }, + { 0.190367, 0.039309, 0.361447 }, + { 0.197297, 0.038400, 0.367535 }, + { 0.204209, 0.037632, 0.373238 }, + { 0.211095, 0.037030, 0.378563 }, + { 0.217949, 0.036615, 0.383522 }, + { 0.224763, 0.036405, 0.388129 }, + { 0.231538, 0.036405, 0.392400 }, + { 0.238273, 0.036621, 0.396353 }, + { 0.244967, 0.037055, 0.400007 }, + { 0.251620, 0.037705, 0.403378 }, + { 0.258234, 0.038571, 0.406485 }, + { 0.264810, 0.039647, 0.409345 }, + { 0.271347, 0.040922, 0.411976 }, + { 0.277850, 0.042353, 0.414392 }, + { 0.284321, 0.043933, 0.416608 }, + { 0.290763, 0.045644, 0.418637 }, + { 0.297178, 0.047470, 0.420491 }, + { 0.303568, 0.049396, 0.422182 }, + { 0.309935, 0.051407, 0.423721 }, + { 0.316282, 0.053490, 0.425116 }, + { 0.322610, 0.055634, 0.426377 }, + { 0.328921, 0.057827, 0.427511 }, + { 0.335217, 0.060060, 0.428524 }, + { 0.341500, 0.062325, 0.429425 }, + { 0.347771, 0.064616, 0.430217 }, + { 0.354032, 0.066925, 0.430906 }, + { 0.360284, 0.069247, 0.431497 }, + { 0.366529, 0.071579, 0.431994 }, + { 0.372768, 0.073915, 0.432400 }, + { 0.379001, 0.076253, 0.432719 }, + { 0.385228, 0.078591, 0.432955 }, + { 0.391453, 0.080927, 0.433109 }, + { 0.397674, 0.083257, 0.433183 }, + { 0.403894, 0.085580, 0.433179 }, + { 0.410113, 0.087896, 0.433098 }, + { 0.416331, 0.090203, 0.432943 }, + { 0.422549, 0.092501, 0.432714 }, + { 0.428768, 0.094790, 0.432412 }, + { 0.434987, 0.097069, 0.432039 }, + { 0.441207, 0.099338, 0.431594 }, + { 0.447428, 0.101597, 0.431080 }, + { 0.453651, 0.103848, 0.430498 }, + { 0.459875, 0.106089, 0.429846 }, + { 0.466100, 0.108322, 0.429125 }, + { 0.472328, 0.110547, 0.428334 }, + { 0.478558, 0.112764, 0.427475 }, + { 0.484789, 0.114974, 0.426548 }, + { 0.491022, 0.117179, 0.425552 }, + { 0.497257, 0.119379, 0.424488 }, + { 0.503493, 0.121575, 0.423356 }, + { 0.509730, 0.123769, 0.422156 }, + { 0.515967, 0.125960, 0.420887 }, + { 0.522206, 0.128150, 0.419549 }, + { 0.528444, 0.130341, 0.418142 }, + { 0.534683, 0.132534, 0.416667 }, + { 0.540920, 0.134729, 0.415123 }, + { 0.547157, 0.136929, 0.413511 }, + { 0.553392, 0.139134, 0.411829 }, + { 0.559624, 0.141346, 0.410078 }, + { 0.565854, 0.143567, 0.408258 }, + { 0.572081, 0.145797, 0.406369 }, + { 0.578304, 0.148039, 0.404411 }, + { 0.584521, 0.150294, 0.402385 }, + { 0.590734, 0.152563, 0.400290 }, + { 0.596940, 0.154848, 0.398125 }, + { 0.603139, 0.157151, 0.395891 }, + { 0.609330, 0.159474, 0.393589 }, + { 0.615513, 0.161817, 0.391219 }, + { 0.621685, 0.164184, 0.388781 }, + { 0.627847, 0.166575, 0.386276 }, + { 0.633998, 0.168992, 0.383704 }, + { 0.640135, 0.171438, 0.381065 }, + { 0.646260, 0.173914, 0.378359 }, + { 0.652369, 0.176421, 0.375586 }, + { 0.658463, 0.178962, 0.372748 }, + { 0.664540, 0.181539, 0.369846 }, + { 0.670599, 0.184153, 0.366879 }, + { 0.676638, 0.186807, 0.363849 }, + { 0.682656, 0.189501, 0.360757 }, + { 0.688653, 0.192239, 0.357603 }, + { 0.694627, 0.195021, 0.354388 }, + { 0.700576, 0.197851, 0.351113 }, + { 0.706500, 0.200728, 0.347777 }, + { 0.712396, 0.203656, 0.344383 }, + { 0.718264, 0.206636, 0.340931 }, + { 0.724103, 0.209670, 0.337424 }, + { 0.729909, 0.212759, 0.333861 }, + { 0.735683, 0.215906, 0.330245 }, + { 0.741423, 0.219112, 0.326576 }, + { 0.747127, 0.222378, 0.322856 }, + { 0.752794, 0.225706, 0.319085 }, + { 0.758422, 0.229097, 0.315266 }, + { 0.764010, 0.232554, 0.311399 }, + { 0.769556, 0.236077, 0.307485 }, + { 0.775059, 0.239667, 0.303526 }, + { 0.780517, 0.243327, 0.299523 }, + { 0.785929, 0.247056, 0.295477 }, + { 0.791293, 0.250856, 0.291390 }, + { 0.796607, 0.254728, 0.287264 }, + { 0.801871, 0.258674, 0.283099 }, + { 0.807082, 0.262692, 0.278898 }, + { 0.812239, 0.266786, 0.274661 }, + { 0.817341, 0.270954, 0.270390 }, + { 0.822386, 0.275197, 0.266085 }, + { 0.827372, 0.279517, 0.261750 }, + { 0.832299, 0.283913, 0.257383 }, + { 0.837165, 0.288385, 0.252988 }, + { 0.841969, 0.292933, 0.248564 }, + { 0.846709, 0.297559, 0.244113 }, + { 0.851384, 0.302260, 0.239636 }, + { 0.855992, 0.307038, 0.235133 }, + { 0.860533, 0.311892, 0.230606 }, + { 0.865006, 0.316822, 0.226055 }, + { 0.869409, 0.321827, 0.221482 }, + { 0.873741, 0.326906, 0.216886 }, + { 0.878001, 0.332060, 0.212268 }, + { 0.882188, 0.337287, 0.207628 }, + { 0.886302, 0.342586, 0.202968 }, + { 0.890341, 0.347957, 0.198286 }, + { 0.894305, 0.353399, 0.193584 }, + { 0.898192, 0.358911, 0.188860 }, + { 0.902003, 0.364492, 0.184116 }, + { 0.905735, 0.370140, 0.179350 }, + { 0.909390, 0.375856, 0.174563 }, + { 0.912966, 0.381636, 0.169755 }, + { 0.916462, 0.387481, 0.164924 }, + { 0.919879, 0.393389, 0.160070 }, + { 0.923215, 0.399359, 0.155193 }, + { 0.926470, 0.405389, 0.150292 }, + { 0.929644, 0.411479, 0.145367 }, + { 0.932737, 0.417627, 0.140417 }, + { 0.935747, 0.423831, 0.135440 }, + { 0.938675, 0.430091, 0.130438 }, + { 0.941521, 0.436405, 0.125409 }, + { 0.944285, 0.442772, 0.120354 }, + { 0.946965, 0.449191, 0.115272 }, + { 0.949562, 0.455660, 0.110164 }, + { 0.952075, 0.462178, 0.105031 }, + { 0.954506, 0.468744, 0.099874 }, + { 0.956852, 0.475356, 0.094695 }, + { 0.959114, 0.482014, 0.089499 }, + { 0.961293, 0.488716, 0.084289 }, + { 0.963387, 0.495462, 0.079073 }, + { 0.965397, 0.502249, 0.073859 }, + { 0.967322, 0.509078, 0.068659 }, + { 0.969163, 0.515946, 0.063488 }, + { 0.970919, 0.522853, 0.058367 }, + { 0.972590, 0.529798, 0.053324 }, + { 0.974176, 0.536780, 0.048392 }, + { 0.975677, 0.543798, 0.043618 }, + { 0.977092, 0.550850, 0.039050 }, + { 0.978422, 0.557937, 0.034931 }, + { 0.979666, 0.565057, 0.031409 }, + { 0.980824, 0.572209, 0.028508 }, + { 0.981895, 0.579392, 0.026250 }, + { 0.982881, 0.586606, 0.024661 }, + { 0.983779, 0.593849, 0.023770 }, + { 0.984591, 0.601122, 0.023606 }, + { 0.985315, 0.608422, 0.024202 }, + { 0.985952, 0.615750, 0.025592 }, + { 0.986502, 0.623105, 0.027814 }, + { 0.986964, 0.630485, 0.030908 }, + { 0.987337, 0.637890, 0.034916 }, + { 0.987622, 0.645320, 0.039886 }, + { 0.987819, 0.652773, 0.045581 }, + { 0.987926, 0.660250, 0.051750 }, + { 0.987945, 0.667748, 0.058329 }, + { 0.987874, 0.675267, 0.065257 }, + { 0.987714, 0.682807, 0.072489 }, + { 0.987464, 0.690366, 0.079990 }, + { 0.987124, 0.697944, 0.087731 }, + { 0.986694, 0.705540, 0.095694 }, + { 0.986175, 0.713153, 0.103863 }, + { 0.985566, 0.720782, 0.112229 }, + { 0.984865, 0.728427, 0.120785 }, + { 0.984075, 0.736087, 0.129527 }, + { 0.983196, 0.743758, 0.138453 }, + { 0.982228, 0.751442, 0.147565 }, + { 0.981173, 0.759135, 0.156863 }, + { 0.980032, 0.766837, 0.166353 }, + { 0.978806, 0.774545, 0.176037 }, + { 0.977497, 0.782258, 0.185923 }, + { 0.976108, 0.789974, 0.196018 }, + { 0.974638, 0.797692, 0.206332 }, + { 0.973088, 0.805409, 0.216877 }, + { 0.971468, 0.813122, 0.227658 }, + { 0.969783, 0.820825, 0.238686 }, + { 0.968041, 0.828515, 0.249972 }, + { 0.966243, 0.836191, 0.261534 }, + { 0.964394, 0.843848, 0.273391 }, + { 0.962517, 0.851476, 0.285546 }, + { 0.960626, 0.859069, 0.298010 }, + { 0.958720, 0.866624, 0.310820 }, + { 0.956834, 0.874129, 0.323974 }, + { 0.954997, 0.881569, 0.337475 }, + { 0.953215, 0.888942, 0.351369 }, + { 0.951546, 0.896226, 0.365627 }, + { 0.950018, 0.903409, 0.380271 }, + { 0.948683, 0.910473, 0.395289 }, + { 0.947594, 0.917399, 0.410665 }, + { 0.946809, 0.924168, 0.426373 }, + { 0.946392, 0.930761, 0.442367 }, + { 0.946403, 0.937159, 0.458592 }, + { 0.946903, 0.943348, 0.474970 }, + { 0.947937, 0.949318, 0.491426 }, + { 0.949545, 0.955063, 0.507860 }, + { 0.951740, 0.960587, 0.524203 }, + { 0.954529, 0.965896, 0.540361 }, + { 0.957896, 0.971003, 0.556275 }, + { 0.961812, 0.975924, 0.571925 }, + { 0.966249, 0.980678, 0.587206 }, + { 0.971162, 0.985282, 0.602154 }, + { 0.976511, 0.989753, 0.616760 }, + { 0.982257, 0.994109, 0.631017 }, + { 0.988362, 0.998364, 0.644924 } +}; + +static double magma_cm[256][3] = { + { 0.001462, 0.000466, 0.013866 }, + { 0.002258, 0.001295, 0.018331 }, + { 0.003279, 0.002305, 0.023708 }, + { 0.004512, 0.003490, 0.029965 }, + { 0.005950, 0.004843, 0.037130 }, + { 0.007588, 0.006356, 0.044973 }, + { 0.009426, 0.008022, 0.052844 }, + { 0.011465, 0.009828, 0.060750 }, + { 0.013708, 0.011771, 0.068667 }, + { 0.016156, 0.013840, 0.076603 }, + { 0.018815, 0.016026, 0.084584 }, + { 0.021692, 0.018320, 0.092610 }, + { 0.024792, 0.020715, 0.100676 }, + { 0.028123, 0.023201, 0.108787 }, + { 0.031696, 0.025765, 0.116965 }, + { 0.035520, 0.028397, 0.125209 }, + { 0.039608, 0.031090, 0.133515 }, + { 0.043830, 0.033830, 0.141886 }, + { 0.048062, 0.036607, 0.150327 }, + { 0.052320, 0.039407, 0.158841 }, + { 0.056615, 0.042160, 0.167446 }, + { 0.060949, 0.044794, 0.176129 }, + { 0.065330, 0.047318, 0.184892 }, + { 0.069764, 0.049726, 0.193735 }, + { 0.074257, 0.052017, 0.202660 }, + { 0.078815, 0.054184, 0.211667 }, + { 0.083446, 0.056225, 0.220755 }, + { 0.088155, 0.058133, 0.229922 }, + { 0.092949, 0.059904, 0.239164 }, + { 0.097833, 0.061531, 0.248477 }, + { 0.102815, 0.063010, 0.257854 }, + { 0.107899, 0.064335, 0.267289 }, + { 0.113094, 0.065492, 0.276784 }, + { 0.118405, 0.066479, 0.286321 }, + { 0.123833, 0.067295, 0.295879 }, + { 0.129380, 0.067935, 0.305443 }, + { 0.135053, 0.068391, 0.315000 }, + { 0.140858, 0.068654, 0.324538 }, + { 0.146785, 0.068738, 0.334011 }, + { 0.152839, 0.068637, 0.343404 }, + { 0.159018, 0.068354, 0.352688 }, + { 0.165308, 0.067911, 0.361816 }, + { 0.171713, 0.067305, 0.370771 }, + { 0.178212, 0.066576, 0.379497 }, + { 0.184801, 0.065732, 0.387973 }, + { 0.191460, 0.064818, 0.396152 }, + { 0.198177, 0.063862, 0.404009 }, + { 0.204935, 0.062907, 0.411514 }, + { 0.211718, 0.061992, 0.418647 }, + { 0.218512, 0.061158, 0.425392 }, + { 0.225302, 0.060445, 0.431742 }, + { 0.232077, 0.059889, 0.437695 }, + { 0.238826, 0.059517, 0.443256 }, + { 0.245543, 0.059352, 0.448436 }, + { 0.252220, 0.059415, 0.453248 }, + { 0.258857, 0.059706, 0.457710 }, + { 0.265447, 0.060237, 0.461840 }, + { 0.271994, 0.060994, 0.465660 }, + { 0.278493, 0.061978, 0.469190 }, + { 0.284951, 0.063168, 0.472451 }, + { 0.291366, 0.064553, 0.475462 }, + { 0.297740, 0.066117, 0.478243 }, + { 0.304081, 0.067835, 0.480812 }, + { 0.310382, 0.069702, 0.483186 }, + { 0.316654, 0.071690, 0.485380 }, + { 0.322899, 0.073782, 0.487408 }, + { 0.329114, 0.075972, 0.489287 }, + { 0.335308, 0.078236, 0.491024 }, + { 0.341482, 0.080564, 0.492631 }, + { 0.347636, 0.082946, 0.494121 }, + { 0.353773, 0.085373, 0.495501 }, + { 0.359898, 0.087831, 0.496778 }, + { 0.366012, 0.090314, 0.497960 }, + { 0.372116, 0.092816, 0.499053 }, + { 0.378211, 0.095332, 0.500067 }, + { 0.384299, 0.097855, 0.501002 }, + { 0.390384, 0.100379, 0.501864 }, + { 0.396467, 0.102902, 0.502658 }, + { 0.402548, 0.105420, 0.503386 }, + { 0.408629, 0.107930, 0.504052 }, + { 0.414709, 0.110431, 0.504662 }, + { 0.420791, 0.112920, 0.505215 }, + { 0.426877, 0.115395, 0.505714 }, + { 0.432967, 0.117855, 0.506160 }, + { 0.439062, 0.120298, 0.506555 }, + { 0.445163, 0.122724, 0.506901 }, + { 0.451271, 0.125132, 0.507198 }, + { 0.457386, 0.127522, 0.507448 }, + { 0.463508, 0.129893, 0.507652 }, + { 0.469640, 0.132245, 0.507809 }, + { 0.475780, 0.134577, 0.507921 }, + { 0.481929, 0.136891, 0.507989 }, + { 0.488088, 0.139186, 0.508011 }, + { 0.494258, 0.141462, 0.507988 }, + { 0.500438, 0.143719, 0.507920 }, + { 0.506629, 0.145958, 0.507806 }, + { 0.512831, 0.148179, 0.507648 }, + { 0.519045, 0.150383, 0.507443 }, + { 0.525270, 0.152569, 0.507192 }, + { 0.531507, 0.154739, 0.506895 }, + { 0.537755, 0.156894, 0.506551 }, + { 0.544015, 0.159033, 0.506159 }, + { 0.550287, 0.161158, 0.505719 }, + { 0.556571, 0.163269, 0.505230 }, + { 0.562866, 0.165368, 0.504692 }, + { 0.569172, 0.167454, 0.504105 }, + { 0.575490, 0.169530, 0.503466 }, + { 0.581819, 0.171596, 0.502777 }, + { 0.588158, 0.173652, 0.502035 }, + { 0.594508, 0.175701, 0.501241 }, + { 0.600868, 0.177743, 0.500394 }, + { 0.607238, 0.179779, 0.499492 }, + { 0.613617, 0.181811, 0.498536 }, + { 0.620005, 0.183840, 0.497524 }, + { 0.626401, 0.185867, 0.496456 }, + { 0.632805, 0.187893, 0.495332 }, + { 0.639216, 0.189921, 0.494150 }, + { 0.645633, 0.191952, 0.492910 }, + { 0.652056, 0.193986, 0.491611 }, + { 0.658483, 0.196027, 0.490253 }, + { 0.664915, 0.198075, 0.488836 }, + { 0.671349, 0.200133, 0.487358 }, + { 0.677786, 0.202203, 0.485819 }, + { 0.684224, 0.204286, 0.484219 }, + { 0.690661, 0.206384, 0.482558 }, + { 0.697098, 0.208501, 0.480835 }, + { 0.703532, 0.210638, 0.479049 }, + { 0.709962, 0.212797, 0.477201 }, + { 0.716387, 0.214982, 0.475290 }, + { 0.722805, 0.217194, 0.473316 }, + { 0.729216, 0.219437, 0.471279 }, + { 0.735616, 0.221713, 0.469180 }, + { 0.742004, 0.224025, 0.467018 }, + { 0.748378, 0.226377, 0.464794 }, + { 0.754737, 0.228772, 0.462509 }, + { 0.761077, 0.231214, 0.460162 }, + { 0.767398, 0.233705, 0.457755 }, + { 0.773695, 0.236249, 0.455289 }, + { 0.779968, 0.238851, 0.452765 }, + { 0.786212, 0.241514, 0.450184 }, + { 0.792427, 0.244242, 0.447543 }, + { 0.798608, 0.247040, 0.444848 }, + { 0.804752, 0.249911, 0.442102 }, + { 0.810855, 0.252861, 0.439305 }, + { 0.816914, 0.255895, 0.436461 }, + { 0.822926, 0.259016, 0.433573 }, + { 0.828886, 0.262229, 0.430644 }, + { 0.834791, 0.265540, 0.427671 }, + { 0.840636, 0.268953, 0.424666 }, + { 0.846416, 0.272473, 0.421631 }, + { 0.852126, 0.276106, 0.418573 }, + { 0.857763, 0.279857, 0.415496 }, + { 0.863320, 0.283729, 0.412403 }, + { 0.868793, 0.287728, 0.409303 }, + { 0.874176, 0.291859, 0.406205 }, + { 0.879464, 0.296125, 0.403118 }, + { 0.884651, 0.300530, 0.400047 }, + { 0.889731, 0.305079, 0.397002 }, + { 0.894700, 0.309773, 0.393995 }, + { 0.899552, 0.314616, 0.391037 }, + { 0.904281, 0.319610, 0.388137 }, + { 0.908884, 0.324755, 0.385308 }, + { 0.913354, 0.330052, 0.382563 }, + { 0.917689, 0.335500, 0.379915 }, + { 0.921884, 0.341098, 0.377376 }, + { 0.925937, 0.346844, 0.374959 }, + { 0.929845, 0.352734, 0.372677 }, + { 0.933606, 0.358764, 0.370541 }, + { 0.937221, 0.364929, 0.368567 }, + { 0.940687, 0.371224, 0.366762 }, + { 0.944006, 0.377643, 0.365136 }, + { 0.947180, 0.384178, 0.363701 }, + { 0.950210, 0.390820, 0.362468 }, + { 0.953099, 0.397563, 0.361438 }, + { 0.955849, 0.404400, 0.360619 }, + { 0.958464, 0.411324, 0.360014 }, + { 0.960949, 0.418323, 0.359630 }, + { 0.963310, 0.425390, 0.359469 }, + { 0.965549, 0.432519, 0.359529 }, + { 0.967671, 0.439703, 0.359810 }, + { 0.969680, 0.446936, 0.360311 }, + { 0.971582, 0.454210, 0.361030 }, + { 0.973381, 0.461520, 0.361965 }, + { 0.975082, 0.468861, 0.363111 }, + { 0.976690, 0.476226, 0.364466 }, + { 0.978210, 0.483612, 0.366025 }, + { 0.979645, 0.491014, 0.367783 }, + { 0.981000, 0.498428, 0.369734 }, + { 0.982279, 0.505851, 0.371874 }, + { 0.983485, 0.513280, 0.374198 }, + { 0.984622, 0.520713, 0.376698 }, + { 0.985693, 0.528148, 0.379371 }, + { 0.986700, 0.535582, 0.382210 }, + { 0.987646, 0.543015, 0.385210 }, + { 0.988533, 0.550446, 0.388365 }, + { 0.989363, 0.557873, 0.391671 }, + { 0.990138, 0.565296, 0.395122 }, + { 0.990871, 0.572706, 0.398714 }, + { 0.991558, 0.580107, 0.402441 }, + { 0.992196, 0.587502, 0.406299 }, + { 0.992785, 0.594891, 0.410283 }, + { 0.993326, 0.602275, 0.414390 }, + { 0.993834, 0.609644, 0.418613 }, + { 0.994309, 0.616999, 0.422950 }, + { 0.994738, 0.624350, 0.427397 }, + { 0.995122, 0.631696, 0.431951 }, + { 0.995480, 0.639027, 0.436607 }, + { 0.995810, 0.646344, 0.441361 }, + { 0.996096, 0.653659, 0.446213 }, + { 0.996341, 0.660969, 0.451160 }, + { 0.996580, 0.668256, 0.456192 }, + { 0.996775, 0.675541, 0.461314 }, + { 0.996925, 0.682828, 0.466526 }, + { 0.997077, 0.690088, 0.471811 }, + { 0.997186, 0.697349, 0.477182 }, + { 0.997254, 0.704611, 0.482635 }, + { 0.997325, 0.711848, 0.488154 }, + { 0.997351, 0.719089, 0.493755 }, + { 0.997351, 0.726324, 0.499428 }, + { 0.997341, 0.733545, 0.505167 }, + { 0.997285, 0.740772, 0.510983 }, + { 0.997228, 0.747981, 0.516859 }, + { 0.997138, 0.755190, 0.522806 }, + { 0.997019, 0.762398, 0.528821 }, + { 0.996898, 0.769591, 0.534892 }, + { 0.996727, 0.776795, 0.541039 }, + { 0.996571, 0.783977, 0.547233 }, + { 0.996369, 0.791167, 0.553499 }, + { 0.996162, 0.798348, 0.559820 }, + { 0.995932, 0.805527, 0.566202 }, + { 0.995680, 0.812706, 0.572645 }, + { 0.995424, 0.819875, 0.579140 }, + { 0.995131, 0.827052, 0.585701 }, + { 0.994851, 0.834213, 0.592307 }, + { 0.994524, 0.841387, 0.598983 }, + { 0.994222, 0.848540, 0.605696 }, + { 0.993866, 0.855711, 0.612482 }, + { 0.993545, 0.862859, 0.619299 }, + { 0.993170, 0.870024, 0.626189 }, + { 0.992831, 0.877168, 0.633109 }, + { 0.992440, 0.884330, 0.640099 }, + { 0.992089, 0.891470, 0.647116 }, + { 0.991688, 0.898627, 0.654202 }, + { 0.991332, 0.905763, 0.661309 }, + { 0.990930, 0.912915, 0.668481 }, + { 0.990570, 0.920049, 0.675675 }, + { 0.990175, 0.927196, 0.682926 }, + { 0.989815, 0.934329, 0.690198 }, + { 0.989434, 0.941470, 0.697519 }, + { 0.989077, 0.948604, 0.704863 }, + { 0.988717, 0.955742, 0.712242 }, + { 0.988367, 0.962878, 0.719649 }, + { 0.988033, 0.970012, 0.727077 }, + { 0.987691, 0.977154, 0.734536 }, + { 0.987387, 0.984288, 0.742002 }, + { 0.987053, 0.991438, 0.749504 } +}; + +static double plasma_cm[256][3] = { + { 0.050383, 0.029803, 0.527975 }, + { 0.063536, 0.028426, 0.533124 }, + { 0.075353, 0.027206, 0.538007 }, + { 0.086222, 0.026125, 0.542658 }, + { 0.096379, 0.025165, 0.547103 }, + { 0.105980, 0.024309, 0.551368 }, + { 0.115124, 0.023556, 0.555468 }, + { 0.123903, 0.022878, 0.559423 }, + { 0.132381, 0.022258, 0.563250 }, + { 0.140603, 0.021687, 0.566959 }, + { 0.148607, 0.021154, 0.570562 }, + { 0.156421, 0.020651, 0.574065 }, + { 0.164070, 0.020171, 0.577478 }, + { 0.171574, 0.019706, 0.580806 }, + { 0.178950, 0.019252, 0.584054 }, + { 0.186213, 0.018803, 0.587228 }, + { 0.193374, 0.018354, 0.590330 }, + { 0.200445, 0.017902, 0.593364 }, + { 0.207435, 0.017442, 0.596333 }, + { 0.214350, 0.016973, 0.599239 }, + { 0.221197, 0.016497, 0.602083 }, + { 0.227983, 0.016007, 0.604867 }, + { 0.234715, 0.015502, 0.607592 }, + { 0.241396, 0.014979, 0.610259 }, + { 0.248032, 0.014439, 0.612868 }, + { 0.254627, 0.013882, 0.615419 }, + { 0.261183, 0.013308, 0.617911 }, + { 0.267703, 0.012716, 0.620346 }, + { 0.274191, 0.012109, 0.622722 }, + { 0.280648, 0.011488, 0.625038 }, + { 0.287076, 0.010855, 0.627295 }, + { 0.293478, 0.010213, 0.629490 }, + { 0.299855, 0.009561, 0.631624 }, + { 0.306210, 0.008902, 0.633694 }, + { 0.312543, 0.008239, 0.635700 }, + { 0.318856, 0.007576, 0.637640 }, + { 0.325150, 0.006915, 0.639512 }, + { 0.331426, 0.006261, 0.641316 }, + { 0.337683, 0.005618, 0.643049 }, + { 0.343925, 0.004991, 0.644710 }, + { 0.350150, 0.004382, 0.646298 }, + { 0.356359, 0.003798, 0.647810 }, + { 0.362553, 0.003243, 0.649245 }, + { 0.368733, 0.002724, 0.650601 }, + { 0.374897, 0.002245, 0.651876 }, + { 0.381047, 0.001814, 0.653068 }, + { 0.387183, 0.001434, 0.654177 }, + { 0.393304, 0.001114, 0.655199 }, + { 0.399411, 0.000859, 0.656133 }, + { 0.405503, 0.000678, 0.656977 }, + { 0.411580, 0.000577, 0.657730 }, + { 0.417642, 0.000564, 0.658390 }, + { 0.423689, 0.000646, 0.658956 }, + { 0.429719, 0.000831, 0.659425 }, + { 0.435734, 0.001127, 0.659797 }, + { 0.441732, 0.001540, 0.660069 }, + { 0.447714, 0.002080, 0.660240 }, + { 0.453677, 0.002755, 0.660310 }, + { 0.459623, 0.003574, 0.660277 }, + { 0.465550, 0.004545, 0.660139 }, + { 0.471457, 0.005678, 0.659897 }, + { 0.477344, 0.006980, 0.659549 }, + { 0.483210, 0.008460, 0.659095 }, + { 0.489055, 0.010127, 0.658534 }, + { 0.494877, 0.011990, 0.657865 }, + { 0.500678, 0.014055, 0.657088 }, + { 0.506454, 0.016333, 0.656202 }, + { 0.512206, 0.018833, 0.655209 }, + { 0.517933, 0.021563, 0.654109 }, + { 0.523633, 0.024532, 0.652901 }, + { 0.529306, 0.027747, 0.651586 }, + { 0.534952, 0.031217, 0.650165 }, + { 0.540570, 0.034950, 0.648640 }, + { 0.546157, 0.038954, 0.647010 }, + { 0.551715, 0.043136, 0.645277 }, + { 0.557243, 0.047331, 0.643443 }, + { 0.562738, 0.051545, 0.641509 }, + { 0.568201, 0.055778, 0.639477 }, + { 0.573632, 0.060028, 0.637349 }, + { 0.579029, 0.064296, 0.635126 }, + { 0.584391, 0.068579, 0.632812 }, + { 0.589719, 0.072878, 0.630408 }, + { 0.595011, 0.077190, 0.627917 }, + { 0.600266, 0.081516, 0.625342 }, + { 0.605485, 0.085854, 0.622686 }, + { 0.610667, 0.090204, 0.619951 }, + { 0.615812, 0.094564, 0.617140 }, + { 0.620919, 0.098934, 0.614257 }, + { 0.625987, 0.103312, 0.611305 }, + { 0.631017, 0.107699, 0.608287 }, + { 0.636008, 0.112092, 0.605205 }, + { 0.640959, 0.116492, 0.602065 }, + { 0.645872, 0.120898, 0.598867 }, + { 0.650746, 0.125309, 0.595617 }, + { 0.655580, 0.129725, 0.592317 }, + { 0.660374, 0.134144, 0.588971 }, + { 0.665129, 0.138566, 0.585582 }, + { 0.669845, 0.142992, 0.582154 }, + { 0.674522, 0.147419, 0.578688 }, + { 0.679160, 0.151848, 0.575189 }, + { 0.683758, 0.156278, 0.571660 }, + { 0.688318, 0.160709, 0.568103 }, + { 0.692840, 0.165141, 0.564522 }, + { 0.697324, 0.169573, 0.560919 }, + { 0.701769, 0.174005, 0.557296 }, + { 0.706178, 0.178437, 0.553657 }, + { 0.710549, 0.182868, 0.550004 }, + { 0.714883, 0.187299, 0.546338 }, + { 0.719181, 0.191729, 0.542663 }, + { 0.723444, 0.196158, 0.538981 }, + { 0.727670, 0.200586, 0.535293 }, + { 0.731862, 0.205013, 0.531601 }, + { 0.736019, 0.209439, 0.527908 }, + { 0.740143, 0.213864, 0.524216 }, + { 0.744232, 0.218288, 0.520524 }, + { 0.748289, 0.222711, 0.516834 }, + { 0.752312, 0.227133, 0.513149 }, + { 0.756304, 0.231555, 0.509468 }, + { 0.760264, 0.235976, 0.505794 }, + { 0.764193, 0.240396, 0.502126 }, + { 0.768090, 0.244817, 0.498465 }, + { 0.771958, 0.249237, 0.494813 }, + { 0.775796, 0.253658, 0.491171 }, + { 0.779604, 0.258078, 0.487539 }, + { 0.783383, 0.262500, 0.483918 }, + { 0.787133, 0.266922, 0.480307 }, + { 0.790855, 0.271345, 0.476706 }, + { 0.794549, 0.275770, 0.473117 }, + { 0.798216, 0.280197, 0.469538 }, + { 0.801855, 0.284626, 0.465971 }, + { 0.805467, 0.289057, 0.462415 }, + { 0.809052, 0.293491, 0.458870 }, + { 0.812612, 0.297928, 0.455338 }, + { 0.816144, 0.302368, 0.451816 }, + { 0.819651, 0.306812, 0.448306 }, + { 0.823132, 0.311261, 0.444806 }, + { 0.826588, 0.315714, 0.441316 }, + { 0.830018, 0.320172, 0.437836 }, + { 0.833422, 0.324635, 0.434366 }, + { 0.836801, 0.329105, 0.430905 }, + { 0.840155, 0.333580, 0.427455 }, + { 0.843484, 0.338062, 0.424013 }, + { 0.846788, 0.342551, 0.420579 }, + { 0.850066, 0.347048, 0.417153 }, + { 0.853319, 0.351553, 0.413734 }, + { 0.856547, 0.356066, 0.410322 }, + { 0.859750, 0.360588, 0.406917 }, + { 0.862927, 0.365119, 0.403519 }, + { 0.866078, 0.369660, 0.400126 }, + { 0.869203, 0.374212, 0.396738 }, + { 0.872303, 0.378774, 0.393355 }, + { 0.875376, 0.383347, 0.389976 }, + { 0.878423, 0.387932, 0.386600 }, + { 0.881443, 0.392529, 0.383229 }, + { 0.884436, 0.397139, 0.379860 }, + { 0.887402, 0.401762, 0.376494 }, + { 0.890340, 0.406398, 0.373130 }, + { 0.893250, 0.411048, 0.369768 }, + { 0.896131, 0.415712, 0.366407 }, + { 0.898984, 0.420392, 0.363047 }, + { 0.901807, 0.425087, 0.359688 }, + { 0.904601, 0.429797, 0.356329 }, + { 0.907365, 0.434524, 0.352970 }, + { 0.910098, 0.439268, 0.349610 }, + { 0.912800, 0.444029, 0.346251 }, + { 0.915471, 0.448807, 0.342890 }, + { 0.918109, 0.453603, 0.339529 }, + { 0.920714, 0.458417, 0.336166 }, + { 0.923287, 0.463251, 0.332801 }, + { 0.925825, 0.468103, 0.329435 }, + { 0.928329, 0.472975, 0.326067 }, + { 0.930798, 0.477867, 0.322697 }, + { 0.933232, 0.482780, 0.319325 }, + { 0.935630, 0.487712, 0.315952 }, + { 0.937990, 0.492667, 0.312575 }, + { 0.940313, 0.497642, 0.309197 }, + { 0.942598, 0.502639, 0.305816 }, + { 0.944844, 0.507658, 0.302433 }, + { 0.947051, 0.512699, 0.299049 }, + { 0.949217, 0.517763, 0.295662 }, + { 0.951344, 0.522850, 0.292275 }, + { 0.953428, 0.527960, 0.288883 }, + { 0.955470, 0.533093, 0.285490 }, + { 0.957469, 0.538250, 0.282096 }, + { 0.959424, 0.543431, 0.278701 }, + { 0.961336, 0.548636, 0.275305 }, + { 0.963203, 0.553865, 0.271909 }, + { 0.965024, 0.559118, 0.268513 }, + { 0.966798, 0.564396, 0.265118 }, + { 0.968526, 0.569700, 0.261721 }, + { 0.970205, 0.575028, 0.258325 }, + { 0.971835, 0.580382, 0.254931 }, + { 0.973416, 0.585761, 0.251540 }, + { 0.974947, 0.591165, 0.248151 }, + { 0.976428, 0.596595, 0.244767 }, + { 0.977856, 0.602051, 0.241387 }, + { 0.979233, 0.607532, 0.238013 }, + { 0.980556, 0.613039, 0.234646 }, + { 0.981826, 0.618572, 0.231287 }, + { 0.983041, 0.624131, 0.227937 }, + { 0.984199, 0.629718, 0.224595 }, + { 0.985301, 0.635330, 0.221265 }, + { 0.986345, 0.640969, 0.217948 }, + { 0.987332, 0.646633, 0.214648 }, + { 0.988260, 0.652325, 0.211364 }, + { 0.989128, 0.658043, 0.208100 }, + { 0.989935, 0.663787, 0.204859 }, + { 0.990681, 0.669558, 0.201642 }, + { 0.991365, 0.675355, 0.198453 }, + { 0.991985, 0.681179, 0.195295 }, + { 0.992541, 0.687030, 0.192170 }, + { 0.993032, 0.692907, 0.189084 }, + { 0.993456, 0.698810, 0.186041 }, + { 0.993814, 0.704741, 0.183043 }, + { 0.994103, 0.710698, 0.180097 }, + { 0.994324, 0.716681, 0.177208 }, + { 0.994474, 0.722691, 0.174381 }, + { 0.994553, 0.728728, 0.171622 }, + { 0.994561, 0.734791, 0.168938 }, + { 0.994495, 0.740880, 0.166335 }, + { 0.994355, 0.746995, 0.163821 }, + { 0.994141, 0.753137, 0.161404 }, + { 0.993851, 0.759304, 0.159092 }, + { 0.993482, 0.765499, 0.156891 }, + { 0.993033, 0.771720, 0.154808 }, + { 0.992505, 0.777967, 0.152855 }, + { 0.991897, 0.784239, 0.151042 }, + { 0.991209, 0.790537, 0.149377 }, + { 0.990439, 0.796859, 0.147870 }, + { 0.989587, 0.803205, 0.146529 }, + { 0.988648, 0.809579, 0.145357 }, + { 0.987621, 0.815978, 0.144363 }, + { 0.986509, 0.822401, 0.143557 }, + { 0.985314, 0.828846, 0.142945 }, + { 0.984031, 0.835315, 0.142528 }, + { 0.982653, 0.841812, 0.142303 }, + { 0.981190, 0.848329, 0.142279 }, + { 0.979644, 0.854866, 0.142453 }, + { 0.977995, 0.861432, 0.142808 }, + { 0.976265, 0.868016, 0.143351 }, + { 0.974443, 0.874622, 0.144061 }, + { 0.972530, 0.881250, 0.144923 }, + { 0.970533, 0.887896, 0.145919 }, + { 0.968443, 0.894564, 0.147014 }, + { 0.966271, 0.901249, 0.148180 }, + { 0.964021, 0.907950, 0.149370 }, + { 0.961681, 0.914672, 0.150520 }, + { 0.959276, 0.921407, 0.151566 }, + { 0.956808, 0.928152, 0.152409 }, + { 0.954287, 0.934908, 0.152921 }, + { 0.951726, 0.941671, 0.152925 }, + { 0.949151, 0.948435, 0.152178 }, + { 0.946602, 0.955190, 0.150328 }, + { 0.944152, 0.961916, 0.146861 }, + { 0.941896, 0.968590, 0.140956 }, + { 0.940015, 0.975158, 0.131326 } +}; + +static double viridis_cm[256][3] = { + { 0.267004, 0.004874, 0.329415 }, + { 0.268510, 0.009605, 0.335427 }, + { 0.269944, 0.014625, 0.341379 }, + { 0.271305, 0.019942, 0.347269 }, + { 0.272594, 0.025563, 0.353093 }, + { 0.273809, 0.031497, 0.358853 }, + { 0.274952, 0.037752, 0.364543 }, + { 0.276022, 0.044167, 0.370164 }, + { 0.277018, 0.050344, 0.375715 }, + { 0.277941, 0.056324, 0.381191 }, + { 0.278791, 0.062145, 0.386592 }, + { 0.279566, 0.067836, 0.391917 }, + { 0.280267, 0.073417, 0.397163 }, + { 0.280894, 0.078907, 0.402329 }, + { 0.281446, 0.084320, 0.407414 }, + { 0.281924, 0.089666, 0.412415 }, + { 0.282327, 0.094955, 0.417331 }, + { 0.282656, 0.100196, 0.422160 }, + { 0.282910, 0.105393, 0.426902 }, + { 0.283091, 0.110553, 0.431554 }, + { 0.283197, 0.115680, 0.436115 }, + { 0.283229, 0.120777, 0.440584 }, + { 0.283187, 0.125848, 0.444960 }, + { 0.283072, 0.130895, 0.449241 }, + { 0.282884, 0.135920, 0.453427 }, + { 0.282623, 0.140926, 0.457517 }, + { 0.282290, 0.145912, 0.461510 }, + { 0.281887, 0.150881, 0.465405 }, + { 0.281412, 0.155834, 0.469201 }, + { 0.280868, 0.160771, 0.472899 }, + { 0.280255, 0.165693, 0.476498 }, + { 0.279574, 0.170599, 0.479997 }, + { 0.278826, 0.175490, 0.483397 }, + { 0.278012, 0.180367, 0.486697 }, + { 0.277134, 0.185228, 0.489898 }, + { 0.276194, 0.190074, 0.493001 }, + { 0.275191, 0.194905, 0.496005 }, + { 0.274128, 0.199721, 0.498911 }, + { 0.273006, 0.204520, 0.501721 }, + { 0.271828, 0.209303, 0.504434 }, + { 0.270595, 0.214069, 0.507052 }, + { 0.269308, 0.218818, 0.509577 }, + { 0.267968, 0.223549, 0.512008 }, + { 0.266580, 0.228262, 0.514349 }, + { 0.265145, 0.232956, 0.516599 }, + { 0.263663, 0.237631, 0.518762 }, + { 0.262138, 0.242286, 0.520837 }, + { 0.260571, 0.246922, 0.522828 }, + { 0.258965, 0.251537, 0.524736 }, + { 0.257322, 0.256130, 0.526563 }, + { 0.255645, 0.260703, 0.528312 }, + { 0.253935, 0.265254, 0.529983 }, + { 0.252194, 0.269783, 0.531579 }, + { 0.250425, 0.274290, 0.533103 }, + { 0.248629, 0.278775, 0.534556 }, + { 0.246811, 0.283237, 0.535941 }, + { 0.244972, 0.287675, 0.537260 }, + { 0.243113, 0.292092, 0.538516 }, + { 0.241237, 0.296485, 0.539709 }, + { 0.239346, 0.300855, 0.540844 }, + { 0.237441, 0.305202, 0.541921 }, + { 0.235526, 0.309527, 0.542944 }, + { 0.233603, 0.313828, 0.543914 }, + { 0.231674, 0.318106, 0.544834 }, + { 0.229739, 0.322361, 0.545706 }, + { 0.227802, 0.326594, 0.546532 }, + { 0.225863, 0.330805, 0.547314 }, + { 0.223925, 0.334994, 0.548053 }, + { 0.221989, 0.339161, 0.548752 }, + { 0.220057, 0.343307, 0.549413 }, + { 0.218130, 0.347432, 0.550038 }, + { 0.216210, 0.351535, 0.550627 }, + { 0.214298, 0.355619, 0.551184 }, + { 0.212395, 0.359683, 0.551710 }, + { 0.210503, 0.363727, 0.552206 }, + { 0.208623, 0.367752, 0.552675 }, + { 0.206756, 0.371758, 0.553117 }, + { 0.204903, 0.375746, 0.553533 }, + { 0.203063, 0.379716, 0.553925 }, + { 0.201239, 0.383670, 0.554294 }, + { 0.199430, 0.387607, 0.554642 }, + { 0.197636, 0.391528, 0.554969 }, + { 0.195860, 0.395433, 0.555276 }, + { 0.194100, 0.399323, 0.555565 }, + { 0.192357, 0.403199, 0.555836 }, + { 0.190631, 0.407061, 0.556089 }, + { 0.188923, 0.410910, 0.556326 }, + { 0.187231, 0.414746, 0.556547 }, + { 0.185556, 0.418570, 0.556753 }, + { 0.183898, 0.422383, 0.556944 }, + { 0.182256, 0.426184, 0.557120 }, + { 0.180629, 0.429975, 0.557282 }, + { 0.179019, 0.433756, 0.557430 }, + { 0.177423, 0.437527, 0.557565 }, + { 0.175841, 0.441290, 0.557685 }, + { 0.174274, 0.445044, 0.557792 }, + { 0.172719, 0.448791, 0.557885 }, + { 0.171176, 0.452530, 0.557965 }, + { 0.169646, 0.456262, 0.558030 }, + { 0.168126, 0.459988, 0.558082 }, + { 0.166617, 0.463708, 0.558119 }, + { 0.165117, 0.467423, 0.558141 }, + { 0.163625, 0.471133, 0.558148 }, + { 0.162142, 0.474838, 0.558140 }, + { 0.160665, 0.478540, 0.558115 }, + { 0.159194, 0.482237, 0.558073 }, + { 0.157729, 0.485932, 0.558013 }, + { 0.156270, 0.489624, 0.557936 }, + { 0.154815, 0.493313, 0.557840 }, + { 0.153364, 0.497000, 0.557724 }, + { 0.151918, 0.500685, 0.557587 }, + { 0.150476, 0.504369, 0.557430 }, + { 0.149039, 0.508051, 0.557250 }, + { 0.147607, 0.511733, 0.557049 }, + { 0.146180, 0.515413, 0.556823 }, + { 0.144759, 0.519093, 0.556572 }, + { 0.143343, 0.522773, 0.556295 }, + { 0.141935, 0.526453, 0.555991 }, + { 0.140536, 0.530132, 0.555659 }, + { 0.139147, 0.533812, 0.555298 }, + { 0.137770, 0.537492, 0.554906 }, + { 0.136408, 0.541173, 0.554483 }, + { 0.135066, 0.544853, 0.554029 }, + { 0.133743, 0.548535, 0.553541 }, + { 0.132444, 0.552216, 0.553018 }, + { 0.131172, 0.555899, 0.552459 }, + { 0.129933, 0.559582, 0.551864 }, + { 0.128729, 0.563265, 0.551229 }, + { 0.127568, 0.566949, 0.550556 }, + { 0.126453, 0.570633, 0.549841 }, + { 0.125394, 0.574318, 0.549086 }, + { 0.124395, 0.578002, 0.548287 }, + { 0.123463, 0.581687, 0.547445 }, + { 0.122606, 0.585371, 0.546557 }, + { 0.121831, 0.589055, 0.545623 }, + { 0.121148, 0.592739, 0.544641 }, + { 0.120565, 0.596422, 0.543611 }, + { 0.120092, 0.600104, 0.542530 }, + { 0.119738, 0.603785, 0.541400 }, + { 0.119512, 0.607464, 0.540218 }, + { 0.119423, 0.611141, 0.538982 }, + { 0.119483, 0.614817, 0.537692 }, + { 0.119699, 0.618490, 0.536347 }, + { 0.120081, 0.622161, 0.534946 }, + { 0.120638, 0.625828, 0.533488 }, + { 0.121380, 0.629492, 0.531973 }, + { 0.122312, 0.633153, 0.530398 }, + { 0.123444, 0.636809, 0.528763 }, + { 0.124780, 0.640461, 0.527068 }, + { 0.126326, 0.644107, 0.525311 }, + { 0.128087, 0.647749, 0.523491 }, + { 0.130067, 0.651384, 0.521608 }, + { 0.132268, 0.655014, 0.519661 }, + { 0.134692, 0.658636, 0.517649 }, + { 0.137339, 0.662252, 0.515571 }, + { 0.140210, 0.665859, 0.513427 }, + { 0.143303, 0.669459, 0.511215 }, + { 0.146616, 0.673050, 0.508936 }, + { 0.150148, 0.676631, 0.506589 }, + { 0.153894, 0.680203, 0.504172 }, + { 0.157851, 0.683765, 0.501686 }, + { 0.162016, 0.687316, 0.499129 }, + { 0.166383, 0.690856, 0.496502 }, + { 0.170948, 0.694384, 0.493803 }, + { 0.175707, 0.697900, 0.491033 }, + { 0.180653, 0.701402, 0.488189 }, + { 0.185783, 0.704891, 0.485273 }, + { 0.191090, 0.708366, 0.482284 }, + { 0.196571, 0.711827, 0.479221 }, + { 0.202219, 0.715272, 0.476084 }, + { 0.208030, 0.718701, 0.472873 }, + { 0.214000, 0.722114, 0.469588 }, + { 0.220124, 0.725509, 0.466226 }, + { 0.226397, 0.728888, 0.462789 }, + { 0.232815, 0.732247, 0.459277 }, + { 0.239374, 0.735588, 0.455688 }, + { 0.246070, 0.738910, 0.452024 }, + { 0.252899, 0.742211, 0.448284 }, + { 0.259857, 0.745492, 0.444467 }, + { 0.266941, 0.748751, 0.440573 }, + { 0.274149, 0.751988, 0.436601 }, + { 0.281477, 0.755203, 0.432552 }, + { 0.288921, 0.758394, 0.428426 }, + { 0.296479, 0.761561, 0.424223 }, + { 0.304148, 0.764704, 0.419943 }, + { 0.311925, 0.767822, 0.415586 }, + { 0.319809, 0.770914, 0.411152 }, + { 0.327796, 0.773980, 0.406640 }, + { 0.335885, 0.777018, 0.402049 }, + { 0.344074, 0.780029, 0.397381 }, + { 0.352360, 0.783011, 0.392636 }, + { 0.360741, 0.785964, 0.387814 }, + { 0.369214, 0.788888, 0.382914 }, + { 0.377779, 0.791781, 0.377939 }, + { 0.386433, 0.794644, 0.372886 }, + { 0.395174, 0.797475, 0.367757 }, + { 0.404001, 0.800275, 0.362552 }, + { 0.412913, 0.803041, 0.357269 }, + { 0.421908, 0.805774, 0.351910 }, + { 0.430983, 0.808473, 0.346476 }, + { 0.440137, 0.811138, 0.340967 }, + { 0.449368, 0.813768, 0.335384 }, + { 0.458674, 0.816363, 0.329727 }, + { 0.468053, 0.818921, 0.323998 }, + { 0.477504, 0.821444, 0.318195 }, + { 0.487026, 0.823929, 0.312321 }, + { 0.496615, 0.826376, 0.306377 }, + { 0.506271, 0.828786, 0.300362 }, + { 0.515992, 0.831158, 0.294279 }, + { 0.525776, 0.833491, 0.288127 }, + { 0.535621, 0.835785, 0.281908 }, + { 0.545524, 0.838039, 0.275626 }, + { 0.555484, 0.840254, 0.269281 }, + { 0.565498, 0.842430, 0.262877 }, + { 0.575563, 0.844566, 0.256415 }, + { 0.585678, 0.846661, 0.249897 }, + { 0.595839, 0.848717, 0.243329 }, + { 0.606045, 0.850733, 0.236712 }, + { 0.616293, 0.852709, 0.230052 }, + { 0.626579, 0.854645, 0.223353 }, + { 0.636902, 0.856542, 0.216620 }, + { 0.647257, 0.858400, 0.209861 }, + { 0.657642, 0.860219, 0.203082 }, + { 0.668054, 0.861999, 0.196293 }, + { 0.678489, 0.863742, 0.189503 }, + { 0.688944, 0.865448, 0.182725 }, + { 0.699415, 0.867117, 0.175971 }, + { 0.709898, 0.868751, 0.169257 }, + { 0.720391, 0.870350, 0.162603 }, + { 0.730889, 0.871916, 0.156029 }, + { 0.741388, 0.873449, 0.149561 }, + { 0.751884, 0.874951, 0.143228 }, + { 0.762373, 0.876424, 0.137064 }, + { 0.772852, 0.877868, 0.131109 }, + { 0.783315, 0.879285, 0.125405 }, + { 0.793760, 0.880678, 0.120005 }, + { 0.804182, 0.882046, 0.114965 }, + { 0.814576, 0.883393, 0.110347 }, + { 0.824940, 0.884720, 0.106217 }, + { 0.835270, 0.886029, 0.102646 }, + { 0.845561, 0.887322, 0.099702 }, + { 0.855810, 0.888601, 0.097452 }, + { 0.866013, 0.889868, 0.095953 }, + { 0.876168, 0.891125, 0.095250 }, + { 0.886271, 0.892374, 0.095374 }, + { 0.896320, 0.893616, 0.096335 }, + { 0.906311, 0.894855, 0.098125 }, + { 0.916242, 0.896091, 0.100717 }, + { 0.926106, 0.897330, 0.104071 }, + { 0.935904, 0.898570, 0.108131 }, + { 0.945636, 0.899815, 0.112838 }, + { 0.955300, 0.901065, 0.118128 }, + { 0.964894, 0.902323, 0.123941 }, + { 0.974417, 0.903590, 0.130215 }, + { 0.983868, 0.904867, 0.136897 }, + { 0.993248, 0.906157, 0.143936 } +}; + +static double parula_cm[256][3] = { + { 0.2081, 0.1663, 0.5292 }, + { 0.2091, 0.1721, 0.5411 }, + { 0.2101, 0.1779, 0.553 }, + { 0.2109, 0.1837, 0.565 }, + { 0.2116, 0.1895, 0.5771 }, + { 0.2121, 0.1954, 0.5892 }, + { 0.2124, 0.2013, 0.6013 }, + { 0.2125, 0.2072, 0.6135 }, + { 0.2123, 0.2132, 0.6258 }, + { 0.2118, 0.2192, 0.6381 }, + { 0.2111, 0.2253, 0.6505 }, + { 0.2099, 0.2315, 0.6629 }, + { 0.2084, 0.2377, 0.6753 }, + { 0.2063, 0.244, 0.6878 }, + { 0.2038, 0.2503, 0.7003 }, + { 0.2006, 0.2568, 0.7129 }, + { 0.1968, 0.2632, 0.7255 }, + { 0.1921, 0.2698, 0.7381 }, + { 0.1867, 0.2764, 0.7507 }, + { 0.1802, 0.2832, 0.7634 }, + { 0.1728, 0.2902, 0.7762 }, + { 0.1641, 0.2975, 0.789 }, + { 0.1541, 0.3052, 0.8017 }, + { 0.1427, 0.3132, 0.8145 }, + { 0.1295, 0.3217, 0.8269 }, + { 0.1147, 0.3306, 0.8387 }, + { 0.0986, 0.3397, 0.8495 }, + { 0.0816, 0.3486, 0.8588 }, + { 0.0646, 0.3572, 0.8664 }, + { 0.0482, 0.3651, 0.8722 }, + { 0.0329, 0.3724, 0.8765 }, + { 0.0213, 0.3792, 0.8796 }, + { 0.0136, 0.3853, 0.8815 }, + { 0.0086, 0.3911, 0.8827 }, + { 0.006, 0.3965, 0.8833 }, + { 0.0051, 0.4017, 0.8834 }, + { 0.0054, 0.4066, 0.8831 }, + { 0.0067, 0.4113, 0.8825 }, + { 0.0089, 0.4159, 0.8816 }, + { 0.0116, 0.4203, 0.8805 }, + { 0.0148, 0.4246, 0.8793 }, + { 0.0184, 0.4288, 0.8779 }, + { 0.0223, 0.4329, 0.8763 }, + { 0.0264, 0.437, 0.8747 }, + { 0.0306, 0.441, 0.8729 }, + { 0.0349, 0.4449, 0.8711 }, + { 0.0394, 0.4488, 0.8692 }, + { 0.0437, 0.4526, 0.8672 }, + { 0.0477, 0.4564, 0.8652 }, + { 0.0514, 0.4602, 0.8632 }, + { 0.0549, 0.464, 0.8611 }, + { 0.0582, 0.4677, 0.8589 }, + { 0.0612, 0.4714, 0.8568 }, + { 0.064, 0.4751, 0.8546 }, + { 0.0666, 0.4788, 0.8525 }, + { 0.0689, 0.4825, 0.8503 }, + { 0.071, 0.4862, 0.8481 }, + { 0.0729, 0.4899, 0.846 }, + { 0.0746, 0.4937, 0.8439 }, + { 0.0761, 0.4974, 0.8418 }, + { 0.0773, 0.5012, 0.8398 }, + { 0.0782, 0.5051, 0.8378 }, + { 0.0789, 0.5089, 0.8359 }, + { 0.0794, 0.5129, 0.8341 }, + { 0.0795, 0.5169, 0.8324 }, + { 0.0793, 0.521, 0.8308 }, + { 0.0788, 0.5251, 0.8293 }, + { 0.0778, 0.5295, 0.828 }, + { 0.0764, 0.5339, 0.827 }, + { 0.0746, 0.5384, 0.8261 }, + { 0.0724, 0.5431, 0.8253 }, + { 0.0698, 0.5479, 0.8247 }, + { 0.0668, 0.5527, 0.8243 }, + { 0.0636, 0.5577, 0.8239 }, + { 0.06, 0.5627, 0.8237 }, + { 0.0562, 0.5677, 0.8234 }, + { 0.0523, 0.5727, 0.8231 }, + { 0.0484, 0.5777, 0.8228 }, + { 0.0445, 0.5826, 0.8223 }, + { 0.0408, 0.5874, 0.8217 }, + { 0.0372, 0.5922, 0.8209 }, + { 0.0342, 0.5968, 0.8198 }, + { 0.0317, 0.6012, 0.8186 }, + { 0.0296, 0.6055, 0.8171 }, + { 0.0279, 0.6097, 0.8154 }, + { 0.0265, 0.6137, 0.8135 }, + { 0.0255, 0.6176, 0.8114 }, + { 0.0248, 0.6214, 0.8091 }, + { 0.0243, 0.625, 0.8066 }, + { 0.0239, 0.6285, 0.8039 }, + { 0.0237, 0.6319, 0.801 }, + { 0.0235, 0.6352, 0.798 }, + { 0.0233, 0.6384, 0.7948 }, + { 0.0231, 0.6415, 0.7916 }, + { 0.023, 0.6445, 0.7881 }, + { 0.0229, 0.6474, 0.7846 }, + { 0.0227, 0.6503, 0.781, }, + { 0.0227, 0.6531, 0.7773 }, + { 0.0232, 0.6558, 0.7735 }, + { 0.0238, 0.6585, 0.7696 }, + { 0.0246, 0.6611, 0.7656 }, + { 0.0263, 0.6637, 0.7615 }, + { 0.0282, 0.6663, 0.7574 }, + { 0.0306, 0.6688, 0.7532 }, + { 0.0338, 0.6712, 0.749 }, + { 0.0373, 0.6737, 0.7446 }, + { 0.0418, 0.6761, 0.7402 }, + { 0.0467, 0.6784, 0.7358 }, + { 0.0516, 0.6808, 0.7313 }, + { 0.0574, 0.6831, 0.7267 }, + { 0.0629, 0.6854, 0.7221 }, + { 0.0692, 0.6877, 0.7173 }, + { 0.0755, 0.6899, 0.7126 }, + { 0.082, 0.6921, 0.7078 }, + { 0.0889, 0.6943, 0.7029 }, + { 0.0956, 0.6965, 0.6979 }, + { 0.1031, 0.6986, 0.6929 }, + { 0.1104, 0.7007, 0.6878 }, + { 0.118, 0.7028, 0.6827 }, + { 0.1258, 0.7049, 0.6775 }, + { 0.1335, 0.7069, 0.6723 }, + { 0.1418, 0.7089, 0.6669 }, + { 0.1499, 0.7109, 0.6616 }, + { 0.1585, 0.7129, 0.6561 }, + { 0.1671, 0.7148, 0.6507 }, + { 0.1758, 0.7168, 0.6451 }, + { 0.1849, 0.7186, 0.6395 }, + { 0.1938, 0.7205, 0.6338 }, + { 0.2033, 0.7223, 0.6281 }, + { 0.2128, 0.7241, 0.6223 }, + { 0.2224, 0.7259, 0.6165 }, + { 0.2324, 0.7275, 0.6107 }, + { 0.2423, 0.7292, 0.6048 }, + { 0.2527, 0.7308, 0.5988 }, + { 0.2631, 0.7324, 0.5929 }, + { 0.2735, 0.7339, 0.5869 }, + { 0.2845, 0.7354, 0.5809 }, + { 0.2953, 0.7368, 0.5749 }, + { 0.3064, 0.7381, 0.5689 }, + { 0.3177, 0.7394, 0.563 }, + { 0.3289, 0.7406, 0.557 }, + { 0.3405, 0.7417, 0.5512 }, + { 0.352, 0.7428, 0.5453 }, + { 0.3635, 0.7438, 0.5396 }, + { 0.3753, 0.7446, 0.5339 }, + { 0.3869, 0.7454, 0.5283 }, + { 0.3986, 0.7461, 0.5229 }, + { 0.4103, 0.7467, 0.5175 }, + { 0.4218, 0.7473, 0.5123 }, + { 0.4334, 0.7477, 0.5072 }, + { 0.4447, 0.7482, 0.5021 }, + { 0.4561, 0.7485, 0.4972 }, + { 0.4672, 0.7487, 0.4924 }, + { 0.4783, 0.7489, 0.4877 }, + { 0.4892, 0.7491, 0.4831 }, + { 0.5, 0.7491, 0.4786 }, + { 0.5106, 0.7492, 0.4741 }, + { 0.5212, 0.7492, 0.4698 }, + { 0.5315, 0.7491, 0.4655 }, + { 0.5418, 0.749, 0.4613 }, + { 0.5519, 0.7489, 0.4571 }, + { 0.5619, 0.7487, 0.4531 }, + { 0.5718, 0.7485, 0.449 }, + { 0.5816, 0.7482, 0.4451 }, + { 0.5913, 0.7479, 0.4412 }, + { 0.6009, 0.7476, 0.4374 }, + { 0.6103, 0.7473, 0.4335 }, + { 0.6197, 0.7469, 0.4298 }, + { 0.629, 0.7465, 0.4261 }, + { 0.6382, 0.746, 0.4224 }, + { 0.6473, 0.7456, 0.4188 }, + { 0.6564, 0.7451, 0.4152 }, + { 0.6653, 0.7446, 0.4116 }, + { 0.6742, 0.7441, 0.4081 }, + { 0.683, 0.7435, 0.4046 }, + { 0.6918, 0.743, 0.4011 }, + { 0.7004, 0.7424, 0.3976 }, + { 0.7091, 0.7418, 0.3942 }, + { 0.7176, 0.7412, 0.3908 }, + { 0.7261, 0.7405, 0.3874 }, + { 0.7346, 0.7399, 0.384 }, + { 0.743, 0.7392, 0.3806 }, + { 0.7513, 0.7385, 0.3773 }, + { 0.7596, 0.7378, 0.3739 }, + { 0.7679, 0.7372, 0.3706 }, + { 0.7761, 0.7364, 0.3673 }, + { 0.7843, 0.7357, 0.3639 }, + { 0.7924, 0.735, 0.3606 }, + { 0.8005, 0.7343, 0.3573 }, + { 0.8085, 0.7336, 0.3539 }, + { 0.8166, 0.7329, 0.3506 }, + { 0.8246, 0.7322, 0.3472 }, + { 0.8325, 0.7315, 0.3438 }, + { 0.8405, 0.7308, 0.3404 }, + { 0.8484, 0.7301, 0.337 }, + { 0.8563, 0.7294, 0.3336 }, + { 0.8642, 0.7288, 0.33 }, + { 0.872, 0.7282, 0.3265 }, + { 0.8798, 0.7276, 0.3229 }, + { 0.8877, 0.7271, 0.3193 }, + { 0.8954, 0.7266, 0.3156 }, + { 0.9032, 0.7262, 0.3117 }, + { 0.911, 0.7259, 0.3078 }, + { 0.9187, 0.7256, 0.3038 }, + { 0.9264, 0.7256, 0.2996 }, + { 0.9341, 0.7256, 0.2953 }, + { 0.9417, 0.7259, 0.2907 }, + { 0.9493, 0.7264, 0.2859 }, + { 0.9567, 0.7273, 0.2808 }, + { 0.9639, 0.7285, 0.2754 }, + { 0.9708, 0.7303, 0.2696 }, + { 0.9773, 0.7326, 0.2634 }, + { 0.9831, 0.7355, 0.257 }, + { 0.9882, 0.739, 0.2504 }, + { 0.9922, 0.7431, 0.2437 }, + { 0.9952, 0.7476, 0.2373 }, + { 0.9973, 0.7524, 0.231 }, + { 0.9986, 0.7573, 0.2251 }, + { 0.9991, 0.7624, 0.2195 }, + { 0.999, 0.7675, 0.2141 }, + { 0.9985, 0.7726, 0.209 }, + { 0.9976, 0.7778, 0.2042 }, + { 0.9964, 0.7829, 0.1995 }, + { 0.995, 0.788, 0.1949 }, + { 0.9933, 0.7931, 0.1905 }, + { 0.9914, 0.7981, 0.1863 }, + { 0.9894, 0.8032, 0.1821 }, + { 0.9873, 0.8083, 0.178 }, + { 0.9851, 0.8133, 0.174 }, + { 0.9828, 0.8184, 0.17 }, + { 0.9805, 0.8235, 0.1661 }, + { 0.9782, 0.8286, 0.1622 }, + { 0.9759, 0.8337, 0.1583 }, + { 0.9736, 0.8389, 0.1544 }, + { 0.9713, 0.8441, 0.1505 }, + { 0.9692, 0.8494, 0.1465 }, + { 0.9672, 0.8548, 0.1425 }, + { 0.9654, 0.8603, 0.1385 }, + { 0.9638, 0.8659, 0.1343 }, + { 0.9623, 0.8716, 0.1301 }, + { 0.9611, 0.8774, 0.1258 }, + { 0.96, 0.8834, 0.1215 }, + { 0.9593, 0.8895, 0.1171 }, + { 0.9588, 0.8958, 0.1126 }, + { 0.9586, 0.9022, 0.1082 }, + { 0.9587, 0.9088, 0.1036 }, + { 0.9591, 0.9155, 0.099 }, + { 0.9599, 0.9225, 0.0944 }, + { 0.961, 0.9296, 0.0897 }, + { 0.9624, 0.9368, 0.085 }, + { 0.9641, 0.9443, 0.0802 }, + { 0.9662, 0.9518, 0.0753 }, + { 0.9685, 0.9595, 0.0703 }, + { 0.971, 0.9673, 0.0651 }, + { 0.9736, 0.9752, 0.0597 }, + { 0.9763, 0.9831, 0.0538 } +}; +} + +template +IGL_INLINE void igl::colormap(const ColorMapType cm, const T x, T * rgb) +{ + return colormap(cm,x,rgb[0],rgb[1],rgb[2]); +} + +template +IGL_INLINE void igl::colormap( + const ColorMapType cm, const T x_in, T & r, T & g, T & b) +{ + switch (cm) + { + case COLOR_MAP_TYPE_INFERNO: + colormap(inferno_cm, x_in, r, g, b); + break; + case COLOR_MAP_TYPE_JET: + // jet is bad so we use turbo instead + // https://ai.googleblog.com/2019/08/turbo-improved-rainbow-colormap-for.html + case COLOR_MAP_TYPE_TURBO: + colormap(turbo_cm, x_in, r, g, b); + break; + case COLOR_MAP_TYPE_MAGMA: + colormap(magma_cm, x_in, r, g, b); + break; + case COLOR_MAP_TYPE_PARULA: + colormap(parula_cm, x_in, r, g, b); + break; + case COLOR_MAP_TYPE_PLASMA: + colormap(plasma_cm, x_in, r, g, b); + break; + case COLOR_MAP_TYPE_VIRIDIS: + colormap(viridis_cm, x_in, r, g, b); + break; + default: + throw std::invalid_argument("igl::colormap(): Selected colormap is unsupported!"); + break; + } +} + +template +IGL_INLINE void igl::colormap( + const double palette[256][3], const T x_in, T & r, T & g, T & b) +{ + static const unsigned int pal = 256; + const T zero = 0.0; + const T one = 1.0; + T x_in_clamped = static_cast(std::max(zero, std::min(one, x_in))); + + // simple rgb lerp from palette + unsigned int least = std::floor(x_in_clamped * static_cast(pal - 1)); + unsigned int most = std::ceil(x_in_clamped * static_cast(pal - 1)); + + T _r[2] = { static_cast(palette[least][0]), static_cast(palette[most][0]) }; + T _g[2] = { static_cast(palette[least][1]), static_cast(palette[most][1]) }; + T _b[2] = { static_cast(palette[least][2]), static_cast(palette[most][2]) }; + + T t = std::max(zero, std::min(one, static_cast(fmod(x_in_clamped * static_cast(pal), one)))); + + r = std::max(zero, std::min(one, (one - t) * _r[0] + t * _r[1])); + g = std::max(zero, std::min(one, (one - t) * _g[0] + t * _g[1])); + b = std::max(zero, std::min(one, (one - t) * _b[0] + t * _b[1])); +} + +template +IGL_INLINE void igl::colormap( + const ColorMapType cm, + const Eigen::MatrixBase & Z, + const bool normalize, + Eigen::PlainObjectBase & C) +{ + const double min_z = normalize ? Z.minCoeff() : 0; + const double max_z = normalize ? Z.maxCoeff() : 1; + return colormap(cm, Z, min_z, max_z, C); +} + +template +IGL_INLINE void igl::colormap( + const ColorMapType cm, + const Eigen::MatrixBase & Z, + const double min_z, + const double max_z, + Eigen::PlainObjectBase & C) +{ + C.resize(Z.rows(),3); + double denom = (max_z - min_z); + denom = (denom == 0) ? 1 : denom; + for(int r = 0; r < Z.rows(); ++r) { + colormap( + cm, + (typename DerivedC::Scalar)((-min_z + Z(r,0)) / denom), + C(r,0), + C(r,1), + C(r,2)); + } +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::colormap(igl::ColorMapType, float, float*); +// generated by autoexplicit.sh +template void igl::colormap, Eigen::Matrix >(igl::ColorMapType, Eigen::MatrixBase > const&, bool, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::colormap, Eigen::Matrix >(igl::ColorMapType, Eigen::MatrixBase > const&, double, double, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::colormap, Eigen::Matrix >(igl::ColorMapType, Eigen::MatrixBase > const&, double, double, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::colormap, Eigen::Matrix >(igl::ColorMapType, Eigen::MatrixBase > const&, bool, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::colormap(igl::ColorMapType, double, double&, double&, double&); +// generated by autoexplicit.sh +template void igl::colormap(igl::ColorMapType, double, double*); +// generated by autoexplicit.sh +template void igl::colormap, Eigen::Matrix >(igl::ColorMapType, Eigen::MatrixBase > const&, double, double, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::colormap, Eigen::Matrix >(igl::ColorMapType, Eigen::MatrixBase > const&, double, double, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::colormap, Eigen::Matrix >(igl::ColorMapType, Eigen::MatrixBase > const&, bool, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::colormap, Eigen::Matrix >(igl::ColorMapType, Eigen::MatrixBase > const&, bool, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::colormap, Eigen::Matrix >(igl::ColorMapType, Eigen::MatrixBase > const&, bool, Eigen::PlainObjectBase >&); + +template void igl::colormap, Eigen::Matrix >(igl::ColorMapType, Eigen::MatrixBase > const&, bool, Eigen::PlainObjectBase >&); +template void igl::colormap(igl::ColorMapType, float, float&, float&, float&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/colormap.h b/src/external/libigl-2.3.0/include/igl/colormap.h new file mode 100644 index 000000000..9ec1aa876 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/colormap.h @@ -0,0 +1,77 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2017 Joe Graus , Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef IGL_COLORMAP_H +#define IGL_COLORMAP_H +#include "igl_inline.h" + +#include + +namespace igl { + + enum ColorMapType + { + COLOR_MAP_TYPE_INFERNO = 0, + COLOR_MAP_TYPE_JET = 1, + COLOR_MAP_TYPE_MAGMA = 2, + COLOR_MAP_TYPE_PARULA = 3, + COLOR_MAP_TYPE_PLASMA = 4, + COLOR_MAP_TYPE_VIRIDIS = 5, + COLOR_MAP_TYPE_TURBO = 6, + NUM_COLOR_MAP_TYPES = 7 + }; + // Comput [r,g,b] values of the selected colormap for + // a given factor f between 0 and 1 + // + // Inputs: + // c colormap enum + // f factor determining color value as if 0 was min and 1 was max + // Outputs: + // rgb red, green, blue value + template + IGL_INLINE void colormap(const ColorMapType cm, const T f, T * rgb); + // Outputs: + // r red value + // g green value + // b blue value + template + IGL_INLINE void colormap(const ColorMapType cm, const T f, T & r, T & g, T & b); + // Inputs: + // palette 256 by 3 array of color values + template + IGL_INLINE void colormap( + const double palette[256][3], const T x_in, T & r, T & g, T & b); + // Inputs: + // cm selected colormap palette to interpolate from + // Z #Z list of factors + // normalize whether to normalize Z to be tightly between [0,1] + // Outputs: + // C #C by 3 list of rgb colors + template + IGL_INLINE void colormap( + const ColorMapType cm, + const Eigen::MatrixBase & Z, + const bool normalize, + Eigen::PlainObjectBase & C); + // Inputs: + // min_z value at "0" + // max_z value at "1" + template + IGL_INLINE void colormap( + const ColorMapType cm, + const Eigen::MatrixBase & Z, + const double min_Z, + const double max_Z, + Eigen::PlainObjectBase & C); +}; + +#ifndef IGL_STATIC_LIBRARY +# include "colormap.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/column_to_quats.cpp b/src/external/libigl-2.3.0/include/igl/column_to_quats.cpp new file mode 100644 index 000000000..f87adab06 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/column_to_quats.cpp @@ -0,0 +1,27 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "column_to_quats.h" +IGL_INLINE bool igl::column_to_quats( + const Eigen::VectorXd & Q, + std::vector< + Eigen::Quaterniond,Eigen::aligned_allocator > & vQ) +{ + using namespace Eigen; + if(Q.size() % 4 != 0) + { + return false; + } + const int nQ = Q.size()/4; + vQ.resize(nQ); + for(int q=0;q +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_COLUMN_TO_QUATS_H +#define IGL_COLUMN_TO_QUATS_H +#include "igl_inline.h" +#include +#include +#include +#include +namespace igl +{ + // "Columnize" a list of quaternions (q1x,q1y,q1z,q1w,q2x,q2y,q2z,q2w,...) + // + // Inputs: + // Q n*4-long list of coefficients + // Outputs: + // vQ n-long list of quaternions + // Returns false if n%4!=0 + IGL_INLINE bool column_to_quats( + const Eigen::VectorXd & Q, + std::vector< + Eigen::Quaterniond,Eigen::aligned_allocator > & vQ); +} + +#ifndef IGL_STATIC_LIBRARY +# include "column_to_quats.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/columnize.cpp b/src/external/libigl-2.3.0/include/igl/columnize.cpp new file mode 100644 index 000000000..29e91c669 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/columnize.cpp @@ -0,0 +1,63 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "columnize.h" +#include + +template +IGL_INLINE void igl::columnize( + const Eigen::PlainObjectBase & A, + const int k, + const int dim, + Eigen::PlainObjectBase & B) +{ + // Eigen matrices must be 2d so dim must be only 1 or 2 + assert(dim == 1 || dim == 2); + + // block height, width, and number of blocks + int m,n; + if(dim == 1) + { + m = A.rows()/k; + assert(m*(int)k == (int)A.rows()); + n = A.cols(); + }else// dim == 2 + { + m = A.rows(); + n = A.cols()/k; + assert(n*(int)k == (int)A.cols()); + } + + // resize output + B.resize(A.rows()*A.cols(),1); + + for(int b = 0;b<(int)k;b++) + { + for(int i = 0;i, Eigen::Matrix >(Eigen::PlainObjectBase > const&, int, int, Eigen::PlainObjectBase >&); +template void igl::columnize, Eigen::Matrix >(Eigen::PlainObjectBase > const&, int, int, Eigen::PlainObjectBase >&); +template void igl::columnize, Eigen::Matrix >(Eigen::PlainObjectBase > const&, int, int, Eigen::PlainObjectBase >&); +template void igl::columnize, Eigen::Matrix >(Eigen::PlainObjectBase > const&, int, int, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/columnize.h b/src/external/libigl-2.3.0/include/igl/columnize.h new file mode 100644 index 000000000..1bb453af1 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/columnize.h @@ -0,0 +1,41 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_COLUMNIZE_H +#define IGL_COLUMNIZE_H +#include "igl_inline.h" + +#include +namespace igl +{ + // "Columnize" a stack of block matrices. If A = [A1,A2,A3,...,Ak] with each A* + // an m by n block then this produces the column vector whose entries are + // B(j*m*k+i*k+b) = A(i,b*n+j); + // or if A = [A1;A2;...;Ak] then + // B(j*m*k+i*k+b) = A(i+b*m,j); + // + // Templates: + // T should be a eigen matrix primitive type like int or double + // Inputs: + // A m*k by n (dim: 1) or m by n*k (dim: 2) eigen Matrix of type T values + // k number of blocks + // dim dimension in which blocks are stacked + // Output + // B m*n*k eigen vector of type T values, + // + // See also: transpose_blocks + template + IGL_INLINE void columnize( + const Eigen::PlainObjectBase & A, + const int k, + const int dim, + Eigen::PlainObjectBase & B); +} +#ifndef IGL_STATIC_LIBRARY +# include "columnize.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/comb_cross_field.cpp b/src/external/libigl-2.3.0/include/igl/comb_cross_field.cpp new file mode 100644 index 000000000..f094ed43c --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/comb_cross_field.cpp @@ -0,0 +1,155 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Daniele Panozzo , Olga Diamanti +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +#include "comb_cross_field.h" + +#include +#include +#include +#include "per_face_normals.h" +#include "is_border_vertex.h" +#include "rotation_matrix_from_directions.h" + +#include "triangle_triangle_adjacency.h" + +namespace igl { + template + class Comb + { + public: + + const Eigen::MatrixBase &V; + const Eigen::MatrixBase &F; + const Eigen::MatrixBase &PD1; + const Eigen::MatrixBase &PD2; + DerivedV N; + + private: + // internal + DerivedF TT; + DerivedF TTi; + + + private: + + + static inline double Sign(double a){return (double)((a>0)?+1:-1);} + + + private: + + // returns the 90 deg rotation of a (around n) most similar to target b + /// a and b should be in the same plane orthogonal to N + static inline Eigen::Matrix K_PI_new(const Eigen::Matrix& a, + const Eigen::Matrix& b, + const Eigen::Matrix& n) + { + Eigen::Matrix c = (a.cross(n)).normalized(); + typename DerivedV::Scalar scorea = a.dot(b); + typename DerivedV::Scalar scorec = c.dot(b); + if (fabs(scorea)>=fabs(scorec)) + return a*Sign(scorea); + else + return c*Sign(scorec); + } + + + + public: + inline Comb(const Eigen::MatrixBase &_V, + const Eigen::MatrixBase &_F, + const Eigen::MatrixBase &_PD1, + const Eigen::MatrixBase &_PD2 + ): + V(_V), + F(_F), + PD1(_PD1), + PD2(_PD2) + { + igl::per_face_normals(V,F,N); + igl::triangle_triangle_adjacency(F,TT,TTi); + } + inline void comb(Eigen::PlainObjectBase &PD1out, + Eigen::PlainObjectBase &PD2out) + { +// PD1out = PD1; +// PD2out = PD2; + PD1out.setZero(F.rows(),3);PD1out< d; + + while (!mark.all()) // Stop until all vertices are marked + { + int unmarked = 0; + while (mark(unmarked)) + unmarked++; + + d.push_back(unmarked); + mark(unmarked) = true; + + while (!d.empty()) + { + int f0 = d.at(0); + d.pop_front(); + for (int k=0; k<3; k++) + { + int f1 = TT(f0,k); + if (f1==-1) continue; + if (mark(f1)) continue; + + Eigen::Matrix dir0 = PD1out.row(f0); + Eigen::Matrix dir1 = PD1out.row(f1); + Eigen::Matrix n0 = N.row(f0); + Eigen::Matrix n1 = N.row(f1); + + + Eigen::Matrix dir0Rot = igl::rotation_matrix_from_directions(n0, n1)*dir0; + dir0Rot.normalize(); + Eigen::Matrix targD = K_PI_new(dir1,dir0Rot,n1); + + PD1out.row(f1) = targD; + PD2out.row(f1) = n1.cross(targD).normalized(); + + mark(f1) = true; + d.push_back(f1); + + } + } + } + + // everything should be marked + for (int i=0; i +IGL_INLINE void igl::comb_cross_field(const Eigen::MatrixBase &V, + const Eigen::MatrixBase &F, + const Eigen::MatrixBase &PD1, + const Eigen::MatrixBase &PD2, + Eigen::PlainObjectBase &PD1out, + Eigen::PlainObjectBase &PD2out) +{ + igl::Comb cmb(V, F, PD1, PD2); + cmb.comb(PD1out, PD2out); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +template void igl::comb_cross_field, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::comb_cross_field, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/comb_cross_field.h b/src/external/libigl-2.3.0/include/igl/comb_cross_field.h new file mode 100644 index 000000000..0cbacb7ab --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/comb_cross_field.h @@ -0,0 +1,41 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Daniele Panozzo , Olga Diamanti +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef IGL_COMB_CROSS_FIELD_H +#define IGL_COMB_CROSS_FIELD_H +#include "igl_inline.h" +#include +namespace igl +{ + // Computes principal matchings of the vectors of a cross field across face edges, + // and generates a combed cross field defined on the mesh faces + + // Inputs: + // V #V by 3 eigen Matrix of mesh vertex 3D positions + // F #F by 4 eigen Matrix of face (quad) indices + // PD1in #F by 3 eigen Matrix of the first per face cross field vector + // PD2in #F by 3 eigen Matrix of the second per face cross field vector + // Output: + // PD1out #F by 3 eigen Matrix of the first combed cross field vector + // PD2out #F by 3 eigen Matrix of the second combed cross field vector + // + + + template + IGL_INLINE void comb_cross_field(const Eigen::MatrixBase &V, + const Eigen::MatrixBase &F, + const Eigen::MatrixBase &PD1in, + const Eigen::MatrixBase &PD2in, + Eigen::PlainObjectBase &PD1out, + Eigen::PlainObjectBase &PD2out); +} +#ifndef IGL_STATIC_LIBRARY +#include "comb_cross_field.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/comb_frame_field.cpp b/src/external/libigl-2.3.0/include/igl/comb_frame_field.cpp new file mode 100644 index 000000000..85672c303 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/comb_frame_field.cpp @@ -0,0 +1,78 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Daniele Panozzo , Olga Diamanti +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +#ifdef WIN32 + #define _USE_MATH_DEFINES +#endif +#include + +#include "comb_frame_field.h" +#include "local_basis.h" +#include "PI.h" + +template +IGL_INLINE void igl::comb_frame_field(const Eigen::MatrixBase &V, + const Eigen::MatrixBase &F, + const Eigen::MatrixBase &PD1, + const Eigen::MatrixBase &PD2, + const Eigen::MatrixBase &BIS1_combed, + const Eigen::MatrixBase &BIS2_combed, + Eigen::PlainObjectBase &PD1_combed, + Eigen::PlainObjectBase &PD2_combed) +{ + DerivedV B1, B2, B3; + igl::local_basis(V,F,B1,B2,B3); + + PD1_combed.resize(BIS1_combed.rows(),3); + PD2_combed.resize(BIS2_combed.rows(),3); + + for (unsigned i=0; i DIRs; + DIRs << + PD1.row(i), + -PD1.row(i), + PD2.row(i), + -PD2.row(i); + + std::vector a(4); + + + double a_combed = atan2(B2.row(i).dot(BIS1_combed.row(i)),B1.row(i).dot(BIS1_combed.row(i))); + + // center on the combed sector center + for (unsigned j=0;j<4;++j) + { + a[j] = atan2(B2.row(i).dot(DIRs.row(j)),B1.row(i).dot(DIRs.row(j))) - a_combed; + //make it positive by adding some multiple of 2pi + a[j] += std::ceil (std::max(0., -a[j]) / (igl::PI*2.)) * (igl::PI*2.); + //take modulo 2pi + a[j] = fmod(a[j], (igl::PI*2.)); + } + // now the max is u and the min is v + + int m = std::min_element(a.begin(),a.end())-a.begin(); + int M = std::max_element(a.begin(),a.end())-a.begin(); + + assert( + ((m>=0 && m<=1) && (M>=2 && M<=3)) + || + ((m>=2 && m<=3) && (M>=0 && M<=1)) + ); + + PD1_combed.row(i) = DIRs.row(m); + PD2_combed.row(i) = DIRs.row(M); + + } +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +template void igl::comb_frame_field, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::comb_frame_field, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/comb_frame_field.h b/src/external/libigl-2.3.0/include/igl/comb_frame_field.h new file mode 100644 index 000000000..ab5a9e7e9 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/comb_frame_field.h @@ -0,0 +1,47 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Daniele Panozzo , Olga Diamanti +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef IGL_COMB_FRAME_FIELD_H +#define IGL_COMB_FRAME_FIELD_H +#include "igl_inline.h" +#include +namespace igl +{ + // Computes principal matchings of the vectors of a frame field across face edges, + // and generates a combed frame field defined on the mesh faces. This makes use of a + // combed cross field generated by combing the field created by the bisectors of the + // frame field. + + // Inputs: + // V #V by 3 eigen Matrix of mesh vertex 3D positions + // F #F by 4 eigen Matrix of face (quad) indices + // PD1 #F by 3 eigen Matrix of the first per face cross field vector + // PD2 #F by 3 eigen Matrix of the second per face cross field vector + // BIS1_combed #F by 3 eigen Matrix of the first combed bisector field vector + // BIS2_combed #F by 3 eigen Matrix of the second combed bisector field vector + // Output: + // PD1_combed #F by 3 eigen Matrix of the first combed cross field vector + // PD2_combed #F by 3 eigen Matrix of the second combed cross field vector + // + + + template + IGL_INLINE void comb_frame_field(const Eigen::MatrixBase &V, + const Eigen::MatrixBase &F, + const Eigen::MatrixBase &PD1, + const Eigen::MatrixBase &PD2, + const Eigen::MatrixBase &BIS1_combed, + const Eigen::MatrixBase &BIS2_combed, + Eigen::PlainObjectBase &PD1_combed, + Eigen::PlainObjectBase &PD2_combed); +} +#ifndef IGL_STATIC_LIBRARY +#include "comb_frame_field.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/comb_line_field.cpp b/src/external/libigl-2.3.0/include/igl/comb_line_field.cpp new file mode 100644 index 000000000..06a2a6406 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/comb_line_field.cpp @@ -0,0 +1,132 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Nico Pietroni +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +#include "comb_line_field.h" + +#include +#include +#include "per_face_normals.h" +#include "is_border_vertex.h" +#include "rotation_matrix_from_directions.h" + +#include "triangle_triangle_adjacency.h" + +namespace igl { +template +class CombLine +{ +public: + + const Eigen::MatrixBase &V; + const Eigen::MatrixBase &F; + const Eigen::MatrixBase &PD1; + DerivedV N; + +private: + // internal + DerivedF TT; + DerivedF TTi; + + +private: + + + static inline double Sign(double a){return (double)((a>0)?+1:-1);} + + +private: + + // returns the 180 deg rotation of a (around n) most similar to target b + // a and b should be in the same plane orthogonal to N + static inline Eigen::Matrix K_PI_line(const Eigen::Matrix& a, + const Eigen::Matrix& b) + { + typename DerivedV::Scalar scorea = a.dot(b); + if (scorea<0) + return -a; + else + return a; + } + + + +public: + + inline CombLine(const Eigen::MatrixBase &_V, + const Eigen::MatrixBase &_F, + const Eigen::MatrixBase &_PD1): + V(_V), + F(_F), + PD1(_PD1) + { + igl::per_face_normals(V,F,N); + igl::triangle_triangle_adjacency(F,TT,TTi); + } + + inline void comb(Eigen::PlainObjectBase &PD1out) + { + PD1out.setZero(F.rows(),3);PD1out< d; + + d.push_back(0); + mark(0) = true; + + while (!d.empty()) + { + int f0 = d.at(0); + d.pop_front(); + for (int k=0; k<3; k++) + { + int f1 = TT(f0,k); + if (f1==-1) continue; + if (mark(f1)) continue; + + Eigen::Matrix dir0 = PD1out.row(f0); + Eigen::Matrix dir1 = PD1out.row(f1); + Eigen::Matrix n0 = N.row(f0); + Eigen::Matrix n1 = N.row(f1); + + Eigen::Matrix dir0Rot = igl::rotation_matrix_from_directions(n0, n1)*dir0; + dir0Rot.normalize(); + Eigen::Matrix targD = K_PI_line(dir1,dir0Rot); + + PD1out.row(f1) = targD; + //PD2out.row(f1) = n1.cross(targD).normalized(); + + mark(f1) = true; + d.push_back(f1); + + } + } + + // everything should be marked + for (int i=0; i +IGL_INLINE void igl::comb_line_field(const Eigen::MatrixBase &V, + const Eigen::MatrixBase &F, + const Eigen::MatrixBase &PD1, + Eigen::PlainObjectBase &PD1out) +{ + igl::CombLine cmb(V, F, PD1); + cmb.comb(PD1out); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +#endif diff --git a/src/external/libigl-2.3.0/include/igl/comb_line_field.h b/src/external/libigl-2.3.0/include/igl/comb_line_field.h new file mode 100644 index 000000000..6ec892016 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/comb_line_field.h @@ -0,0 +1,36 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Nico Pietroni +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef IGL_COMB_LINE_FIELD_H +#define IGL_COMB_LINE_FIELD_H +#include "igl_inline.h" +#include +namespace igl +{ + // Computes principal matchings of the vectors of a cross field across face edges, + // and generates a combed cross field defined on the mesh faces + + // Inputs: + // V #V by 3 eigen Matrix of mesh vertex 3D positions + // F #F by 4 eigen Matrix of face (quad) indices + // PD1in #F by 3 eigen Matrix of the first per face cross field vector + // Output: + // PD1out #F by 3 eigen Matrix of the first combed cross field vector + + + template + IGL_INLINE void comb_line_field(const Eigen::MatrixBase &V, + const Eigen::MatrixBase &F, + const Eigen::MatrixBase &PD1in, + Eigen::PlainObjectBase &PD1out); +} +#ifndef IGL_STATIC_LIBRARY +#include "comb_line_field.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/combine.cpp b/src/external/libigl-2.3.0/include/igl/combine.cpp new file mode 100644 index 000000000..d77bf3f54 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/combine.cpp @@ -0,0 +1,99 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "combine.h" +#include + +template < + typename DerivedVV, + typename DerivedFF, + typename DerivedV, + typename DerivedF, + typename DerivedVsizes, + typename DerivedFsizes> +IGL_INLINE void igl::combine( + const std::vector & VV, + const std::vector & FF, + Eigen::PlainObjectBase & V, + Eigen::PlainObjectBase & F, + Eigen::PlainObjectBase & Vsizes, + Eigen::PlainObjectBase & Fsizes) +{ + assert(VV.size() == FF.size() && + "Lists of verex lists and face lists should be same size"); + Vsizes.resize(VV.size()); + Fsizes.resize(FF.size()); + // Dimension of vertex positions + const int dim = VV.size() > 0 ? VV[0].cols() : 0; + // Simplex/element size + const int ss = FF.size() > 0 ? FF[0].cols() : 0; + int n = 0; + int m = 0; + for(int i = 0;i0) + { + F.block(kf,0,mi,ss) = Fi.array()+kv; + } + kf+=mi; + if(Vi.size() >0) + { + V.block(kv,0,ni,dim) = Vi; + } + kv+=ni; + } + assert(kv == V.rows()); + assert(kf == F.rows()); + } +} + +template < + typename DerivedVV, + typename DerivedFF, + typename DerivedV, + typename DerivedF> +IGL_INLINE void igl::combine( + const std::vector & VV, + const std::vector & FF, + Eigen::PlainObjectBase & V, + Eigen::PlainObjectBase & F) +{ + Eigen::VectorXi Vsizes,Fsizes; + return igl::combine(VV,FF,V,F,Vsizes,Fsizes); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::combine, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(std::vector, std::allocator > > const&, std::vector, std::allocator > > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::combine, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(std::vector, std::allocator > > const&, std::vector, std::allocator > > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::combine, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(std::vector, std::allocator > > const&, std::vector, std::allocator > > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::combine, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(std::vector, std::allocator > > const&, std::vector, std::allocator > > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#ifdef WIN32 +template void igl::combine, Eigen::Matrix,Eigen::Matrix,Eigen::Matrix,Eigen::Matrix,Eigen::Matrix >(class std::vector,class std::allocator > > const &,class std::vector,class std::allocator > > const &,Eigen::PlainObjectBase > &,Eigen::PlainObjectBase > &,Eigen::PlainObjectBase > &,Eigen::PlainObjectBase > &); +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/combine.h b/src/external/libigl-2.3.0/include/igl/combine.h new file mode 100644 index 000000000..ff5e1ae34 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/combine.h @@ -0,0 +1,65 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_COMBINE_H +#define IGL_COMBINE_H + +#include "igl_inline.h" +#include +#include + +namespace igl +{ + // Concatenate k meshes into a single >=k connected component mesh with a + // single vertex list and face list. Similar to Maya's Combine operation. + // + // Inputs: + // VV k-long list of lists of mesh vertex positions + // FF k-long list of lists of mesh face indices so that FF[i] indexes + // VV[i] + // Outputs: + // V VV[0].rows()+...+VV[k-1].rows() by VV[0].cols() list of mesh + // vertex positions + // F FF[0].rows()+...+FF[k-1].rows() by FF[0].cols() list of mesh faces + // indices into V + // Vsizes k list so that Vsizes(i) is the #vertices in the ith input + // Fsizes k list so that Fsizes(i) is the #faces in the ith input + // Example: + // // Suppose you have mesh A (VA,FA) and mesh B (VB,FB) + // igl::combine({VA,VB},{FA,FB},V,F); + // + // + template < + typename DerivedVV, + typename DerivedFF, + typename DerivedV, + typename DerivedF, + typename DerivedVsizes, + typename DerivedFsizes> + IGL_INLINE void combine( + const std::vector & VV, + const std::vector & FF, + Eigen::PlainObjectBase & V, + Eigen::PlainObjectBase & F, + Eigen::PlainObjectBase & Vsizes, + Eigen::PlainObjectBase & Fsizes); + template < + typename DerivedVV, + typename DerivedFF, + typename DerivedV, + typename DerivedF> + IGL_INLINE void combine( + const std::vector & VV, + const std::vector & FF, + Eigen::PlainObjectBase & V, + Eigen::PlainObjectBase & F); +} + +#ifndef IGL_STATIC_LIBRARY +# include "combine.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/compute_frame_field_bisectors.cpp b/src/external/libigl-2.3.0/include/igl/compute_frame_field_bisectors.cpp new file mode 100644 index 000000000..ceca66e5d --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/compute_frame_field_bisectors.cpp @@ -0,0 +1,86 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Daniele Panozzo , Olga Diamanti +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +#ifdef WIN32 + #define _USE_MATH_DEFINES +#endif +#include + +#include "compute_frame_field_bisectors.h" +#include "igl/local_basis.h" +#include "PI.h" + +template +IGL_INLINE void igl::compute_frame_field_bisectors( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + const Eigen::MatrixBase& B1, + const Eigen::MatrixBase& B2, + const Eigen::MatrixBase& PD1, + const Eigen::MatrixBase& PD2, + Eigen::PlainObjectBase& BIS1, + Eigen::PlainObjectBase& BIS2) +{ + BIS1.resize(PD1.rows(),3); + BIS2.resize(PD1.rows(),3); + + for (unsigned i=0; i +IGL_INLINE void igl::compute_frame_field_bisectors( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + const Eigen::MatrixBase& PD1, + const Eigen::MatrixBase& PD2, + Eigen::PlainObjectBase& BIS1, + Eigen::PlainObjectBase& BIS2) +{ + DerivedV B1, B2, B3; + igl::local_basis(V,F,B1,B2,B3); + + compute_frame_field_bisectors( V, F, B1, B2, PD1, PD2, BIS1, BIS2); + +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +template void igl::compute_frame_field_bisectors, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::compute_frame_field_bisectors, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::compute_frame_field_bisectors, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/compute_frame_field_bisectors.h b/src/external/libigl-2.3.0/include/igl/compute_frame_field_bisectors.h new file mode 100644 index 000000000..f5cef3a11 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/compute_frame_field_bisectors.h @@ -0,0 +1,53 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Daniele Panozzo , Olga Diamanti +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef IGL_COMPUTE_FRAME_FIELD_BISECTORS_H +#define IGL_COMPUTE_FRAME_FIELD_BISECTORS_H +#include "igl_inline.h" +#include +namespace igl +{ + // Compute bisectors of a frame field defined on mesh faces + // Inputs: + // V #V by 3 eigen Matrix of mesh vertex 3D positions + // F #F by 3 eigen Matrix of face (triangle) indices + // B1 #F by 3 eigen Matrix of face (triangle) base vector 1 + // B2 #F by 3 eigen Matrix of face (triangle) base vector 2 + // PD1 #F by 3 eigen Matrix of the first per face frame field vector + // PD2 #F by 3 eigen Matrix of the second per face frame field vector + // Output: + // BIS1 #F by 3 eigen Matrix of the first per face frame field bisector + // BIS2 #F by 3 eigen Matrix of the second per face frame field bisector + // + template + IGL_INLINE void compute_frame_field_bisectors( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + const Eigen::MatrixBase& B1, + const Eigen::MatrixBase& B2, + const Eigen::MatrixBase& PD1, + const Eigen::MatrixBase& PD2, + Eigen::PlainObjectBase& BIS1, + Eigen::PlainObjectBase& BIS2); + + // Wrapper without given basis vectors. + template + IGL_INLINE void compute_frame_field_bisectors( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + const Eigen::MatrixBase& PD1, + const Eigen::MatrixBase& PD2, + Eigen::PlainObjectBase& BIS1, + Eigen::PlainObjectBase& BIS2); +} + +#ifndef IGL_STATIC_LIBRARY +# include "compute_frame_field_bisectors.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/connect_boundary_to_infinity.cpp b/src/external/libigl-2.3.0/include/igl/connect_boundary_to_infinity.cpp new file mode 100644 index 000000000..e0b7aec37 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/connect_boundary_to_infinity.cpp @@ -0,0 +1,55 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "connect_boundary_to_infinity.h" +#include "boundary_facets.h" + +template +IGL_INLINE void igl::connect_boundary_to_infinity( + const Eigen::MatrixBase & F, + Eigen::PlainObjectBase & FO) +{ + return connect_boundary_to_infinity(F,F.maxCoeff(),FO); +} +template +IGL_INLINE void igl::connect_boundary_to_infinity( + const Eigen::MatrixBase & F, + const typename DerivedF::Scalar inf_index, + Eigen::PlainObjectBase & FO) +{ + // Determine boundary edges + Eigen::Matrix O; + boundary_facets(F,O); + FO.resize(F.rows()+O.rows(),F.cols()); + typedef Eigen::Matrix VectorXI; + FO.topLeftCorner(F.rows(),F.cols()) = F; + FO.bottomLeftCorner(O.rows(),O.cols()) = O.rowwise().reverse(); + FO.bottomRightCorner(O.rows(),1).setConstant(inf_index); +} + +template < + typename DerivedV, + typename DerivedF, + typename DerivedVO, + typename DerivedFO> +IGL_INLINE void igl::connect_boundary_to_infinity( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + Eigen::PlainObjectBase & VO, + Eigen::PlainObjectBase & FO) +{ + typename DerivedV::Index inf_index = V.rows(); + connect_boundary_to_infinity(F,inf_index,FO); + VO.resize(V.rows()+1,V.cols()); + VO.topLeftCorner(V.rows(),V.cols()) = V; + auto inf = std::numeric_limits::infinity(); + VO.row(V.rows()).setConstant(inf); +} + +#ifdef IGL_STATIC_LIBRARY +template void igl::connect_boundary_to_infinity, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/connect_boundary_to_infinity.h b/src/external/libigl-2.3.0/include/igl/connect_boundary_to_infinity.h new file mode 100644 index 000000000..3109fc952 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/connect_boundary_to_infinity.h @@ -0,0 +1,56 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_CONNECT_BOUNDARY_TO_INFINITY_H +#define IGL_CONNECT_BOUNDARY_TO_INFINITY_H +#include "igl_inline.h" +#include +namespace igl +{ + // Connect all boundary edges to a fictitious point at infinity. + // + // Inputs: + // F #F by 3 list of face indices into some V + // Outputs: + // FO #F+#O by 3 list of face indices into [V;inf inf inf], original F are + // guaranteed to come first. If (V,F) was a manifold mesh, now it is + // closed with a possibly non-manifold vertex at infinity (but it will be + // edge-manifold). + template + IGL_INLINE void connect_boundary_to_infinity( + const Eigen::MatrixBase & F, + Eigen::PlainObjectBase & FO); + // Inputs: + // inf_index index of point at infinity (usually V.rows() or F.maxCoeff()) + template + IGL_INLINE void connect_boundary_to_infinity( + const Eigen::MatrixBase & F, + const typename DerivedF::Scalar inf_index, + Eigen::PlainObjectBase & FO); + // Inputs: + // V #V by 3 list of vertex positions + // F #F by 3 list of face indices into some V + // Outputs: + // VO #V+1 by 3 list of vertex positions, original V are guaranteed to + // come first. Last point is inf, inf, inf + // FO #F+#O by 3 list of face indices into VO + // + template < + typename DerivedV, + typename DerivedF, + typename DerivedVO, + typename DerivedFO> + IGL_INLINE void connect_boundary_to_infinity( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + Eigen::PlainObjectBase & VO, + Eigen::PlainObjectBase & FO); +} +#ifndef IGL_STATIC_LIBRARY +# include "connect_boundary_to_infinity.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/connected_components.cpp b/src/external/libigl-2.3.0/include/igl/connected_components.cpp new file mode 100644 index 000000000..263b3f7a8 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/connected_components.cpp @@ -0,0 +1,61 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2020 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +#include "connected_components.h" +#include + +template < typename Atype, typename DerivedC, typename DerivedK> +IGL_INLINE int igl::connected_components( + const Eigen::SparseMatrix & A, + Eigen::PlainObjectBase & C, + Eigen::PlainObjectBase & K) +{ + typedef typename Eigen::SparseMatrix::Index Index; + const auto m = A.rows(); + assert(A.cols() == A.rows() && "A should be square"); + // 1.1 sec + // m means not yet visited + C.setConstant(m,1,m); + // Could use amortized dynamic array but didn't see real win. + K.setZero(m,1); + typename DerivedC::Scalar c = 0; + for(Eigen::Index f = 0;f Q; + Q.push(f); + while(!Q.empty()) + { + const Index g = Q.front(); + Q.pop(); + // already seen + if(C(g)::InnerIterator it (A,g); it; ++it) + { + const Index n = it.index(); + // already seen + if(C(n), Eigen::Matrix >(Eigen::SparseMatrix const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/connected_components.h b/src/external/libigl-2.3.0/include/igl/connected_components.h new file mode 100644 index 000000000..81fe9dbd2 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/connected_components.h @@ -0,0 +1,35 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2020 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_CONNECTED_COMPONENTS_H +#define IGL_CONNECTED_COMPONENTS_H +#include "igl_inline.h" +#include +#include +namespace igl +{ + // Determine the connected components of a graph described by the input + // adjacency matrix (similar to MATLAB's graphconncomp). + // + // Inputs: + // A #A by #A adjacency matrix (treated as describing an undirected graph) + // Outputs: + // C #A list of component indices into [0,#K-1] + // K #K list of sizes of each component + // Returns number of connected components + template < typename Atype, typename DerivedC, typename DerivedK> + IGL_INLINE int connected_components( + const Eigen::SparseMatrix & A, + Eigen::PlainObjectBase & C, + Eigen::PlainObjectBase & K); +} + +#ifndef IGL_STATIC_LIBRARY +# include "connected_components.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/README.md b/src/external/libigl-2.3.0/include/igl/copyleft/README.md new file mode 100644 index 000000000..78454affc --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/README.md @@ -0,0 +1,14 @@ +## IGL copyleft subdirectory + +Functions in the `include/igl/copyleft/` subdirectory are in the +`igl::copyleft::` namespace to indicate that they are under a more aggressive +[copyleft](https://en.wikipedia.org/wiki/Copyleft) than +[MPL2](https://en.wikipedia.org/wiki/Mozilla_Public_License) used for the main +`include/igl` directory and `igl::` namespace. Most notably, this subdirectory +includes code that is under +[GPL](https://en.wikipedia.org/wiki/GNU_General_Public_License). + +Typically a company planning on developing software without releasing its +source code will avoid or purchase licenses for such dependencies. If you do +obtain such a license for the dependencies employed here, you are free to use +the libigl functions here as per their MPL2 license. diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/BinaryWindingNumberOperations.h b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/BinaryWindingNumberOperations.h new file mode 100644 index 000000000..9bae0b7bb --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/BinaryWindingNumberOperations.h @@ -0,0 +1,167 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Qingnan Zhou +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +// +#ifndef IGL_COPYLEFT_CGAL_BINARY_WINDING_NUMBER_OPERATIONS_H +#define IGL_COPYLEFT_CGAL_BINARY_WINDING_NUMBER_OPERATIONS_H + +#include +#include "../../igl_inline.h" +#include "../../MeshBooleanType.h" +#include + +// TODO: This is not written according to libigl style. These should be +// function handles. +// +// Why is this templated on DerivedW +// +// These are all generalized to n-ary operations +namespace igl +{ + namespace copyleft + { + namespace cgal + { + template + class BinaryWindingNumberOperations { + public: + template + typename DerivedW::Scalar operator()( + const Eigen::PlainObjectBase& /*win_nums*/) const { + throw (std::runtime_error("not implemented!")); + } + }; + + // A ∪ B ∪ ... ∪ Z + template <> + class BinaryWindingNumberOperations { + public: + template + typename DerivedW::Scalar operator()( + const Eigen::PlainObjectBase& win_nums) const + { + for(int i = 0;i 0) return true; + } + return false; + } + }; + + // A ∩ B ∩ ... ∩ Z + template <> + class BinaryWindingNumberOperations { + public: + template + typename DerivedW::Scalar operator()( + const Eigen::PlainObjectBase& win_nums) const + { + for(int i = 0;i + class BinaryWindingNumberOperations { + public: + template + typename DerivedW::Scalar operator()( + const Eigen::PlainObjectBase& win_nums) const + { + assert(win_nums.size()>1); + // Union of objects 1 through n-1 + bool union_rest = false; + for(int i = 1;i 0; + if(union_rest) break; + } + // Must be in object 0 and not in union of objects 1 through n-1 + return win_nums(0) > 0 && !union_rest; + } + }; + + // A ∆ B ∆ ... ∆ Z (equivalent to set inside odd number of objects) + template <> + class BinaryWindingNumberOperations { + public: + template + typename DerivedW::Scalar operator()( + const Eigen::PlainObjectBase& win_nums) const + { + // If inside an odd number of objects + int count = 0; + for(int i = 0;i 0) count++; + } + return count % 2 == 1; + } + }; + + template <> + class BinaryWindingNumberOperations { + public: + template + typename DerivedW::Scalar operator()( + const Eigen::PlainObjectBase& /*win_nums*/) const { + return true; + } + }; + + typedef BinaryWindingNumberOperations BinaryUnion; + typedef BinaryWindingNumberOperations BinaryIntersect; + typedef BinaryWindingNumberOperations BinaryMinus; + typedef BinaryWindingNumberOperations BinaryXor; + typedef BinaryWindingNumberOperations BinaryResolve; + + enum KeeperType { + KEEP_INSIDE, + KEEP_ALL + }; + + template + class WindingNumberFilter { + public: + template + short operator()( + const Eigen::PlainObjectBase& /*win_nums*/) const { + throw std::runtime_error("Not implemented"); + } + }; + + template<> + class WindingNumberFilter { + public: + template + short operator()(T out_w, T in_w) const { + if (in_w > 0 && out_w <= 0) return 1; + else if (in_w <= 0 && out_w > 0) return -1; + else return 0; + } + }; + + template<> + class WindingNumberFilter { + public: + template + short operator()(T /*out_w*/, T /*in_w*/) const { + return 1; + } + }; + + typedef WindingNumberFilter KeepInside; + typedef WindingNumberFilter KeepAll; + } + } +} + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/CGAL_includes.hpp b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/CGAL_includes.hpp new file mode 100644 index 000000000..38d2fc749 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/CGAL_includes.hpp @@ -0,0 +1,50 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_CGAL_INCLUDES_H +#define IGL_CGAL_INCLUDES_H + +// This causes unknown bugs during intersection meshing: +//// http://www.alecjacobson.com/weblog/?p=4291 +//#define CGAL_INTERSECTION_VERSION 1 +// Use this instead to mute errors resulting from bad CGAL assertions +#define CGAL_KERNEL_NO_ASSERTIONS +// Triangle triangle intersection +#include +// THIS CANNOT BE INCLUDED IN THE SAME FILE AS +// #include + +// Constrained Delaunay Triangulation types +#include +#include + +// Axis-align boxes for all-pairs self-intersection detection +#include +#include +#include +#include +#include +#include +#include + +// Axis-aligned bounding box tree for tet tri intersection +#include +#include +#include + +// Boolean operations +#include +// Is this actually used? +//#include + +// Delaunay Triangulation in 3D +#include + +#include +#include + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/CSGTree.h b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/CSGTree.h new file mode 100644 index 000000000..599572d3f --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/CSGTree.h @@ -0,0 +1,189 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_COPYLEFT_CGAL_CSG_TREE_H +#define IGL_COPYLEFT_CGAL_CSG_TREE_H + +#include "../../MeshBooleanType.h" +#include "string_to_mesh_boolean_type.h" +#include "mesh_boolean.h" +#include +#include + +namespace igl +{ + namespace copyleft + { + namespace cgal + { + // Class for defining and computing a constructive solid geometry result + // out of a tree of boolean operations on "solid" triangle meshes. + // + //template + class CSGTree + { + public: + typedef CGAL::Epeck::FT ExactScalar; + //typedef Eigen::PlainObjectBase POBF; + typedef Eigen::MatrixXi POBF; + typedef POBF::Index FIndex; + typedef Eigen::Matrix MatrixX3E; + typedef Eigen::Matrix VectorJ; + private: + // Resulting mesh + MatrixX3E m_V; + POBF m_F; + VectorJ m_J; + // Number of birth faces in A + those in B. I.e. sum of original "leaf" + // faces involved in result. + size_t m_number_of_birth_faces; + public: + CSGTree() + { + } + //typedef Eigen::MatrixXd MatrixX3E; + //typedef Eigen::MatrixXi POBF; + // http://stackoverflow.com/a/3279550/148668 + CSGTree(const CSGTree & other) + : + // copy things + m_V(other.m_V), + // This is an issue if m_F is templated + // https://forum.kde.org/viewtopic.php?f=74&t=128414 + m_F(other.m_F), + m_J(other.m_J), + m_number_of_birth_faces(other.m_number_of_birth_faces) + { + } + // copy-swap idiom + friend void swap(CSGTree& first, CSGTree& second) + { + using std::swap; + // swap things + swap(first.m_V,second.m_V); + // This is an issue if m_F is templated, similar to + // https://forum.kde.org/viewtopic.php?f=74&t=128414 + swap(first.m_F,second.m_F); + swap(first.m_J,second.m_J); + swap(first.m_number_of_birth_faces,second.m_number_of_birth_faces); + } + // Pass-by-value (aka copy) + CSGTree& operator=(CSGTree other) + { + swap(*this,other); + return *this; + } + CSGTree(CSGTree&& other): + // initialize via default constructor + CSGTree() + { + swap(*this,other); + } + // Construct and compute a boolean operation on existing CSGTree nodes. + // + // Inputs: + // A Solid result of previous CSG operation (or identity, see below) + // B Solid result of previous CSG operation (or identity, see below) + // type type of mesh boolean to compute + CSGTree( + const CSGTree & A, + const CSGTree & B, + const MeshBooleanType & type) + { + // conduct boolean operation + mesh_boolean(A.V(),A.F(),B.V(),B.F(),type,m_V,m_F,m_J); + // reindex m_J + std::for_each(m_J.data(),m_J.data()+m_J.size(), + [&](typename VectorJ::Scalar & j) -> void + { + if(j < A.F().rows()) + { + j = A.J()(j); + }else + { + assert(j<(A.F().rows()+B.F().rows())); + j = A.number_of_birth_faces()+(B.J()(j-A.F().rows())); + } + }); + m_number_of_birth_faces = + A.number_of_birth_faces() + B.number_of_birth_faces(); + } + // Overload using string for type + CSGTree( + const CSGTree & A, + const CSGTree & B, + const std::string & s): + CSGTree(A,B,string_to_mesh_boolean_type(s)) + { + // do nothing (all done in constructor). + } + // "Leaf" node with identity operation on assumed "solid" mesh (V,F) + // + // Inputs: + // V #V by 3 list of mesh vertices (in any precision, will be + // converted to exact) + // F #F by 3 list of mesh face indices into V + template + CSGTree(const Eigen::PlainObjectBase & V, const POBF & F)//: + // Possible Eigen bug: + // https://forum.kde.org/viewtopic.php?f=74&t=128414 + //m_V(V.template cast()),m_F(F) + { + m_V = V.template cast(); + m_F = F; + // number of faces + m_number_of_birth_faces = m_F.rows(); + // identity birth index + m_J = VectorJ::LinSpaced( + m_number_of_birth_faces,0,m_number_of_birth_faces-1); + } + // Returns reference to resulting mesh vertices m_V in exact scalar + // representation + const MatrixX3E & V() const + { + return m_V; + } + // Returns mesh vertices in the desired output type, casting when + // appropriate to floating precision. + template + DerivedV cast_V() const + { + DerivedV dV; + dV.resize(m_V.rows(),m_V.cols()); + for(int i = 0;i +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_COPYLEFT_CGAL_REMESH_SELF_INTERSECTIONS_PARAM_H +#define IGL_COPYLEFT_CGAL_REMESH_SELF_INTERSECTIONS_PARAM_H + +namespace igl +{ + namespace copyleft + { + namespace cgal + { + // Optional Parameters + // DetectOnly Only compute IF, leave VV and FF alone + struct RemeshSelfIntersectionsParam + { + bool detect_only; + bool first_only; + bool stitch_all; + inline RemeshSelfIntersectionsParam( + bool _detect_only=false, + bool _first_only=false, + bool _stitch_all=false): + detect_only(_detect_only), + first_only(_first_only), + stitch_all(_stitch_all){}; + }; + } + } +} + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/SelfIntersectMesh.h b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/SelfIntersectMesh.h new file mode 100644 index 000000000..5a70fc39e --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/SelfIntersectMesh.h @@ -0,0 +1,939 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_COPYLEFT_CGAL_SELFINTERSECTMESH_H +#define IGL_COPYLEFT_CGAL_SELFINTERSECTMESH_H + +#include "CGAL_includes.hpp" +#include "RemeshSelfIntersectionsParam.h" +#include "../../unique.h" + +#include +#include +#include +#include +#include +#include + +//#define IGL_SELFINTERSECTMESH_DEBUG +#ifndef IGL_FIRST_HIT_EXCEPTION +#define IGL_FIRST_HIT_EXCEPTION 10 +#endif + +// The easiest way to keep track of everything is to use a class + +namespace igl +{ + namespace copyleft + { + namespace cgal + { + // Kernel is a CGAL kernel like: + // CGAL::Exact_predicates_inexact_constructions_kernel + // or + // CGAL::Exact_predicates_exact_constructions_kernel + + template < + typename Kernel, + typename DerivedV, + typename DerivedF, + typename DerivedVV, + typename DerivedFF, + typename DerivedIF, + typename DerivedJ, + typename DerivedIM> + class SelfIntersectMesh + { + typedef + SelfIntersectMesh< + Kernel, + DerivedV, + DerivedF, + DerivedVV, + DerivedFF, + DerivedIF, + DerivedJ, + DerivedIM> Self; + public: + // 3D Primitives + typedef CGAL::Point_3 Point_3; + typedef CGAL::Segment_3 Segment_3; + typedef CGAL::Triangle_3 Triangle_3; + typedef CGAL::Plane_3 Plane_3; + typedef CGAL::Tetrahedron_3 Tetrahedron_3; + // 2D Primitives + typedef CGAL::Point_2 Point_2; + typedef CGAL::Segment_2 Segment_2; + typedef CGAL::Triangle_2 Triangle_2; + // 2D Constrained Delaunay Triangulation types + typedef CGAL::Exact_intersections_tag Itag; + // Axis-align boxes for all-pairs self-intersection detection + typedef std::vector Triangles; + typedef typename Triangles::iterator TrianglesIterator; + typedef typename Triangles::const_iterator TrianglesConstIterator; + typedef + CGAL::Box_intersection_d::Box_with_handle_d + Box; + + // Input mesh + const Eigen::MatrixBase & V; + const Eigen::MatrixBase & F; + // Number of self-intersecting triangle pairs + typedef typename DerivedF::Index Index; + Index count; + typedef std::vector> ObjectList; + // Using a vector here makes this **not** output sensitive + Triangles T; + typedef std::vector IndexList; + IndexList lIF; + // #F-long list of faces with intersections mapping to the order in + // which they were first found + std::map offending; + // Make a short name for the edge map's key + typedef std::pair EMK; + // Make a short name for the type stored at each edge, the edge map's + // value + typedef std::vector EMV; + // Make a short name for the edge map + typedef std::map EdgeMap; + // Maps edges of offending faces to all incident offending faces + std::vector > + candidate_triangle_pairs; + + public: + RemeshSelfIntersectionsParam params; + public: + // Constructs (VV,FF) a new mesh with self-intersections of (V,F) + // subdivided + // + // See also: remesh_self_intersections.h + inline SelfIntersectMesh( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const RemeshSelfIntersectionsParam & params, + Eigen::PlainObjectBase & VV, + Eigen::PlainObjectBase & FF, + Eigen::PlainObjectBase & IF, + Eigen::PlainObjectBase & J, + Eigen::PlainObjectBase & IM); + private: + // Helper function to mark a face as offensive + // + // Inputs: + // f index of face in F + inline void mark_offensive(const Index f); + // Helper function to count intersections between faces + // + // Input: + // fa index of face A in F + // fb index of face B in F + inline void count_intersection( const Index fa, const Index fb); + // Helper function for box_intersect. Intersect two triangles A and B, + // append the intersection object (point,segment,triangle) to a running + // list for A and B + // + // Inputs: + // A triangle in 3D + // B triangle in 3D + // fa index of A in F (and key into offending) + // fb index of B in F (and key into offending) + // Returns true only if A intersects B + // + inline bool intersect( + const Triangle_3 & A, + const Triangle_3 & B, + const Index fa, + const Index fb); + // Helper function for box_intersect. In the case where A and B have + // already been identified to share a vertex, then we only want to + // add possible segment intersections. Assumes truly duplicate + // triangles are not given as input + // + // Inputs: + // A triangle in 3D + // B triangle in 3D + // fa index of A in F (and key into offending) + // fb index of B in F (and key into offending) + // va index of shared vertex in A (and key into offending) + // vb index of shared vertex in B (and key into offending) + // Returns true if intersection (besides shared point) + // + inline bool single_shared_vertex( + const Triangle_3 & A, + const Triangle_3 & B, + const Index fa, + const Index fb, + const Index va, + const Index vb); + // Helper handling one direction + inline bool single_shared_vertex( + const Triangle_3 & A, + const Triangle_3 & B, + const Index fa, + const Index fb, + const Index va); + // Helper function for box_intersect. In the case where A and B have + // already been identified to share two vertices, then we only want + // to add a possible coplanar (Triangle) intersection. Assumes truly + // degenerate facets are not givin as input. + inline bool double_shared_vertex( + const Triangle_3 & A, + const Triangle_3 & B, + const Index fa, + const Index fb, + const std::vector > shared); + + public: + // Callback function called during box self intersections test. Means + // boxes a and b intersect. This method then checks if the triangles + // in each box intersect and if so, then processes the intersections + // + // Inputs: + // a box containing a triangle + // b box containing a triangle + inline void box_intersect(const Box& a, const Box& b); + inline void process_intersecting_boxes(); + public: + // Getters: + //const IndexList& get_lIF() const{ return lIF;} + static inline void box_intersect_static( + SelfIntersectMesh * SIM, + const Box &a, + const Box &b); + private: + std::mutex m_offending_lock; + }; + } + } +} + +// Implementation + +#include "mesh_to_cgal_triangle_list.h" +#include "remesh_intersections.h" + +#include "../../REDRUM.h" +#include "../../get_seconds.h" +#include "../../C_STR.h" + + +#include +#include +#include +#include +#include + +// References: +// http://minregret.googlecode.com/svn/trunk/skyline/src/extern/CGAL-3.3.1/examples/Polyhedron/polyhedron_self_intersection.cpp +// http://www.cgal.org/Manual/3.9/examples/Boolean_set_operations_2/do_intersect.cpp + +// Q: Should we be using CGAL::Polyhedron_3? +// A: No! Input is just a list of unoriented triangles. Polyhedron_3 requires +// a 2-manifold. +// A: But! It seems we could use CGAL::Triangulation_3. Though it won't be easy +// to take advantage of functions like insert_in_facet because we want to +// constrain segments. Hmmm. Actually Triangulation_3 doesn't look right... + +// CGAL's box_self_intersection_d uses C-style function callbacks without +// userdata. This is a leapfrog method for calling a member function. It should +// be bound as if the prototype was: +// static void box_intersect(const Box &a, const Box &b) +// using boost: +// boost::function cb +// = boost::bind(&::box_intersect, this, _1,_2); +// +template < + typename Kernel, + typename DerivedV, + typename DerivedF, + typename DerivedVV, + typename DerivedFF, + typename DerivedIF, + typename DerivedJ, + typename DerivedIM> +inline void igl::copyleft::cgal::SelfIntersectMesh< + Kernel, + DerivedV, + DerivedF, + DerivedVV, + DerivedFF, + DerivedIF, + DerivedJ, + DerivedIM>::box_intersect_static( + Self * SIM, + const typename Self::Box &a, + const typename Self::Box &b) +{ + SIM->box_intersect(a,b); +} + +template < + typename Kernel, + typename DerivedV, + typename DerivedF, + typename DerivedVV, + typename DerivedFF, + typename DerivedIF, + typename DerivedJ, + typename DerivedIM> +inline igl::copyleft::cgal::SelfIntersectMesh< + Kernel, + DerivedV, + DerivedF, + DerivedVV, + DerivedFF, + DerivedIF, + DerivedJ, + DerivedIM>::SelfIntersectMesh( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const RemeshSelfIntersectionsParam & params, + Eigen::PlainObjectBase & VV, + Eigen::PlainObjectBase & FF, + Eigen::PlainObjectBase & IF, + Eigen::PlainObjectBase & J, + Eigen::PlainObjectBase & IM): + V(V), + F(F), + count(0), + T(), + lIF(), + offending(), + params(params) +{ + using namespace std; + using namespace Eigen; + +#ifdef IGL_SELFINTERSECTMESH_DEBUG + const auto & tictoc = []() -> double + { + static double t_start = igl::get_seconds(); + double diff = igl::get_seconds()-t_start; + t_start += diff; + return diff; + }; + const auto log_time = [&](const std::string& label) -> void{ + std::cout << "SelfIntersectMesh." << label << ": " + << tictoc() << std::endl; + }; + tictoc(); +#endif + + // Compute and process self intersections + mesh_to_cgal_triangle_list(V,F,T); +#ifdef IGL_SELFINTERSECTMESH_DEBUG + log_time("convert_to_triangle_list"); +#endif + // http://www.cgal.org/Manual/latest/doc_html/cgal_manual/Box_intersection_d/Chapter_main.html#Section_63.5 + // Create the corresponding vector of bounding boxes + std::vector boxes; + boxes.reserve(T.size()); + for ( + TrianglesIterator tit = T.begin(); + tit != T.end(); + ++tit) + { + if (!tit->is_degenerate()) + { + boxes.push_back(Box(tit->bbox(), tit)); + } + } + // Leapfrog callback + std::function cb = + std::bind(&box_intersect_static, this, + // Explicitly use std namespace to avoid confusion with boost (who puts + // _1 etc. in global namespace) + std::placeholders::_1, + std::placeholders::_2); +#ifdef IGL_SELFINTERSECTMESH_DEBUG + log_time("box_and_bind"); +#endif + // Run the self intersection algorithm with all defaults + CGAL::box_self_intersection_d(boxes.begin(), boxes.end(),cb); +#ifdef IGL_SELFINTERSECTMESH_DEBUG + log_time("box_intersection_d"); +#endif + try{ + process_intersecting_boxes(); + }catch(int e) + { + // Rethrow if not IGL_FIRST_HIT_EXCEPTION + if(e != IGL_FIRST_HIT_EXCEPTION) + { + throw e; + } + // Otherwise just fall through + } +#ifdef IGL_SELFINTERSECTMESH_DEBUG + log_time("resolve_intersection"); +#endif + + // Convert lIF to Eigen matrix + assert(lIF.size()%2 == 0); + IF.resize(lIF.size()/2,2); + { + Index i=0; + for( + typename IndexList::const_iterator ifit = lIF.begin(); + ifit!=lIF.end(); + ) + { + IF(i,0) = (*ifit); + ifit++; + IF(i,1) = (*ifit); + ifit++; + i++; + } + } +#ifdef IGL_SELFINTERSECTMESH_DEBUG + log_time("store_intersecting_face_pairs"); +#endif + + if(params.detect_only) + { + return; + } + + remesh_intersections( + V,F,T,offending,params.stitch_all,VV,FF,J,IM); + +#ifdef IGL_SELFINTERSECTMESH_DEBUG + log_time("remesh_intersection"); +#endif +} + + +template < + typename Kernel, + typename DerivedV, + typename DerivedF, + typename DerivedVV, + typename DerivedFF, + typename DerivedIF, + typename DerivedJ, + typename DerivedIM> +inline void igl::copyleft::cgal::SelfIntersectMesh< + Kernel, + DerivedV, + DerivedF, + DerivedVV, + DerivedFF, + DerivedIF, + DerivedJ, + DerivedIM>::mark_offensive(const Index f) +{ + using namespace std; + lIF.push_back(f); + if(offending.count(f) == 0) + { + // first time marking, initialize with new id and empty list + offending[f] = {}; + } +} + +template < + typename Kernel, + typename DerivedV, + typename DerivedF, + typename DerivedVV, + typename DerivedFF, + typename DerivedIF, + typename DerivedJ, + typename DerivedIM> +inline void igl::copyleft::cgal::SelfIntersectMesh< + Kernel, + DerivedV, + DerivedF, + DerivedVV, + DerivedFF, + DerivedIF, + DerivedJ, + DerivedIM>::count_intersection( + const Index fa, + const Index fb) +{ + std::lock_guard guard(m_offending_lock); + mark_offensive(fa); + mark_offensive(fb); + this->count++; + // We found the first intersection + if(params.first_only && this->count >= 1) + { + throw IGL_FIRST_HIT_EXCEPTION; + } + +} + +template < + typename Kernel, + typename DerivedV, + typename DerivedF, + typename DerivedVV, + typename DerivedFF, + typename DerivedIF, + typename DerivedJ, + typename DerivedIM> +inline bool igl::copyleft::cgal::SelfIntersectMesh< + Kernel, + DerivedV, + DerivedF, + DerivedVV, + DerivedFF, + DerivedIF, + DerivedJ, + DerivedIM>::intersect( + const Triangle_3 & A, + const Triangle_3 & B, + const Index fa, + const Index fb) +{ + // Determine whether there is an intersection + if(!CGAL::do_intersect(A,B)) + { + return false; + } + count_intersection(fa,fb); + if(!params.detect_only) + { + // Construct intersection + CGAL::Object result = CGAL::intersection(A,B); + std::lock_guard guard(m_offending_lock); + offending[fa].push_back({fb, result}); + offending[fb].push_back({fa, result}); + } + return true; +} + +template < + typename Kernel, + typename DerivedV, + typename DerivedF, + typename DerivedVV, + typename DerivedFF, + typename DerivedIF, + typename DerivedJ, + typename DerivedIM> +inline bool igl::copyleft::cgal::SelfIntersectMesh< + Kernel, + DerivedV, + DerivedF, + DerivedVV, + DerivedFF, + DerivedIF, + DerivedJ, + DerivedIM>::single_shared_vertex( + const Triangle_3 & A, + const Triangle_3 & B, + const Index fa, + const Index fb, + const Index va, + const Index vb) +{ + if(single_shared_vertex(A,B,fa,fb,va)) + { + return true; + } + return single_shared_vertex(B,A,fb,fa,vb); +} + +template < + typename Kernel, + typename DerivedV, + typename DerivedF, + typename DerivedVV, + typename DerivedFF, + typename DerivedIF, + typename DerivedJ, + typename DerivedIM> +inline bool igl::copyleft::cgal::SelfIntersectMesh< + Kernel, + DerivedV, + DerivedF, + DerivedVV, + DerivedFF, + DerivedIF, + DerivedJ, + DerivedIM>::single_shared_vertex( + const Triangle_3 & A, + const Triangle_3 & B, + const Index fa, + const Index fb, + const Index va) +{ + // This was not a good idea. It will not handle coplanar triangles well. + using namespace std; + Segment_3 sa( + A.vertex((va+1)%3), + A.vertex((va+2)%3)); + + if(CGAL::do_intersect(sa,B)) + { + // can't put count_intersection(fa,fb) here since we use intersect below + // and then it will be counted twice. + if(params.detect_only) + { + count_intersection(fa,fb); + return true; + } + CGAL::Object result = CGAL::intersection(sa,B); + if(const Point_3 * p = CGAL::object_cast(&result)) + { + // Single intersection --> segment from shared point to intersection + CGAL::Object seg = CGAL::make_object(Segment_3( + A.vertex(va), + *p)); + count_intersection(fa,fb); + std::lock_guard guard(m_offending_lock); + offending[fa].push_back({fb, seg}); + offending[fb].push_back({fa, seg}); + return true; + }else if(CGAL::object_cast(&result)) + { + // Need to do full test. Intersection could be a general poly. + bool test = intersect(A,B,fa,fb); + ((void)test); + assert(test && "intersect should agree with do_intersect"); + return true; + }else + { + cerr< +inline bool igl::copyleft::cgal::SelfIntersectMesh< + Kernel, + DerivedV, + DerivedF, + DerivedVV, + DerivedFF, + DerivedIF, + DerivedJ, + DerivedIM>::double_shared_vertex( + const Triangle_3 & A, + const Triangle_3 & B, + const Index fa, + const Index fb, + const std::vector > shared) +{ + using namespace std; + + // must be co-planar + if( + A.supporting_plane() != B.supporting_plane() && + A.supporting_plane() != B.supporting_plane().opposite()) + { + return false; + } + // Since A and B are non-degenerate the intersection must be a polygon + // (triangle). Either + // - the vertex of A (B) opposite the shared edge of lies on B (A), or + // - an edge of A intersects and edge of B without sharing a vertex + // + // Determine if the vertex opposite edge (a0,a1) in triangle A lies in + // (intersects) triangle B + const auto & opposite_point_inside = []( + const Triangle_3 & A, const Index a0, const Index a1, const Triangle_3 & B) + -> bool + { + // get opposite index + Index a2 = -1; + for(int c = 0;c<3;c++) + { + if(c != a0 && c != a1) + { + a2 = c; + break; + } + } + assert(a2 != -1); + bool ret = CGAL::do_intersect(A.vertex(a2),B); + return ret; + }; + + // Determine if edge opposite vertex va in triangle A intersects edge + // opposite vertex vb in triangle B. + const auto & opposite_edges_intersect = []( + const Triangle_3 & A, const Index va, + const Triangle_3 & B, const Index vb) -> bool + { + Segment_3 sa( A.vertex((va+1)%3), A.vertex((va+2)%3)); + Segment_3 sb( B.vertex((vb+1)%3), B.vertex((vb+2)%3)); + bool ret = CGAL::do_intersect(sa,sb); + return ret; + }; + + if( + !opposite_point_inside(A,shared[0].first,shared[1].first,B) && + !opposite_point_inside(B,shared[0].second,shared[1].second,A) && + !opposite_edges_intersect(A,shared[0].first,B,shared[1].second) && + !opposite_edges_intersect(A,shared[1].first,B,shared[0].second)) + { + return false; + } + + // there is an intersection indeed + count_intersection(fa,fb); + if(params.detect_only) + { + return true; + } + // Construct intersection + try + { + // This can fail for Epick but not Epeck + CGAL::Object result = CGAL::intersection(A,B); + if(!result.empty()) + { + if(CGAL::object_cast(&result)) + { + // not coplanar + assert(false && + "Co-planar non-degenerate triangles should intersect over triangle"); + return false; + } else if(CGAL::object_cast(&result)) + { + // this "shouldn't" happen but does for inexact + assert(false && + "Co-planar non-degenerate triangles should intersect over triangle"); + return false; + } else + { + // Triangle object + std::lock_guard guard(m_offending_lock); + offending[fa].push_back({fb, result}); + offending[fb].push_back({fa, result}); + return true; + } + }else + { + // CGAL::intersection is disagreeing with do_intersect + assert(false && "CGAL::intersection should agree with predicate tests"); + return false; + } + }catch(...) + { + // This catches some cgal assertion: + // CGAL error: assertion violation! + // Expression : is_finite(d) + // File : /opt/local/include/CGAL/GMP/Gmpq_type.h + // Line : 132 + // Explanation: + // But only if NDEBUG is not defined, otherwise there's an uncaught + // "Floating point exception: 8" SIGFPE + return false; + } + // No intersection. + return false; +} + +template < + typename Kernel, + typename DerivedV, + typename DerivedF, + typename DerivedVV, + typename DerivedFF, + typename DerivedIF, + typename DerivedJ, + typename DerivedIM> +inline void igl::copyleft::cgal::SelfIntersectMesh< + Kernel, + DerivedV, + DerivedF, + DerivedVV, + DerivedFF, + DerivedIF, + DerivedJ, + DerivedIM>::box_intersect( + const Box& a, + const Box& b) +{ + candidate_triangle_pairs.push_back({a.handle(), b.handle()}); +} + +template < + typename Kernel, + typename DerivedV, + typename DerivedF, + typename DerivedVV, + typename DerivedFF, + typename DerivedIF, + typename DerivedJ, + typename DerivedIM> +inline void igl::copyleft::cgal::SelfIntersectMesh< + Kernel, + DerivedV, + DerivedF, + DerivedVV, + DerivedFF, + DerivedIF, + DerivedJ, + DerivedIM>::process_intersecting_boxes() +{ + std::vector triangle_locks(T.size()); + std::vector vertex_locks(V.rows()); + std::mutex index_lock; + std::mutex exception_mutex; + bool exception_fired = false; + int exception = -1; + auto process_chunk = + [&]( + const size_t first, + const size_t last) -> void + { + try + { + assert(last >= first); + + for (size_t i=first; i guard(index_lock); + const auto& tri_pair = candidate_triangle_pairs[i]; + fa = tri_pair.first - T.begin(); + fb = tri_pair.second - T.begin(); + } + assert(fa < T.size()); + assert(fb < T.size()); + + // Lock triangles + std::lock_guard guard_A(triangle_locks[fa]); + std::lock_guard guard_B(triangle_locks[fb]); + + // Lock vertices + std::list > guard_vertices; + { + std::vector unique_vertices; + std::vector tmp1, tmp2; + igl::unique({F(fa,0), F(fa,1), F(fa,2), F(fb,0), F(fb,1), F(fb,2)}, + unique_vertices, tmp1, tmp2); + std::for_each(unique_vertices.begin(), unique_vertices.end(), + [&](const typename DerivedF::Scalar& vi) { + guard_vertices.emplace_back(vertex_locks[vi]); + }); + } + if(exception_fired) return; + + const Triangle_3& A = T[fa]; + const Triangle_3& B = T[fb]; + + // Number of combinatorially shared vertices + Index comb_shared_vertices = 0; + // Number of geometrically shared vertices (*not* including + // combinatorially shared) + Index geo_shared_vertices = 0; + // Keep track of shared vertex indices + std::vector > shared; + Index ea,eb; + for(ea=0;ea<3;ea++) + { + for(eb=0;eb<3;eb++) + { + if(F(fa,ea) == F(fb,eb)) + { + comb_shared_vertices++; + shared.emplace_back(ea,eb); + }else if(A.vertex(ea) == B.vertex(eb)) + { + geo_shared_vertices++; + shared.emplace_back(ea,eb); + } + } + } + const Index total_shared_vertices = + comb_shared_vertices + geo_shared_vertices; + if(exception_fired) return; + + if(comb_shared_vertices== 3) + { + assert(shared.size() == 3); + // Combinatorially duplicate face, these should be removed by + // preprocessing + continue; + } + if(total_shared_vertices== 3) + { + assert(shared.size() == 3); + // Geometrically duplicate face, these should be removed by + // preprocessing + continue; + } + if(total_shared_vertices == 2) + { + assert(shared.size() == 2); + // Q: What about coplanar? + // + // o o + // |\ /| + // | \/ | + // | /\ | + // |/ \| + // o----o + double_shared_vertex(A,B,fa,fb,shared); + continue; + } + assert(total_shared_vertices<=1); + if(total_shared_vertices==1) + { + single_shared_vertex(A,B,fa,fb,shared[0].first,shared[0].second); + }else + { + intersect(A,B,fa,fb); + } + } + }catch(int e) + { + std::lock_guard exception_lock(exception_mutex); + exception_fired = true; + exception = e; + } + }; + size_t num_threads=0; + const size_t hardware_limit = std::thread::hardware_concurrency(); + if (const char* igl_num_threads = std::getenv("LIBIGL_NUM_THREADS")) { + num_threads = atoi(igl_num_threads); + } + if (num_threads == 0 || num_threads > hardware_limit) { + num_threads = hardware_limit; + } + assert(num_threads > 0); + const size_t num_pairs = candidate_triangle_pairs.size(); + const size_t chunk_size = num_pairs / num_threads; + std::vector threads; + for (size_t i=0; i +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "assign.h" +#include "assign_scalar.h" + +template +IGL_INLINE void igl::copyleft::cgal::assign( + const Eigen::MatrixBase & C, + Eigen::PlainObjectBase & D) +{ + D.resizeLike(C); + for(int i = 0;i +IGL_INLINE +Eigen::Matrix< + ReturnScalar, + DerivedC::RowsAtCompileTime, + DerivedC::ColsAtCompileTime, + 1, + DerivedC::MaxRowsAtCompileTime, + DerivedC::MaxColsAtCompileTime> +igl::copyleft::cgal::assign( + const Eigen::MatrixBase & C) +{ + Eigen::Matrix< + ReturnScalar, + DerivedC::RowsAtCompileTime, + DerivedC::ColsAtCompileTime, + 1, + DerivedC::MaxRowsAtCompileTime, + DerivedC::MaxColsAtCompileTime> D; + assign(C,D); + return D; +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::copyleft::cgal::assign, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::copyleft::cgal::assign, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::copyleft::cgal::assign, Eigen::Matrix, -1, 3, 0, -1, 3> >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase, -1, 3, 0, -1, 3> >&); +// generated by autoexplicit.sh +template void igl::copyleft::cgal::assign, -1, -1, 0, -1, -1>, Eigen::Matrix >(Eigen::MatrixBase, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::copyleft::cgal::assign, -1, -1, 1, -1, -1>, Eigen::Matrix >(Eigen::MatrixBase, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::copyleft::cgal::assign, Eigen::Matrix, -1, -1, 1, -1, -1> >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase, -1, -1, 1, -1, -1> >&); +// generated by autoexplicit.sh +template void igl::copyleft::cgal::assign, Eigen::Matrix, -1, -1, 1, -1, -1> >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase, -1, -1, 1, -1, -1> >&); +// generated by autoexplicit.sh +template void igl::copyleft::cgal::assign, -1, 3, 0, -1, 3>, Eigen::Matrix >(Eigen::MatrixBase, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::copyleft::cgal::assign, -1, -1, 1, -1, -1>, Eigen::Matrix >(Eigen::MatrixBase, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::copyleft::cgal::assign, -1, -1, 1, -1, -1>, Eigen::Matrix, -1, -1, 0, -1, -1> >(Eigen::MatrixBase, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase, -1, -1, 0, -1, -1> >&); +// generated by autoexplicit.sh +template void igl::copyleft::cgal::assign, -1, -1, 1, -1, -1>, Eigen::Matrix, -1, 3, 0, -1, 3> >(Eigen::MatrixBase, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase, -1, 3, 0, -1, 3> >&); +// generated by autoexplicit.sh +template void igl::copyleft::cgal::assign, -1, -1, 1, -1, -1>, Eigen::Matrix >(Eigen::MatrixBase, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase >&); +template void igl::copyleft::cgal::assign, -1, -1, 0, -1, -1>, Eigen::Matrix >(Eigen::MatrixBase, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase >&); +template void igl::copyleft::cgal::assign, -1, -1, 0, -1, -1>, Eigen::Matrix, -1, 3, 0, -1, 3> >(Eigen::MatrixBase, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase, -1, 3, 0, -1, 3> >&); +template void igl::copyleft::cgal::assign, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::copyleft::cgal::assign, Eigen::Matrix, -1, -1, 0, -1, -1> >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase, -1, -1, 0, -1, -1> >&); +template void igl::copyleft::cgal::assign, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::copyleft::cgal::assign, Eigen::Matrix, -1, -1, 0, -1, -1> >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase, -1, -1, 0, -1, -1> >&); +template void igl::copyleft::cgal::assign, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::copyleft::cgal::assign, Eigen::Matrix, -1, 3, 0, -1, 3> >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase, -1, 3, 0, -1, 3> >&); +template void igl::copyleft::cgal::assign, -1, -1, 0, -1, -1>, Eigen::Matrix >(Eigen::MatrixBase, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase >&); +template void igl::copyleft::cgal::assign, -1, 3, 0, -1, 3>, Eigen::Matrix, -1, 3, 0, -1, 3> >(Eigen::MatrixBase, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase, -1, 3, 0, -1, 3> >&); +template void igl::copyleft::cgal::assign, -1, 3, 0, -1, 3>, Eigen::Matrix >(Eigen::MatrixBase, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase >&); +template void igl::copyleft::cgal::assign, 8, 3, 0, 8, 3>, Eigen::Matrix, 8, 3, 0, 8, 3> >(Eigen::MatrixBase, 8, 3, 0, 8, 3> > const&, Eigen::PlainObjectBase, 8, 3, 0, 8, 3> >&); +template void igl::copyleft::cgal::assign, 8, 3, 0, 8, 3>, Eigen::Matrix >(Eigen::MatrixBase, 8, 3, 0, 8, 3> > const&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/assign.h b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/assign.h new file mode 100644 index 000000000..db9081f23 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/assign.h @@ -0,0 +1,42 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_COPYLEFT_CGAL_ASSIGN_H +#define IGL_COPYLEFT_CGAL_ASSIGN_H +#include "../../igl_inline.h" +#include +#include + +namespace igl +{ + namespace copyleft + { + namespace cgal + { + template + IGL_INLINE void assign( + const Eigen::MatrixBase & C, + Eigen::PlainObjectBase & D); + template + IGL_INLINE + Eigen::Matrix< + ReturnScalar, + DerivedC::RowsAtCompileTime, + DerivedC::ColsAtCompileTime, + 1, + DerivedC::MaxRowsAtCompileTime, + DerivedC::MaxColsAtCompileTime> + assign( + const Eigen::MatrixBase & C); + } + } +} + +#ifndef IGL_STATIC_LIBRARY +# include "assign.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/assign_scalar.cpp b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/assign_scalar.cpp new file mode 100644 index 000000000..c38ee03a1 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/assign_scalar.cpp @@ -0,0 +1,136 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "assign_scalar.h" + +IGL_INLINE void igl::copyleft::cgal::assign_scalar( + const CGAL::Epeck::FT & cgal, + CGAL::Epeck::FT & d) +{ + d = cgal; +} + +IGL_INLINE void igl::copyleft::cgal::assign_scalar( + const CGAL::Epeck::FT & _cgal, + double & d) +{ + // FORCE evaluation of the exact type otherwise interval might be huge. + const CGAL::Epeck::FT cgal = _cgal.exact(); + const auto interval = CGAL::to_interval(cgal); + d = interval.first; + do { + const double next = nextafter(d, interval.second); + if (CGAL::abs(cgal-d) < CGAL::abs(cgal-next)) break; + d = next; + } while (d < interval.second); +} + +IGL_INLINE void igl::copyleft::cgal::assign_scalar( + const CGAL::Epeck::FT & _cgal, + float& d) +{ + // FORCE evaluation of the exact type otherwise interval might be huge. + const CGAL::Epeck::FT cgal = _cgal.exact(); + const auto interval = CGAL::to_interval(cgal); + d = interval.first; + do { + const float next = nextafter(d, float(interval.second)); + if (CGAL::abs(cgal-d) < CGAL::abs(cgal-next)) break; + d = next; + } while (d < float(interval.second)); +} + +IGL_INLINE void igl::copyleft::cgal::assign_scalar( + const double & c, + double & d) +{ + d = c; +} + +IGL_INLINE void igl::copyleft::cgal::assign_scalar( + const float& c, + float& d) +{ + d = c; +} + +IGL_INLINE void igl::copyleft::cgal::assign_scalar( + const float& c, + double& d) +{ + d = c; +} + +IGL_INLINE void igl::copyleft::cgal::assign_scalar( + const CGAL::Exact_predicates_exact_constructions_kernel_with_sqrt::FT & cgal, + CGAL::Exact_predicates_exact_constructions_kernel_with_sqrt::FT & d) +{ + d = cgal; +} + +IGL_INLINE void igl::copyleft::cgal::assign_scalar( + const CGAL::Exact_predicates_exact_constructions_kernel_with_sqrt::FT & cgal, + double & d) +{ + const auto interval = CGAL::to_interval(cgal); + d = interval.first; + do { + const double next = nextafter(d, interval.second); + if (CGAL::abs(cgal-d) < CGAL::abs(cgal-next)) break; + d = next; + } while (d < interval.second); +} + +IGL_INLINE void igl::copyleft::cgal::assign_scalar( + const CGAL::Exact_predicates_exact_constructions_kernel_with_sqrt::FT & cgal, + float& d) +{ + const auto interval = CGAL::to_interval(cgal); + d = interval.first; + do { + const float next = nextafter(d, float(interval.second)); + if (CGAL::abs(cgal-d) < CGAL::abs(cgal-next)) break; + d = next; + } while (d < float(interval.second)); +} + +#ifndef WIN32 + +IGL_INLINE void igl::copyleft::cgal::assign_scalar( + const CGAL::Simple_cartesian::FT & cgal, + CGAL::Simple_cartesian::FT & d) +{ + d = cgal; +} + +IGL_INLINE void igl::copyleft::cgal::assign_scalar( + const CGAL::Simple_cartesian::FT & cgal, + double & d) +{ + const auto interval = CGAL::to_interval(cgal); + d = interval.first; + do { + const double next = nextafter(d, interval.second); + if (CGAL::abs(cgal-d) < CGAL::abs(cgal-next)) break; + d = next; + } while (d < interval.second); +} + +IGL_INLINE void igl::copyleft::cgal::assign_scalar( + const CGAL::Simple_cartesian::FT & cgal, + float& d) +{ + const auto interval = CGAL::to_interval(cgal); + d = interval.first; + do { + const float next = nextafter(d, float(interval.second)); + if (CGAL::abs(cgal-d) < CGAL::abs(cgal-next)) break; + d = next; + } while (d < float(interval.second)); +} + +#endif // WIN32 diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/assign_scalar.h b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/assign_scalar.h new file mode 100644 index 000000000..feec928d5 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/assign_scalar.h @@ -0,0 +1,74 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_COPYLEFT_CGAL_ASSIGN_SCALAR_H +#define IGL_COPYLEFT_CGAL_ASSIGN_SCALAR_H +#include "../../igl_inline.h" +#include +#include +#ifndef WIN32 +#include +#endif + +namespace igl +{ + namespace copyleft + { + namespace cgal + { + // Inputs: + // cgal cgal scalar + // Outputs: + // d output scalar + IGL_INLINE void assign_scalar( + const CGAL::Epeck::FT & cgal, + CGAL::Epeck::FT & d); + IGL_INLINE void assign_scalar( + const CGAL::Epeck::FT & cgal, + double & d); + IGL_INLINE void assign_scalar( + const CGAL::Epeck::FT & cgal, + float& d); + IGL_INLINE void assign_scalar( + const double & c, + double & d); + IGL_INLINE void assign_scalar( + const float& c, + float & d); + IGL_INLINE void assign_scalar( + const float& c, + double& d); + + IGL_INLINE void assign_scalar( + const CGAL::Exact_predicates_exact_constructions_kernel_with_sqrt::FT & cgal, + CGAL::Exact_predicates_exact_constructions_kernel_with_sqrt::FT & d); + IGL_INLINE void assign_scalar( + const CGAL::Exact_predicates_exact_constructions_kernel_with_sqrt::FT & cgal, + double & d); + IGL_INLINE void assign_scalar( + const CGAL::Exact_predicates_exact_constructions_kernel_with_sqrt::FT & cgal, + float& d); + +#ifndef WIN32 + IGL_INLINE void assign_scalar( + const CGAL::Simple_cartesian::FT & cgal, + CGAL::Simple_cartesian::FT & d); + IGL_INLINE void assign_scalar( + const CGAL::Simple_cartesian::FT & cgal, + double & d); + IGL_INLINE void assign_scalar( + const CGAL::Simple_cartesian::FT & cgal, + float& d); +#endif // WIN32 + + } + } +} +#ifndef IGL_STATIC_LIBRARY +# include "assign_scalar.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/barycenter.cpp b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/barycenter.cpp new file mode 100644 index 000000000..b3ed8aeaf --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/barycenter.cpp @@ -0,0 +1,15 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2017 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "../../barycenter.h" +#include +#include +#ifdef IGL_STATIC_LIBRARY +#undef IGL_STATIC_LIBRARY +#include "../../barycenter.cpp" +template void igl::barycenter, -1, -1, 0, -1, -1>, Eigen::Matrix, Eigen::Matrix, -1, -1, 0, -1, -1> >(Eigen::MatrixBase, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase, -1, -1, 0, -1, -1> >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/cell_adjacency.cpp b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/cell_adjacency.cpp new file mode 100644 index 000000000..1824a37c8 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/cell_adjacency.cpp @@ -0,0 +1,34 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Qingnan Zhou +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +// + +#include "cell_adjacency.h" + +template +IGL_INLINE void igl::copyleft::cgal::cell_adjacency( + const Eigen::PlainObjectBase& per_patch_cells, + const size_t num_cells, + std::vector > >& + adjacency_list) { + + const size_t num_patches = per_patch_cells.rows(); + adjacency_list.resize(num_cells); + for (size_t i=0; i >(Eigen::PlainObjectBase > const&, unsigned long, std::vector::Scalar, bool, unsigned long>, std::less::Scalar, bool, unsigned long> >, std::allocator::Scalar, bool, unsigned long> > >, std::allocator::Scalar, bool, unsigned long>, std::less::Scalar, bool, unsigned long> >, std::allocator::Scalar, bool, unsigned long> > > > >&); +#ifdef WIN32 +template void igl::copyleft::cgal::cell_adjacency>(class Eigen::PlainObjectBase> const &, unsigned __int64, class std::vector, struct std::less>, class std::allocator>>, class std::allocator, struct std::less>, class std::allocator>>>> &); +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/cell_adjacency.h b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/cell_adjacency.h new file mode 100644 index 000000000..2244d3c4a --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/cell_adjacency.h @@ -0,0 +1,50 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Qingnan Zhou +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +// +#ifndef IGL_COPYLEFT_CGAL_CELL_ADJACENCY_H +#define IGL_COPYLEFT_CGAL_CELL_ADJACENCY_H +#include "../../igl_inline.h" +#include +#include +#include +#include + +namespace igl +{ + namespace copyleft + { + namespace cgal + { + // Inputs: + // per_patch_cells #P by 2 list of cell labels on each side of each + // patch. Cell labels are assumed to be continuous + // from 0 to #C. + // num_cells number of cells. + // + // Outputs: + // adjacency_list #C array of list of adjcent cell information. If + // cell i and cell j are adjacent via patch x, where i + // is on the positive side of x, and j is on the + // negative side. Then, + // adjacency_list[i] will contain the entry {j, false, x} + // and + // adjacency_list[j] will contain the entry {i, true, x} + template < typename DerivedC > + IGL_INLINE void cell_adjacency( + const Eigen::PlainObjectBase& per_patch_cells, + const size_t num_cells, + std::vector > >& + adjacency_list); + } + } +} + +#ifndef IGL_STATIC_LIBRARY +# include "cell_adjacency.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/closest_facet.cpp b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/closest_facet.cpp new file mode 100644 index 000000000..0b08dd4bc --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/closest_facet.cpp @@ -0,0 +1,504 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Qingnan Zhou +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +// +#include "closest_facet.h" + +#include +#include +#include + +#include "order_facets_around_edge.h" +#include "submesh_aabb_tree.h" +#include "../../vertex_triangle_adjacency.h" +#include "../../LinSpaced.h" +//#include "../../writePLY.h" + +template< + typename DerivedV, + typename DerivedF, + typename DerivedI, + typename DerivedP, + typename uE2EType, + typename DerivedEMAP, + typename DerivedR, + typename DerivedS > +IGL_INLINE void igl::copyleft::cgal::closest_facet( + const Eigen::PlainObjectBase& V, + const Eigen::PlainObjectBase& F, + const Eigen::PlainObjectBase& I, + const Eigen::PlainObjectBase& P, + const std::vector >& uE2E, + const Eigen::PlainObjectBase& EMAP, + Eigen::PlainObjectBase& R, + Eigen::PlainObjectBase& S) +{ + + typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel; + typedef Kernel::Point_3 Point_3; + typedef Kernel::Plane_3 Plane_3; + typedef Kernel::Segment_3 Segment_3; + typedef Kernel::Triangle_3 Triangle; + typedef std::vector::iterator Iterator; + typedef CGAL::AABB_triangle_primitive Primitive; + typedef CGAL::AABB_traits AABB_triangle_traits; + typedef CGAL::AABB_tree Tree; + + if (F.rows() <= 0 || I.rows() <= 0) { + throw std::runtime_error( + "Closest facet cannot be computed on empty mesh."); + } + + std::vector > VF, VFi; + igl::vertex_triangle_adjacency(V.rows(), F, VF, VFi); + std::vector in_I; + std::vector triangles; + Tree tree; + submesh_aabb_tree(V,F,I,tree,triangles,in_I); + + return closest_facet( + V,F,I,P,uE2E,EMAP,VF,VFi,tree,triangles,in_I,R,S); +} + +template< + typename DerivedV, + typename DerivedF, + typename DerivedI, + typename DerivedP, + typename uE2EType, + typename DerivedEMAP, + typename Kernel, + typename DerivedR, + typename DerivedS > +IGL_INLINE void igl::copyleft::cgal::closest_facet( + const Eigen::PlainObjectBase& V, + const Eigen::PlainObjectBase& F, + const Eigen::PlainObjectBase& I, + const Eigen::PlainObjectBase& P, + const std::vector >& uE2E, + const Eigen::PlainObjectBase& EMAP, + const std::vector > & VF, + const std::vector > & VFi, + const CGAL::AABB_tree< + CGAL::AABB_traits< + Kernel, + CGAL::AABB_triangle_primitive< + Kernel, typename std::vector< + typename Kernel::Triangle_3 >::iterator > > > & tree, + const std::vector & triangles, + const std::vector & in_I, + Eigen::PlainObjectBase& R, + Eigen::PlainObjectBase& S) +{ + typedef typename Kernel::Point_3 Point_3; + typedef typename Kernel::Plane_3 Plane_3; + typedef typename Kernel::Segment_3 Segment_3; + typedef typename Kernel::Triangle_3 Triangle; + typedef typename std::vector::iterator Iterator; + typedef typename CGAL::AABB_triangle_primitive Primitive; + typedef typename CGAL::AABB_traits AABB_triangle_traits; + typedef typename CGAL::AABB_tree Tree; + + const size_t num_faces = I.rows(); + if (F.rows() <= 0 || I.rows() <= 0) { + throw std::runtime_error( + "Closest facet cannot be computed on empty mesh."); + } + + auto on_the_positive_side = [&](size_t fid, const Point_3& p) -> bool + { + const auto& f = F.row(fid).eval(); + Point_3 v0(V(f[0], 0), V(f[0], 1), V(f[0], 2)); + Point_3 v1(V(f[1], 0), V(f[1], 1), V(f[1], 2)); + Point_3 v2(V(f[2], 0), V(f[2], 1), V(f[2], 2)); + auto ori = CGAL::orientation(v0, v1, v2, p); + switch (ori) { + case CGAL::POSITIVE: + return true; + case CGAL::NEGATIVE: + return false; + case CGAL::COPLANAR: + // Warning: + // This can only happen if fid contains a boundary edge. + // Categorized this ambiguous case as negative side. + return false; + default: + throw std::runtime_error("Unknown CGAL state."); + } + return false; + }; + + auto get_orientation = [&](size_t fid, size_t s, size_t d) -> bool + { + const auto& f = F.row(fid); + if ((size_t)f[0] == s && (size_t)f[1] == d) return false; + else if ((size_t)f[1] == s && (size_t)f[2] == d) return false; + else if ((size_t)f[2] == s && (size_t)f[0] == d) return false; + else if ((size_t)f[0] == d && (size_t)f[1] == s) return true; + else if ((size_t)f[1] == d && (size_t)f[2] == s) return true; + else if ((size_t)f[2] == d && (size_t)f[0] == s) return true; + else { + throw std::runtime_error( + "Cannot compute orientation due to incorrect connectivity"); + return false; + } + }; + auto index_to_signed_index = [&](size_t index, bool ori) -> int{ + return (index+1) * (ori? 1:-1); + }; + //auto signed_index_to_index = [&](int signed_index) -> size_t { + // return abs(signed_index) - 1; + //}; + + enum ElementType { VERTEX, EDGE, FACE }; + auto determine_element_type = [&](const Point_3& p, const size_t fid, + size_t& element_index) -> ElementType { + const auto& tri = triangles[fid]; + const Point_3 p0 = tri[0]; + const Point_3 p1 = tri[1]; + const Point_3 p2 = tri[2]; + + if (p == p0) { element_index = 0; return VERTEX; } + if (p == p1) { element_index = 1; return VERTEX; } + if (p == p2) { element_index = 2; return VERTEX; } + if (CGAL::collinear(p0, p1, p)) { element_index = 2; return EDGE; } + if (CGAL::collinear(p1, p2, p)) { element_index = 0; return EDGE; } + if (CGAL::collinear(p2, p0, p)) { element_index = 1; return EDGE; } + + element_index = 0; + return FACE; + }; + + auto process_edge_case = [&]( + size_t query_idx, + const size_t s, const size_t d, + size_t preferred_facet, + bool& orientation) -> size_t + { + Point_3 query_point( + P(query_idx, 0), + P(query_idx, 1), + P(query_idx, 2)); + + size_t corner_idx = std::numeric_limits::max(); + if ((s == F(preferred_facet, 0) && d == F(preferred_facet, 1)) || + (s == F(preferred_facet, 1) && d == F(preferred_facet, 0))) + { + corner_idx = 2; + } else if ((s == F(preferred_facet, 0) && d == F(preferred_facet, 2)) || + (s == F(preferred_facet, 2) && d == F(preferred_facet, 0))) + { + corner_idx = 1; + } else if ((s == F(preferred_facet, 1) && d == F(preferred_facet, 2)) || + (s == F(preferred_facet, 2) && d == F(preferred_facet, 1))) + { + corner_idx = 0; + } else + { + std::cerr << "s: " << s << "\t d:" << d << std::endl; + std::cerr << F.row(preferred_facet) << std::endl; + throw std::runtime_error( + "Invalid connectivity, edge does not belong to facet"); + } + + auto ueid = EMAP(preferred_facet + corner_idx * F.rows()); + auto eids = uE2E[ueid]; + std::vector intersected_face_indices; + for (auto eid : eids) + { + const size_t fid = eid % F.rows(); + if (in_I[fid]) + { + intersected_face_indices.push_back(fid); + } + } + + const size_t num_intersected_faces = intersected_face_indices.size(); + std::vector intersected_face_signed_indices(num_intersected_faces); + std::transform( + intersected_face_indices.begin(), + intersected_face_indices.end(), + intersected_face_signed_indices.begin(), + [&](size_t index) { + return index_to_signed_index( + index, get_orientation(index, s,d)); + }); + + assert(num_intersected_faces >= 1); + if (num_intersected_faces == 1) + { + // The edge must be a boundary edge. Thus, the orientation can be + // simply determined by checking if the query point is on the + // positive side of the facet. + const size_t fid = intersected_face_indices[0]; + orientation = on_the_positive_side(fid, query_point); + return fid; + } + + Eigen::VectorXi order; + DerivedP pivot = P.row(query_idx).eval(); + igl::copyleft::cgal::order_facets_around_edge(V, F, s, d, + intersected_face_signed_indices, + pivot, order); + + // Although first and last are equivalent, make the choice based on + // preferred_facet. + const size_t first = order[0]; + const size_t last = order[num_intersected_faces-1]; + if (intersected_face_indices[first] == preferred_facet) { + orientation = intersected_face_signed_indices[first] < 0; + return intersected_face_indices[first]; + } else if (intersected_face_indices[last] == preferred_facet) { + orientation = intersected_face_signed_indices[last] > 0; + return intersected_face_indices[last]; + } else { + orientation = intersected_face_signed_indices[order[0]] < 0; + return intersected_face_indices[order[0]]; + } + }; + + auto process_face_case = [&]( + const size_t query_idx, const Point_3& closest_point, + const size_t fid, bool& orientation) -> size_t { + const auto& f = F.row(I(fid, 0)); + return process_edge_case(query_idx, f[0], f[1], I(fid, 0), orientation); + }; + + // Given that the closest point to query point P(query_idx,:) on (V,F(I,:)) + // is the vertex at V(s,:) which is incident at least on triangle + // F(preferred_facet,:), determine a facet incident on V(s,:) that is + // _exposed_ to the query point and determine whether that facet is facing + // _toward_ or _away_ from the query point. + // + // Inputs: + // query_idx index into P of query point + // s index into V of closest point at vertex + // preferred_facet facet incident on s + // Outputs: + // orientation whether returned face is facing toward or away from + // query (parity unclear) + // Returns face guaranteed to be "exposed" to P(query_idx,:) + auto process_vertex_case = [&]( + const size_t query_idx, + size_t s, + size_t preferred_facet, + bool& orientation) -> size_t + { + const Point_3 query_point( + P(query_idx, 0), P(query_idx, 1), P(query_idx, 2)); + const Point_3 closest_point(V(s, 0), V(s, 1), V(s, 2)); + std::vector adj_faces; + std::vector adj_face_corners; + { + // Gather adj faces to s within I. + const auto& all_adj_faces = VF[s]; + const auto& all_adj_face_corners = VFi[s]; + const size_t num_all_adj_faces = all_adj_faces.size(); + for (size_t i=0; i 0); + + std::set adj_vertices_set; + std::unordered_multimap v2f; + for (size_t i=0; i adj_vertices(num_adj_vertices); + std::copy(adj_vertices_set.begin(), adj_vertices_set.end(), + adj_vertices.begin()); + + std::vector adj_points; + for (size_t vid : adj_vertices) + { + adj_points.emplace_back(V(vid,0), V(vid,1), V(vid,2)); + } + + // A plane is on the exterior if all adj_points lies on or to + // one side of the plane. + auto is_on_exterior = [&](const Plane_3& separator) -> bool{ + size_t positive=0; + size_t negative=0; + size_t coplanar=0; + for (const auto& point : adj_points) { + switch(separator.oriented_side(point)) { + case CGAL::ON_POSITIVE_SIDE: + positive++; + break; + case CGAL::ON_NEGATIVE_SIDE: + negative++; + break; + case CGAL::ON_ORIENTED_BOUNDARY: + coplanar++; + break; + default: + throw "Unknown plane-point orientation"; + } + } + auto query_orientation = separator.oriented_side(query_point); + if (query_orientation == CGAL::ON_ORIENTED_BOUNDARY && + (positive == 0 && negative == 0)) { + // All adj vertices and query point are coplanar. + // In this case, all separators are equally valid. + return true; + } else { + bool r = (positive == 0 && query_orientation == CGAL::POSITIVE) + || (negative == 0 && query_orientation == CGAL::NEGATIVE); + return r; + } + }; + + size_t d = std::numeric_limits::max(); + for (size_t i=0; i::max()) { + Eigen::MatrixXd tmp_vertices(V.rows(), V.cols()); + for (size_t i=0; isecond, orientation); + }; + + const size_t num_queries = P.rows(); + R.resize(num_queries, 1); + S.resize(num_queries, 1); + for (size_t i=0; i intersected_faces; + tree.all_intersected_primitives(Segment_3(closest_point, query), + std::back_inserter(intersected_faces)); + const size_t num_intersected_faces = intersected_faces.size(); + std::vector intersected_face_indices(num_intersected_faces); + std::transform(intersected_faces.begin(), + intersected_faces.end(), + intersected_face_indices.begin(), + [&](const typename Tree::Primitive_id& itr) -> size_t + { return I(itr-triangles.begin(), 0); }); + + size_t element_index; + auto element_type = determine_element_type(closest_point, fid, + element_index); + switch(element_type) { + case VERTEX: + { + const auto& f = F.row(I(fid, 0)); + const size_t s = f[element_index]; + fid = process_vertex_case(i, s, I(fid, 0), fid_ori); + } + break; + case EDGE: + { + const auto& f = F.row(I(fid, 0)); + const size_t s = f[(element_index+1)%3]; + const size_t d = f[(element_index+2)%3]; + fid = process_edge_case(i, s, d, I(fid, 0), fid_ori); + } + break; + case FACE: + { + fid = process_face_case(i, closest_point, fid, fid_ori); + } + break; + default: + throw std::runtime_error("Unknown element type."); + } + + + R(i,0) = fid; + S(i,0) = fid_ori; + } +} + +template< + typename DerivedV, + typename DerivedF, + typename DerivedP, + typename uE2EType, + typename DerivedEMAP, + typename DerivedR, + typename DerivedS > +IGL_INLINE void igl::copyleft::cgal::closest_facet( + const Eigen::PlainObjectBase& V, + const Eigen::PlainObjectBase& F, + const Eigen::PlainObjectBase& P, + const std::vector >& uE2E, + const Eigen::PlainObjectBase& EMAP, + Eigen::PlainObjectBase& R, + Eigen::PlainObjectBase& S) { + const size_t num_faces = F.rows(); + Eigen::VectorXi I = igl::LinSpaced(num_faces, 0, num_faces-1); + igl::copyleft::cgal::closest_facet(V, F, I, P, uE2E, EMAP, R, S); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::copyleft::cgal::closest_facet, -1, -1, 1, -1, -1>, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, -1, -1, 1, -1, -1>, unsigned long, Eigen::Matrix, CGAL::Epeck, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase, -1, -1, 1, -1, -1> > const&, std::vector >, std::allocator > > > const&, Eigen::PlainObjectBase > const&, std::vector >, std::allocator > > > const&, std::vector >, std::allocator > > > const&, CGAL::AABB_tree >::iterator, CGAL::Boolean_tag > > > const&, std::vector > const&, std::vector > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::copyleft::cgal::closest_facet, -1, -1, 1, -1, -1>, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, -1, -1, 1, -1, -1>, unsigned long, Eigen::Matrix, CGAL::Epeck, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase, -1, -1, 1, -1, -1> > const&, std::vector >, std::allocator > > > const&, Eigen::PlainObjectBase > const&, std::vector >, std::allocator > > > const&, std::vector >, std::allocator > > > const&, CGAL::AABB_tree >::iterator, CGAL::Boolean_tag > > > const&, std::vector > const&, std::vector > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::copyleft::cgal::closest_facet, -1, -1, 0, -1, -1>, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, -1, -1, 0, -1, -1>, unsigned long, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase, -1, -1, 0, -1, -1> > const&, std::vector >, std::allocator > > > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#ifdef WIN32 +template void igl::copyleft::cgal::closest_facet, -1, -1, 0, -1, -1>, class Eigen::Matrix, class Eigen::Matrix, class Eigen::Matrix, -1, -1, 0, -1, -1>, unsigned __int64, class Eigen::Matrix, class CGAL::Epeck, class Eigen::Matrix, class Eigen::Matrix>(class Eigen::PlainObjectBase, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase> const &, class Eigen::PlainObjectBase> const &, class Eigen::PlainObjectBase, -1, -1, 0, -1, -1>> const &, class std::vector>, class std::allocator>>> const &, class Eigen::PlainObjectBase> const &, class std::vector>, class std::allocator>>> const &, class std::vector>, class std::allocator>>> const &, class CGAL::AABB_tree>>>, struct CGAL::Boolean_tag<0>>>> const &, class std::vector, class std::allocator>> const &, class std::vector> const &, class Eigen::PlainObjectBase> &, class Eigen::PlainObjectBase> &); +template void igl::copyleft::cgal::closest_facet, -1, -1, 1, -1, -1>, class Eigen::Matrix, class Eigen::Matrix, class Eigen::Matrix, -1, -1, 1, -1, -1>, unsigned __int64, class Eigen::Matrix, class CGAL::Epeck, class Eigen::Matrix, class Eigen::Matrix>(class Eigen::PlainObjectBase, -1, -1, 1, -1, -1>> const &, class Eigen::PlainObjectBase> const &, class Eigen::PlainObjectBase> const &, class Eigen::PlainObjectBase, -1, -1, 1, -1, -1>> const &, class std::vector>, class std::allocator>>> const &, class Eigen::PlainObjectBase> const &, class std::vector>, class std::allocator>>> const &, class std::vector>, class std::allocator>>> const &, class CGAL::AABB_tree>>>, struct CGAL::Boolean_tag<0>>>> const &, class std::vector, class std::allocator>> const &, class std::vector> const &, class Eigen::PlainObjectBase> &, class Eigen::PlainObjectBase> &); +template void igl::copyleft::cgal::closest_facet, -1, -1, 1, -1, -1>, class Eigen::Matrix, class Eigen::Matrix, class Eigen::Matrix, -1, -1, 1, -1, -1>, unsigned __int64, class Eigen::Matrix, class CGAL::Epeck, class Eigen::Matrix, class Eigen::Matrix>(class Eigen::PlainObjectBase, -1, -1, 1, -1, -1>> const &, class Eigen::PlainObjectBase> const &, class Eigen::PlainObjectBase> const &, class Eigen::PlainObjectBase, -1, -1, 1, -1, -1>> const &, class std::vector>, class std::allocator>>> const &, class Eigen::PlainObjectBase> const &, class std::vector>, class std::allocator>>> const &, class std::vector>, class std::allocator>>> const &, class CGAL::AABB_tree>>>, struct CGAL::Boolean_tag<0>>>> const &, class std::vector, class std::allocator>> const &, class std::vector> const &, class Eigen::PlainObjectBase> &, class Eigen::PlainObjectBase> &); +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/closest_facet.h b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/closest_facet.h new file mode 100644 index 000000000..737ca2e22 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/closest_facet.h @@ -0,0 +1,110 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Qingnan Zhou +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +// +#ifndef IGL_COPYLET_CGAL_CLOSEST_FACET_H +#define IGL_COPYLET_CGAL_CLOSEST_FACET_H + +#include "../../igl_inline.h" +#include +#include + +#include +#include +#include +#include +#include + +namespace igl +{ + namespace copyleft + { + namespace cgal + { + // Determine the closest facet for each of the input points. + // + // Inputs: + // V #V by 3 array of vertices. + // F #F by 3 array of faces. + // I #I list of triangle indices to consider. + // P #P by 3 array of query points. + // + // Outputs: + // R #P list of closest facet indices. + // S #P list of bools indicating on which side of the closest facet + // each query point lies. + template< + typename DerivedV, + typename DerivedF, + typename DerivedI, + typename DerivedP, + typename uE2EType, + typename DerivedEMAP, + typename DerivedR, + typename DerivedS > + IGL_INLINE void closest_facet( + const Eigen::PlainObjectBase& V, + const Eigen::PlainObjectBase& F, + const Eigen::PlainObjectBase& I, + const Eigen::PlainObjectBase& P, + const std::vector >& uE2E, + const Eigen::PlainObjectBase& EMAP, + Eigen::PlainObjectBase& R, + Eigen::PlainObjectBase& S); + template< + typename DerivedV, + typename DerivedF, + typename DerivedP, + typename uE2EType, + typename DerivedEMAP, + typename DerivedR, + typename DerivedS > + IGL_INLINE void closest_facet( + const Eigen::PlainObjectBase& V, + const Eigen::PlainObjectBase& F, + const Eigen::PlainObjectBase& P, + const std::vector >& uE2E, + const Eigen::PlainObjectBase& EMAP, + Eigen::PlainObjectBase& R, + Eigen::PlainObjectBase& S); + template< + typename DerivedV, + typename DerivedF, + typename DerivedI, + typename DerivedP, + typename uE2EType, + typename DerivedEMAP, + typename Kernel, + typename DerivedR, + typename DerivedS > + IGL_INLINE void closest_facet( + const Eigen::PlainObjectBase& V, + const Eigen::PlainObjectBase& F, + const Eigen::PlainObjectBase& I, + const Eigen::PlainObjectBase& P, + const std::vector >& uE2E, + const Eigen::PlainObjectBase& EMAP, + const std::vector > & VF, + const std::vector > & VFi, + const CGAL::AABB_tree< + CGAL::AABB_traits< + Kernel, + CGAL::AABB_triangle_primitive< + Kernel, typename std::vector< + typename Kernel::Triangle_3 >::iterator > > > & tree, + const std::vector & triangles, + const std::vector & in_I, + Eigen::PlainObjectBase& R, + Eigen::PlainObjectBase& S); + } + } +} + +#ifndef IGL_STATIC_LIBRARY +#include "closest_facet.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/complex_to_mesh.cpp b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/complex_to_mesh.cpp new file mode 100644 index 000000000..74bf085ab --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/complex_to_mesh.cpp @@ -0,0 +1,152 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "complex_to_mesh.h" + +#include "../../centroid.h" +#include "../../remove_unreferenced.h" + +#include +#include +#include +#include + +template +IGL_INLINE bool igl::copyleft::cgal::complex_to_mesh( + const CGAL::Complex_2_in_triangulation_3 & c2t3, + Eigen::PlainObjectBase & V, + Eigen::PlainObjectBase & F) +{ + using namespace Eigen; + // CGAL/IO/Complex_2_in_triangulation_3_file_writer.h + using CGAL::Surface_mesher::number_of_facets_on_surface; + + typedef typename CGAL::Complex_2_in_triangulation_3 C2t3; + typedef typename Tr::Finite_facets_iterator Finite_facets_iterator; + typedef typename Tr::Finite_vertices_iterator Finite_vertices_iterator; + typedef typename Tr::Facet Facet; + typedef typename Tr::Edge Edge; + typedef typename Tr::Vertex_handle Vertex_handle; + + // Header. + const Tr& tr = c2t3.triangulation(); + + bool success = true; + + const int n = tr.number_of_vertices(); + const int m = c2t3.number_of_facets(); + + assert(m == number_of_facets_on_surface(tr)); + + // Finite vertices coordinates. + std::map v2i; + V.resize(n,3); + { + int v = 0; + for(Finite_vertices_iterator vit = tr.finite_vertices_begin(); + vit != tr.finite_vertices_end(); + ++vit) + { + V(v,0) = vit->point().x(); + V(v,1) = vit->point().y(); + V(v,2) = vit->point().z(); + v2i[vit] = v++; + } + } + + { + Finite_facets_iterator fit = tr.finite_facets_begin(); + std::set oriented_set; + std::stack stack; + + while ((int)oriented_set.size() != m) + { + while ( fit->first->is_facet_on_surface(fit->second) == false || + oriented_set.find(*fit) != oriented_set.end() || + oriented_set.find(c2t3.opposite_facet(*fit)) != + oriented_set.end() ) + { + ++fit; + } + oriented_set.insert(*fit); + stack.push(*fit); + while(! stack.empty() ) + { + Facet f = stack.top(); + stack.pop(); + for(int ih = 0 ; ih < 3 ; ++ih) + { + const int i1 = tr.vertex_triple_index(f.second, tr. cw(ih)); + const int i2 = tr.vertex_triple_index(f.second, tr.ccw(ih)); + + const typename C2t3::Face_status face_status + = c2t3.face_status(Edge(f.first, i1, i2)); + if(face_status == C2t3::REGULAR) + { + Facet fn = c2t3.neighbor(f, ih); + if (oriented_set.find(fn) == oriented_set.end()) + { + if(oriented_set.find(c2t3.opposite_facet(fn)) == oriented_set.end()) + { + oriented_set.insert(fn); + stack.push(fn); + }else { + success = false; // non-orientable + } + } + }else if(face_status != C2t3::BOUNDARY) + { + success = false; // non manifold, thus non-orientable + } + } // end "for each neighbor of f" + } // end "stack non empty" + } // end "oriented_set not full" + + F.resize(m,3); + int f = 0; + for(typename std::set::const_iterator fit = + oriented_set.begin(); + fit != oriented_set.end(); + ++fit) + { + const typename Tr::Cell_handle cell = fit->first; + const int& index = fit->second; + const int index1 = v2i[cell->vertex(tr.vertex_triple_index(index, 0))]; + const int index2 = v2i[cell->vertex(tr.vertex_triple_index(index, 1))]; + const int index3 = v2i[cell->vertex(tr.vertex_triple_index(index, 2))]; + // This order is flipped + F(f,0) = index1; + F(f,1) = index2; + F(f,2) = index3; + f++; + } + assert(f == m); + } // end if(facets must be oriented) + + // This CGAL code seems to randomly assign the global orientation + // Flip based on the signed volume. + Eigen::Vector3d cen; + double vol; + igl::centroid(V,F,cen,vol); + if(vol < 0) + { + // Flip + F = F.rowwise().reverse().eval(); + } + + // CGAL code somehow can end up with unreferenced vertices + { + VectorXi _1; + remove_unreferenced( MatrixXd(V), MatrixXi(F), V,F,_1); + } + + return success; +} + +#ifdef IGL_STATIC_LIBRARY +template bool igl::copyleft::cgal::complex_to_mesh, CGAL::Triangulation_data_structure_3, CGAL::Triangulation_vertex_base_3, CGAL::Triangulation_ds_vertex_base_3 > >, CGAL::Delaunay_triangulation_cell_base_with_circumcenter_3, CGAL::Surface_mesh_cell_base_3, CGAL::Triangulation_cell_base_3, CGAL::Triangulation_ds_cell_base_3 > > >, CGAL::Sequential_tag>, CGAL::Default, CGAL::Default>, Eigen::Matrix, Eigen::Matrix >(CGAL::Complex_2_in_triangulation_3, CGAL::Triangulation_data_structure_3, CGAL::Triangulation_vertex_base_3, CGAL::Triangulation_ds_vertex_base_3 > >, CGAL::Delaunay_triangulation_cell_base_with_circumcenter_3, CGAL::Surface_mesh_cell_base_3, CGAL::Triangulation_cell_base_3, CGAL::Triangulation_ds_cell_base_3 > > >, CGAL::Sequential_tag>, CGAL::Default, CGAL::Default>, void> const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/complex_to_mesh.h b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/complex_to_mesh.h new file mode 100644 index 000000000..ed66064b7 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/complex_to_mesh.h @@ -0,0 +1,47 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_COPYLEFT_CGAL_COMPLEX_TO_MESH_H +#define IGL_COPYLEFT_CGAL_COMPLEX_TO_MESH_H +#include "../../igl_inline.h" + +#include +#include + +namespace igl +{ + namespace copyleft + { + namespace cgal + { + // Templates: + // Tr CGAL triangulation type, e.g. + // CGAL::Surface_mesh_default_triangulation_3 + // Inputs + // c2t3 2-complex (surface) living in a 3d triangulation (e.g. result of + // CGAL::make_surface_mesh) + // Outputs: + // V #V by 3 list of vertex positions + // F #F by 3 list of triangle indices + // Returns true iff conversion was successful, failure can ok if CGAL code + // can't figure out ordering. + // + template + IGL_INLINE bool complex_to_mesh( + const CGAL::Complex_2_in_triangulation_3 & c2t3, + Eigen::PlainObjectBase & V, + Eigen::PlainObjectBase & F); + } + } +} + +#ifndef IGL_STATIC_LIBRARY +# include "complex_to_mesh.cpp" +#endif + +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/component_inside_component.cpp b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/component_inside_component.cpp new file mode 100644 index 000000000..251e91949 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/component_inside_component.cpp @@ -0,0 +1,83 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Qingnan Zhou +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "component_inside_component.h" + +#include "order_facets_around_edge.h" +#include "../../LinSpaced.h" +#include "points_inside_component.h" + +#include +#include +#include +#include + +#include +#include +#include +#include + +template +IGL_INLINE bool igl::copyleft::cgal::component_inside_component( + const Eigen::PlainObjectBase& V1, + const Eigen::PlainObjectBase& F1, + const Eigen::PlainObjectBase& I1, + const Eigen::PlainObjectBase& V2, + const Eigen::PlainObjectBase& F2, + const Eigen::PlainObjectBase& I2) { + if (F1.rows() <= 0 || I1.rows() <= 0 || F2.rows() <= 0 || I2.rows() <= 0) { + throw "Component inside test cannot be done on empty component!"; + } + + const Eigen::Vector3i& f = F1.row(I1(0, 0)); + const Eigen::Matrix query( + (V1(f[0],0) + V1(f[1],0) + V1(f[2],0))/3.0, + (V1(f[0],1) + V1(f[1],1) + V1(f[2],1))/3.0, + (V1(f[0],2) + V1(f[1],2) + V1(f[2],2))/3.0); + Eigen::VectorXi inside; + igl::copyleft::cgal::points_inside_component(V2, F2, I2, query, inside); + assert(inside.size() == 1); + return inside[0]; +} + +template +IGL_INLINE bool igl::copyleft::cgal::component_inside_component( + const Eigen::PlainObjectBase& V1, + const Eigen::PlainObjectBase& F1, + const Eigen::PlainObjectBase& V2, + const Eigen::PlainObjectBase& F2) { + if (F1.rows() <= 0 || F2.rows() <= 0) { + throw "Component inside test cannot be done on empty component!"; + } + Eigen::VectorXi I1(F1.rows()), I2(F2.rows()); + I1 = igl::LinSpaced(F1.rows(), 0, F1.rows()-1); + I2 = igl::LinSpaced(F2.rows(), 0, F2.rows()-1); + return igl::copyleft::cgal::component_inside_component(V1, F1, I1, V2, F2, I2); +} + + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +template bool igl::copyleft::cgal::component_inside_component< +Eigen::Matrix, +Eigen::Matrix< int, -1, -1, 0, -1, -1>, +Eigen::Matrix< int, -1, -1, 0, -1, -1> > ( +Eigen::PlainObjectBase > const&, +Eigen::PlainObjectBase > const&, +Eigen::PlainObjectBase > const&, +Eigen::PlainObjectBase > const&, +Eigen::PlainObjectBase > const&, +Eigen::PlainObjectBase > const&); + +template bool igl::copyleft::cgal::component_inside_component< +Eigen::Matrix, +Eigen::Matrix< int, -1, -1, 0, -1, -1> > ( +Eigen::PlainObjectBase > const&, +Eigen::PlainObjectBase > const&, +Eigen::PlainObjectBase > const&, +Eigen::PlainObjectBase > const&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/component_inside_component.h b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/component_inside_component.h new file mode 100644 index 000000000..17fdd6255 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/component_inside_component.h @@ -0,0 +1,75 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Qingnan Zhou +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_COPYLEFT_CGAL_COMONENT_INSIDE_COMPONENT +#define IGL_COPYLEFT_CGAL_COMONENT_INSIDE_COMPONENT + +#include "../../igl_inline.h" +#include +#include + +namespace igl { + namespace copyleft + { + namespace cgal { + + // Determine if connected facet component (V1, F1, I1) is inside of + // connected facet component (V2, F2, I2). + // + // Precondition: + // Both components must represent closed, self-intersection free, + // non-degenerated surfaces that are the boundary of 3D volumes. In + // addition, (V1, F1, I1) must not intersect with (V2, F2, I2). + // + // Inputs: + // V1 #V1 by 3 list of vertex position of mesh 1 + // F1 #F1 by 3 list of triangles indices into V1 + // I1 #I1 list of indices into F1, indicate the facets of component + // V2 #V2 by 3 list of vertex position of mesh 2 + // F2 #F2 by 3 list of triangles indices into V2 + // I2 #I2 list of indices into F2, indicate the facets of component + // + // Outputs: + // return true iff (V1, F1, I1) is entirely inside of (V2, F2, I2). + template + IGL_INLINE bool component_inside_component( + const Eigen::PlainObjectBase& V1, + const Eigen::PlainObjectBase& F1, + const Eigen::PlainObjectBase& I1, + const Eigen::PlainObjectBase& V2, + const Eigen::PlainObjectBase& F2, + const Eigen::PlainObjectBase& I2); + + // Determine if mesh (V1, F1) is inside of mesh (V2, F2). + // + // Precondition: + // Both meshes must be closed, self-intersection free, non-degenerated + // surfaces that are the boundary of 3D volumes. They should not + // intersect each other. + // + // Inputs: + // V1 #V1 by 3 list of vertex position of mesh 1 + // F1 #F1 by 3 list of triangles indices into V1 + // V2 #V2 by 3 list of vertex position of mesh 2 + // F2 #F2 by 3 list of triangles indices into V2 + // + // Outputs: + // return true iff (V1, F1) is entirely inside of (V2, F2). + template + IGL_INLINE bool component_inside_component( + const Eigen::PlainObjectBase& V1, + const Eigen::PlainObjectBase& F1, + const Eigen::PlainObjectBase& V2, + const Eigen::PlainObjectBase& F2); + } + } +} + +#ifndef IGL_STATIC_LIBRARY +#include "component_inside_component.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/convex_hull.cpp b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/convex_hull.cpp new file mode 100644 index 000000000..991b07dfc --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/convex_hull.cpp @@ -0,0 +1,104 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2017 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "convex_hull.h" +#include "../../ismember.h" +#include "polyhedron_to_mesh.h" +#include +#include +#include +#include +#include + +template < + typename DerivedV, + typename DerivedW, + typename DerivedG> +IGL_INLINE void igl::copyleft::cgal::convex_hull( + const Eigen::MatrixBase & V, + Eigen::PlainObjectBase & W, + Eigen::PlainObjectBase & G) +{ + typedef CGAL::Exact_predicates_inexact_constructions_kernel K; + switch(V.cols()) + { + case 3: + { + typedef K::Point_3 Point_3; + //typedef CGAL::Delaunay_triangulation_3 Delaunay; + //typedef Delaunay::Vertex_handle Vertex_handle; + //typedef CGAL::Surface_mesh Surface_mesh; + typedef CGAL::Polyhedron_3 Polyhedron_3; + std::vector points(V.rows()); + for(int i = 0;i points(V.rows()); + std::vector result; + for(int i = 0;i +IGL_INLINE void igl::copyleft::cgal::convex_hull( + const Eigen::MatrixBase & V, + Eigen::PlainObjectBase & F) +{ + Eigen::Matrix W; + Eigen::Matrix G; + convex_hull(V,W,G); + // This is a lazy way to reindex into the original mesh + Eigen::Matrix I; + Eigen::VectorXi J; + igl::ismember_rows(W,V,I,J); + assert(I.all() && "Should find all W in V"); + F.resizeLike(G); + for(int f = 0;f, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::copyleft::cgal::convex_hull, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::copyleft::cgal::convex_hull, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::copyleft::cgal::convex_hull, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/convex_hull.h b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/convex_hull.h new file mode 100644 index 000000000..ba04dd7cc --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/convex_hull.h @@ -0,0 +1,56 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2017 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_COPYLEFT_CGAL_CONVEX_HULL_H +#define IGL_COPYLEFT_CGAL_CONVEX_HULL_H +#include "../../igl_inline.h" +#include + +namespace igl +{ + namespace copyleft + { + namespace cgal + { + // Given a set of points (V), compute the convex hull as a triangle mesh (W,G) + // + // Inputs: + // V #V by 3 list of input points + // Outputs: + // W #W by 3 list of convex hull points + // G #G by 3 list of triangle indices into W + template < + typename DerivedV, + typename DerivedW, + typename DerivedG> + IGL_INLINE void convex_hull( + const Eigen::MatrixBase & V, + Eigen::PlainObjectBase & W, + Eigen::PlainObjectBase & G); + // Given a set of points (V), compute the convex hull as a triangle mesh (F) + // over input vertex set (V) + // + // Inputs: + // V #V by 3 list of input points + // Outputs: + // F #F by 3 list of triangle indices into V + // + template < + typename DerivedV, + typename DerivedF> + IGL_INLINE void convex_hull( + const Eigen::MatrixBase & V, + Eigen::PlainObjectBase & F); + } + } +} + +#ifndef IGL_STATIC_LIBRARY +# include "convex_hull.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/coplanar.cpp b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/coplanar.cpp new file mode 100644 index 000000000..912ec1b59 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/coplanar.cpp @@ -0,0 +1,49 @@ +#include "coplanar.h" +#include "row_to_point.h" +#include +#include + +template +IGL_INLINE bool igl::copyleft::cgal::coplanar( + const Eigen::MatrixBase & V) +{ + // 3 points in 3D are always coplanar + if(V.rows() < 4){ return true; } + // spanning points found so far + std::vector > p; + for(int i = 0;i pi(V(i,0), V(i,1), V(i,2)); + switch(p.size()) + { + case 0: + p.push_back(pi); + break; + case 1: + if(p[0] != pi) + { + p.push_back(pi); + } + break; + case 2: + if(!CGAL::collinear(p[0],p[1],pi)) + { + p.push_back(pi); + } + break; + case 3: + if(!CGAL::coplanar(p[0],p[1],p[2],pi)) + { + return false; + } + break; + } + } + return true; +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template bool igl::copyleft::cgal::coplanar >(Eigen::MatrixBase > const&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/coplanar.h b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/coplanar.h new file mode 100644 index 000000000..31e66d092 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/coplanar.h @@ -0,0 +1,26 @@ +#ifndef IGL_COPYLEFT_CGAL_COPLANAR_H +#define IGL_COPYLEFT_CGAL_COPLANAR_H +#include "../../igl_inline.h" +#include +namespace igl +{ + namespace copyleft + { + namespace cgal + { + // Test whether all points are on same plane. + // + // Inputs: + // V #V by 3 list of 3D vertex positions + // Returns true if all points lie on the same plane + template + IGL_INLINE bool coplanar( + const Eigen::MatrixBase & V); + } + } +} +#ifndef IGL_STATIC_LIBRARY +# include "coplanar.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/delaunay_triangulation.cpp b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/delaunay_triangulation.cpp new file mode 100644 index 000000000..73bfe8ecc --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/delaunay_triangulation.cpp @@ -0,0 +1,67 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2018 Alec Jacobson +// Copyright (C) 2016 Qingnan Zhou +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +#include "delaunay_triangulation.h" +#include "../../delaunay_triangulation.h" +#include "orient2D.h" +#include "incircle.h" + +template< + typename DerivedV, + typename DerivedF> +IGL_INLINE void igl::copyleft::cgal::delaunay_triangulation( + const Eigen::MatrixBase& V, + Eigen::PlainObjectBase& F) +{ + typedef typename DerivedV::Scalar Scalar; + igl::delaunay_triangulation(V, orient2D, incircle, F); + // This function really exists to test our igl::delaunay_triangulation + // + // It's currently much faster to call cgal's native Delaunay routine + // +//#include +//#include +//#include +//#include +// const auto delaunay = +// [&](const Eigen::MatrixXd & V,Eigen::MatrixXi & F) +// { +// typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel; +// typedef CGAL::Triangulation_vertex_base_with_info_2 Vb; +// typedef CGAL::Triangulation_data_structure_2 Tds; +// typedef CGAL::Delaunay_triangulation_2 Delaunay; +// typedef Kernel::Point_2 Point; +// std::vector< std::pair > points(V.rows()); +// for(int i = 0;ivertex(0)->info(); +// F(j,1) = face->vertex(1)->info(); +// F(j,2) = face->vertex(2)->info(); +// j++; +// } +// } +// }; +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::copyleft::cgal::delaunay_triangulation, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/delaunay_triangulation.h b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/delaunay_triangulation.h new file mode 100644 index 000000000..962c93312 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/delaunay_triangulation.h @@ -0,0 +1,47 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Qingan Zhou +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef IGL_COPYLEFT_CGAL_DELAUNAY_TRIANGULATION_H +#define IGL_COPYLEFT_CGAL_DELAUNAY_TRIANGULATION_H + +#include "../../igl_inline.h" +#include + +namespace igl +{ + namespace copyleft + { + namespace cgal + { + + // Given a set of points in 2D, return a Delaunay triangulation of these + // points. + // + // Inputs: + // V #V by 2 list of vertex positions + // + // Outputs: + // F #F by 3 of faces in Delaunay triangulation. + template< + typename DerivedV, + typename DerivedF + > + IGL_INLINE void delaunay_triangulation( + const Eigen::MatrixBase& V, + Eigen::PlainObjectBase& F); + } + } +} + + + + +#ifndef IGL_STATIC_LIBRARY +# include "delaunay_triangulation.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/extract_cells.cpp b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/extract_cells.cpp new file mode 100644 index 000000000..b11e8680b --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/extract_cells.cpp @@ -0,0 +1,548 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Qingnan Zhou +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +// +#include "extract_cells.h" +#include "closest_facet.h" +#include "order_facets_around_edge.h" +#include "outer_facet.h" +#include "submesh_aabb_tree.h" +#include "../../extract_manifold_patches.h" +#include "../../facet_components.h" +#include "../../get_seconds.h" +#include "../../triangle_triangle_adjacency.h" +#include "../../unique_edge_map.h" +#include "../../vertex_triangle_adjacency.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +//#define EXTRACT_CELLS_DEBUG + +template< + typename DerivedV, + typename DerivedF, + typename DerivedC > +IGL_INLINE size_t igl::copyleft::cgal::extract_cells( + const Eigen::PlainObjectBase& V, + const Eigen::PlainObjectBase& F, + Eigen::PlainObjectBase& cells) +{ + const size_t num_faces = F.rows(); + // Construct edge adjacency + Eigen::MatrixXi E, uE; + Eigen::VectorXi EMAP; + std::vector > uE2E; + igl::unique_edge_map(F, E, uE, EMAP, uE2E); + // Cluster into manifold patches + Eigen::VectorXi P; + igl::extract_manifold_patches(F, EMAP, uE2E, P); + // Extract cells + DerivedC per_patch_cells; + const size_t num_cells = + igl::copyleft::cgal::extract_cells(V,F,P,E,uE,uE2E,EMAP,per_patch_cells); + // Distribute per-patch cell information to each face + cells.resize(num_faces, 2); + for (size_t i=0; i +IGL_INLINE size_t igl::copyleft::cgal::extract_cells( + const Eigen::PlainObjectBase& V, + const Eigen::PlainObjectBase& F, + const Eigen::PlainObjectBase& P, + const Eigen::PlainObjectBase& E, + const Eigen::PlainObjectBase& uE, + const std::vector >& uE2E, + const Eigen::PlainObjectBase& EMAP, + Eigen::PlainObjectBase& cells) +{ + // Trivial base case + if(P.size() == 0) + { + assert(F.size() == 0); + cells.resize(0,2); + return 0; + } + + typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel; + typedef Kernel::Point_3 Point_3; + typedef Kernel::Plane_3 Plane_3; + typedef Kernel::Segment_3 Segment_3; + typedef Kernel::Triangle_3 Triangle; + typedef std::vector::iterator Iterator; + typedef CGAL::AABB_triangle_primitive Primitive; + typedef CGAL::AABB_traits AABB_triangle_traits; + typedef CGAL::AABB_tree Tree; + +#ifdef EXTRACT_CELLS_DEBUG + const auto & tictoc = []() -> double + { + static double t_start = igl::get_seconds(); + double diff = igl::get_seconds()-t_start; + t_start += diff; + return diff; + }; + const auto log_time = [&](const std::string& label) -> void { + std::cout << "extract_cells." << label << ": " + << tictoc() << std::endl; + }; + tictoc(); +#else + // no-op + const auto log_time = [](const std::string){}; +#endif + const size_t num_faces = F.rows(); + typedef typename DerivedF::Scalar Index; + assert(P.size() > 0); + const size_t num_patches = P.maxCoeff()+1; + + // Extract all cells... + DerivedC raw_cells; + const size_t num_raw_cells = + extract_cells_single_component(V,F,P,uE,uE2E,EMAP,raw_cells); + log_time("extract_single_component_cells"); + + // Compute triangle-triangle adjacency data-structure + std::vector > > TT,_1; + igl::triangle_triangle_adjacency(E, EMAP, uE2E, false, TT, _1); + log_time("compute_face_adjacency"); + + // Compute connected components of the mesh + Eigen::VectorXi C, counts; + igl::facet_components(TT, C, counts); + log_time("form_components"); + + const size_t num_components = counts.size(); + // components[c] --> list of face indices into F of faces in component c + std::vector > components(num_components); + // Loop over all faces + for (size_t i=0; i > VF,VFi; + igl::vertex_triangle_adjacency(V.rows(), F, VF, VFi); + std::vector Is(num_components); + std::vector< + CGAL::AABB_tree< + CGAL::AABB_traits< + Kernel, + CGAL::AABB_triangle_primitive< + Kernel, std::vector< + Kernel::Triangle_3 >::iterator > > > > trees(num_components); + std::vector< std::vector > + triangle_lists(num_components); + std::vector > in_Is(num_components); + + // Find outer facets, their orientations and cells for each component + Eigen::VectorXi outer_facets(num_components); + Eigen::VectorXi outer_facet_orientation(num_components); + Eigen::VectorXi outer_cells(num_components); + for (size_t i=0; i > nested_cells(num_raw_cells); + std::vector > ambient_cells(num_raw_cells); + std::vector > ambient_comps(num_components); + // Only bother if there's more than one component + if(num_components > 1) + { + // construct bounding boxes for each component + DerivedV bbox_min(num_components, 3); + DerivedV bbox_max(num_components, 3); + // Assuming our mesh (in exact numbers) fits in the range of double. + bbox_min.setConstant(std::numeric_limits::max()); + bbox_max.setConstant(std::numeric_limits::lowest()); + // Loop over faces + for (size_t i=0; i candidate_comps; + candidate_comps.reserve(num_components); + // Loop over components + for (size_t j=0; j component index inside component i, because the cell of the + // closest facet on i to component index is **not** the same as the + // "outer cell" of component i: component index is **not** outside of + // component i (therefore it's inside). + nested_cells[ambient_cell].push_back(outer_cells[index]); + ambient_cells[outer_cells[index]].push_back(ambient_cell); + ambient_comps[index].push_back(i); + } + } + } + } + +#ifdef EXTRACT_CELLS_DEBUG + log_time("nested_relationship"); +#endif + + const size_t INVALID = std::numeric_limits::max(); + const size_t INFINITE_CELL = num_raw_cells; + std::vector embedded_cells(num_raw_cells, INVALID); + for (size_t i=0; i 0) { + size_t embedded_comp = INVALID; + size_t embedded_cell = INVALID; + for (size_t j=0; j mapped_indices(num_raw_cells+1, INVALID); + // Always map infinite cell to index 0. + mapped_indices[INFINITE_CELL] = count; + count++; + + for (size_t i=0; i +IGL_INLINE size_t igl::copyleft::cgal::extract_cells_single_component( + const Eigen::PlainObjectBase& V, + const Eigen::PlainObjectBase& F, + const Eigen::PlainObjectBase& P, + const Eigen::PlainObjectBase& uE, + const std::vector >& uE2E, + const Eigen::PlainObjectBase& EMAP, + Eigen::PlainObjectBase& cells) +{ + const size_t num_faces = F.rows(); + // Input: + // index index into #F*3 list of undirect edges + // Returns index into face + const auto edge_index_to_face_index = [&num_faces](size_t index) + { + return index % num_faces; + }; + // Determine if a face (containing undirected edge {s,d} is consistently + // oriented with directed edge {s,d} (or otherwise it is with {d,s}) + // + // Inputs: + // fid face index into F + // s source index of edge + // d destination index of edge + // Returns true if face F(fid,:) is consistent with {s,d} + const auto is_consistent = + [&F](const size_t fid, const size_t s, const size_t d) -> bool + { + if ((size_t)F(fid, 0) == s && (size_t)F(fid, 1) == d) return false; + if ((size_t)F(fid, 1) == s && (size_t)F(fid, 2) == d) return false; + if ((size_t)F(fid, 2) == s && (size_t)F(fid, 0) == d) return false; + + if ((size_t)F(fid, 0) == d && (size_t)F(fid, 1) == s) return true; + if ((size_t)F(fid, 1) == d && (size_t)F(fid, 2) == s) return true; + if ((size_t)F(fid, 2) == d && (size_t)F(fid, 0) == s) return true; + throw "Invalid face!"; + return false; + }; + + const size_t num_unique_edges = uE.rows(); + const size_t num_patches = P.maxCoeff() + 1; + + // Build patch-patch adjacency list. + std::vector > patch_adj(num_patches); + for (size_t i=0; i 2) { + for (size_t j=0; j::max(); + std::vector cell_labels(num_patches * 2); + for (size_t i=0; i > equivalent_cells(num_patches*2); + std::vector processed(num_unique_edges, false); + + size_t label_count=0; + for (size_t i=0; i 2); + + const size_t s = uE(uei,0); + const size_t d = uE(uei,1); + + std::vector signed_adj_faces; + for (auto ej : adj_faces) + { + const size_t fid = edge_index_to_face_index(ej); + bool cons = is_consistent(fid, s, d); + signed_adj_faces.push_back((fid+1)*(cons ? 1:-1)); + } + { + // Sort adjacent faces cyclically around {s,d} + Eigen::VectorXi order; + // order[f] will reveal the order of face f in signed_adj_faces + order_facets_around_edge(V, F, s, d, signed_adj_faces, order); + for (size_t j=0; j 0; + const bool next_cons = signed_adj_faces[order[next_idx]] > 0; + const size_t curr_cell_idx = curr_patch_idx*2 + (curr_cons?0:1); + const size_t next_cell_idx = next_patch_idx*2 + (next_cons?1:0); + equivalent_cells[curr_cell_idx].insert(next_cell_idx); + equivalent_cells[next_cell_idx].insert(curr_cell_idx); + } + } + } + } + + size_t count=0; + cells.resize(num_patches, 2); + cells.setConstant(INVALID); + const auto extract_equivalent_cells = [&](size_t i) { + if (cells(i/2, i%2) != INVALID) return; + std::queue Q; + Q.push(i); + cells(i/2, i%2) = count; + while (!Q.empty()) { + const size_t index = Q.front(); + Q.pop(); + for (const auto j : equivalent_cells[index]) { + if (cells(j/2, j%2) == INVALID) { + cells(j/2, j%2) = count; + Q.push(j); + } + } + } + count++; + }; + for (size_t i=0; i, -1, -1, 1, -1, -1>, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, unsigned long, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, std::vector >, std::allocator > > > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template unsigned long igl::copyleft::cgal::extract_cells, -1, -1, 1, -1, -1>, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, unsigned long, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, std::vector >, std::allocator > > > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&); +#include +template unsigned long igl::copyleft::cgal::extract_cells, -1, -1, 0, -1, -1>, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, unsigned long, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, std::vector >, std::allocator > > > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&); +template unsigned long igl::copyleft::cgal::extract_cells, -1, -1, 0, -1, -1>, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&); +#ifdef WIN32 +template unsigned __int64 igl::copyleft::cgal::extract_cells, -1, -1, 0, -1, -1>, class Eigen::Matrix, class Eigen::Matrix, class Eigen::Matrix, class Eigen::Matrix, unsigned __int64, class Eigen::Matrix, class Eigen::Matrix>(class Eigen::PlainObjectBase, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase> const &, class Eigen::PlainObjectBase> const &, class Eigen::PlainObjectBase> const &, class Eigen::PlainObjectBase> const &, class std::vector>, class std::allocator>>> const &, class Eigen::PlainObjectBase> const &, class Eigen::PlainObjectBase> &); +template unsigned __int64 igl::copyleft::cgal::extract_cells, -1, -1, 1, -1, -1>, class Eigen::Matrix, class Eigen::Matrix, class Eigen::Matrix, class Eigen::Matrix, unsigned __int64, class Eigen::Matrix, class Eigen::Matrix>(class Eigen::PlainObjectBase, -1, -1, 1, -1, -1>> const &, class Eigen::PlainObjectBase> const &, class Eigen::PlainObjectBase> const &, class Eigen::PlainObjectBase> const &, class Eigen::PlainObjectBase> const &, class std::vector>, class std::allocator>>> const &, class Eigen::PlainObjectBase> const &, class Eigen::PlainObjectBase> &); +template unsigned __int64 igl::copyleft::cgal::extract_cells, -1, -1, 1, -1, -1>, class Eigen::Matrix, class Eigen::Matrix, class Eigen::Matrix, class Eigen::Matrix, unsigned __int64, class Eigen::Matrix, class Eigen::Matrix>(class Eigen::PlainObjectBase, -1, -1, 1, -1, -1>> const &, class Eigen::PlainObjectBase> const &, class Eigen::PlainObjectBase> const &, class Eigen::PlainObjectBase> const &, class Eigen::PlainObjectBase> const &, class std::vector>, class std::allocator>>> const &, class Eigen::PlainObjectBase> const &, class Eigen::PlainObjectBase> &); +template unsigned __int64 igl::copyleft::cgal::extract_cells,-1,-1,0,-1,-1>,class Eigen::Matrix,class Eigen::Matrix >(class Eigen::PlainObjectBase,-1,-1,0,-1,-1> > const &,class Eigen::PlainObjectBase > const &,class Eigen::PlainObjectBase > &); +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/extract_cells.h b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/extract_cells.h new file mode 100644 index 000000000..9575ffbae --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/extract_cells.h @@ -0,0 +1,116 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Qingnan Zhou +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +// +#ifndef IGL_COPYLEFT_CGAL_EXTRACT_CELLS +#define IGL_COPYLEFT_CGAL_EXTRACT_CELLS + +#include "../../igl_inline.h" +#include +#include + +namespace igl { + namespace copyleft + { + namespace cgal + { + // Extract connected 3D space partitioned by mesh (V, F). + // + // Inputs: + // V #V by 3 array of vertices. + // F #F by 3 array of faces. + // + // Output: + // cells #F by 2 array of cell indices. cells(i,0) represents the + // cell index on the positive side of face i, and cells(i,1) + // represents cell index of the negqtive side. + // By convension cell with index 0 is the infinite cell. + // Returns the number of cells + template< + typename DerivedV, + typename DerivedF, + typename DerivedC > + IGL_INLINE size_t extract_cells( + const Eigen::PlainObjectBase& V, + const Eigen::PlainObjectBase& F, + Eigen::PlainObjectBase& cells); + + // Extract connected 3D space partitioned by mesh (V, F). + // + // Inputs: + // V #V by 3 array of vertices. + // F #F by 3 array of faces. + // P #F list of patch indices. + // E #E by 2 array of vertex indices, one edge per row. + // uE #uE by 2 list of vertex_indices, represents undirected edges. + // uE2E #uE list of lists that maps uE to E. (a one-to-many map) + // EMAP #F*3 list of indices into uE. + // + // Output: + // cells #P by 2 array of cell indices. cells(i,0) represents the + // cell index on the positive side of patch i, and cells(i,1) + // represents cell index of the negqtive side. + // By convension cell with index 0 is the infinite cell. + template< + typename DerivedV, + typename DerivedF, + typename DerivedP, + typename DerivedE, + typename DeriveduE, + typename uE2EType, + typename DerivedEMAP, + typename DerivedC > + IGL_INLINE size_t extract_cells( + const Eigen::PlainObjectBase& V, + const Eigen::PlainObjectBase& F, + const Eigen::PlainObjectBase& P, + const Eigen::PlainObjectBase& E, + const Eigen::PlainObjectBase& uE, + const std::vector >& uE2E, + const Eigen::PlainObjectBase& EMAP, + Eigen::PlainObjectBase& cells); + + // Extract connected 3D space partitioned by mesh (V,F) composed of + // **possibly multiple components** (the name of this function is + // dubious). + // + // Inputs: + // V #V by 3 array of vertices. + // F #F by 3 array of faces. + // P #F list of patch indices. + // E #E by 2 array of vertex indices, one edge per row. + // uE #uE by 2 list of vertex_indices, represents undirected edges. + // uE2E #uE list of lists that maps uE to E. (a one-to-many map) + // EMAP #F*3 list of indices into uE. + // Output: + // cells #P by 2 array of cell indices. cells(i,0) represents the + // cell index on the positive side of patch i, and cells(i,1) + // represents cell index of the negative side. + template< + typename DerivedV, + typename DerivedF, + typename DerivedP, + typename DeriveduE, + typename uE2EType, + typename DerivedEMAP, + typename DerivedC > + IGL_INLINE size_t extract_cells_single_component( + const Eigen::PlainObjectBase& V, + const Eigen::PlainObjectBase& F, + const Eigen::PlainObjectBase& P, + const Eigen::PlainObjectBase& uE, + const std::vector >& uE2E, + const Eigen::PlainObjectBase& EMAP, + Eigen::PlainObjectBase& cells); + } + } +} + +#ifndef IGL_STATIC_LIBRARY +# include "extract_cells.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/extract_feature.cpp b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/extract_feature.cpp new file mode 100644 index 000000000..e81dc4ab0 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/extract_feature.cpp @@ -0,0 +1,124 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Qingnan Zhou +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +#include "extract_feature.h" +#include "../../unique_edge_map.h" +#include "../../PI.h" +#include +#include + +template< + typename DerivedV, + typename DerivedF, + typename DerivedE > +IGL_INLINE void igl::copyleft::cgal::extract_feature( + const Eigen::PlainObjectBase& V, + const Eigen::PlainObjectBase& F, + const double tol, + Eigen::PlainObjectBase& feature_edges) { + + using IndexType = typename DerivedE::Scalar; + DerivedE E, uE; + Eigen::VectorXi EMAP; + std::vector > uE2E; + igl::unique_edge_map(F, E, uE, EMAP, uE2E); + + igl::copyleft::cgal::extract_feature(V, F, tol, E, uE, uE2E, feature_edges); +} + +template< + typename DerivedV, + typename DerivedF, + typename DerivedE > +IGL_INLINE void igl::copyleft::cgal::extract_feature( + const Eigen::PlainObjectBase& V, + const Eigen::PlainObjectBase& F, + const double tol, + const Eigen::PlainObjectBase& E, + const Eigen::PlainObjectBase& uE, + const std::vector >& uE2E, + Eigen::PlainObjectBase& feature_edges) { + + assert(V.cols() == 3); + assert(F.cols() == 3); + using Scalar = typename DerivedV::Scalar; + using IndexType = typename DerivedE::Scalar; + using Vertex = Eigen::Matrix; + using Kernel = typename CGAL::Exact_predicates_exact_constructions_kernel; + using Point = typename Kernel::Point_3; + + const size_t num_unique_edges = uE.rows(); + const size_t num_faces = F.rows(); + // NOTE: CGAL's definition of dihedral angle measures the angle between two + // facets instead of facet normals. + const double cos_tol = cos(igl::PI - tol); + std::vector result; // Indices into uE + + auto is_non_manifold = [&uE2E](size_t ei) -> bool { + return uE2E[ei].size() > 2; + }; + + auto is_boundary = [&uE2E](size_t ei) -> bool { + return uE2E[ei].size() == 1; + }; + + auto opposite_vertex = [&uE, &F](size_t ei, size_t fi) -> IndexType { + const size_t v0 = uE(ei, 0); + const size_t v1 = uE(ei, 1); + for (size_t i=0; i<3; i++) { + const size_t v = F(fi, i); + if (v != v0 && v != v1) { return v; } + } + throw "Input face must be topologically degenerate!"; + }; + + auto is_feature = [&V, &F, &uE, &uE2E, &opposite_vertex, num_faces]( + size_t ei, double cos_tol) -> bool { + auto adj_faces = uE2E[ei]; + assert(adj_faces.size() == 2); + const Vertex v0 = V.row(uE(ei, 0)); + const Vertex v1 = V.row(uE(ei, 1)); + const Vertex v2 = V.row(opposite_vertex(ei, adj_faces[0] % num_faces)); + const Vertex v3 = V.row(opposite_vertex(ei, adj_faces[1] % num_faces)); + const Point p0(v0[0], v0[1], v0[2]); + const Point p1(v1[0], v1[1], v1[2]); + const Point p2(v2[0], v2[1], v2[2]); + const Point p3(v3[0], v3[1], v3[2]); + const auto ori = CGAL::orientation(p0, p1, p2, p3); + switch (ori) { + case CGAL::POSITIVE: + return CGAL::compare_dihedral_angle(p0, p1, p2, p3, cos_tol) == + CGAL::SMALLER; + case CGAL::NEGATIVE: + return CGAL::compare_dihedral_angle(p0, p1, p3, p2, cos_tol) == + CGAL::SMALLER; + case CGAL::COPLANAR: + if (!CGAL::collinear(p0, p1, p2) && !CGAL::collinear(p0, p1, p3)) { + return CGAL::compare_dihedral_angle(p0, p1, p2, p3, cos_tol) == + CGAL::SMALLER; + } else { + throw "Dihedral angle (and feature edge) is not well defined for" + " degenerate triangles!"; + } + default: + throw "Unknown CGAL orientation"; + } + }; + + for (size_t i=0; i +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef IGL_COPYLEFT_CGAL_EXTRACT_FEATURE_H +#define IGL_COPYLEFT_CGAL_EXTRACT_FEATURE_H +#include "../../igl_inline.h" +#include +#include + +namespace igl +{ + namespace copyleft + { + namespace cgal + { + // Extract feature edges based on dihedral angle. + // Here, dihedral angle is defined as the angle between surface + // __normals__ as described in + // http://mathworld.wolfram.com/DihedralAngle.html + // + // Non-manifold and boundary edges are automatically considered as + // features. + // + // Inputs: + // V #V by 3 array of vertices. + // F #F by 3 array of faces. + // tol Edges with dihedral angle larger than this are considered + // as features. Angle is measured in radian. + // + // Output: + // feature_edges: #E by 2 array of edges. Each edge satisfies at + // least one of the following criteria: + // + // * Edge has dihedral angle larger than tol. + // * Edge is boundary. + // * Edge is non-manifold (i.e. it has more than 2 adjacent + // faces). + template < + typename DerivedV, + typename DerivedF, + typename DerivedE> + IGL_INLINE void extract_feature( + const Eigen::PlainObjectBase& V, + const Eigen::PlainObjectBase& F, + const double tol, + Eigen::PlainObjectBase& feature_edges); + + // Inputs: + // V #V by 3 array of vertices. + // F #F by 3 array of faces. + // tol Edges with dihedral angle larger than this are considered + // as features. Angle is measured in radian. + // E #E by 2 array of directed edges. + // uE #uE by 2 array of undirected edges. + // uE2E #uE list of lists mapping undirected edges to all corresponding + // directed edges. + // + // Output: + // feature_edges: #E by 2 array of edges. Each edge satisfies at + // least one of the following criteria: + // + // * Edge has dihedral angle larger than tol. + // * Edge is boundary. + // * Edge is non-manifold (i.e. it has more than 2 adjacent + // faces). + template < + typename DerivedV, + typename DerivedF, + typename DerivedE> + IGL_INLINE void extract_feature( + const Eigen::PlainObjectBase& V, + const Eigen::PlainObjectBase& F, + const double tol, + const Eigen::PlainObjectBase& E, + const Eigen::PlainObjectBase& uE, + const std::vector >& uE2E, + Eigen::PlainObjectBase& feature_edges); + } + } +} + +#ifndef IGL_STATIC_LIBRARY +# include "extract_feature.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/fast_winding_number.cpp b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/fast_winding_number.cpp new file mode 100644 index 000000000..4a70cd140 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/fast_winding_number.cpp @@ -0,0 +1,65 @@ +#include "fast_winding_number.h" +#include "../../fast_winding_number.h" +#include "../../octree.h" +#include "../../knn.h" +#include "../../parallel_for.h" +#include "point_areas.h" +#include + +template < + typename DerivedP, + typename DerivedN, + typename DerivedQ, + typename BetaType, + typename DerivedWN> +IGL_INLINE void igl::copyleft::cgal::fast_winding_number( + const Eigen::MatrixBase& P, + const Eigen::MatrixBase& N, + const Eigen::MatrixBase& Q, + const int expansion_order, + const BetaType beta, + Eigen::PlainObjectBase& WN) +{ + typedef typename DerivedWN::Scalar real; + typedef typename Eigen::Matrix + RealMatrix; + + std::vector > point_indices; + Eigen::Matrix CH; + Eigen::Matrix CN; + Eigen::Matrix W; + Eigen::MatrixXi I; + Eigen::Matrix A; + + octree(P,point_indices,CH,CN,W); + knn(P,21,point_indices,CH,CN,W,I); + point_areas(P,I,N,A); + + Eigen::Matrix EC; + Eigen::Matrix CM; + Eigen::Matrix R; + + igl::fast_winding_number( + P,N,A,point_indices,CH,expansion_order,CM,R,EC); + igl::fast_winding_number( + P,N,A,point_indices,CH,CM,R,EC,Q,beta,WN); +} + +template < + typename DerivedP, + typename DerivedN, + typename DerivedQ, + typename DerivedWN> +IGL_INLINE void igl::copyleft::cgal::fast_winding_number( + const Eigen::MatrixBase& P, + const Eigen::MatrixBase& N, + const Eigen::MatrixBase& Q, + Eigen::PlainObjectBase& WN) +{ + fast_winding_number(P,N,Q,2,2.0,WN); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +template void igl::copyleft::cgal::fast_winding_number, Eigen::Matrix, Eigen::Matrix, double, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, int, double, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/fast_winding_number.h b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/fast_winding_number.h new file mode 100644 index 000000000..509eafb02 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/fast_winding_number.h @@ -0,0 +1,79 @@ +#ifndef IGL_COPYLEFT_CGAL_FAST_WINDING_NUMBER +#define IGL_COPYLEFT_CGAL_FAST_WINDING_NUMBER +#include "../../igl_inline.h" +#include +#include +namespace igl +{ + namespace copyleft + { + namespace cgal + { + // Evaluate the fast winding number for point data, without known areas. The + // areas are calculated using igl::knn and igl::copyleft::cgal::point_areas. + // + // This function performes the precomputation and evaluation all in one. + // If you need to acess the precomuptation for repeated evaluations, use the + // two functions designed for exposed precomputation, which are the first two + // functions see in igl/fast_winding_number.h + // + // Inputs: + // P #P by 3 list of point locations + // N #P by 3 list of point normals + // Q #Q by 3 list of query points for the winding number + // beta This is a Barnes-Hut style accuracy term that separates near feild + // from far field. The higher the beta, the more accurate and slower + // the evaluation. We reccommend using a beta value of 2. + // expansion_order the order of the taylor expansion. We support 0,1,2. + // Outputs: + // WN #Q by 1 list of windinng number values at each query point + // + template < + typename DerivedP, + typename DerivedN, + typename DerivedQ, + typename BetaType, + typename DerivedWN> + IGL_INLINE void fast_winding_number( + const Eigen::MatrixBase& P, + const Eigen::MatrixBase& N, + const Eigen::MatrixBase& Q, + const int expansion_order, + const BetaType beta, + Eigen::PlainObjectBase& WN); + + // Evaluate the fast winding number for point data, without known areas. The + // areas are calculated using igl::knn and + // igl::point_areas. This function uses the default expansion + // order and beta (both are set to 2). + // + // This function performes the precomputation and evaluation all in one. + // If you need to acess the precomuptation for repeated evaluations, use the + // two functions designed for exposed precomputation (described above). + + // Inputs: + // P #P by 3 list of point locations + // N #P by 3 list of point normals + // Q #Q by 3 list of query points for the winding number + // Outputs: + // WN #Q by 1 list of windinng number values at each query point + // + template < + typename DerivedP, + typename DerivedN, + typename DerivedQ, + typename DerivedWN> + IGL_INLINE void fast_winding_number( + const Eigen::MatrixBase& P, + const Eigen::MatrixBase& N, + const Eigen::MatrixBase& Q, + Eigen::PlainObjectBase& WN); + } + } +} +#ifndef IGL_STATIC_LIBRARY +# include "fast_winding_number.cpp" +#endif + +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/half_space_box.cpp b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/half_space_box.cpp new file mode 100644 index 000000000..1bfa8ea52 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/half_space_box.cpp @@ -0,0 +1,123 @@ +#include "half_space_box.h" +#include "assign_scalar.h" +#include +#include + +template +IGL_INLINE void igl::copyleft::cgal::half_space_box( + const CGAL::Plane_3 & P, + const Eigen::MatrixBase & V, + Eigen::Matrix & BV, + Eigen::Matrix & BF) +{ + typedef CGAL::Plane_3 Plane; + typedef CGAL::Point_3 Point; + typedef CGAL::Vector_3 Vector; + typedef CGAL::Epeck::FT EScalar; + Eigen::Matrix avg(0,0,0); + for(int v = 0;v vBV;vBV.reserve(8); + Vector v = CGAL::cross_product(u,n); + // Scale u,v,n to be longer than bbd + const auto & longer_than = [](const EScalar min_sqr, Vector & x) + { + assert(x.squared_length() > 0); + while(x.squared_length() < min_sqr) + { + x = 2.*x; + } + }; + longer_than(bbd*bbd,u); + longer_than(bbd*bbd,v); + longer_than(bbd*bbd,n); + vBV.emplace_back( o2 + u + v); + vBV.emplace_back( o2 - u + v); + vBV.emplace_back( o2 - u - v); + vBV.emplace_back( o2 + u - v); + vBV.emplace_back( o2 + u + v - n); + vBV.emplace_back( o2 - u + v - n); + vBV.emplace_back( o2 - u - v - n); + vBV.emplace_back( o2 + u - v - n); + BV.resize(8,3); + for(int b = 0;b<8;b++) + { + igl::copyleft::cgal::assign_scalar(vBV[b].x(),BV(b,0)); + igl::copyleft::cgal::assign_scalar(vBV[b].y(),BV(b,1)); + igl::copyleft::cgal::assign_scalar(vBV[b].z(),BV(b,2)); + } + BF.resize(12,3); + BF<< + 1,0,2, + 2,0,3, + 4,5,6, + 4,6,7, + 0,1,4, + 4,1,5, + 1,2,5, + 5,2,6, + 2,3,6, + 6,3,7, + 3,0,7, + 7,0,4; +} + +template +IGL_INLINE void igl::copyleft::cgal::half_space_box( + const Eigen::MatrixBase & p, + const Eigen::MatrixBase & n, + const Eigen::MatrixBase & V, + Eigen::Matrix & BV, + Eigen::Matrix & BF) +{ + typedef CGAL::Plane_3 Plane; + typedef CGAL::Point_3 Point; + typedef CGAL::Vector_3 Vector; + Plane P(Point(p(0),p(1),p(2)),Vector(n(0),n(1),n(2))); + return half_space_box(P,V,BV,BF); +} + +template +IGL_INLINE void igl::copyleft::cgal::half_space_box( + const Eigen::MatrixBase & equ, + const Eigen::MatrixBase & V, + Eigen::Matrix & BV, + Eigen::Matrix & BF) +{ + typedef CGAL::Plane_3 Plane; + Plane P(equ(0),equ(1),equ(2),equ(3)); + return half_space_box(P,V,BV,BF); +} +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::copyleft::cgal::half_space_box >(CGAL::Plane_3 const&, Eigen::MatrixBase > const&, Eigen::Matrix, 8, 3, 0, 8, 3>&, Eigen::Matrix&); +// generated by autoexplicit.sh +template void igl::copyleft::cgal::half_space_box >(CGAL::Plane_3 const&, Eigen::MatrixBase > const&, Eigen::Matrix, 8, 3, 0, 8, 3>&, Eigen::Matrix&); +template void igl::copyleft::cgal::half_space_box, 1, 4, 1, 1, 4>, Eigen::Matrix, -1, 3, 0, -1, 3> >(Eigen::MatrixBase, 1, 4, 1, 1, 4> > const&, Eigen::MatrixBase, -1, 3, 0, -1, 3> > const&, Eigen::Matrix, 8, 3, 0, 8, 3>&, Eigen::Matrix&); +template void igl::copyleft::cgal::half_space_box, 1, 4, 1, 1, 4>, Eigen::Matrix, -1, 4, 0, -1, 4> >(Eigen::MatrixBase, 1, 4, 1, 1, 4> > const&, Eigen::MatrixBase, -1, 4, 0, -1, 4> > const&, Eigen::Matrix, 8, 3, 0, 8, 3>&, Eigen::Matrix&); +template void igl::copyleft::cgal::half_space_box, 1, 4, 1, 1, 4>, Eigen::Matrix >(Eigen::MatrixBase, 1, 4, 1, 1, 4> > const&, Eigen::MatrixBase > const&, Eigen::Matrix, 8, 3, 0, 8, 3>&, Eigen::Matrix&); +template void igl::copyleft::cgal::half_space_box, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::Matrix, 8, 3, 0, 8, 3>&, Eigen::Matrix&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/half_space_box.h b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/half_space_box.h new file mode 100644 index 000000000..275502235 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/half_space_box.h @@ -0,0 +1,63 @@ +#ifndef IGL_COPYLEFT_CGAL_HALF_SPACE_BOX_H +#define IGL_COPYLEFT_CGAL_HALF_SPACE_BOX_H +#include "../../igl_inline.h" +#include +#include +#include + +namespace igl +{ + namespace copyleft + { + namespace cgal + { + // Construct a mesh of box (BV,BF) so that it contains the intersection of + // the half-space under the plane (P) and the bounding box of V, and does not + // contain any of the half-space above (P). + // + // Inputs: + // P plane so that normal points away from half-space + // V #V by 3 list of vertex positions + // Outputs: + // BV #BV by 3 list of box vertex positions + // BF #BF b3 list of box triangle indices into BV + template + IGL_INLINE void half_space_box( + const CGAL::Plane_3 & P, + const Eigen::MatrixBase & V, + Eigen::Matrix & BV, + Eigen::Matrix & BF); + // Inputs: + // p 3d point on plane + // n 3d vector of normal of plane pointing away from inside + // V #V by 3 list of vertex positions + // Outputs: + // BV #BV by 3 list of box vertex positions + // BF #BF b3 list of box triangle indices into BV + template + IGL_INLINE void half_space_box( + const Eigen::MatrixBase & p, + const Eigen::MatrixBase & n, + const Eigen::MatrixBase & V, + Eigen::Matrix & BV, + Eigen::Matrix & BF); + // Inputs: + // equ plane equation: a*x+b*y+c*z + d = 0 + // V #V by 3 list of vertex positions + // Outputs: + // BV #BV by 3 list of box vertex positions + // BF #BF b3 list of box triangle indices into BV + template + IGL_INLINE void half_space_box( + const Eigen::MatrixBase & equ, + const Eigen::MatrixBase & V, + Eigen::Matrix & BV, + Eigen::Matrix & BF); + } + } +} + +#ifndef IGL_STATIC_LIBRARY +# include "half_space_box.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/hausdorff.cpp b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/hausdorff.cpp new file mode 100644 index 000000000..270af2005 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/hausdorff.cpp @@ -0,0 +1,44 @@ +#include "hausdorff.h" +#include "../../hausdorff.h" +#include + +template < + typename DerivedV, + typename Kernel, + typename Scalar> +IGL_INLINE void igl::copyleft::cgal::hausdorff( + const Eigen::MatrixBase& V, + const CGAL::AABB_tree< + CGAL::AABB_traits >::iterator + > + > + > & treeB, + const std::vector > & /*TB*/, + Scalar & l, + Scalar & u) +{ + // Not sure why using `auto` here doesn't work with the `hausdorff` function + // parameter but explicitly naming the type does... + const std::function + dist_to_B = [&treeB]( + const double & x, const double & y, const double & z)->double + { + CGAL::Point_3 query(x,y,z); + typename CGAL::AABB_tree< + CGAL::AABB_traits >::iterator + > + > + >::Point_and_primitive_id pp = treeB.closest_point_and_primitive(query); + return std::sqrt((query-pp.first).squared_length()); + }; + return igl::hausdorff(V,dist_to_B,l,u); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +template void igl::copyleft::cgal::hausdorff, CGAL::Simple_cartesian, double>(Eigen::MatrixBase > const&, CGAL::AABB_tree, CGAL::AABB_triangle_primitive, std::vector >, std::allocator > > >::iterator, CGAL::Boolean_tag >, CGAL::Default> > const&, std::vector >, std::allocator > > > const&, double&, double&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/hausdorff.h b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/hausdorff.h new file mode 100644 index 000000000..c377d4576 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/hausdorff.h @@ -0,0 +1,62 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_COPYLEFT_CGAL_HAUSDORFF_H +#define IGL_COPYLEFT_CGAL_HAUSDORFF_H +#include "../../igl_inline.h" + +#include +#include "CGAL_includes.hpp" +#include + +namespace igl +{ + namespace copyleft + { + namespace cgal + { + // Compute lower and upper bounds (l,u) on the Hausdorff distance between a triangle + // (V) and a pointset (e.g., mesh, triangle soup) given by a distance function + // handle (dist_to_B). + // + // Inputs: + // V 3 by 3 list of corner positions so that V.row(i) is the position of the + // ith corner + // treeB CGAL's AABB tree containing triangle soup (VB,FB) + // TB list of CGAL triangles in order of FB (for determining which was found + // in computation) + // Outputs: + // l lower bound on Hausdorff distance + // u upper bound on Hausdorff distance + // + template < + typename DerivedV, + typename Kernel, + typename Scalar> + IGL_INLINE void hausdorff( + const Eigen::MatrixBase& V, + const CGAL::AABB_tree< + CGAL::AABB_traits >::iterator + > + > + > & treeB, + const std::vector > & TB, + Scalar & l, + Scalar & u); + } + } +} + +#ifndef IGL_STATIC_LIBRARY +# include "hausdorff.cpp" +#endif + +#endif + + diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/incircle.cpp b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/incircle.cpp new file mode 100644 index 000000000..a0a5573b9 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/incircle.cpp @@ -0,0 +1,48 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Qingan Zhou +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +#include "incircle.h" +#include +#include + +template +IGL_INLINE short igl::copyleft::cgal::incircle( + const Scalar *pa, + const Scalar *pb, + const Scalar *pc, + const Scalar *pd) +{ + typedef CGAL::Exact_predicates_exact_constructions_kernel Epeck; + typedef CGAL::Exact_predicates_inexact_constructions_kernel Epick; + typedef typename std::conditional::value, + Epeck, Epick>::type Kernel; + + switch(CGAL::side_of_oriented_circle( + typename Kernel::Point_2(pa[0], pa[1]), + typename Kernel::Point_2(pb[0], pb[1]), + typename Kernel::Point_2(pc[0], pc[1]), + typename Kernel::Point_2(pd[0], pd[1]))) { + case CGAL::ON_POSITIVE_SIDE: + return 1; + case CGAL::ON_NEGATIVE_SIDE: + return -1; + case CGAL::ON_ORIENTED_BOUNDARY: + return 0; + default: + throw "Invalid incircle result"; + } +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template short igl::copyleft::cgal::incircle(double const*, double const*, double const*, double const*); +#ifdef WIN32 +template short igl::copyleft::cgal::incircle(double const * const,double const * const,double const * const,double const * const); +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/incircle.h b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/incircle.h new file mode 100644 index 000000000..3ee0fbcc9 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/incircle.h @@ -0,0 +1,39 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Qingan Zhou +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef IGL_COPYLEFT_CGAL_INCIRCLE_H +#define IGL_COPYLEFT_CGAL_INCIRCLE_H + +#include "../../igl_inline.h" + +namespace igl +{ + namespace copyleft + { + namespace cgal + { + // Inputs: + // pa,pb,pc,pd 2D points. + // Output: + // 1 if pd is inside of the oriented circle formed by pa,pb,pc. + // 0 if pd is co-circular with pa,pb,pc. + // -1 if pd is outside of the oriented circle formed by pa,pb,pc. + template + IGL_INLINE short incircle( + const Scalar *pa, + const Scalar *pb, + const Scalar *pc, + const Scalar *pd); + } + } +} + +#ifndef IGL_STATIC_LIBRARY +# include "incircle.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/insert_into_cdt.cpp b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/insert_into_cdt.cpp new file mode 100644 index 000000000..2ea4e6de1 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/insert_into_cdt.cpp @@ -0,0 +1,68 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "insert_into_cdt.h" +#include +#include +#include + +template +IGL_INLINE void igl::copyleft::cgal::insert_into_cdt( + const CGAL::Object & obj, + const CGAL::Plane_3 & P, + CGAL::Constrained_triangulation_plus_2< + CGAL::Constrained_Delaunay_triangulation_2< + Kernel, + CGAL::Triangulation_data_structure_2< + CGAL::Triangulation_vertex_base_2, + CGAL::Constrained_triangulation_face_base_2< Kernel> + >, + CGAL::Exact_intersections_tag + > + > + & cdt) +{ + typedef CGAL::Point_3 Point_3; + typedef CGAL::Segment_3 Segment_3; + typedef CGAL::Triangle_3 Triangle_3; + + if(const Segment_3 *iseg = CGAL::object_cast(&obj)) + { + // Add segment constraint + cdt.insert_constraint( P.to_2d(iseg->vertex(0)),P.to_2d(iseg->vertex(1))); + }else if(const Point_3 *ipoint = CGAL::object_cast(&obj)) + { + // Add point + cdt.insert(P.to_2d(*ipoint)); + } else if(const Triangle_3 *itri = CGAL::object_cast(&obj)) + { + // Add 3 segment constraints + cdt.insert_constraint( P.to_2d(itri->vertex(0)),P.to_2d(itri->vertex(1))); + cdt.insert_constraint( P.to_2d(itri->vertex(1)),P.to_2d(itri->vertex(2))); + cdt.insert_constraint( P.to_2d(itri->vertex(2)),P.to_2d(itri->vertex(0))); + } else if(const std::vector *polyp = + CGAL::object_cast< std::vector >(&obj)) + { + const std::vector & poly = *polyp; + const size_t m = poly.size(); + assert(m>=2); + for(size_t p = 0;p +template void igl::copyleft::cgal::insert_into_cdt(CGAL::Object const&, CGAL::Plane_3 const&, CGAL::Constrained_triangulation_plus_2 >, CGAL::Constrained_triangulation_face_base_2 > > >, CGAL::Exact_intersections_tag> >&); +template void igl::copyleft::cgal::insert_into_cdt(CGAL::Object const&, CGAL::Plane_3 const&, CGAL::Constrained_triangulation_plus_2 >, CGAL::Constrained_triangulation_face_base_2 > > >, CGAL::Exact_intersections_tag> >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/insert_into_cdt.h b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/insert_into_cdt.h new file mode 100644 index 000000000..afca0233f --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/insert_into_cdt.h @@ -0,0 +1,60 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_COPYLEFT_CGAL_INSERT_INTO_CDT_H +#define IGL_COPYLEFT_CGAL_INSERT_INTO_CDT_H +#include "../../igl_inline.h" + +#include // Workaround https://github.com/CGAL/cgal/issues/2182 with CGAL 4.10-1 +#include +#include +#include + +namespace igl +{ + namespace copyleft + { + namespace cgal + { + // Given a current 2D constrained Delaunay triangulation (cdt), insert a + // 3D "object" (e.g., resulting from intersecting two triangles) into the + // cdt, by projecting it via the given plane (P) and adding appropriate + // constraints. + // + // Inputs: + // obj CGAL::Object representing a vertex, segment, or (convex) + // polygon. All vertices should lie on the plane P. If not, then this + // adds the _projection_ of this object to the cdt and that might not + // be what you wanted to do. + // P plane obj lies on and upon which the cdt is being performed + // cdt current CDT, see output + // Outputs: + // cdt CDT updated to contain constraints for the given object + // + template + IGL_INLINE void insert_into_cdt( + const CGAL::Object & obj, + const CGAL::Plane_3 & P, + CGAL::Constrained_triangulation_plus_2< + CGAL::Constrained_Delaunay_triangulation_2< + Kernel, + CGAL::Triangulation_data_structure_2< + CGAL::Triangulation_vertex_base_2, + CGAL::Constrained_triangulation_face_base_2< Kernel> + >, + CGAL::Exact_intersections_tag + > + > + & cdt); + } + } +} + +#ifndef IGL_STATIC_LIBRARY +# include "insert_into_cdt.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/insphere.cpp b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/insphere.cpp new file mode 100644 index 000000000..db12fea33 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/insphere.cpp @@ -0,0 +1,41 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Qingan Zhou +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +#include "insphere.h" +#include +#include + +template +IGL_INLINE short igl::copyleft::cgal::insphere( + const Scalar pa[3], + const Scalar pb[3], + const Scalar pc[3], + const Scalar pd[3], + const Scalar pe[3]) +{ + typedef CGAL::Exact_predicates_exact_constructions_kernel Epeck; + typedef CGAL::Exact_predicates_inexact_constructions_kernel Epick; + typedef typename std::conditional::value, + Epeck, Epick>::type Kernel; + + switch(CGAL::side_of_oriented_sphere( + typename Kernel::Point_3(pa[0], pa[1], pa[2]), + typename Kernel::Point_3(pb[0], pb[1], pb[2]), + typename Kernel::Point_3(pc[0], pc[1], pc[2]), + typename Kernel::Point_3(pd[0], pd[1], pd[2]), + typename Kernel::Point_3(pe[0], pe[1], pe[2]))) { + case CGAL::ON_POSITIVE_SIDE: + return 1; + case CGAL::ON_NEGATIVE_SIDE: + return -1; + case CGAL::ON_ORIENTED_BOUNDARY: + return 0; + default: + throw "Invalid incircle result"; + } +} diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/insphere.h b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/insphere.h new file mode 100644 index 000000000..88a926668 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/insphere.h @@ -0,0 +1,40 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Qingan Zhou +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef IGL_COPYLEFT_CGAL_INSPHERE_H +#define IGL_COPYLEFT_CGAL_INSPHERE_H + +#include "../../igl_inline.h" + +namespace igl +{ + namespace copyleft + { + namespace cgal + { + // Inputs: + // pa,pb,pc,pd,pe 3D points. + // Output: + // 1 if pe is inside of the oriented sphere formed by pa,pb,pc,pd. + // 0 if pe is co-spherical with pa,pb,pc,pd. + // -1 if pe is outside of the oriented sphere formed by pa,pb,pc,pd. + template + IGL_INLINE short insphere( + const Scalar pa[3], + const Scalar pb[3], + const Scalar pc[3], + const Scalar pd[3], + const Scalar pe[3]); + } + } +} + +#ifndef IGL_STATIC_LIBRARY +# include "insphere.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/intersect_other.cpp b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/intersect_other.cpp new file mode 100644 index 000000000..9f984f956 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/intersect_other.cpp @@ -0,0 +1,289 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "intersect_other.h" +#include "CGAL_includes.hpp" +#include "mesh_to_cgal_triangle_list.h" +#include "remesh_intersections.h" +#include "../../slice_mask.h" +#include "../../remove_unreferenced.h" + +#ifndef IGL_FIRST_HIT_EXCEPTION +#define IGL_FIRST_HIT_EXCEPTION 10 +#endif + +// Un-exposed helper functions +namespace igl +{ + namespace copyleft + { + namespace cgal + { + template + static IGL_INLINE void push_result( + const Eigen::PlainObjectBase & F, + const int f, + const int f_other, + const CGAL::Object & result, + std::map< + typename DerivedF::Index, + std::vector > > & + offending) + //std::map< + // std::pair, + // std::vector > & edge2faces) + { + typedef typename DerivedF::Index Index; + typedef std::pair EMK; + if(offending.count(f) == 0) + { + // first time marking, initialize with new id and empty list + offending[f] = {}; + for(Index e = 0; e<3;e++) + { + // append face to edge's list + Index i = F(f,(e+1)%3) < F(f,(e+2)%3) ? F(f,(e+1)%3) : F(f,(e+2)%3); + Index j = F(f,(e+1)%3) < F(f,(e+2)%3) ? F(f,(e+2)%3) : F(f,(e+1)%3); + //edge2faces[EMK(i,j)].push_back(f); + } + } + offending[f].push_back({f_other,result}); + } + template < + typename Kernel, + typename DerivedVA, + typename DerivedFA, + typename DerivedVB, + typename DerivedFB, + typename DerivedIF, + typename DerivedVVAB, + typename DerivedFFAB, + typename DerivedJAB, + typename DerivedIMAB> + static IGL_INLINE bool intersect_other_helper( + const Eigen::PlainObjectBase & VA, + const Eigen::PlainObjectBase & FA, + const Eigen::PlainObjectBase & VB, + const Eigen::PlainObjectBase & FB, + const RemeshSelfIntersectionsParam & params, + Eigen::PlainObjectBase & IF, + Eigen::PlainObjectBase & VVAB, + Eigen::PlainObjectBase & FFAB, + Eigen::PlainObjectBase & JAB, + Eigen::PlainObjectBase & IMAB) + { + + using namespace std; + using namespace Eigen; + + typedef typename DerivedFA::Index Index; + // 3D Primitives + typedef CGAL::Point_3 Point_3; + typedef CGAL::Segment_3 Segment_3; + typedef CGAL::Triangle_3 Triangle_3; + typedef CGAL::Plane_3 Plane_3; + typedef CGAL::Tetrahedron_3 Tetrahedron_3; + // 2D Primitives + typedef CGAL::Point_2 Point_2; + typedef CGAL::Segment_2 Segment_2; + typedef CGAL::Triangle_2 Triangle_2; + // 2D Constrained Delaunay Triangulation types + typedef CGAL::Triangulation_vertex_base_2 TVB_2; + typedef CGAL::Constrained_triangulation_face_base_2 CTAB_2; + typedef CGAL::Triangulation_data_structure_2 TDS_2; + typedef CGAL::Exact_intersections_tag Itag; + // Axis-align boxes for all-pairs self-intersection detection + typedef std::vector Triangles; + typedef typename Triangles::iterator TrianglesIterator; + typedef typename Triangles::const_iterator TrianglesConstIterator; + typedef + CGAL::Box_intersection_d::Box_with_handle_d + Box; + typedef + std::map > > + OffendingMap; + typedef std::map,std::vector > EdgeMap; + typedef std::pair EMK; + + Triangles TA,TB; + // Compute and process self intersections + mesh_to_cgal_triangle_list(VA,FA,TA); + mesh_to_cgal_triangle_list(VB,FB,TB); + // http://www.cgal.org/Manual/latest/doc_html/cgal_manual/Box_intersection_d/Chapter_main.html#Section_63.5 + // Create the corresponding vector of bounding boxes + std::vector A_boxes,B_boxes; + const auto box_up = [](Triangles & T, std::vector & boxes) -> void + { + boxes.reserve(T.size()); + for ( + TrianglesIterator tit = T.begin(); + tit != T.end(); + ++tit) + { + boxes.push_back(Box(tit->bbox(), tit)); + } + }; + box_up(TA,A_boxes); + box_up(TB,B_boxes); + OffendingMap offendingA,offendingB; + //EdgeMap edge2facesA,edge2facesB; + + std::list lIF; + const auto cb = [&](const Box &a, const Box &b) -> void + { + using namespace std; + // index in F and T + int fa = a.handle()-TA.begin(); + int fb = b.handle()-TB.begin(); + const Triangle_3 & A = *a.handle(); + const Triangle_3 & B = *b.handle(); + if(CGAL::do_intersect(A,B)) + { + // There was an intersection + lIF.push_back(fa); + lIF.push_back(fb); + if(params.first_only) + { + throw IGL_FIRST_HIT_EXCEPTION; + } + if(!params.detect_only) + { + CGAL::Object result = CGAL::intersection(A,B); + + push_result(FA,fa,fb,result,offendingA); + push_result(FB,fb,fa,result,offendingB); + } + } + }; + try{ + CGAL::box_intersection_d( + A_boxes.begin(), A_boxes.end(), + B_boxes.begin(), B_boxes.end(), + cb); + }catch(int e) + { + // Rethrow if not FIRST_HIT_EXCEPTION + if(e != IGL_FIRST_HIT_EXCEPTION) + { + throw e; + } + // Otherwise just fall through + } + + // Convert lIF to Eigen matrix + assert(lIF.size()%2 == 0); + IF.resize(lIF.size()/2,2); + { + int i=0; + for( + list::const_iterator ifit = lIF.begin(); + ifit!=lIF.end(); + ) + { + IF(i,0) = (*ifit); + ifit++; + IF(i,1) = (*ifit); + ifit++; + i++; + } + } + if(!params.detect_only) + { + // Obsolete, now remesh_intersections expects a single mesh + // remesh_intersections(VA,FA,TA,offendingA,VVA,FFA,JA,IMA); + // remesh_intersections(VB,FB,TB,offendingB,VVB,FFB,JB,IMB); + // Combine mesh and offending maps + DerivedVA VAB(VA.rows()+VB.rows(),3); + VAB< 0; + } + } + } +} + +template < + typename DerivedVA, + typename DerivedFA, + typename DerivedVB, + typename DerivedFB, + typename DerivedIF, + typename DerivedVVAB, + typename DerivedFFAB, + typename DerivedJAB, + typename DerivedIMAB> +IGL_INLINE bool igl::copyleft::cgal::intersect_other( + const Eigen::PlainObjectBase & VA, + const Eigen::PlainObjectBase & FA, + const Eigen::PlainObjectBase & VB, + const Eigen::PlainObjectBase & FB, + const RemeshSelfIntersectionsParam & params, + Eigen::PlainObjectBase & IF, + Eigen::PlainObjectBase & VVAB, + Eigen::PlainObjectBase & FFAB, + Eigen::PlainObjectBase & JAB, + Eigen::PlainObjectBase & IMAB) +{ + if(params.detect_only) + { + return intersect_other_helper + (VA,FA,VB,FB,params,IF,VVAB,FFAB,JAB,IMAB); + }else + { + return intersect_other_helper + (VA,FA,VB,FB,params,IF,VVAB,FFAB,JAB,IMAB); + } +} + +IGL_INLINE bool igl::copyleft::cgal::intersect_other( + const Eigen::MatrixXd & VA, + const Eigen::MatrixXi & FA, + const Eigen::MatrixXd & VB, + const Eigen::MatrixXi & FB, + const bool first_only, + Eigen::MatrixXi & IF) +{ + Eigen::MatrixXd VVAB; + Eigen::MatrixXi FFAB; + Eigen::VectorXi JAB,IMAB; + return intersect_other( + VA,FA,VB,FB,{true,first_only},IF,VVAB,FFAB,JAB,IMAB); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template bool igl::copyleft::cgal::intersect_other, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, -1, 3, 0, -1, 3>, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, igl::copyleft::cgal::RemeshSelfIntersectionsParam const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template bool igl::copyleft::cgal::intersect_other, -1, -1, 1, -1, -1>, Eigen::Matrix, Eigen::Matrix, -1, -1, 1, -1, -1>, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, -1, -1, 1, -1, -1>, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase > const&, igl::copyleft::cgal::RemeshSelfIntersectionsParam const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase, -1, -1, 1, -1, -1> >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/intersect_other.h b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/intersect_other.h new file mode 100644 index 000000000..c1afdf87d --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/intersect_other.h @@ -0,0 +1,91 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_COPYLEFT_CGAL_INTERSECT_OTHER_H +#define IGL_COPYLEFT_CGAL_INTERSECT_OTHER_H +#include "../../igl_inline.h" +#include "RemeshSelfIntersectionsParam.h" + +#include + +namespace igl +{ + namespace copyleft + { + namespace cgal + { + // INTERSECT_OTHER Given a triangle mesh (VA,FA) and another mesh (VB,FB) + // find all pairs of intersecting faces. Note that self-intersections are + // ignored. + // + // Inputs: + // VA #V by 3 list of vertex positions + // FA #F by 3 list of triangle indices into VA + // VB #V by 3 list of vertex positions + // FB #F by 3 list of triangle indices into VB + // params whether to detect only and then whether to only find first + // intersection + // Outputs: + // IF #intersecting face pairs by 2 list of intersecting face pairs, + // indexing FA and FB + // VVAB #VVAB by 3 list of vertex positions + // FFAB #FFAB by 3 list of triangle indices into VVA + // JAB #FFAB list of indices into [FA;FB] denoting birth triangle + // IMAB #VVAB list of indices stitching duplicates (resulting from + // mesh intersections) together + template < + typename DerivedVA, + typename DerivedFA, + typename DerivedVB, + typename DerivedFB, + typename DerivedIF, + typename DerivedVVAB, + typename DerivedFFAB, + typename DerivedJAB, + typename DerivedIMAB> + IGL_INLINE bool intersect_other( + const Eigen::PlainObjectBase & VA, + const Eigen::PlainObjectBase & FA, + const Eigen::PlainObjectBase & VB, + const Eigen::PlainObjectBase & FB, + const RemeshSelfIntersectionsParam & params, + Eigen::PlainObjectBase & IF, + Eigen::PlainObjectBase & VVAB, + Eigen::PlainObjectBase & FFAB, + Eigen::PlainObjectBase & JAB, + Eigen::PlainObjectBase & IMAB); + // Legacy wrapper for detect only using common types. + // + // Inputs: + // VA #V by 3 list of vertex positions + // FA #F by 3 list of triangle indices into VA + // VB #V by 3 list of vertex positions + // FB #F by 3 list of triangle indices into VB + // first_only whether to only detect the first intersection. + // Outputs: + // IF #intersecting face pairs by 2 list of intersecting face pairs, + // indexing FA and FB + // Returns true if any intersections were found + // + // See also: remesh_self_intersections + IGL_INLINE bool intersect_other( + const Eigen::MatrixXd & VA, + const Eigen::MatrixXi & FA, + const Eigen::MatrixXd & VB, + const Eigen::MatrixXi & FB, + const bool first_only, + Eigen::MatrixXi & IF); + } + } +} + +#ifndef IGL_STATIC_LIBRARY +# include "intersect_other.cpp" +#endif + +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/intersect_with_half_space.cpp b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/intersect_with_half_space.cpp new file mode 100644 index 000000000..c4ba4dbb8 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/intersect_with_half_space.cpp @@ -0,0 +1,88 @@ +#include "intersect_with_half_space.h" +#include "mesh_boolean.h" +#include "half_space_box.h" + +template < + typename DerivedV, + typename DerivedF, + typename Derivedp, + typename Derivedn, + typename DerivedVC, + typename DerivedFC, + typename DerivedJ> +IGL_INLINE bool igl::copyleft::cgal::intersect_with_half_space( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const Eigen::MatrixBase & p, + const Eigen::MatrixBase & n, + Eigen::PlainObjectBase & VC, + Eigen::PlainObjectBase & FC, + Eigen::PlainObjectBase & J) +{ + typedef CGAL::Plane_3 Plane; + typedef CGAL::Point_3 Point; + typedef CGAL::Vector_3 Vector; + Plane P(Point(p(0),p(1),p(2)),Vector(n(0),n(1),n(2))); + return intersect_with_half_space(V,F,P,VC,FC,J); +} + +template < + typename DerivedV, + typename DerivedF, + typename Derivedequ, + typename DerivedVC, + typename DerivedFC, + typename DerivedJ> +IGL_INLINE bool igl::copyleft::cgal::intersect_with_half_space( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const Eigen::MatrixBase & equ, + Eigen::PlainObjectBase & VC, + Eigen::PlainObjectBase & FC, + Eigen::PlainObjectBase & J) +{ + typedef CGAL::Plane_3 Plane; + Plane P(equ(0),equ(1),equ(2),equ(3)); + return intersect_with_half_space(V,F,P,VC,FC,J); +} + +template < + typename DerivedV, + typename DerivedF, + typename DerivedVC, + typename DerivedFC, + typename DerivedJ> +IGL_INLINE bool igl::copyleft::cgal::intersect_with_half_space( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const CGAL::Plane_3 & P, + Eigen::PlainObjectBase & VC, + Eigen::PlainObjectBase & FC, + Eigen::PlainObjectBase & J) +{ + Eigen::Matrix BV; + Eigen::Matrix BF; + half_space_box(P,V,BV,BF); + // Disturbingly, (BV,BF) must be first argument + const bool ret = mesh_boolean(BV,BF,V,F,MESH_BOOLEAN_TYPE_INTERSECT,VC,FC,J); + // But now J is wrong... + std::for_each( + J.data(), + J.data()+J.size(), + [&BF,&F](typename DerivedJ::Scalar & j) + {j = (j, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, -1, -1, 1, -1, -1>, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase, -1, -1, 1, -1, -1> >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template bool igl::copyleft::cgal::intersect_with_half_space, Eigen::Matrix, Eigen::Matrix, Eigen::CwiseUnaryOp, Eigen::Matrix const>, Eigen::Matrix, -1, -1, 1, -1, -1>, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase, Eigen::Matrix const> > const&, Eigen::PlainObjectBase, -1, -1, 1, -1, -1> >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template bool igl::copyleft::cgal::intersect_with_half_space, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, -1, -1, 1, -1, -1>, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase, -1, -1, 1, -1, -1> >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template bool igl::copyleft::cgal::intersect_with_half_space, Eigen::Matrix, Eigen::Matrix, Eigen::CwiseUnaryOp, Eigen::Matrix const>, Eigen::Matrix, -1, -1, 1, -1, -1>, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase, Eigen::Matrix const> > const&, Eigen::PlainObjectBase, -1, -1, 1, -1, -1> >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/intersect_with_half_space.h b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/intersect_with_half_space.h new file mode 100644 index 000000000..9fdf9ae2b --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/intersect_with_half_space.h @@ -0,0 +1,96 @@ +#ifndef IGL_COPYLEFT_CGAL_INTERSECT_WITH_HALF_SPACE_H +#define IGL_COPYLEFT_CGAL_INTERSECT_WITH_HALF_SPACE_H +#include "../../igl_inline.h" +#include +#include +#include + +namespace igl +{ + namespace copyleft + { + namespace cgal + { + // Intersect a PWN mesh with a half-space. Point on plane, normal pointing + // outward. + // + // Inputs: + // V #V by 3 list of mesh vertex positions + // p 3d point on plane + // n 3d vector of normal of plane pointing away from inside + // Outputs: + // VC #VC by 3 list of vertex positions of boolean result mesh + // FC #FC by 3 list of triangle indices into VC + // J #FC list of indices into [F;F.rows()+[1;2]] revealing "birth" + // facet + template < + typename DerivedV, + typename DerivedF, + typename Derivedp, + typename Derivedn, + typename DerivedVC, + typename DerivedFC, + typename DerivedJ> + IGL_INLINE bool intersect_with_half_space( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const Eigen::MatrixBase & p, + const Eigen::MatrixBase & n, + Eigen::PlainObjectBase & VC, + Eigen::PlainObjectBase & FC, + Eigen::PlainObjectBase & J); + // Intersect a PWN mesh with a half-space. Plane equation. + // + // Inputs: + // V #V by 3 list of mesh vertex positions + // equ plane equation: P(x,y,z) = a*x+b*y+c*z + d = 0, P(x,y,z) < 0 is + // _inside_. + // Outputs: + // VC #VC by 3 list of vertex positions of boolean result mesh + // FC #FC by 3 list of triangle indices into VC + // J #FC list of indices into [F;F.rows()+[1;2]] revealing "birth" facet + template < + typename DerivedV, + typename DerivedF, + typename Derivedequ, + typename DerivedVC, + typename DerivedFC, + typename DerivedJ> + IGL_INLINE bool intersect_with_half_space( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const Eigen::MatrixBase & equ, + Eigen::PlainObjectBase & VC, + Eigen::PlainObjectBase & FC, + Eigen::PlainObjectBase & J); + // Intersect a PWN mesh with a half-space. CGAL Plane. + // + // Inputs: + // V #V by 3 list of mesh vertex positions + // P plane + // Outputs: + // VC #VC by 3 list of vertex positions of boolean result mesh + // FC #FC by 3 list of triangle indices into VC + // J #FC list of indices into [F;F.rows()+[1;2]] revealing "birth" facet + template < + typename DerivedV, + typename DerivedF, + typename DerivedVC, + typename DerivedFC, + typename DerivedJ> + IGL_INLINE bool intersect_with_half_space( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const CGAL::Plane_3 & P, + Eigen::PlainObjectBase & VC, + Eigen::PlainObjectBase & FC, + Eigen::PlainObjectBase & J); + } + } +} + +#ifndef IGL_STATIC_LIBRARY +# include "intersect_with_half_space.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/lexicographic_triangulation.cpp b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/lexicographic_triangulation.cpp new file mode 100644 index 000000000..719b50dbf --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/lexicographic_triangulation.cpp @@ -0,0 +1,24 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// Qingan Zhou +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +#include "lexicographic_triangulation.h" +#include "../../lexicographic_triangulation.h" +#include "orient2D.h" + +template< + typename DerivedP, + typename DerivedF + > +IGL_INLINE void igl::copyleft::cgal::lexicographic_triangulation( + const Eigen::PlainObjectBase& P, + Eigen::PlainObjectBase& F) +{ + typedef typename DerivedP::Scalar Scalar; + igl::lexicographic_triangulation(P, orient2D, F); +} diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/lexicographic_triangulation.h b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/lexicographic_triangulation.h new file mode 100644 index 000000000..5773a3942 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/lexicographic_triangulation.h @@ -0,0 +1,47 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// Qingan Zhou +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef IGL_COPYLEFT_CGAL_LEXICOGRAPHIC_TRIANGULATION_H +#define IGL_COPYLEFT_CGAL_LEXICOGRAPHIC_TRIANGULATION_H +#include "../../igl_inline.h" +#include + +namespace igl +{ + namespace copyleft + { + namespace cgal + { + + // Given a set of points in 2D, return a lexicographic triangulation of these + // points. + // + // Inputs: + // P #P by 2 list of vertex positions + // + // Outputs: + // F #F by 3 of faces in lexicographic triangulation. + template< + typename DerivedP, + typename DerivedF + > + IGL_INLINE void lexicographic_triangulation( + const Eigen::PlainObjectBase& P, + Eigen::PlainObjectBase& F); + } + } +} + + + + +#ifndef IGL_STATIC_LIBRARY +# include "lexicographic_triangulation.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/list_to_matrix.cpp b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/list_to_matrix.cpp new file mode 100644 index 000000000..e94dde6b8 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/list_to_matrix.cpp @@ -0,0 +1,15 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2017 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "../../list_to_matrix.h" +#include +#include +#ifdef IGL_STATIC_LIBRARY +#undef IGL_STATIC_LIBRARY +#include "../../list_to_matrix.cpp" +template bool igl::list_to_matrix, Eigen::Matrix, -1, 3, 0, -1, 3> >(std::vector, std::allocator > >, std::allocator, std::allocator > > > > const&, Eigen::PlainObjectBase, -1, 3, 0, -1, 3> >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/mesh_boolean.cpp b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/mesh_boolean.cpp new file mode 100644 index 000000000..4997c3573 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/mesh_boolean.cpp @@ -0,0 +1,468 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// Qingnan Zhou +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +// +#include "mesh_boolean.h" +#include "assign.h" +#include "extract_cells.h" +#include "mesh_boolean_type_to_funcs.h" +#include "propagate_winding_numbers.h" +#include "relabel_small_immersed_cells.h" +#include "remesh_self_intersections.h" +#include "string_to_mesh_boolean_type.h" +#include "../../combine.h" +#include "../../cumsum.h" +#include "../../extract_manifold_patches.h" +#include "../../get_seconds.h" +#include "../../remove_unreferenced.h" +#include "../../resolve_duplicated_faces.h" +#include "../../slice.h" +#include "../../unique_edge_map.h" +#include "../../unique_simplices.h" + +#include +#include + +//#define MESH_BOOLEAN_TIMING +//#define DOUBLE_CHECK_EXACT_OUTPUT +//#define SMALL_CELL_REMOVAL + +template < + typename DerivedVA, + typename DerivedFA, + typename DerivedVB, + typename DerivedFB, + typename DerivedVC, + typename DerivedFC, + typename DerivedJ> +IGL_INLINE bool igl::copyleft::cgal::mesh_boolean( + const Eigen::MatrixBase & VA, + const Eigen::MatrixBase & FA, + const Eigen::MatrixBase & VB, + const Eigen::MatrixBase & FB, + const MeshBooleanType & type, + Eigen::PlainObjectBase & VC, + Eigen::PlainObjectBase & FC, + Eigen::PlainObjectBase & J) +{ + std::function keep; + std::function) > wind_num_op; + mesh_boolean_type_to_funcs(type,wind_num_op,keep); + return mesh_boolean(VA,FA,VB,FB,wind_num_op,keep,VC,FC,J); +} +template < + typename DerivedVA, + typename DerivedFA, + typename DerivedVB, + typename DerivedFB, + typename DerivedVC, + typename DerivedFC, + typename DerivedJ> +IGL_INLINE bool igl::copyleft::cgal::mesh_boolean( + const Eigen::MatrixBase & VA, + const Eigen::MatrixBase & FA, + const Eigen::MatrixBase & VB, + const Eigen::MatrixBase & FB, + const std::string & type_str, + Eigen::PlainObjectBase & VC, + Eigen::PlainObjectBase & FC, + Eigen::PlainObjectBase & J) +{ + return mesh_boolean( + VA,FA,VB,FB,string_to_mesh_boolean_type(type_str),VC,FC,J); +} + +template < + typename DerivedVA, + typename DerivedFA, + typename DerivedVB, + typename DerivedFB, + typename DerivedVC, + typename DerivedFC, + typename DerivedJ> +IGL_INLINE bool igl::copyleft::cgal::mesh_boolean( + const Eigen::MatrixBase & VA, + const Eigen::MatrixBase & FA, + const Eigen::MatrixBase & VB, + const Eigen::MatrixBase & FB, + const std::function) >& wind_num_op, + const std::function & keep, + Eigen::PlainObjectBase & VC, + Eigen::PlainObjectBase & FC, + Eigen::PlainObjectBase & J) +{ + // Generate combined mesh (VA,FA,VB,FB) -> (V,F) + Eigen::Matrix sizes(FA.rows(),FB.rows()); + // TODO: This is a precision template **bug** that results in failure to + // compile. If DerivedVA::Scalar is double and DerivedVB::Scalar is + // CGAL::Epeck::FT then the following assignment will not compile. This + // implies that VA must have the trumping precision (and a valid assignment + // operator from VB's type). + Eigen::Matrix VV(VA.rows() + VB.rows(), 3); + DerivedFC FF(FA.rows() + FB.rows(), 3); + // Can't use comma initializer + for(int a = 0;a 0) + { + FF.block(FA.rows(), 0, FB.rows(), 3) = FB.array() + VA.rows(); + } + return mesh_boolean(VV,FF,sizes,wind_num_op,keep,VC,FC,J); +} + +template < + typename DerivedV, + typename DerivedF, + typename DerivedVC, + typename DerivedFC, + typename DerivedJ> +IGL_INLINE bool igl::copyleft::cgal::mesh_boolean( + const std::vector & Vlist, + const std::vector & Flist, + const std::function) >& wind_num_op, + const std::function & keep, + Eigen::PlainObjectBase & VC, + Eigen::PlainObjectBase & FC, + Eigen::PlainObjectBase & J) +{ + DerivedV VV; + DerivedF FF; + Eigen::Matrix Vsizes,Fsizes; + igl::combine(Vlist,Flist,VV,FF,Vsizes,Fsizes); + return mesh_boolean(VV,FF,Fsizes,wind_num_op,keep,VC,FC,J); +} + +template < + typename DerivedV, + typename DerivedF, + typename DerivedVC, + typename DerivedFC, + typename DerivedJ> +IGL_INLINE bool igl::copyleft::cgal::mesh_boolean( + const std::vector & Vlist, + const std::vector & Flist, + const MeshBooleanType & type, + Eigen::PlainObjectBase & VC, + Eigen::PlainObjectBase & FC, + Eigen::PlainObjectBase & J) +{ + DerivedV VV; + DerivedF FF; + Eigen::Matrix Vsizes,Fsizes; + igl::combine(Vlist,Flist,VV,FF,Vsizes,Fsizes); + std::function keep; + std::function) > wind_num_op; + mesh_boolean_type_to_funcs(type,wind_num_op,keep); + return mesh_boolean(VV,FF,Fsizes,wind_num_op,keep,VC,FC,J); +} + +template < + typename DerivedVV, + typename DerivedFF, + typename Derivedsizes, + typename DerivedVC, + typename DerivedFC, + typename DerivedJ> +IGL_INLINE bool igl::copyleft::cgal::mesh_boolean( + const Eigen::MatrixBase & VV, + const Eigen::MatrixBase & FF, + const Eigen::MatrixBase & sizes, + const std::function) >& wind_num_op, + const std::function & keep, + Eigen::PlainObjectBase & VC, + Eigen::PlainObjectBase & FC, + Eigen::PlainObjectBase & J) +{ +#ifdef MESH_BOOLEAN_TIMING + const auto & tictoc = []() -> double + { + static double t_start = igl::get_seconds(); + double diff = igl::get_seconds()-t_start; + t_start += diff; + return diff; + }; + const auto log_time = [&](const std::string& label) -> void { + std::cout << "mesh_boolean." << label << ": " + << tictoc() << std::endl; + }; + tictoc(); +#endif + typedef typename DerivedVC::Scalar Scalar; + typedef CGAL::Epeck Kernel; + typedef Kernel::FT ExactScalar; + typedef Eigen::Matrix MatrixX3S; + typedef Eigen::Matrix VectorXJ; + typedef Eigen::Matrix< + ExactScalar, + Eigen::Dynamic, + Eigen::Dynamic, + DerivedVC::IsRowMajor> MatrixXES; + MatrixXES V; + DerivedFC F; + VectorXJ CJ; + { + Eigen::VectorXi I; + igl::copyleft::cgal::RemeshSelfIntersectionsParam params; + params.stitch_all = true; + MatrixXES Vr; + DerivedFC Fr; + Eigen::MatrixXi IF; + igl::copyleft::cgal::remesh_self_intersections( + VV, FF, params, Vr, Fr, IF, CJ, I); + assert(I.size() == Vr.rows()); + // Merge coinciding vertices into non-manifold vertices. + std::for_each(Fr.data(), Fr.data()+Fr.size(), + [&I](typename DerivedFC::Scalar& a) { a=I[a]; }); + // Remove unreferenced vertices. + Eigen::VectorXi UIM; + igl::remove_unreferenced(Vr, Fr, V, F, UIM); + } +#ifdef MESH_BOOLEAN_TIMING + log_time("resolve_self_intersection"); +#endif + + // Compute edges of (F) --> (E,uE,EMAP,uE2E) + Eigen::MatrixXi E, uE; + Eigen::VectorXi EMAP; + std::vector > uE2E; + igl::unique_edge_map(F, E, uE, EMAP, uE2E); + + // Compute patches (F,EMAP,uE2E) --> (P) + Eigen::VectorXi P; + const size_t num_patches = igl::extract_manifold_patches(F, EMAP, uE2E, P); +#ifdef MESH_BOOLEAN_TIMING + log_time("patch_extraction"); +#endif + + // Compute cells (V,F,P,E,uE,EMAP) -> (per_patch_cells) + Eigen::MatrixXi per_patch_cells; + const size_t num_cells = + igl::copyleft::cgal::extract_cells( + V, F, P, E, uE, uE2E, EMAP, per_patch_cells); +#ifdef MESH_BOOLEAN_TIMING + log_time("cell_extraction"); +#endif + + // Compute winding numbers on each side of each facet. + const size_t num_faces = F.rows(); + // W(f,:) --> [w1out,w1in,w2out,w2in, ... wnout,wnint] winding numbers above + // and below each face w.r.t. each input mesh, so that W(f,2*i) is the + // winding number above face f w.r.t. input i, and W(f,2*i+1) is the winding + // number below face f w.r.t. input i. + Eigen::MatrixXi W; + // labels(f) = i means that face f comes from mesh i + Eigen::VectorXi labels(num_faces); + // cumulative sizes + Derivedsizes cumsizes; + igl::cumsum(sizes,1,cumsizes); + const size_t num_inputs = sizes.size(); + std::transform( + CJ.data(), + CJ.data()+CJ.size(), + labels.data(), + // Determine which input mesh birth face i comes from + [&num_inputs,&cumsizes](int i)->int + { + for(int k = 0;k 0) + { + valid = valid & + igl::copyleft::cgal::propagate_winding_numbers( + V, F, uE, uE2E, num_patches, P, num_cells, per_patch_cells, labels, W); + } else + { + W.resize(0, 2*num_inputs); + } + assert((size_t)W.rows() == num_faces); + // If W doesn't have enough columns, pad with zeros + if (W.cols() <= 2*num_inputs) + { + const int old_ncols = W.cols(); + W.conservativeResize(num_faces,2*num_inputs); + W.rightCols(2*num_inputs-old_ncols).setConstant(0); + } + assert((size_t)W.cols() == 2*num_inputs); +#ifdef MESH_BOOLEAN_TIMING + log_time("propagate_input_winding_number"); +#endif + + // Compute resulting winding number. + Eigen::MatrixXi Wr(num_faces, 2); + for (size_t i=0; i int + { + return (i+1)*(ori?1:-1); + }; + //auto signed_index_to_index = [&](int i) -> size_t { + // return abs(i) - 1; + //}; + std::vector selected; + for(size_t i=0; i 0) + { + selected.push_back(index_to_signed_index(i, true)); + } else if (should_keep < 0) + { + selected.push_back(index_to_signed_index(i, false)); + } + } + + const size_t num_selected = selected.size(); + DerivedFC kept_faces(num_selected, 3); + DerivedJ kept_face_indices(num_selected, 1); + for (size_t i=0; i 0) + { + kept_faces.row(i) = F.row(idx); + } else + { + kept_faces.row(i) = F.row(idx).reverse(); + } + kept_face_indices(i, 0) = CJ[idx]; + } +#ifdef MESH_BOOLEAN_TIMING + log_time("extract_output"); +#endif + + // Finally, remove duplicated faces and unreferenced vertices. + { + DerivedFC G; + DerivedJ JJ; + igl::resolve_duplicated_faces(kept_faces, G, JJ); + igl::slice(kept_face_indices, JJ, 1, J); + +#ifdef DOUBLE_CHECK_EXACT_OUTPUT + { + // Sanity check on exact output. + igl::copyleft::cgal::RemeshSelfIntersectionsParam params; + params.detect_only = true; + params.first_only = true; + MatrixXES dummy_VV; + DerivedFC dummy_FF, dummy_IF; + Eigen::VectorXi dummy_J, dummy_IM; + igl::copyleft::cgal::SelfIntersectMesh< + Kernel, + MatrixXES, DerivedFC, + MatrixXES, DerivedFC, + DerivedFC, + Eigen::VectorXi, + Eigen::VectorXi + > checker(V, G, params, + dummy_VV, dummy_FF, dummy_IF, dummy_J, dummy_IM); + if (checker.count != 0) + { + throw "Self-intersection not fully resolved."; + } + } +#endif + + MatrixX3S Vs; + assign(V,Vs); + Eigen::VectorXi newIM; + igl::remove_unreferenced(Vs,G,VC,FC,newIM); + } +#ifdef MESH_BOOLEAN_TIMING + log_time("clean_up"); +#endif + return valid; +} + +template < + typename DerivedVA, + typename DerivedFA, + typename DerivedVB, + typename DerivedFB, + typename DerivedVC, + typename DerivedFC> +IGL_INLINE bool igl::copyleft::cgal::mesh_boolean( + const Eigen::MatrixBase & VA, + const Eigen::MatrixBase & FA, + const Eigen::MatrixBase & VB, + const Eigen::MatrixBase & FB, + const MeshBooleanType & type, + Eigen::PlainObjectBase & VC, + Eigen::PlainObjectBase & FC) +{ + Eigen::Matrix J; + return igl::copyleft::cgal::mesh_boolean(VA,FA,VB,FB,type,VC,FC,J); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template bool igl::copyleft::cgal::mesh_boolean, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, igl::MeshBooleanType const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template bool igl::copyleft::cgal::mesh_boolean, 8, 3, 0, 8, 3>, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, -1, -1, 1, -1, -1>, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase, 8, 3, 0, 8, 3> > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, igl::MeshBooleanType const&, Eigen::PlainObjectBase, -1, -1, 1, -1, -1> >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template bool igl::copyleft::cgal::mesh_boolean, -1, -1, 1, -1, -1>, Eigen::Matrix, Eigen::Matrix, -1, -1, 1, -1, -1>, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase > const&, igl::MeshBooleanType const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template bool igl::copyleft::cgal::mesh_boolean, -1, -1, 1, -1, -1>, Eigen::Matrix, Eigen::Matrix, -1, -1, 1, -1, -1>, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase > const&, igl::MeshBooleanType const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template bool igl::copyleft::cgal::mesh_boolean, -1, -1, 1, -1, -1>, Eigen::Matrix, Eigen::Matrix, -1, -1, 0, -1, -1>, Eigen::Matrix, Eigen::Matrix, -1, -1, 1, -1, -1>, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase > const&, igl::MeshBooleanType const&, Eigen::PlainObjectBase, -1, -1, 1, -1, -1> >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template bool igl::copyleft::cgal::mesh_boolean, -1, -1, 1, -1, -1>, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, -1, -1, 1, -1, -1>, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, igl::MeshBooleanType const&, Eigen::PlainObjectBase, -1, -1, 1, -1, -1> >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template bool igl::copyleft::cgal::mesh_boolean, 8, 3, 0, 8, 3>, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, -1, -1, 1, -1, -1>, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase, 8, 3, 0, 8, 3> > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, igl::MeshBooleanType const&, Eigen::PlainObjectBase, -1, -1, 1, -1, -1> >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template bool igl::copyleft::cgal::mesh_boolean, -1, -1, 1, -1, -1>, Eigen::Matrix, Eigen::Matrix, -1, -1, 1, -1, -1>, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase > const&, igl::MeshBooleanType const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template bool igl::copyleft::cgal::mesh_boolean, 8, 3, 0, 8, 3>, Eigen::Matrix, Eigen::Matrix, -1, 3, 0, -1, 3>, Eigen::Matrix, Eigen::Matrix, -1, 3, 0, -1, 3>, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase, 8, 3, 0, 8, 3> > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase > const&, igl::MeshBooleanType const&, Eigen::PlainObjectBase, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template bool igl::copyleft::cgal::mesh_boolean, 8, 3, 0, 8, 3>, Eigen::Matrix, Eigen::Matrix, -1, 4, 0, -1, 4>, Eigen::Matrix, Eigen::Matrix, -1, 4, 0, -1, 4>, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase, 8, 3, 0, 8, 3> > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase, -1, 4, 0, -1, 4> > const&, Eigen::MatrixBase > const&, igl::MeshBooleanType const&, Eigen::PlainObjectBase, -1, 4, 0, -1, 4> >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template bool igl::copyleft::cgal::mesh_boolean, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, igl::MeshBooleanType const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template bool igl::copyleft::cgal::mesh_boolean, -1, 3, 0, -1, 3>, Eigen::Matrix, Eigen::Matrix, -1, 3, 0, -1, 3>, Eigen::Matrix, Eigen::Matrix, -1, 3, 0, -1, 3>, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase > const&, igl::MeshBooleanType const&, Eigen::PlainObjectBase, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template bool igl::copyleft::cgal::mesh_boolean, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, igl::MeshBooleanType const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template bool igl::copyleft::cgal::mesh_boolean, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, std::basic_string, std::allocator > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template bool igl::copyleft::cgal::mesh_boolean, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, std::basic_string, std::allocator > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template bool igl::copyleft::cgal::mesh_boolean, -1, 3, 0, -1, 3>, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, -1, 3, 0, -1, 3>, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, std::basic_string, std::allocator > const&, Eigen::PlainObjectBase, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template bool igl::copyleft::cgal::mesh_boolean, -1, 3, 0, -1, 3>, Eigen::Matrix, Eigen::Matrix, -1, 3, 0, -1, 3>, Eigen::Matrix, Eigen::Matrix, -1, 3, 0, -1, 3>, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase > const&, std::basic_string, std::allocator > const&, Eigen::PlainObjectBase, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template bool igl::copyleft::cgal::mesh_boolean, 8, 3, 0, 8, 3>, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase, 8, 3, 0, 8, 3> > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, igl::MeshBooleanType const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template bool igl::copyleft::cgal::mesh_boolean, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, igl::MeshBooleanType const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template bool igl::copyleft::cgal::mesh_boolean, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(std::vector, std::allocator > > const&, std::vector, std::allocator > > const&, std::function)> const&, std::function const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template bool igl::copyleft::cgal::mesh_boolean, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(std::vector, std::allocator > > const&, std::vector, std::allocator > > const&, igl::MeshBooleanType const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#ifdef WIN32 +template bool igl::copyleft::cgal::mesh_boolean, -1, 3, 0, -1, 3>, class Eigen::Matrix, class Eigen::Matrix, -1, 3, 0, -1, 3>, class Eigen::Matrix, class Eigen::Matrix, -1, 3, 0, -1, 3>, class Eigen::Matrix, class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>>(class Eigen::MatrixBase, -1, 3, 0, -1, 3>> const &, class Eigen::MatrixBase> const &, class Eigen::MatrixBase, -1, 3, 0, -1, 3>> const &, class Eigen::MatrixBase> const &, enum igl::MeshBooleanType const &, class Eigen::PlainObjectBase, -1, 3, 0, -1, 3>> &, class Eigen::PlainObjectBase> &, class Eigen::PlainObjectBase> &); +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/mesh_boolean.h b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/mesh_boolean.h new file mode 100644 index 000000000..24c99ed41 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/mesh_boolean.h @@ -0,0 +1,229 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// Qingnan Zhou +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +// +#ifndef IGL_COPYLEFT_CGAL_MESH_BOOLEAN_H +#define IGL_COPYLEFT_CGAL_MESH_BOOLEAN_H + +#include "../../igl_inline.h" +#include "../../MeshBooleanType.h" +#include +#include +#include + +namespace igl +{ + namespace copyleft + { + namespace cgal + { + // MESH_BOOLEAN Compute boolean csg operations on "solid", consistently + // oriented meshes. + // + // Inputs: + // VA #VA by 3 list of vertex positions of first mesh + // FA #FA by 3 list of triangle indices into VA + // VB #VB by 3 list of vertex positions of second mesh + // FB #FB by 3 list of triangle indices into VB + // type type of boolean operation + // Outputs: + // VC #VC by 3 list of vertex positions of boolean result mesh + // FC #FC by 3 list of triangle indices into VC + // J #FC list of indices into [FA;FA.rows()+FB] revealing "birth" facet + // Returns true if inputs induce a piecewise constant winding number + // field and type is valid + // + // See also: mesh_boolean_cork, intersect_other, + // remesh_self_intersections + template < + typename DerivedVA, + typename DerivedFA, + typename DerivedVB, + typename DerivedFB, + typename DerivedVC, + typename DerivedFC, + typename DerivedJ> + IGL_INLINE bool mesh_boolean( + const Eigen::MatrixBase & VA, + const Eigen::MatrixBase & FA, + const Eigen::MatrixBase & VB, + const Eigen::MatrixBase & FB, + const MeshBooleanType & type, + Eigen::PlainObjectBase & VC, + Eigen::PlainObjectBase & FC, + Eigen::PlainObjectBase & J); + template < + typename DerivedVA, + typename DerivedFA, + typename DerivedVB, + typename DerivedFB, + typename DerivedVC, + typename DerivedFC, + typename DerivedJ> + IGL_INLINE bool mesh_boolean( + const Eigen::MatrixBase & VA, + const Eigen::MatrixBase & FA, + const Eigen::MatrixBase & VB, + const Eigen::MatrixBase & FB, + const std::string & type_str, + Eigen::PlainObjectBase & VC, + Eigen::PlainObjectBase & FC, + Eigen::PlainObjectBase & J); + // + // Inputs: + // VA #VA by 3 list of vertex positions of first mesh + // FA #FA by 3 list of triangle indices into VA + // VB #VB by 3 list of vertex positions of second mesh + // FB #FB by 3 list of triangle indices into VB + // wind_num_op function handle for filtering winding numbers from + // tuples of integer values to [0,1] outside/inside values + // keep function handle for determining if a patch should be "kept" + // in the output based on the winding number on either side + // Outputs: + // VC #VC by 3 list of vertex positions of boolean result mesh + // FC #FC by 3 list of triangle indices into VC + // J #FC list of indices into [FA;FB] revealing "birth" facet + // Returns true iff inputs induce a piecewise constant winding number + // field + // + // See also: mesh_boolean_cork, intersect_other, + // remesh_self_intersections + template < + typename DerivedVA, + typename DerivedFA, + typename DerivedVB, + typename DerivedFB, + typename DerivedVC, + typename DerivedFC, + typename DerivedJ> + IGL_INLINE bool mesh_boolean( + const Eigen::MatrixBase & VA, + const Eigen::MatrixBase & FA, + const Eigen::MatrixBase & VB, + const Eigen::MatrixBase & FB, + const std::function) >& wind_num_op, + const std::function & keep, + Eigen::PlainObjectBase & VC, + Eigen::PlainObjectBase & FC, + Eigen::PlainObjectBase & J); + // MESH_BOOLEAN Variadic boolean operations + // + // Inputs: + // Vlist k-long list of lists of mesh vertex positions + // Flist k-long list of lists of mesh face indices, so that Flist[i] indexes + // vertices in Vlist[i] + // wind_num_op function handle for filtering winding numbers from + // n-tuples of integer values to [0,1] outside/inside values + // keep function handle for determining if a patch should be "kept" + // in the output based on the winding number on either side + // Outputs: + // VC #VC by 3 list of vertex positions of boolean result mesh + // FC #FC by 3 list of triangle indices into VC + // J #FC list of indices into [Flist[0];Flist[1];...;Flist[k]] + // revealing "birth" facet + // Returns true iff inputs induce a piecewise constant winding number + // field + // + // See also: mesh_boolean_cork, intersect_other, + // remesh_self_intersections + template < + typename DerivedV, + typename DerivedF, + typename DerivedVC, + typename DerivedFC, + typename DerivedJ> + IGL_INLINE bool mesh_boolean( + const std::vector & Vlist, + const std::vector & Flist, + const std::function) >& wind_num_op, + const std::function & keep, + Eigen::PlainObjectBase & VC, + Eigen::PlainObjectBase & FC, + Eigen::PlainObjectBase & J); + template < + typename DerivedV, + typename DerivedF, + typename DerivedVC, + typename DerivedFC, + typename DerivedJ> + IGL_INLINE bool mesh_boolean( + const std::vector & Vlist, + const std::vector & Flist, + const MeshBooleanType & type, + Eigen::PlainObjectBase & VC, + Eigen::PlainObjectBase & FC, + Eigen::PlainObjectBase & J); + // Given a merged mesh (V,F) and list of sizes of inputs + // + // Inputs: + // V #V by 3 list of merged mesh vertex positions + // F #F by 3 list of merged mesh face indices so that first sizes(0) + // faces come from the first input, and the next sizes(1) faces come + // from the second input, and so on. + // sizes #inputs list of sizes so that sizes(i) is the #faces in the + // ith input + // wind_num_op function handle for filtering winding numbers from + // tuples of integer values to [0,1] outside/inside values + // keep function handle for determining if a patch should be "kept" + // in the output based on the winding number on either side + // Outputs: + // VC #VC by 3 list of vertex positions of boolean result mesh + // FC #FC by 3 list of triangle indices into VC + // J #FC list of birth parent indices + // + template < + typename DerivedVV, + typename DerivedFF, + typename Derivedsizes, + typename DerivedVC, + typename DerivedFC, + typename DerivedJ> + IGL_INLINE bool mesh_boolean( + const Eigen::MatrixBase & VV, + const Eigen::MatrixBase & FF, + const Eigen::MatrixBase & sizes, + const std::function) >& wind_num_op, + const std::function & keep, + Eigen::PlainObjectBase & VC, + Eigen::PlainObjectBase & FC, + Eigen::PlainObjectBase & J); + // Inputs: + // VA #VA by 3 list of vertex positions of first mesh + // FA #FA by 3 list of triangle indices into VA + // VB #VB by 3 list of vertex positions of second mesh + // FB #FB by 3 list of triangle indices into VB + // type type of boolean operation + // Outputs: + // VC #VC by 3 list of vertex positions of boolean result mesh + // FC #FC by 3 list of triangle indices into VC + // Returns true ff inputs induce a piecewise constant winding number + // field and type is valid + template < + typename DerivedVA, + typename DerivedFA, + typename DerivedVB, + typename DerivedFB, + typename DerivedVC, + typename DerivedFC> + IGL_INLINE bool mesh_boolean( + const Eigen::MatrixBase & VA, + const Eigen::MatrixBase & FA, + const Eigen::MatrixBase & VB, + const Eigen::MatrixBase & FB, + const MeshBooleanType & type, + Eigen::PlainObjectBase & VC, + Eigen::PlainObjectBase & FC); + } + } +} + +#ifndef IGL_STATIC_LIBRARY +# include "mesh_boolean.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/mesh_boolean_type_to_funcs.cpp b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/mesh_boolean_type_to_funcs.cpp new file mode 100644 index 000000000..41b67c1b7 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/mesh_boolean_type_to_funcs.cpp @@ -0,0 +1,39 @@ +#include "mesh_boolean_type_to_funcs.h" +#include "BinaryWindingNumberOperations.h" + +IGL_INLINE void igl::copyleft::cgal::mesh_boolean_type_to_funcs( + const MeshBooleanType & type, + std::function) >& wind_num_op, + std::function & keep) +{ + switch (type) + { + case MESH_BOOLEAN_TYPE_UNION: + wind_num_op = BinaryUnion(); + keep = KeepInside(); + return; + case MESH_BOOLEAN_TYPE_INTERSECT: + wind_num_op = BinaryIntersect(); + keep = KeepInside(); + return; + case MESH_BOOLEAN_TYPE_MINUS: + wind_num_op = BinaryMinus(); + keep = KeepInside(); + return; + case MESH_BOOLEAN_TYPE_XOR: + wind_num_op = BinaryXor(); + keep = KeepInside(); + return; + case MESH_BOOLEAN_TYPE_RESOLVE: + wind_num_op = BinaryResolve(); + keep = KeepAll(); + return; + default: + assert(false && "Unsupported boolean type."); + return; + } +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/mesh_boolean_type_to_funcs.h b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/mesh_boolean_type_to_funcs.h new file mode 100644 index 000000000..2a269d770 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/mesh_boolean_type_to_funcs.h @@ -0,0 +1,37 @@ +#ifndef IGL_COPYLEFT_CGAL_MESH_BOOLEAN_TYPE_TO_FUNCS_H +#define IGL_COPYLEFT_CGAL_MESH_BOOLEAN_TYPE_TO_FUNCS_H + +#include "../../igl_inline.h" +#include "../../MeshBooleanType.h" +#include +#include +namespace igl +{ + namespace copyleft + { + namespace cgal + { + // Convert a MeshBooleanType enum to a pair of winding number conversion + // function and "keep" function used by mesh_boolean + // + // Inputs: + // type MeshBooleanType enum value + // Outputs: + // wind_num_op function handle for filtering winding numbers from + // tuples of integer values to [0,1] outside/inside values + // keep function handle for determining if a patch should be "kept" + // in the output based on the winding number on either side + // + // See also: string_to_mesh_boolean_type + IGL_INLINE void mesh_boolean_type_to_funcs( + const MeshBooleanType & type, + std::function) >& + wind_num_op, + std::function & keep); + } + } +} +#ifndef IGL_STATIC_LIBRARY +# include "mesh_boolean_type_to_funcs.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/mesh_to_cgal_triangle_list.cpp b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/mesh_to_cgal_triangle_list.cpp new file mode 100644 index 000000000..131837939 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/mesh_to_cgal_triangle_list.cpp @@ -0,0 +1,83 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "mesh_to_cgal_triangle_list.h" +#include "assign.h" + +#include + +template < + typename DerivedV, + typename DerivedF, + typename Kernel> +IGL_INLINE void igl::copyleft::cgal::mesh_to_cgal_triangle_list( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + std::vector > & T) +{ + typedef CGAL::Point_3 Point_3; + typedef CGAL::Triangle_3 Triangle_3; + // Must be 3D + assert(V.cols() == 3); + // **Copy** to convert to output type (this is especially/only needed if the + // input type DerivedV::Scalar is CGAL::Epeck + Eigen::Matrix< + typename Kernel::FT, + DerivedV::RowsAtCompileTime, + DerivedV::ColsAtCompileTime> + KV(V.rows(),V.cols()); + assign(V,KV); + // Must be triangles + assert(F.cols() == 3); + T.reserve(F.rows()); + // Loop over faces + for(int f = 0;f<(int)F.rows();f++) + { + T.push_back( + Triangle_3( + Point_3( KV(F(f,0),0), KV(F(f,0),1), KV(F(f,0),2)), + Point_3( KV(F(f,1),0), KV(F(f,1),1), KV(F(f,1),2)), + Point_3( KV(F(f,2),0), KV(F(f,2),1), KV(F(f,2),2)))); + } +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::copyleft::cgal::mesh_to_cgal_triangle_list, Eigen::Matrix, CGAL::Simple_cartesian >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, std::vector >, std::allocator > > >&); +// generated by autoexplicit.sh +template void igl::copyleft::cgal::mesh_to_cgal_triangle_list, Eigen::Matrix, CGAL::Epick>(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, std::vector, std::allocator > >&); +// generated by autoexplicit.sh +template void igl::copyleft::cgal::mesh_to_cgal_triangle_list, Eigen::Matrix, CGAL::Epeck>(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, std::vector, std::allocator > >&); +// generated by autoexplicit.sh +template void igl::copyleft::cgal::mesh_to_cgal_triangle_list, -1, 3, 0, -1, 3>, Eigen::Matrix, CGAL::Epick>(Eigen::MatrixBase, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase > const&, std::vector, std::allocator > >&); +// generated by autoexplicit.sh +template void igl::copyleft::cgal::mesh_to_cgal_triangle_list, -1, 3, 0, -1, 3>, Eigen::Matrix, CGAL::Epeck>(Eigen::MatrixBase, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase > const&, std::vector, std::allocator > >&); +// generated by autoexplicit.sh +template void igl::copyleft::cgal::mesh_to_cgal_triangle_list, -1, -1, 1, -1, -1>, Eigen::Matrix, CGAL::Epick>(Eigen::MatrixBase, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase > const&, std::vector, std::allocator > >&); +// generated by autoexplicit.sh +template void igl::copyleft::cgal::mesh_to_cgal_triangle_list, -1, -1, 1, -1, -1>, Eigen::Matrix, CGAL::Epeck>(Eigen::MatrixBase, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase > const&, std::vector, std::allocator > >&); +// generated by autoexplicit.sh +template void igl::copyleft::cgal::mesh_to_cgal_triangle_list, Eigen::Matrix, CGAL::Epick>(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, std::vector, std::allocator > >&); +// generated by autoexplicit.sh +template void igl::copyleft::cgal::mesh_to_cgal_triangle_list, Eigen::Matrix, CGAL::Epeck>(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, std::vector, std::allocator > >&); +// generated by autoexplicit.sh +template void igl::copyleft::cgal::mesh_to_cgal_triangle_list, Eigen::Matrix, CGAL::Epick>(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, std::vector, std::allocator > >&); +// generated by autoexplicit.sh +template void igl::copyleft::cgal::mesh_to_cgal_triangle_list, Eigen::Matrix, CGAL::Epeck>(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, std::vector, std::allocator > >&); +template void igl::copyleft::cgal::mesh_to_cgal_triangle_list, Eigen::Matrix, CGAL::Epeck>(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, std::vector, std::allocator > >&); +template void igl::copyleft::cgal::mesh_to_cgal_triangle_list, Eigen::Matrix, CGAL::Epick>(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, std::vector, std::allocator > >&); +template void igl::copyleft::cgal::mesh_to_cgal_triangle_list, Eigen::Matrix, CGAL::Epeck>(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, std::vector, std::allocator > >&); +template void igl::copyleft::cgal::mesh_to_cgal_triangle_list, Eigen::Matrix, CGAL::Epick>(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, std::vector, std::allocator > >&); +template void igl::copyleft::cgal::mesh_to_cgal_triangle_list, -1, 3, 0, -1, 3>, Eigen::Matrix, CGAL::Epeck>(Eigen::MatrixBase, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase > const&, std::vector, std::allocator > >&); +template void igl::copyleft::cgal::mesh_to_cgal_triangle_list, -1, 3, 0, -1, 3>, Eigen::Matrix, CGAL::Epick>(Eigen::MatrixBase, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase > const&, std::vector, std::allocator > >&); +template void igl::copyleft::cgal::mesh_to_cgal_triangle_list, -1, 3, 0, -1, 3>, Eigen::Matrix, CGAL::Epick>(Eigen::MatrixBase, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase > const&, std::vector, std::allocator > >&); +template void igl::copyleft::cgal::mesh_to_cgal_triangle_list, -1, 3, 0, -1, 3>, Eigen::Matrix, CGAL::Epeck>(Eigen::MatrixBase, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase > const&, std::vector, std::allocator > >&); +template void igl::copyleft::cgal::mesh_to_cgal_triangle_list, 8, 3, 0, 8, 3>, Eigen::Matrix, CGAL::Epick>(Eigen::MatrixBase, 8, 3, 0, 8, 3> > const&, Eigen::MatrixBase > const&, std::vector, std::allocator > >&); +template void igl::copyleft::cgal::mesh_to_cgal_triangle_list, 8, 3, 0, 8, 3>, Eigen::Matrix, CGAL::Epeck>(Eigen::MatrixBase, 8, 3, 0, 8, 3> > const&, Eigen::MatrixBase > const&, std::vector, std::allocator > >&); +template void igl::copyleft::cgal::mesh_to_cgal_triangle_list, Eigen::Matrix, CGAL::Simple_cartesian >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, std::vector >, std::allocator > > >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/mesh_to_cgal_triangle_list.h b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/mesh_to_cgal_triangle_list.h new file mode 100644 index 000000000..492215bd5 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/mesh_to_cgal_triangle_list.h @@ -0,0 +1,44 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_COPYLEFT_CGAL_MESH_TO_CGAL_TRIANGLE_LIST_H +#define IGL_COPYLEFT_CGAL_MESH_TO_CGAL_TRIANGLE_LIST_H +#include "../../igl_inline.h" +#include +#include "CGAL_includes.hpp" +namespace igl +{ + namespace copyleft + { + namespace cgal + { + // Convert a mesh (V,F) to a list of CGAL triangles + // + // Templates: + // Kernal CGAL computation and construction kernel (e.g. + // CGAL::Exact_predicates_exact_constructions_kernel) + // Inputs: + // V #V by 3 list of vertex positions + // F #F by 3 list of triangle indices + // Outputs: + // T #F list of CGAL triangles + template < + typename DerivedV, + typename DerivedF, + typename Kernel> + IGL_INLINE void mesh_to_cgal_triangle_list( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + std::vector > & T); + } + } +} +#ifndef IGL_STATIC_LIBRARY +# include "mesh_to_cgal_triangle_list.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/mesh_to_polyhedron.cpp b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/mesh_to_polyhedron.cpp new file mode 100644 index 000000000..cf459795f --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/mesh_to_polyhedron.cpp @@ -0,0 +1,57 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "mesh_to_polyhedron.h" +#include +#include + +template < + typename DerivedV, + typename DerivedF, + typename Polyhedron> +IGL_INLINE bool igl::copyleft::cgal::mesh_to_polyhedron( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + Polyhedron& poly) +{ + typedef typename Polyhedron::HalfedgeDS HalfedgeDS; + // Postcondition: hds is a valid polyhedral surface. + CGAL::Polyhedron_incremental_builder_3 B(poly.hds()); + B.begin_surface(V.rows(),F.rows()); + typedef typename HalfedgeDS::Vertex Vertex; + typedef typename Vertex::Point Point; + assert(V.cols() == 3 && "V must be #V by 3"); + for(int v = 0;v +#include +#include +template bool igl::copyleft::cgal::mesh_to_polyhedron, Eigen::Matrix, CGAL::Polyhedron_3, CGAL::Polyhedron_items_with_id_3, CGAL::HalfedgeDS_default, std::allocator > >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, CGAL::Polyhedron_3, CGAL::Polyhedron_items_with_id_3, CGAL::HalfedgeDS_default, std::allocator >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/mesh_to_polyhedron.h b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/mesh_to_polyhedron.h new file mode 100644 index 000000000..9ce1ed4fb --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/mesh_to_polyhedron.h @@ -0,0 +1,45 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_COPYLEFT_CGAL_MESH_TO_POLYHEDRON_H +#define IGL_COPYLEFT_CGAL_MESH_TO_POLYHEDRON_H +#include "../../igl_inline.h" +#include + +namespace igl +{ + namespace copyleft + { + namespace cgal + { + // Convert a mesh (V,F) to a CGAL Polyhedron + // + // Templates: + // Polyhedron CGAL Polyhedron type (e.g. Polyhedron_3) + // Inputs: + // V #V by 3 list of vertex positions + // F #F by 3 list of triangle indices + // Outputs: + // poly cgal polyhedron + // Returns true only if (V,F) can be converted to a valid polyhedron (i.e. if + // (V,F) is vertex and edge manifold). + template < + typename DerivedV, + typename DerivedF, + typename Polyhedron> + IGL_INLINE bool mesh_to_polyhedron( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + Polyhedron & poly); + } + } +} +#ifndef IGL_STATIC_LIBRARY +# include "mesh_to_polyhedron.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/minkowski_sum.cpp b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/minkowski_sum.cpp new file mode 100644 index 000000000..14741212e --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/minkowski_sum.cpp @@ -0,0 +1,397 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "minkowski_sum.h" +#include "mesh_boolean.h" + +#include "../../slice.h" +#include "../../slice_mask.h" +#include "../../LinSpaced.h" +#include "../../unique_rows.h" +#include "../../get_seconds.h" +#include "../../edges.h" +#include +#include +#include +#include + + +template < + typename DerivedVA, + typename DerivedFA, + typename DerivedVB, + typename DerivedFB, + typename DerivedW, + typename DerivedG, + typename DerivedJ> +IGL_INLINE void igl::copyleft::cgal::minkowski_sum( + const Eigen::MatrixBase & VA, + const Eigen::MatrixBase & FA, + const Eigen::MatrixBase & VB, + const Eigen::MatrixBase & FB, + const bool resolve_overlaps, + Eigen::PlainObjectBase & W, + Eigen::PlainObjectBase & G, + Eigen::PlainObjectBase & J) +{ + using namespace std; + using namespace Eigen; + assert(FA.cols() == 3 && "FA must contain a closed triangle mesh"); + assert(FB.cols() <= FA.cols() && + "FB must contain lower diemnsional simplices than FA"); + const auto tictoc = []()->double + { + static double t_start; + double now = igl::get_seconds(); + double interval = now-t_start; + t_start = now; + return interval; + }; + tictoc(); + Matrix EB; + edges(FB,EB); + Matrix EA(0,2); + if(FB.cols() == 3) + { + edges(FA,EA); + } + // number of copies of A along edges of B + const int n_ab = EB.rows(); + // number of copies of B along edges of A + const int n_ba = EA.rows(); + + vector vW(n_ab + n_ba); + vector vG(n_ab + n_ba); + vector vJ(n_ab + n_ba); + vector offsets(n_ab + n_ba + 1); + offsets[0] = 0; + // sweep A along edges of B + for(int e = 0;e eJ; + minkowski_sum( + VA, + FA, + VB.row(EB(e,0)).eval(), + VB.row(EB(e,1)).eval(), + false, + vW[e], + vG[e], + eJ); + assert(vG[e].rows() == eJ.rows()); + assert(eJ.cols() == 1); + vJ[e].resize(vG[e].rows(),2); + vJ[e].col(0) = eJ; + vJ[e].col(1).setConstant(e); + offsets[e+1] = offsets[e] + vW[e].rows(); + } + // sweep B along edges of A + for(int e = 0;e eJ; + const int ee = n_ab+e; + minkowski_sum( + VB, + FB, + VA.row(EA(e,0)).eval(), + VA.row(EA(e,1)).eval(), + false, + vW[ee], + vG[ee], + eJ); + vJ[ee].resize(vG[ee].rows(),2); + vJ[ee].col(0) = eJ.array() + (FA.rows()+1); + vJ[ee].col(1).setConstant(ee); + offsets[ee+1] = offsets[ee] + vW[ee].rows(); + } + // Combine meshes + int n=0,m=0; + for_each(vW.begin(),vW.end(),[&n](const DerivedW & w){n+=w.rows();}); + for_each(vG.begin(),vG.end(),[&m](const DerivedG & g){m+=g.rows();}); + assert(n == offsets.back()); + + W.resize(n,3); + G.resize(m,3); + J.resize(m,2); + { + int m_off = 0,n_off = 0; + for(int i = 0;i SJ; + mesh_boolean( + DerivedW(W), + DerivedG(G), + Matrix(), + Matrix(), + MESH_BOOLEAN_TYPE_UNION, + W, + G, + SJ); + slice(DerivedJ(J),SJ,1,J); + } +} + +template < + typename DerivedVA, + typename DerivedFA, + typename sType, int sCols, int sOptions, + typename dType, int dCols, int dOptions, + typename DerivedW, + typename DerivedG, + typename DerivedJ> +IGL_INLINE void igl::copyleft::cgal::minkowski_sum( + const Eigen::MatrixBase & VA, + const Eigen::MatrixBase & FA, + const Eigen::Matrix & s, + const Eigen::Matrix & d, + const bool resolve_overlaps, + Eigen::PlainObjectBase & W, + Eigen::PlainObjectBase & G, + Eigen::PlainObjectBase & J) +{ + using namespace Eigen; + using namespace std; + assert(s.cols() == 3 && "s should be a 3d point"); + assert(d.cols() == 3 && "d should be a 3d point"); + // silly base case + if(FA.size() == 0) + { + W.resize(0,3); + G.resize(0,3); + return; + } + const int dim = VA.cols(); + assert(dim == 3 && "dim must be 3D"); + assert(s.size() == 3 && "s must be 3D point"); + assert(d.size() == 3 && "d must be 3D point"); + // segment vector + const CGAL::Vector_3 v(d(0)-s(0),d(1)-s(1),d(2)-s(2)); + // number of vertices + const int n = VA.rows(); + // duplicate vertices at s and d, we'll remove unreferernced later + W.resize(2*n,dim); + for(int i = 0;i P(m,1),N(m,1); + // loop over faces + int mp = 0,mn = 0; + for(int f = 0;f plane( + CGAL::Point_3(VA(FA(f,0),0),VA(FA(f,0),1),VA(FA(f,0),2)), + CGAL::Point_3(VA(FA(f,1),0),VA(FA(f,1),1),VA(FA(f,1),2)), + CGAL::Point_3(VA(FA(f,2),0),VA(FA(f,2),1),VA(FA(f,2),2))); + const auto normal = plane.orthogonal_vector(); + const auto dt = normal * v; + if(dt > 0) + { + P(f) = true; + N(f) = false; + mp++; + }else + //}else if(dt < 0) + { + P(f) = false; + N(f) = true; + mn++; + //}else + //{ + // P(f) = false; + // N(f) = false; + } + } + + typedef Matrix MatrixXI; + typedef Matrix VectorXI; + MatrixXI GT(mp+mn,3); + GT<< slice_mask(FA,N,1), slice_mask((FA.array()+n).eval(),P,1); + // J indexes FA for parts at s and m+FA for parts at d + J.derived() = igl::LinSpaced(m,0,m-1); + DerivedJ JT(mp+mn); + JT << slice_mask(J,P,1), slice_mask(J,N,1); + JT.block(mp,0,mn,1).array()+=m; + + // Original non-co-planar faces with positively oriented reversed + MatrixXI BA(mp+mn,3); + BA << slice_mask(FA,P,1).rowwise().reverse(), slice_mask(FA,N,1); + // Quads along **all** sides + MatrixXI GQ((mp+mn)*3,4); + GQ<< + BA.col(1), BA.col(0), BA.col(0).array()+n, BA.col(1).array()+n, + BA.col(2), BA.col(1), BA.col(1).array()+n, BA.col(2).array()+n, + BA.col(0), BA.col(2), BA.col(2).array()+n, BA.col(0).array()+n; + + MatrixXI uGQ; + VectorXI S,sI,sJ; + // Inputs: + // F #F by d list of polygons + // Outputs: + // S #uF list of signed incidences for each unique face + // uF #uF by d list of unique faces + // I #uF index vector so that uF = sort(F,2)(I,:) + // J #F index vector so that sort(F,2) = uF(J,:) + []( + const MatrixXI & F, + VectorXI & S, + MatrixXI & uF, + VectorXI & I, + VectorXI & J) + { + const int m = F.rows(); + const int d = F.cols(); + MatrixXI sF = F; + const auto MN = sF.rowwise().minCoeff().eval(); + // rotate until smallest index is first + for(int p = 0;p M = Matrix::Zero(m,1); + { + VectorXI P = igl::LinSpaced(d,0,d-1); + for(int p = 0;p SJ; + mesh_boolean( + DerivedW(W),DerivedG(G), + Matrix(),MatrixXI(), + MESH_BOOLEAN_TYPE_UNION, + W,G,SJ); + J.derived() = slice(DerivedJ(J),SJ,1); + } +} + +template < + typename DerivedVA, + typename DerivedFA, + typename sType, int sCols, int sOptions, + typename dType, int dCols, int dOptions, + typename DerivedW, + typename DerivedG, + typename DerivedJ> +IGL_INLINE void igl::copyleft::cgal::minkowski_sum( + const Eigen::MatrixBase & VA, + const Eigen::MatrixBase & FA, + const Eigen::Matrix & s, + const Eigen::Matrix & d, + Eigen::PlainObjectBase & W, + Eigen::PlainObjectBase & G, + Eigen::PlainObjectBase & J) +{ + return minkowski_sum(VA,FA,s,d,true,W,G,J); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::copyleft::cgal::minkowski_sum, Eigen::Matrix, double, 3, 1, double, 3, 1, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::Matrix const&, Eigen::Matrix const&, bool, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::copyleft::cgal::minkowski_sum, -1, -1, 1, -1, -1>, Eigen::Matrix, CGAL::Lazy_exact_nt, 3, 1, CGAL::Lazy_exact_nt, 3, 1, Eigen::Matrix, -1, -1, 1, -1, -1>, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase > const&, Eigen::Matrix, 1, 3, 1, 1, 3> const&, Eigen::Matrix, 1, 3, 1, 1, 3> const&, bool, Eigen::PlainObjectBase, -1, -1, 1, -1, -1> >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::copyleft::cgal::minkowski_sum< + Eigen::Matrix, + Eigen::Matrix, + double, 3, 1, + float, 3, 1, + Eigen::Matrix, -1, -1, 1, -1, -1>, + Eigen::Matrix, + Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::Matrix const&, Eigen::Matrix const&, bool, Eigen::PlainObjectBase, -1, -1, 1, -1, -1> >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/minkowski_sum.h b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/minkowski_sum.h new file mode 100644 index 000000000..1631f0766 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/minkowski_sum.h @@ -0,0 +1,110 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_COPYLEFT_CGAL_MINKOWSKI_SUM_H +#define IGL_COPYLEFT_CGAL_MINKOWSKI_SUM_H + +#include "../../igl_inline.h" +#include + +namespace igl +{ + namespace copyleft + { + namespace cgal + { + // Compute the Minkowski sum of a closed triangle mesh (V,F) and a + // set of simplices in 3D. + // + // Inputs: + // VA #VA by 3 list of mesh vertices in 3D + // FA #FA by 3 list of triangle indices into VA + // VB #VB by 3 list of mesh vertices in 3D + // FB #FB by ss list of simplex indices into VB, ss<=3 + // resolve_overlaps whether or not to resolve self-union. If false + // then result may contain self-intersections if input mesh is + // non-convex. + // Outputs: + // W #W by 3 list of mesh vertices in 3D + // G #G by 3 list of triangle indices into W + // J #G by 2 list of indices into + // + template < + typename DerivedVA, + typename DerivedFA, + typename DerivedVB, + typename DerivedFB, + typename DerivedW, + typename DerivedG, + typename DerivedJ> + IGL_INLINE void minkowski_sum( + const Eigen::MatrixBase & VA, + const Eigen::MatrixBase & FA, + const Eigen::MatrixBase & VB, + const Eigen::MatrixBase & FB, + const bool resolve_overlaps, + Eigen::PlainObjectBase & W, + Eigen::PlainObjectBase & G, + Eigen::PlainObjectBase & J); + // Compute the Minkowski sum of a closed triangle mesh (V,F) and a + // segment [s,d] in 3D. + // + // Inputs: + // VA #VA by 3 list of mesh vertices in 3D + // FA #FA by 3 list of triangle indices into VA + // s segment source endpoint in 3D + // d segment source endpoint in 3D + // resolve_overlaps whether or not to resolve self-union. If false + // then result may contain self-intersections if input mesh is + // non-convex. + // Outputs: + // W #W by 3 list of mesh vertices in 3D + // G #G by 3 list of triangle indices into W + // J #G list of indices into [F;#V+F;[s d]] of birth parents + // + template < + typename DerivedVA, + typename DerivedFA, + typename sType, int sCols, int sOptions, + typename dType, int dCols, int dOptions, + typename DerivedW, + typename DerivedG, + typename DerivedJ> + IGL_INLINE void minkowski_sum( + const Eigen::MatrixBase & VA, + const Eigen::MatrixBase & FA, + const Eigen::Matrix & s, + const Eigen::Matrix & d, + const bool resolve_overlaps, + Eigen::PlainObjectBase & W, + Eigen::PlainObjectBase & G, + Eigen::PlainObjectBase & J); + template < + typename DerivedVA, + typename DerivedFA, + typename sType, int sCols, int sOptions, + typename dType, int dCols, int dOptions, + typename DerivedW, + typename DerivedG, + typename DerivedJ> + IGL_INLINE void minkowski_sum( + const Eigen::MatrixBase & VA, + const Eigen::MatrixBase & FA, + const Eigen::Matrix & s, + const Eigen::Matrix & d, + Eigen::PlainObjectBase & W, + Eigen::PlainObjectBase & G, + Eigen::PlainObjectBase & J); + } + } +} + +#ifndef IGL_STATIC_LIBRARY +# include "minkowski_sum.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/order_facets_around_edge.cpp b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/order_facets_around_edge.cpp new file mode 100644 index 000000000..13b585b50 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/order_facets_around_edge.cpp @@ -0,0 +1,428 @@ +#include "order_facets_around_edge.h" +#include +#include + +#include + +// adj_faces contains signed index starting from +- 1. +template< + typename DerivedV, + typename DerivedF, + typename DerivedI > +void igl::copyleft::cgal::order_facets_around_edge( + const Eigen::PlainObjectBase& V, + const Eigen::PlainObjectBase& F, + size_t s, + size_t d, + const std::vector& adj_faces, + Eigen::PlainObjectBase& order, bool debug) +{ + // Although we only need exact predicates in the algorithm, + // exact constructions are needed to avoid degeneracies due to + // casting to double. + typedef CGAL::Exact_predicates_exact_constructions_kernel K; + typedef K::Point_3 Point_3; + typedef K::Plane_3 Plane_3; + + auto get_face_index = [&](int adj_f)->size_t + { + return abs(adj_f) - 1; + }; + + auto get_opposite_vertex = [&](size_t fid)->size_t + { + typedef typename DerivedF::Scalar Index; + if (F(fid, 0) != (Index)s && F(fid, 0) != (Index)d) return F(fid, 0); + if (F(fid, 1) != (Index)s && F(fid, 1) != (Index)d) return F(fid, 1); + if (F(fid, 2) != (Index)s && F(fid, 2) != (Index)d) return F(fid, 2); + assert(false); + return -1; + }; + + // Handle base cases + if (adj_faces.size() == 0) + { + order.resize(0, 1); + return; + } else if (adj_faces.size() == 1) + { + order.resize(1, 1); + order(0, 0) = 0; + return; + } else if (adj_faces.size() == 2) + { + const size_t o1 = get_opposite_vertex(get_face_index(adj_faces[0])); + const size_t o2 = get_opposite_vertex(get_face_index(adj_faces[1])); + const Point_3 ps(V(s, 0), V(s, 1), V(s, 2)); + const Point_3 pd(V(d, 0), V(d, 1), V(d, 2)); + const Point_3 p1(V(o1, 0), V(o1, 1), V(o1, 2)); + const Point_3 p2(V(o2, 0), V(o2, 1), V(o2, 2)); + order.resize(2, 1); + switch (CGAL::orientation(ps, pd, p1, p2)) + { + case CGAL::POSITIVE: + order(0, 0) = 1; + order(1, 0) = 0; + break; + case CGAL::NEGATIVE: + order(0, 0) = 0; + order(1, 0) = 1; + break; + case CGAL::COPLANAR: + { + switch (CGAL::coplanar_orientation(ps, pd, p1, p2)) { + case CGAL::POSITIVE: + // Duplicated face, use index to break tie. + order(0, 0) = adj_faces[0] < adj_faces[1] ? 0:1; + order(1, 0) = adj_faces[0] < adj_faces[1] ? 1:0; + break; + case CGAL::NEGATIVE: + // Coplanar faces, one on each side of the edge. + // It is equally valid to order them (0, 1) or (1, 0). + // I cannot think of any reason to prefer one to the + // other. So just use (0, 1) ordering by default. + order(0, 0) = 0; + order(1, 0) = 1; + break; + case CGAL::COLLINEAR: + std::cerr << "Degenerated triangle detected." << + std::endl; + assert(false); + break; + default: + assert(false); + } + } + break; + default: + assert(false); + } + return; + } + + const size_t num_adj_faces = adj_faces.size(); + const size_t o = get_opposite_vertex( get_face_index(adj_faces[0])); + const Point_3 p_s(V(s, 0), V(s, 1), V(s, 2)); + const Point_3 p_d(V(d, 0), V(d, 1), V(d, 2)); + const Point_3 p_o(V(o, 0), V(o, 1), V(o, 2)); + const Plane_3 separator(p_s, p_d, p_o); + if (separator.is_degenerate()) { + throw std::runtime_error( + "Cannot order facets around edge due to degenerated facets"); + } + + std::vector opposite_vertices; + for (size_t i=0; i positive_side; + std::vector negative_side; + std::vector tie_positive_oriented; + std::vector tie_negative_oriented; + + std::vector positive_side_index; + std::vector negative_side_index; + std::vector tie_positive_oriented_index; + std::vector tie_negative_oriented_index; + + for (size_t i=0; i& data) -> std::vector{ + const size_t len = data.size(); + std::vector order(len); + for (size_t i=0; i tie_positive_order = index_sort(tie_positive_oriented); + std::vector tie_negative_order = index_sort(tie_negative_oriented); + + // Copy results into order vector. + const size_t tie_positive_size = tie_positive_oriented.size(); + const size_t tie_negative_size = tie_negative_oriented.size(); + const size_t positive_size = positive_order.size(); + const size_t negative_size = negative_order.size(); + + order.resize( + tie_positive_size + positive_size + tie_negative_size + negative_size,1); + + size_t count=0; + for (size_t i=0; i +IGL_INLINE +void igl::copyleft::cgal::order_facets_around_edge( + const Eigen::PlainObjectBase& V, + const Eigen::PlainObjectBase& F, + size_t s, + size_t d, + const std::vector& adj_faces, + const Eigen::PlainObjectBase& pivot_point, + Eigen::PlainObjectBase& order) +{ + assert(V.cols() == 3); + assert(F.cols() == 3); + assert(pivot_point.cols() == 3); + auto signed_index_to_index = [&](int signed_idx) + { + return abs(signed_idx) -1; + }; + auto get_opposite_vertex_index = [&](size_t fid) -> typename DerivedF::Scalar + { + typedef typename DerivedF::Scalar Index; + if (F(fid, 0) != (Index)s && F(fid, 0) != (Index)d) return F(fid, 0); + if (F(fid, 1) != (Index)s && F(fid, 1) != (Index)d) return F(fid, 1); + if (F(fid, 2) != (Index)s && F(fid, 2) != (Index)d) return F(fid, 2); + assert(false); + // avoid warning + return -1; + }; + + { + // Check if s, d and pivot are collinear. + typedef CGAL::Exact_predicates_exact_constructions_kernel K; + K::Point_3 ps(V(s,0), V(s,1), V(s,2)); + K::Point_3 pd(V(d,0), V(d,1), V(d,2)); + K::Point_3 pp(pivot_point(0,0), pivot_point(0,1), pivot_point(0,2)); + if (CGAL::collinear(ps, pd, pp)) { + throw std::runtime_error( + "Pivot point is collinear with the outer edge!"); + } + } + + const size_t N = adj_faces.size(); + const size_t num_faces = N + 1; // N adj faces + 1 pivot face + + // Because face indices are used for tie breaking, the original face indices + // in the new faces array must be ascending. + auto comp = [&](int i, int j) + { + return signed_index_to_index(adj_faces[i]) < + signed_index_to_index(adj_faces[j]); + }; + std::vector adj_order(N); + for (size_t i=0; i adj_faces_with_pivot(num_faces); + for (size_t i=0; i, -1, -1, 1, -1, -1>, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase > const&, unsigned long, unsigned long, std::vector > const&, Eigen::PlainObjectBase, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::copyleft::cgal::order_facets_around_edge, -1, -1, 1, -1, -1>, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase > const&, unsigned long, unsigned long, std::vector > const&, Eigen::PlainObjectBase >&, bool); +// generated by autoexplicit.sh +template void igl::copyleft::cgal::order_facets_around_edge, -1, -1, 1, -1, -1>, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase > const&, unsigned long, unsigned long, std::vector > const&, Eigen::PlainObjectBase, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::copyleft::cgal::order_facets_around_edge, -1, -1, 1, -1, -1>, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase > const&, unsigned long, unsigned long, std::vector > const&, Eigen::PlainObjectBase >&, bool); +template void igl::copyleft::cgal::order_facets_around_edge, -1, 3, 0, -1, 3>, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase > const&, unsigned long, unsigned long, std::vector > const&, Eigen::PlainObjectBase >&, bool); +template void igl::copyleft::cgal::order_facets_around_edge, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, unsigned long, unsigned long, std::vector > const&, Eigen::PlainObjectBase >&, bool); +template void igl::copyleft::cgal::order_facets_around_edge, -1, 3, 0, -1, 3>, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase > const&, unsigned long, unsigned long, std::vector > const&, Eigen::PlainObjectBase, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase >&); +template void igl::copyleft::cgal::order_facets_around_edge, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, unsigned long, unsigned long, std::vector > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&); +template void igl::copyleft::cgal::order_facets_around_edge, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, unsigned long, unsigned long, std::vector > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&); +template void igl::copyleft::cgal::order_facets_around_edge, -1, -1, 0, -1, -1>, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase > const&, unsigned long, unsigned long, std::vector > const&, Eigen::PlainObjectBase, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase >&); +#ifdef WIN32 +template void igl::copyleft::cgal::order_facets_around_edge, -1, -1, 0, -1, -1>, class Eigen::Matrix, class Eigen::Matrix>(class Eigen::PlainObjectBase, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase> const &, unsigned __int64, unsigned __int64, class std::vector> const &, class Eigen::PlainObjectBase, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase> &); +template void igl::copyleft::cgal::order_facets_around_edge, -1, -1, 0, -1, -1>, class Eigen::Matrix, class Eigen::Matrix>(class Eigen::PlainObjectBase, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase> const &, unsigned __int64, unsigned __int64, class std::vector> const &, class Eigen::PlainObjectBase> &, bool); +template void igl::copyleft::cgal::order_facets_around_edge, -1, -1, 1, -1, -1>, class Eigen::Matrix, class Eigen::Matrix>(class Eigen::PlainObjectBase, -1, -1, 1, -1, -1>> const &, class Eigen::PlainObjectBase> const &, unsigned __int64, unsigned __int64, class std::vector> const &, class Eigen::PlainObjectBase, -1, -1, 1, -1, -1>> const &, class Eigen::PlainObjectBase> &); +template void igl::copyleft::cgal::order_facets_around_edge, -1, -1, 1, -1, -1>, class Eigen::Matrix, class Eigen::Matrix>(class Eigen::PlainObjectBase, -1, -1, 1, -1, -1>> const &, class Eigen::PlainObjectBase> const &, unsigned __int64, unsigned __int64, class std::vector> const &, class Eigen::PlainObjectBase> &, bool); +template void igl::copyleft::cgal::order_facets_around_edge, -1, -1, 1, -1, -1>, class Eigen::Matrix, class Eigen::Matrix>(class Eigen::PlainObjectBase, -1, -1, 1, -1, -1>> const &, class Eigen::PlainObjectBase> const &, unsigned __int64, unsigned __int64, class std::vector> const &, class Eigen::PlainObjectBase, -1, -1, 1, -1, -1>> const &, class Eigen::PlainObjectBase> &); +template void igl::copyleft::cgal::order_facets_around_edge, -1, -1, 1, -1, -1>, class Eigen::Matrix, class Eigen::Matrix>(class Eigen::PlainObjectBase, -1, -1, 1, -1, -1>> const &, class Eigen::PlainObjectBase> const &, unsigned __int64, unsigned __int64, class std::vector> const &, class Eigen::PlainObjectBase> &, bool); +template void igl::copyleft::cgal::order_facets_around_edge, -1, 3, 0, -1, 3>, class Eigen::Matrix, class Eigen::Matrix>(class Eigen::PlainObjectBase, -1, 3, 0, -1, 3>> const &, class Eigen::PlainObjectBase> const &, unsigned __int64, unsigned __int64, class std::vector> const &, class Eigen::PlainObjectBase, -1, 3, 0, -1, 3>> const &, class Eigen::PlainObjectBase> &); +template void igl::copyleft::cgal::order_facets_around_edge, class Eigen::Matrix, class Eigen::Matrix>(class Eigen::PlainObjectBase> const &, class Eigen::PlainObjectBase> const &, unsigned __int64, unsigned __int64, class std::vector> const &, class Eigen::PlainObjectBase> const &, class Eigen::PlainObjectBase> &); +template void igl::copyleft::cgal::order_facets_around_edge, class Eigen::Matrix, class Eigen::Matrix>(class Eigen::PlainObjectBase> const &, class Eigen::PlainObjectBase> const &, unsigned __int64, unsigned __int64, class std::vector> const &, class Eigen::PlainObjectBase> const &, class Eigen::PlainObjectBase> &); +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/order_facets_around_edge.h b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/order_facets_around_edge.h new file mode 100644 index 000000000..6e09129ac --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/order_facets_around_edge.h @@ -0,0 +1,77 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Qingnan Zhou +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +// +#ifndef IGL_COPYLEFT_CGAL_ORDER_FACETS_AROUND_EDGE_H +#define IGL_COPYLEFT_CGAL_ORDER_FACETS_AROUND_EDGE_H +#include "../../igl_inline.h" +#include +#include + +namespace igl +{ + namespace copyleft + { + namespace cgal + { + // Given a directed edge, sort its adjacent faces. Assuming the + // directed edge is (s, d). Sort the adjacent faces clockwise around the + // axis (d - s), i.e. left-hand rule. An adjacent face is consistently + // oriented if it contains (d, s) as a directed edge. + // + // For overlapping faces, break the tie using signed face index, smaller + // signed index comes before the larger signed index. Signed index is + // computed as (consistent? 1:-1) * (face_index + 1). + // + // Inputs: + // V #V by 3 list of vertices. + // F #F by 3 list of faces + // s Index of source vertex. + // d Index of destination vertex. + // adj_faces List of adjacent face signed indices. + // Output: + // order List of face indices that orders adjacent faces around edge + // (s, d) clockwise. + template< + typename DerivedV, + typename DerivedF, + typename DerivedI > + IGL_INLINE + void order_facets_around_edge( + const Eigen::PlainObjectBase& V, + const Eigen::PlainObjectBase& F, + size_t s, + size_t d, + const std::vector& adj_faces, + Eigen::PlainObjectBase& order, + bool debug=false); + + // This function is a wrapper around the one above. Since the ordering + // is circular, the pivot point is used to define a starting point. So + // order[0] is the index into adj_face that is immediately after the + // pivot face (s, d, pivot point) in clockwise order. + template< + typename DerivedV, + typename DerivedF, + typename DerivedI> + IGL_INLINE + void order_facets_around_edge( + const Eigen::PlainObjectBase& V, + const Eigen::PlainObjectBase& F, + size_t s, + size_t d, + const std::vector& adj_faces, + const Eigen::PlainObjectBase& pivot_point, + Eigen::PlainObjectBase& order); + } + } +} + +#ifndef IGL_STATIC_LIBRARY +#include "order_facets_around_edge.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/order_facets_around_edges.cpp b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/order_facets_around_edges.cpp new file mode 100644 index 000000000..a7d45b8df --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/order_facets_around_edges.cpp @@ -0,0 +1,337 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "order_facets_around_edges.h" +#include "order_facets_around_edge.h" +#include "../../sort_angles.h" +#include +#include +#include + +template< + typename DerivedV, + typename DerivedF, + typename DerivedN, + typename DeriveduE, + typename uE2EType, + typename uE2oEType, + typename uE2CType > +IGL_INLINE +typename std::enable_if::value, void>::type +igl::copyleft::cgal::order_facets_around_edges( + const Eigen::PlainObjectBase& V, + const Eigen::PlainObjectBase& F, + const Eigen::PlainObjectBase& N, + const Eigen::PlainObjectBase& uE, + const std::vector >& uE2E, + std::vector >& uE2oE, + std::vector >& uE2C ) { + + typedef Eigen::Matrix Vector3F; + const typename DerivedV::Scalar EPS = 1e-12; + const size_t num_faces = F.rows(); + const size_t num_undirected_edges = uE.rows(); + + auto edge_index_to_face_index = [&](size_t ei) { return ei % num_faces; }; + auto edge_index_to_corner_index = [&](size_t ei) { return ei / num_faces; }; + + uE2oE.resize(num_undirected_edges); + uE2C.resize(num_undirected_edges); + + for(size_t ui = 0;ui 0); + + const auto ref_edge = adj_edges[0]; + const auto ref_face = edge_index_to_face_index(ref_edge); + Vector3F ref_normal = N.row(ref_face); + + const auto ref_corner_o = edge_index_to_corner_index(ref_edge); + const auto ref_corner_s = (ref_corner_o+1)%3; + const auto ref_corner_d = (ref_corner_o+2)%3; + + const typename DerivedF::Scalar o = F(ref_face, ref_corner_o); + const typename DerivedF::Scalar s = F(ref_face, ref_corner_s); + const typename DerivedF::Scalar d = F(ref_face, ref_corner_d); + + Vector3F edge = V.row(d) - V.row(s); + auto edge_len = edge.norm(); + bool degenerated = edge_len < EPS; + if (degenerated) { + if (edge_valance <= 2) { + // There is only one way to order 2 or less faces. + edge.setZero(); + } else { + edge.setZero(); + Eigen::Matrix + normals(edge_valance, 3); + for (size_t fei=0; fei= EPS) { + edge.normalize(); + break; + } + } + + // Ensure edge direction are consistent with reference face. + Vector3F in_face_vec = V.row(o) - V.row(s); + if (edge.cross(in_face_vec).dot(ref_normal) < 0) { + edge *= -1; + } + + if (edge.norm() < EPS) { + std::cerr << "=====================================" << std::endl; + std::cerr << " ui: " << ui << std::endl; + std::cerr << "edge: " << ref_edge << std::endl; + std::cerr << "face: " << ref_face << std::endl; + std::cerr << " vs: " << V.row(s) << std::endl; + std::cerr << " vd: " << V.row(d) << std::endl; + std::cerr << "adj face normals: " << std::endl; + std::cerr << normals << std::endl; + std::cerr << "Very degenerated case detected:" << std::endl; + std::cerr << "Near zero edge surrounded by " + << edge_valance << " neearly colinear faces" << + std::endl; + std::cerr << "=====================================" << std::endl; + } + } + } else { + edge.normalize(); + } + + Eigen::MatrixXd angle_data(edge_valance, 3); + std::vector cons(edge_valance); + + for (size_t fei=0; fei +IGL_INLINE +typename std::enable_if::value, void>::type +igl::copyleft::cgal::order_facets_around_edges( + const Eigen::PlainObjectBase& V, + const Eigen::PlainObjectBase& F, + const Eigen::PlainObjectBase& N, + const Eigen::PlainObjectBase& uE, + const std::vector >& uE2E, + std::vector >& uE2oE, + std::vector >& uE2C ) { + + typedef Eigen::Matrix Vector3F; + typedef Eigen::Matrix Vector3E; + const typename DerivedV::Scalar EPS = 1e-12; + const size_t num_faces = F.rows(); + const size_t num_undirected_edges = uE.rows(); + + auto edge_index_to_face_index = [&](size_t ei) { return ei % num_faces; }; + auto edge_index_to_corner_index = [&](size_t ei) { return ei / num_faces; }; + + uE2oE.resize(num_undirected_edges); + uE2C.resize(num_undirected_edges); + + for(size_t ui = 0;ui 0); + + const auto ref_edge = adj_edges[0]; + const auto ref_face = edge_index_to_face_index(ref_edge); + Vector3F ref_normal = N.row(ref_face); + + const auto ref_corner_o = edge_index_to_corner_index(ref_edge); + const auto ref_corner_s = (ref_corner_o+1)%3; + const auto ref_corner_d = (ref_corner_o+2)%3; + + const typename DerivedF::Scalar o = F(ref_face, ref_corner_o); + const typename DerivedF::Scalar s = F(ref_face, ref_corner_s); + const typename DerivedF::Scalar d = F(ref_face, ref_corner_d); + + Vector3E exact_edge = V.row(d) - V.row(s); + exact_edge.array() /= exact_edge.squaredNorm(); + Vector3F edge( + CGAL::to_double(exact_edge[0]), + CGAL::to_double(exact_edge[1]), + CGAL::to_double(exact_edge[2])); + edge.normalize(); + + Eigen::MatrixXd angle_data(edge_valance, 3); + std::vector cons(edge_valance); + + for (size_t fei=0; fei +IGL_INLINE void igl::copyleft::cgal::order_facets_around_edges( + const Eigen::PlainObjectBase& V, + const Eigen::PlainObjectBase& F, + const Eigen::PlainObjectBase& uE, + const std::vector >& uE2E, + std::vector >& uE2oE, + std::vector >& uE2C ) { + + //typedef Eigen::Matrix Vector3E; + const size_t num_faces = F.rows(); + const size_t num_undirected_edges = uE.rows(); + + auto edge_index_to_face_index = [&](size_t ei) { return ei % num_faces; }; + auto edge_index_to_corner_index = [&](size_t ei) { return ei / num_faces; }; + + uE2oE.resize(num_undirected_edges); + uE2C.resize(num_undirected_edges); + + for(size_t ui = 0;ui 0); + + const auto ref_edge = adj_edges[0]; + const auto ref_face = edge_index_to_face_index(ref_edge); + + const auto ref_corner_o = edge_index_to_corner_index(ref_edge); + const auto ref_corner_s = (ref_corner_o+1)%3; + const auto ref_corner_d = (ref_corner_o+2)%3; + + //const typename DerivedF::Scalar o = F(ref_face, ref_corner_o); + const typename DerivedF::Scalar s = F(ref_face, ref_corner_s); + const typename DerivedF::Scalar d = F(ref_face, ref_corner_d); + + std::vector cons(edge_valance); + std::vector adj_faces(edge_valance); + for (size_t fei=0; fei, Eigen::Matrix, Eigen::Matrix, int, int, bool>(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, std::vector >, std::allocator > > > const&, std::vector >, std::allocator > > >&, std::vector >, std::allocator > > >&); +// generated by autoexplicit.sh +template std::enable_if::Scalar, CGAL::Lazy_exact_nt >::value), void>::type igl::copyleft::cgal::order_facets_around_edges, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, int, int, bool>(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, std::vector >, std::allocator > > > const&, std::vector >, std::allocator > > >&, std::vector >, std::allocator > > >&); +template void igl::copyleft::cgal::order_facets_around_edges, -1, 3, 0, -1, 3>, Eigen::Matrix, Eigen::Matrix, long, long, bool>(Eigen::PlainObjectBase, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, std::vector >, std::allocator > > > const&, std::vector >, std::allocator > > >&, std::vector >, std::allocator > > >&); +template void igl::copyleft::cgal::order_facets_around_edges, Eigen::Matrix, Eigen::Matrix, long, long, bool>(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, std::vector >, std::allocator > > > const&, std::vector >, std::allocator > > >&, std::vector >, std::allocator > > >&); +template void igl::copyleft::cgal::order_facets_around_edges, Eigen::Matrix, Eigen::Matrix, long, long, bool>(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, std::vector >, std::allocator > > > const&, std::vector >, std::allocator > > >&, std::vector >, std::allocator > > >&); +template void igl::copyleft::cgal::order_facets_around_edges, -1, -1, 0, -1, -1>, Eigen::Matrix, Eigen::Matrix, long, long, bool>(Eigen::PlainObjectBase, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, std::vector >, std::allocator > > > const&, std::vector >, std::allocator > > >&, std::vector >, std::allocator > > >&); +#ifdef WIN32 +template void igl::copyleft::cgal::order_facets_around_edges,-1,-1,0,-1,-1>,class Eigen::Matrix,class Eigen::Matrix,__int64,__int64,bool>(class Eigen::PlainObjectBase,-1,-1,0,-1,-1> > const &,class Eigen::PlainObjectBase > const &,class Eigen::PlainObjectBase > const &,class std::vector >,class std::allocator > > > const &,class std::vector >,class std::allocator > > > &,class std::vector >,class std::allocator > > > &); +template void igl::copyleft::cgal::order_facets_around_edges,class Eigen::Matrix,class Eigen::Matrix,__int64,__int64,bool>(class Eigen::PlainObjectBase > const &,class Eigen::PlainObjectBase > const &,class Eigen::PlainObjectBase > const &,class std::vector >,class std::allocator > > > const &,class std::vector >,class std::allocator > > > &,class std::vector >,class std::allocator > > > &); +template void igl::copyleft::cgal::order_facets_around_edges,class Eigen::Matrix,class Eigen::Matrix,__int64,__int64,bool>(class Eigen::PlainObjectBase > const &,class Eigen::PlainObjectBase > const &,class Eigen::PlainObjectBase > const &,class std::vector >,class std::allocator > > > const &,class std::vector >,class std::allocator > > > &,class std::vector >,class std::allocator > > > &); +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/order_facets_around_edges.h b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/order_facets_around_edges.h new file mode 100644 index 000000000..89ac2918e --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/order_facets_around_edges.h @@ -0,0 +1,107 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_COPYLEFT_CGAL_ORDER_FACETS_AROUND_EDGES_H +#define IGL_COPYLEFT_CGAL_ORDER_FACETS_AROUND_EDGES_H +#include "../../igl_inline.h" +#include +#include +#include + +namespace igl +{ + namespace copyleft + { + namespace cgal + { + // For each undirected edge, sort its adjacent faces. Assuming the + // undirected edge is (s, d). Sort the adjacent faces clockwise around the + // axis (d - s), i.e. left-hand rule. An adjacent face is consistently + // oriented if it contains (d, s) as a directed edge. + // + // For overlapping faces, break the tie using signed face index, smaller + // signed index comes before the larger signed index. Signed index is + // computed as (consistent? 1:-1) * index. + // + // Inputs: + // V #V by 3 list of vertices. + // F #F by 3 list of faces + // N #F by 3 list of face normals. + // uE #uE by 2 list of vertex_indices, represents undirected edges. + // uE2E #uE list of lists that maps uE to E. (a one-to-many map) + // + // Outputs: + // uE2oE #uE list of lists that maps uE to an ordered list of E. (a + // one-to-many map) + // uE2C #uE list of lists of bools indicates whether each face in + // uE2oE[i] is consistently orientated as the ordering. + // + template< + typename DerivedV, + typename DerivedF, + typename DerivedN, + typename DeriveduE, + typename uE2EType, + typename uE2oEType, + typename uE2CType > + IGL_INLINE + typename std::enable_if::value, void>::type + order_facets_around_edges( + const Eigen::PlainObjectBase& V, + const Eigen::PlainObjectBase& F, + const Eigen::PlainObjectBase& N, + const Eigen::PlainObjectBase& uE, + const std::vector >& uE2E, + std::vector >& uE2oE, + std::vector >& uE2C ); + + template< + typename DerivedV, + typename DerivedF, + typename DerivedN, + typename DeriveduE, + typename uE2EType, + typename uE2oEType, + typename uE2CType > + IGL_INLINE + typename std::enable_if::value, void>::type + order_facets_around_edges( + const Eigen::PlainObjectBase& V, + const Eigen::PlainObjectBase& F, + const Eigen::PlainObjectBase& N, + const Eigen::PlainObjectBase& uE, + const std::vector >& uE2E, + std::vector >& uE2oE, + std::vector >& uE2C ); + + // Order faces around each edge. Only exact predicate is used in the algorithm. + // Normal is not needed. + template< + typename DerivedV, + typename DerivedF, + typename DeriveduE, + typename uE2EType, + typename uE2oEType, + typename uE2CType > + IGL_INLINE void order_facets_around_edges( + const Eigen::PlainObjectBase& V, + const Eigen::PlainObjectBase& F, + const Eigen::PlainObjectBase& uE, + const std::vector >& uE2E, + std::vector >& uE2oE, + std::vector >& uE2C ); + } + } +} + +#ifndef IGL_STATIC_LIBRARY +#include "order_facets_around_edges.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/orient2D.cpp b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/orient2D.cpp new file mode 100644 index 000000000..6e6cfe649 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/orient2D.cpp @@ -0,0 +1,47 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Qingan Zhou +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +#include "orient2D.h" +#include +#include + +template +IGL_INLINE short igl::copyleft::cgal::orient2D( + const Scalar *pa, + const Scalar *pb, + const Scalar *pc) +{ + typedef CGAL::Exact_predicates_exact_constructions_kernel Epeck; + typedef CGAL::Exact_predicates_inexact_constructions_kernel Epick; + typedef typename std::conditional::value, + Epeck, Epick>::type Kernel; + + switch(CGAL::orientation( + typename Kernel::Point_2(pa[0], pa[1]), + typename Kernel::Point_2(pb[0], pb[1]), + typename Kernel::Point_2(pc[0], pc[1]))) + { + case CGAL::LEFT_TURN: + return 1; + case CGAL::RIGHT_TURN: + return -1; + case CGAL::COLLINEAR: + return 0; + default: + throw "Invalid orientation"; + } +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template short igl::copyleft::cgal::orient2D(double const*, double const*, double const*); +#ifdef WIN32 +template short igl::copyleft::cgal::orient2D(double const * const, double const * const, double const * const); +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/orient2D.h b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/orient2D.h new file mode 100644 index 000000000..6f816aa66 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/orient2D.h @@ -0,0 +1,38 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Qingan Zhou +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef IGL_COPYLEFT_CGAL_ORIENT_2D_H +#define IGL_COPYLEFT_CGAL_ORIENT_2D_H + +#include "../../igl_inline.h" + +namespace igl +{ + namespace copyleft + { + namespace cgal + { + // Inputs: + // pa,pb,pc 2D points. + // Output: + // 1 if pa,pb,pc are counterclockwise oriented. + // 0 if pa,pb,pc are collinear. + // -1 if pa,pb,pc are clockwise oriented. + template + IGL_INLINE short orient2D( + const Scalar *pa, + const Scalar *pb, + const Scalar *pc); + } + } +} + +#ifndef IGL_STATIC_LIBRARY +# include "orient2D.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/orient3D.cpp b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/orient3D.cpp new file mode 100644 index 000000000..3bdbfb80e --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/orient3D.cpp @@ -0,0 +1,39 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Qingan Zhou +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +#include "orient3D.h" +#include +#include + +template +IGL_INLINE short igl::copyleft::cgal::orient3D( + const Scalar pa[3], + const Scalar pb[3], + const Scalar pc[3], + const Scalar pd[3]) +{ + typedef CGAL::Exact_predicates_exact_constructions_kernel Epeck; + typedef CGAL::Exact_predicates_inexact_constructions_kernel Epick; + typedef typename std::conditional::value, + Epeck, Epick>::type Kernel; + + switch(CGAL::orientation( + typename Kernel::Point_3(pa[0], pa[1], pa[2]), + typename Kernel::Point_3(pb[0], pb[1], pb[2]), + typename Kernel::Point_3(pc[0], pc[1], pc[2]), + typename Kernel::Point_3(pd[0], pd[1], pd[2]))) { + case CGAL::POSITIVE: + return 1; + case CGAL::NEGATIVE: + return -1; + case CGAL::COPLANAR: + return 0; + default: + throw "Invalid orientation"; + } +} diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/orient3D.h b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/orient3D.h new file mode 100644 index 000000000..029e208b1 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/orient3D.h @@ -0,0 +1,39 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Qingan Zhou +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef IGL_COPYLEFT_CGAL_ORIENT_3D_H +#define IGL_COPYLEFT_CGAL_ORIENT_3D_H + +#include "../../igl_inline.h" + +namespace igl +{ + namespace copyleft + { + namespace cgal + { + // Inputs: + // pa,pb,pc,pd 3D points. + // Output: + // 1 if pa,pb,pc,pd forms a tet of positive volume. + // 0 if pa,pb,pc,pd are coplanar. + // -1 if pa,pb,pc,pd forms a tet of negative volume. + template + IGL_INLINE short orient3D( + const Scalar pa[3], + const Scalar pb[3], + const Scalar pc[3], + const Scalar pd[3]); + } + } +} + +#ifndef IGL_STATIC_LIBRARY +# include "orient3D.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/outer_element.cpp b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/outer_element.cpp new file mode 100644 index 000000000..cdf8a35cf --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/outer_element.cpp @@ -0,0 +1,234 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Qingnan Zhou +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "outer_element.h" +#include +#include + +template < + typename DerivedV, + typename DerivedF, + typename DerivedI, + typename IndexType, + typename DerivedA + > +IGL_INLINE void igl::copyleft::cgal::outer_vertex( + const Eigen::PlainObjectBase & V, + const Eigen::PlainObjectBase & F, + const Eigen::PlainObjectBase & I, + IndexType & v_index, + Eigen::PlainObjectBase & A) +{ + // Algorithm: + // Find an outer vertex (i.e. vertex reachable from infinity) + // Return the vertex with the largest X value. + // If there is a tie, pick the one with largest Y value. + // If there is still a tie, pick the one with the largest Z value. + // If there is still a tie, then there are duplicated vertices within the + // mesh, which violates the precondition. + typedef typename DerivedF::Scalar Index; + const Index INVALID = std::numeric_limits::max(); + const size_t num_selected_faces = I.rows(); + std::vector candidate_faces; + Index outer_vid = INVALID; + typename DerivedV::Scalar outer_val = 0; + for (size_t i=0; i outer_val) + { + outer_val = vx; + outer_vid = v; + candidate_faces = {f}; + } else if (v == outer_vid) + { + candidate_faces.push_back(f); + } else if (vx == outer_val) + { + // Break tie. + auto vy = V(v,1); + auto vz = V(v, 2); + auto outer_y = V(outer_vid, 1); + auto outer_z = V(outer_vid, 2); + assert(!(vy == outer_y && vz == outer_z)); + bool replace = (vy > outer_y) || + ((vy == outer_y) && (vz > outer_z)); + if (replace) + { + outer_val = vx; + outer_vid = v; + candidate_faces = {f}; + } + } + } + } + + assert(outer_vid != INVALID); + assert(candidate_faces.size() > 0); + v_index = outer_vid; + A.resize(candidate_faces.size()); + std::copy(candidate_faces.begin(), candidate_faces.end(), A.data()); +} + +template< + typename DerivedV, + typename DerivedF, + typename DerivedI, + typename IndexType, + typename DerivedA + > +IGL_INLINE void igl::copyleft::cgal::outer_edge( + const Eigen::PlainObjectBase & V, + const Eigen::PlainObjectBase & F, + const Eigen::PlainObjectBase & I, + IndexType & v1, + IndexType & v2, + Eigen::PlainObjectBase & A) { + // Algorithm: + // Find an outer vertex first. + // Find the incident edge with largest abs slope when projected onto XY plane. + // If there is a tie, check the signed slope and use the positive one. + // If there is still a tie, break it using the projected slope onto ZX plane. + // If there is still a tie, again check the signed slope and use the positive one. + // If there is still a tie, then there are multiple overlapping edges, + // which violates the precondition. + typedef typename DerivedV::Scalar Scalar; + typedef typename DerivedV::Index Index; + typedef typename Eigen::Matrix ScalarArray3; + typedef typename Eigen::Matrix IndexArray3; + const Index INVALID = std::numeric_limits::max(); + + Index outer_vid; + Eigen::Matrix candidate_faces; + outer_vertex(V, F, I, outer_vid, candidate_faces); + const ScalarArray3& outer_v = V.row(outer_vid); + assert(candidate_faces.size() > 0); + + auto get_vertex_index = [&](const IndexArray3& f, Index vid) -> Index + { + if (f[0] == vid) return 0; + if (f[1] == vid) return 1; + if (f[2] == vid) return 2; + assert(false); + return -1; + }; + + auto unsigned_value = [](Scalar v) -> Scalar { + if (v < 0) return v * -1; + else return v; + }; + + Scalar outer_slope_YX = 0; + Scalar outer_slope_ZX = 0; + Index outer_opp_vid = INVALID; + bool infinite_slope_detected = false; + std::vector incident_faces; + auto check_and_update_outer_edge = [&](Index opp_vid, Index fid) -> void { + if (opp_vid == outer_opp_vid) + { + incident_faces.push_back(fid); + return; + } + + const ScalarArray3 opp_v = V.row(opp_vid); + if (!infinite_slope_detected && outer_v[0] != opp_v[0]) + { + // Finite slope + const ScalarArray3 diff = opp_v - outer_v; + const Scalar slope_YX = diff[1] / diff[0]; + const Scalar slope_ZX = diff[2] / diff[0]; + const Scalar u_slope_YX = unsigned_value(slope_YX); + const Scalar u_slope_ZX = unsigned_value(slope_ZX); + bool update = false; + if (outer_opp_vid == INVALID) { + update = true; + } else { + const Scalar u_outer_slope_YX = unsigned_value(outer_slope_YX); + if (u_slope_YX > u_outer_slope_YX) { + update = true; + } else if (u_slope_YX == u_outer_slope_YX && + slope_YX > outer_slope_YX) { + update = true; + } else if (slope_YX == outer_slope_YX) { + const Scalar u_outer_slope_ZX = + unsigned_value(outer_slope_ZX); + if (u_slope_ZX > u_outer_slope_ZX) { + update = true; + } else if (u_slope_ZX == u_outer_slope_ZX && + slope_ZX > outer_slope_ZX) { + update = true; + } else if (slope_ZX == u_outer_slope_ZX) { + assert(false); + } + } + } + + if (update) { + outer_opp_vid = opp_vid; + outer_slope_YX = slope_YX; + outer_slope_ZX = slope_ZX; + incident_faces = {fid}; + } + } else if (!infinite_slope_detected) + { + // Infinite slope + outer_opp_vid = opp_vid; + infinite_slope_detected = true; + incident_faces = {fid}; + } + }; + + const size_t num_candidate_faces = candidate_faces.size(); + for (size_t i=0; i +template void igl::copyleft::cgal::outer_edge, -1, 3, 0, -1, 3>, Eigen::Matrix, Eigen::Matrix, long, Eigen::Matrix >(Eigen::PlainObjectBase, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, long&, long&, Eigen::PlainObjectBase >&); +template void igl::copyleft::cgal::outer_edge, -1, -1, 0, -1, -1>, Eigen::Matrix, Eigen::Matrix, long, Eigen::Matrix >(Eigen::PlainObjectBase, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, long&, long&, Eigen::PlainObjectBase >&); +template void igl::copyleft::cgal::outer_edge, Eigen::Matrix, Eigen::Matrix, long, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, long&, long&, Eigen::PlainObjectBase >&); +template void igl::copyleft::cgal::outer_edge, Eigen::Matrix, Eigen::Matrix, long, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, long&, long&, Eigen::PlainObjectBase >&); +template void igl::copyleft::cgal::outer_edge, Eigen::Matrix, Eigen::Matrix, long, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, long&, long&, Eigen::PlainObjectBase >&); +template void igl::copyleft::cgal::outer_edge, -1, -1, 0, -1, -1>, Eigen::Matrix, Eigen::Matrix, long, Eigen::Matrix >(Eigen::PlainObjectBase, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, long&, long&, Eigen::PlainObjectBase >&); +template void igl::copyleft::cgal::outer_edge, Eigen::Matrix, Eigen::Matrix, long, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, long&, long&, Eigen::PlainObjectBase >&); +template void igl::copyleft::cgal::outer_edge, -1, -1, 1, -1, -1>, Eigen::Matrix, Eigen::Matrix, long, Eigen::Matrix >(Eigen::PlainObjectBase, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, long&, long&, Eigen::PlainObjectBase >&); +template void igl::copyleft::cgal::outer_edge, -1, -1, 1, -1, -1>, Eigen::Matrix, Eigen::Matrix, long, Eigen::Matrix >(Eigen::PlainObjectBase, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, long&, long&, Eigen::PlainObjectBase >&); +#ifdef WIN32 +template void igl::copyleft::cgal::outer_edge, -1, -1, 0, -1, -1>, class Eigen::Matrix, class Eigen::Matrix, __int64, class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>>(class Eigen::PlainObjectBase, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase> const &, class Eigen::PlainObjectBase> const &, __int64 &, __int64 &, class Eigen::PlainObjectBase> &); +template void igl::copyleft::cgal::outer_edge, -1, -1, 0, -1, -1>, class Eigen::Matrix, class Eigen::Matrix, __int64, class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>>(class Eigen::PlainObjectBase, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase> const &, class Eigen::PlainObjectBase> const &, __int64 &, __int64 &, class Eigen::PlainObjectBase> &); +template void igl::copyleft::cgal::outer_edge, -1, -1, 1, -1, -1>, class Eigen::Matrix, class Eigen::Matrix, __int64, class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>>(class Eigen::PlainObjectBase, -1, -1, 1, -1, -1>> const &, class Eigen::PlainObjectBase> const &, class Eigen::PlainObjectBase> const &, __int64 &, __int64 &, class Eigen::PlainObjectBase> &); +template void igl::copyleft::cgal::outer_edge, -1, -1, 1, -1, -1>, class Eigen::Matrix, class Eigen::Matrix, __int64, class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>>(class Eigen::PlainObjectBase, -1, -1, 1, -1, -1>> const &, class Eigen::PlainObjectBase> const &, class Eigen::PlainObjectBase> const &, __int64 &, __int64 &, class Eigen::PlainObjectBase> &); +template void igl::copyleft::cgal::outer_edge, -1, 3, 0, -1, 3>, class Eigen::Matrix, class Eigen::Matrix, __int64, class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>>(class Eigen::PlainObjectBase, -1, 3, 0, -1, 3>> const &, class Eigen::PlainObjectBase> const &, class Eigen::PlainObjectBase> const &, __int64 &, __int64 &, class Eigen::PlainObjectBase> &); +template void igl::copyleft::cgal::outer_edge,-1,-1,0,-1,-1>,class Eigen::Matrix,class Eigen::Matrix<__int64,-1,1,0,-1,1>,__int64,class Eigen::Matrix<__int64,-1,1,0,-1,1> >(class Eigen::PlainObjectBase,-1,-1,0,-1,-1> > const &,class Eigen::PlainObjectBase > const &,class Eigen::PlainObjectBase > const &,__int64 &,__int64 &,class Eigen::PlainObjectBase > &); +template void igl::copyleft::cgal::outer_edge, class Eigen::Matrix, class Eigen::Matrix, __int64, class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>>(class Eigen::PlainObjectBase> const &, class Eigen::PlainObjectBase> const &, class Eigen::PlainObjectBase> const &, __int64 &, __int64 &, class Eigen::PlainObjectBase> &); +template void igl::copyleft::cgal::outer_edge, class Eigen::Matrix, class Eigen::Matrix, __int64, class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>>(class Eigen::PlainObjectBase> const &, class Eigen::PlainObjectBase> const &, class Eigen::PlainObjectBase> const &, __int64 &, __int64 &, class Eigen::PlainObjectBase> &); +template void igl::copyleft::cgal::outer_edge, class Eigen::Matrix, class Eigen::Matrix, __int64, class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>>(class Eigen::PlainObjectBase> const &, class Eigen::PlainObjectBase> const &, class Eigen::PlainObjectBase> const &, __int64 &, __int64 &, class Eigen::PlainObjectBase> &); +template void igl::copyleft::cgal::outer_edge, class Eigen::Matrix, class Eigen::Matrix, __int64, class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>>(class Eigen::PlainObjectBase> const &, class Eigen::PlainObjectBase> const &, class Eigen::PlainObjectBase> const &, __int64 &, __int64 &, class Eigen::PlainObjectBase> &); +template void igl::copyleft::cgal::outer_edge,class Eigen::Matrix,class Eigen::Matrix<__int64,-1,1,0,-1,1>,__int64,class Eigen::Matrix<__int64,-1,1,0,-1,1> >(class Eigen::PlainObjectBase > const &,class Eigen::PlainObjectBase > const &,class Eigen::PlainObjectBase > const &,__int64 &,__int64 &,class Eigen::PlainObjectBase > &); +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/outer_element.h b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/outer_element.h new file mode 100644 index 000000000..adaef3464 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/outer_element.h @@ -0,0 +1,83 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Qingan Zhou +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_COPYLEFT_CGAL_OUTER_ELEMENT_H +#define IGL_COPYLEFT_CGAL_OUTER_ELEMENT_H +#include "../../igl_inline.h" +#include +namespace igl +{ + namespace copyleft + { + namespace cgal + { + // Find a vertex that is reachable from infinite without crossing any faces. + // Such vertex is called "outer vertex." + // + // Precondition: The input mesh must have all self-intersection resolved and + // no duplicated vertices. See cgal::remesh_self_intersections.h for how to + // obtain such input. + // + // Inputs: + // V #V by 3 list of vertex positions + // F #F by 3 list of triangle indices into V + // I #I list of facets to consider + // Outputs: + // v_index index of outer vertex + // A #A list of facets incident to the outer vertex + template < + typename DerivedV, + typename DerivedF, + typename DerivedI, + typename IndexType, + typename DerivedA + > + IGL_INLINE void outer_vertex( + const Eigen::PlainObjectBase & V, + const Eigen::PlainObjectBase & F, + const Eigen::PlainObjectBase & I, + IndexType & v_index, + Eigen::PlainObjectBase & A); + // Find an edge that is reachable from infinity without crossing any faces. + // Such edge is called "outer edge." + // + // Precondition: The input mesh must have all self-intersection resolved + // and no duplicated vertices. The correctness of the output depends on + // the fact that there is no edge overlap. See + // cgal::remesh_self_intersections.h for how to obtain such input. + // + // Inputs: + // V #V by 3 list of vertex positions + // F #F by 3 list of triangle indices into V + // I #I list of facets to consider + // Outputs: + // v1 index of the first end point of outer edge + // v2 index of the second end point of outer edge + // A #A list of facets incident to the outer edge + template< + typename DerivedV, + typename DerivedF, + typename DerivedI, + typename IndexType, + typename DerivedA + > + IGL_INLINE void outer_edge( + const Eigen::PlainObjectBase & V, + const Eigen::PlainObjectBase & F, + const Eigen::PlainObjectBase & I, + IndexType & v1, + IndexType & v2, + Eigen::PlainObjectBase & A); + + } + } +} + +#ifndef IGL_STATIC_LIBRARY +# include "outer_element.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/outer_facet.cpp b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/outer_facet.cpp new file mode 100644 index 000000000..40cfa7ac0 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/outer_facet.cpp @@ -0,0 +1,183 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Qingnan Zhou +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +#include "outer_facet.h" +#include "outer_element.h" +#include "order_facets_around_edge.h" +#include +#include + +template< + typename DerivedV, + typename DerivedF, + typename DerivedI, + typename IndexType + > +IGL_INLINE void igl::copyleft::cgal::outer_facet( + const Eigen::PlainObjectBase & V, + const Eigen::PlainObjectBase & F, + const Eigen::PlainObjectBase & I, + IndexType & f, + bool & flipped) { + + // Algorithm: + // + // 1. Find an outer edge (s, d). + // + // 2. Order adjacent facets around this edge. Because the edge is an + // outer edge, there exists a plane passing through it such that all its + // adjacent facets lie on the same side. The implementation of + // order_facets_around_edge() will find a natural start facet such that + // The first and last facets according to this order are on the outside. + // + // 3. Because the vertex s is an outer vertex by construction (see + // implemnetation of outer_edge()). The first adjacent facet is facing + // outside (i.e. flipped=false) if it has positive X normal component. + // If it has zero normal component, it is facing outside if it contains + // directed edge (s, d). + + //typedef typename DerivedV::Scalar Scalar; + typedef typename DerivedV::Index Index; + + Index s,d; + Eigen::Matrix incident_faces; + outer_edge(V, F, I, s, d, incident_faces); + assert(incident_faces.size() > 0); + + auto convert_to_signed_index = [&](size_t fid) -> int{ + if ((F(fid, 0) == s && F(fid, 1) == d) || + (F(fid, 1) == s && F(fid, 2) == d) || + (F(fid, 2) == s && F(fid, 0) == d) ) { + return int(fid+1) * -1; + } else { + return int(fid+1); + } + }; + + auto signed_index_to_index = [&](int signed_id) -> size_t { + return size_t(abs(signed_id) - 1); + }; + + std::vector adj_faces(incident_faces.size()); + std::transform(incident_faces.data(), + incident_faces.data() + incident_faces.size(), + adj_faces.begin(), + convert_to_signed_index); + + DerivedV pivot_point = V.row(s); + pivot_point(0, 0) += 1.0; + + Eigen::VectorXi order; + order_facets_around_edge(V, F, s, d, adj_faces, pivot_point, order); + + f = signed_index_to_index(adj_faces[order[0]]); + flipped = adj_faces[order[0]] > 0; +} + + + +template< + typename DerivedV, + typename DerivedF, + typename DerivedN, + typename DerivedI, + typename IndexType + > +IGL_INLINE void igl::copyleft::cgal::outer_facet( + const Eigen::PlainObjectBase & V, + const Eigen::PlainObjectBase & F, + const Eigen::PlainObjectBase & N, + const Eigen::PlainObjectBase & I, + IndexType & f, + bool & flipped) { + // Algorithm: + // Find an outer edge. + // Find the incident facet with the largest absolute X normal component. + // If there is a tie, keep the one with positive X component. + // If there is still a tie, pick the face with the larger signed index + // (flipped face has negative index). + typedef typename DerivedV::Scalar Scalar; + typedef typename DerivedV::Index Index; + const size_t INVALID = std::numeric_limits::max(); + + Index v1,v2; + Eigen::Matrix incident_faces; + outer_edge(V, F, I, v1, v2, incident_faces); + assert(incident_faces.size() > 0); + + auto generic_fabs = [&](const Scalar& val) -> const Scalar { + if (val >= 0) return val; + else return -val; + }; + + Scalar max_nx = 0; + size_t outer_fid = INVALID; + const size_t num_incident_faces = incident_faces.size(); + for (size_t i=0; i generic_fabs(max_nx)) { + max_nx = nx; + outer_fid = fid; + } else if (nx == -max_nx && nx > 0) { + max_nx = nx; + outer_fid = fid; + } else if (nx == max_nx) { + if ((max_nx >= 0 && outer_fid < fid) || + (max_nx < 0 && outer_fid > fid)) { + max_nx = nx; + outer_fid = fid; + } + } + } + } + + assert(outer_fid != INVALID); + f = outer_fid; + flipped = max_nx < 0; +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::copyleft::cgal::outer_facet, -1, -1, 1, -1, -1>, Eigen::Matrix, Eigen::Matrix, unsigned long>(Eigen::PlainObjectBase, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, unsigned long&, bool&); +// generated by autoexplicit.sh +template void igl::copyleft::cgal::outer_facet, -1, -1, 1, -1, -1>, Eigen::Matrix, Eigen::Matrix, int>(Eigen::PlainObjectBase, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, int&, bool&); +// generated by autoexplicit.sh +template void igl::copyleft::cgal::outer_facet, -1, -1, 1, -1, -1>, Eigen::Matrix, Eigen::Matrix, unsigned long>(Eigen::PlainObjectBase, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, unsigned long&, bool&); +// generated by autoexplicit.sh +template void igl::copyleft::cgal::outer_facet, -1, -1, 1, -1, -1>, Eigen::Matrix, Eigen::Matrix, int>(Eigen::PlainObjectBase, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, int&, bool&); +// generated by autoexplicit.sh +template void igl::copyleft::cgal::outer_facet, Eigen::Matrix, Eigen::Matrix, unsigned long>(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, unsigned long&, bool&); +#include +#include +template void igl::copyleft::cgal::outer_facet, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, int>(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, int&, bool&); +template void igl::copyleft::cgal::outer_facet, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, unsigned long>(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, unsigned long&, bool&); +template void igl::copyleft::cgal::outer_facet, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, int>(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, int&, bool&); +template void igl::copyleft::cgal::outer_facet, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, int>(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, int&, bool&); +template void igl::copyleft::cgal::outer_facet, -1, 3, 0, -1, 3>, Eigen::Matrix, Eigen::Matrix, int>(Eigen::PlainObjectBase, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, int&, bool&); +template void igl::copyleft::cgal::outer_facet, Eigen::Matrix, Eigen::Matrix, int>(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, int&, bool&); +template void igl::copyleft::cgal::outer_facet, Eigen::Matrix, Eigen::Matrix, int>(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, int&, bool&); +template void igl::copyleft::cgal::outer_facet, -1, -1, 0, -1, -1>, Eigen::Matrix, Eigen::Matrix, unsigned long>(Eigen::PlainObjectBase, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, unsigned long&, bool&); +template void igl::copyleft::cgal::outer_facet, -1, -1, 0, -1, -1>, Eigen::Matrix, Eigen::Matrix, int>(Eigen::PlainObjectBase, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, int&, bool&); +template void igl::copyleft::cgal::outer_facet, -1, -1, 0, -1, -1>, Eigen::Matrix, Eigen::Matrix, int>(Eigen::PlainObjectBase, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, int&, bool&); +template void igl::copyleft::cgal::outer_facet, Eigen::Matrix, Eigen::Matrix, int>(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, int&, bool&); +#ifdef WIN32 +template void igl::copyleft::cgal::outer_facet, -1, -1, 0, -1, -1>, class Eigen::Matrix, class Eigen::Matrix, unsigned __int64>(class Eigen::PlainObjectBase, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase> const &, class Eigen::PlainObjectBase> const &, unsigned __int64 &, bool &); +template void igl::copyleft::cgal::outer_facet, -1, -1, 1, -1, -1>, class Eigen::Matrix, class Eigen::Matrix, unsigned __int64>(class Eigen::PlainObjectBase, -1, -1, 1, -1, -1>> const &, class Eigen::PlainObjectBase> const &, class Eigen::PlainObjectBase> const &, unsigned __int64 &, bool &); +template void igl::copyleft::cgal::outer_facet, -1, -1, 1, -1, -1>, class Eigen::Matrix, class Eigen::Matrix, unsigned __int64>(class Eigen::PlainObjectBase, -1, -1, 1, -1, -1>> const &, class Eigen::PlainObjectBase> const &, class Eigen::PlainObjectBase> const &, unsigned __int64 &, bool &); +template void igl::copyleft::cgal::outer_facet,-1,-1,0,-1,-1>,class Eigen::Matrix,class Eigen::Matrix<__int64,-1,1,0,-1,1>,int>(class Eigen::PlainObjectBase,-1,-1,0,-1,-1> > const &,class Eigen::PlainObjectBase > const &,class Eigen::PlainObjectBase > const &,int &,bool &); +template void igl::copyleft::cgal::outer_facet,class Eigen::Matrix,class Eigen::Matrix,unsigned __int64>(class Eigen::PlainObjectBase > const &,class Eigen::PlainObjectBase > const &,class Eigen::PlainObjectBase > const &,unsigned __int64 &,bool &); +template void igl::copyleft::cgal::outer_facet,class Eigen::Matrix,class Eigen::Matrix<__int64,-1,1,0,-1,1>,int>(class Eigen::PlainObjectBase > const &,class Eigen::PlainObjectBase > const &,class Eigen::PlainObjectBase > const &,int &,bool &); +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/outer_facet.h b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/outer_facet.h new file mode 100644 index 000000000..b025a94ab --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/outer_facet.h @@ -0,0 +1,91 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Qingnan Zhou +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef IGL_COPYLEFT_CGAL_OUTER_FACET_H +#define IGL_COPYLEFT_CGAL_OUTER_FACET_H +#include "../../igl_inline.h" +#include + +namespace igl +{ + namespace copyleft + { + namespace cgal + { + // Find a facet that is reachable from infinity without crossing any faces. + // Such facet is called "outer facet." + // + // Precondition: The input mesh must have all self-intersection resolved. I.e + // there is no duplicated vertices, no overlapping edge and no intersecting + // faces (the only exception is there could be topologically duplicated faces). + // See cgal::remesh_self_intersections.h for how to obtain such input. + // + // This function differ from igl::outer_facet() in the fact this + // function is more robust because it does not rely on facet normals. + // + // Inputs: + // V #V by 3 list of vertex positions + // F #F by 3 list of triangle indices into V + // I #I list of facets to consider + // Outputs: + // f Index of the outer facet. + // flipped true iff the normal of f points inwards. + template< + typename DerivedV, + typename DerivedF, + typename DerivedI, + typename IndexType + > + IGL_INLINE void outer_facet( + const Eigen::PlainObjectBase & V, + const Eigen::PlainObjectBase & F, + const Eigen::PlainObjectBase & I, + IndexType & f, + bool & flipped); + + // Find a facet that is reachable from infinity without crossing any faces. + // Such facet is called "outer facet." + // + // Precondition: The input mesh must have all self-intersection resolved. + // I.e there is no duplicated vertices, no overlapping edge and no + // intersecting faces (the only exception is there could be topologically + // duplicated faces). See cgal::remesh_self_intersections.h for how to + // obtain such input. + // + // Inputs: + // V #V by 3 list of vertex positions + // F #F by 3 list of triangle indices into V + // N #N by 3 list of face normals + // I #I list of facets to consider + // Outputs: + // f Index of the outer facet. + // flipped true iff the normal of f points inwards. + template< + typename DerivedV, + typename DerivedF, + typename DerivedN, + typename DerivedI, + typename IndexType + > + IGL_INLINE void outer_facet( + const Eigen::PlainObjectBase & V, + const Eigen::PlainObjectBase & F, + const Eigen::PlainObjectBase & N, + const Eigen::PlainObjectBase & I, + IndexType & f, + bool & flipped); + + } + + } +} + +#ifndef IGL_STATIC_LIBRARY +# include "outer_facet.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/outer_hull.cpp b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/outer_hull.cpp new file mode 100644 index 000000000..16cce0869 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/outer_hull.cpp @@ -0,0 +1,539 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "outer_hull.h" +#include "extract_cells.h" +#include "remesh_self_intersections.h" +#include "assign.h" +#include "../../remove_unreferenced.h" + +#include +#include +#include +#include +#include + +template < + typename DerivedV, + typename DerivedF, + typename DerivedHV, + typename DerivedHF, + typename DerivedJ, + typename Derivedflip> +IGL_INLINE void igl::copyleft::cgal::outer_hull( + const Eigen::PlainObjectBase & V, + const Eigen::PlainObjectBase & F, + Eigen::PlainObjectBase & HV, + Eigen::PlainObjectBase & HF, + Eigen::PlainObjectBase & J, + Eigen::PlainObjectBase & flip) +{ + // Exact types + typedef CGAL::Epeck Kernel; + typedef Kernel::FT ExactScalar; + typedef + Eigen::Matrix< + ExactScalar, + Eigen::Dynamic, + Eigen::Dynamic, + DerivedHV::IsRowMajor> + MatrixXES; + // Remesh self-intersections + MatrixXES Vr; + DerivedHF Fr; + DerivedJ Jr; + { + RemeshSelfIntersectionsParam params; + params.stitch_all = true; + Eigen::VectorXi I; + Eigen::MatrixXi IF; + remesh_self_intersections(V, F, params, Vr, Fr, IF, Jr, I); + // Merge coinciding vertices into non-manifold vertices. + std::for_each(Fr.data(), Fr.data()+Fr.size(), + [&I](typename DerivedHF::Scalar& a) { a=I[a]; }); + // Remove unreferenced vertices. + Eigen::VectorXi UIM; + remove_unreferenced(MatrixXES(Vr),DerivedHF(Fr), Vr, Fr, UIM); + } + // Extract cells for each face + Eigen::MatrixXi C; + extract_cells(Vr,Fr,C); + // Extract faces on ambient cell + int num_outer = 0; + for(int i = 0;i +#include +#include +#include +#include +#include +#include +//#define IGL_OUTER_HULL_DEBUG + +template < + typename DerivedV, + typename DerivedF, + typename DerivedG, + typename DerivedJ, + typename Derivedflip> +IGL_INLINE void igl::copyleft::cgal::outer_hull_legacy( + const Eigen::PlainObjectBase & V, + const Eigen::PlainObjectBase & F, + Eigen::PlainObjectBase & G, + Eigen::PlainObjectBase & J, + Eigen::PlainObjectBase & flip) +{ +#ifdef IGL_OUTER_HULL_DEBUG + std::cerr << "Extracting outer hull" << std::endl; +#endif + using namespace Eigen; + using namespace std; + typedef typename DerivedF::Index Index; + Matrix C; + typedef Matrix MatrixXV; + //typedef Matrix MatrixXF; + typedef Matrix MatrixXG; + typedef Matrix MatrixXJ; + const Index m = F.rows(); + + // UNUSED: + //const auto & duplicate_simplex = [&F](const int f, const int g)->bool + //{ + // return + // (F(f,0) == F(g,0) && F(f,1) == F(g,1) && F(f,2) == F(g,2)) || + // (F(f,1) == F(g,0) && F(f,2) == F(g,1) && F(f,0) == F(g,2)) || + // (F(f,2) == F(g,0) && F(f,0) == F(g,1) && F(f,1) == F(g,2)) || + // (F(f,0) == F(g,2) && F(f,1) == F(g,1) && F(f,2) == F(g,0)) || + // (F(f,1) == F(g,2) && F(f,2) == F(g,1) && F(f,0) == F(g,0)) || + // (F(f,2) == F(g,2) && F(f,0) == F(g,1) && F(f,1) == F(g,0)); + //}; + +#ifdef IGL_OUTER_HULL_DEBUG + cout<<"outer hull..."< MatrixX2I; + typedef Matrix VectorXI; + //typedef Matrix Vector3F; + MatrixX2I E,uE; + VectorXI EMAP; + vector > uE2E; + unique_edge_map(F,E,uE,EMAP,uE2E); +#ifdef IGL_OUTER_HULL_DEBUG + for (size_t ui=0; ui > uE2oE; + std::vector > uE2C; + order_facets_around_edges(V, F, uE, uE2E, uE2oE, uE2C); + uE2E = uE2oE; + VectorXI diIM(3*m); + for (auto ue : uE2E) { + for (size_t i=0; i > > TT,_1; + triangle_triangle_adjacency(E,EMAP,uE2E,false,TT,_1); + VectorXI counts; +#ifdef IGL_OUTER_HULL_DEBUG + cout<<"facet components..."< FH(m,false); + vector EH(3*m,false); + vector vG(ncc); + vector vJ(ncc); + vector vIM(ncc); + //size_t face_count = 0; + for(size_t id = 0;id g(ncc,0); + // place order of each face in its respective component + for(Index f = 0;f Q; + Q.push(f+0*m); + Q.push(f+1*m); + Q.push(f+2*m); + flip(f) = f_flip; + //std::cout << "face " << face_count++ << ": " << f << std::endl; + //std::cout << "f " << F.row(f).array()+1 << std::endl; + //cout<<"flip("< "<<(nf+1)<<", |"<< + // di[EMAP(e)][diIM(e)]<<" - "< "<<(nf+1)<= 0) + { + max_ne = uE2E[EMAP(e)][nfei]; + } + + if(max_ne>=0) + { + // face of neighbor + const int nf = max_ne%m; +#ifdef IGL_OUTER_HULL_DEBUG + if(!FH[nf]) + { + // first time seeing face + cout<<(f+1)<<" --> "<<(nf+1)< & V, + const MatrixXG & A, + const MatrixXG & B)->bool + { + const auto & bounding_box = []( + const Eigen::PlainObjectBase & V, + const MatrixXG & F)-> + DerivedV + { + DerivedV BB(2,3); + BB<< + 1e26,1e26,1e26, + -1e26,-1e26,-1e26; + const size_t m = F.rows(); + for(size_t f = 0;f0 || + (ABB.row(0)-BBB.row(1)).maxCoeff()>0 ) + { + // bounding boxes do not overlap + return false; + } else { + return true; + } + }; + + // Reject components which are completely inside other components + vector keep(ncc,true); + size_t nG = 0; + // This is O( ncc * ncc * m) + for(size_t id = 0;id unresolved; + for(size_t oid = 0;oid, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::copyleft::cgal::outer_hull_legacy< Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > &, Eigen::PlainObjectBase > &, Eigen::PlainObjectBase > &); +template void igl::copyleft::cgal::outer_hull_legacy< Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::copyleft::cgal::outer_hull_legacy, -1, -1, 0, -1, -1>, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::copyleft::cgal::outer_hull_legacy, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#ifdef WIN32 +template void igl::copyleft::cgal::outer_hull_legacy,-1,-1,0,-1,-1>,class Eigen::Matrix,class Eigen::Matrix,class Eigen::Matrix<__int64,-1,1,0,-1,1>,class Eigen::Matrix >(class Eigen::PlainObjectBase,-1,-1,0,-1,-1> > const &,class Eigen::PlainObjectBase > const &,class Eigen::PlainObjectBase > &,class Eigen::PlainObjectBase > &,class Eigen::PlainObjectBase > &); +template void igl::copyleft::cgal::outer_hull_legacy,class Eigen::Matrix,class Eigen::Matrix,class Eigen::Matrix<__int64,-1,1,0,-1,1>,class Eigen::Matrix >(class Eigen::PlainObjectBase > const &,class Eigen::PlainObjectBase > const &,class Eigen::PlainObjectBase > &,class Eigen::PlainObjectBase > &,class Eigen::PlainObjectBase > &); +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/outer_hull.h b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/outer_hull.h new file mode 100644 index 000000000..191a8d492 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/outer_hull.h @@ -0,0 +1,84 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_COPYLEFT_CGAL_OUTER_HULL_H +#define IGL_COPYLEFT_CGAL_OUTER_HULL_H +#include "../../igl_inline.h" +#include +namespace igl +{ + namespace copyleft + { + namespace cgal + { + // Compute the "outer hull" of a piecewise constant winding number induce + // triangle mesh (V,F). + // + // Inputs: + // V #V by 3 list of vertex positions + // F #F by 3 list of triangle indices into V + // Outputs: + // HV #HV by 3 list of output vertex positions + // HF #HF by 3 list of output triangle indices into HV + // J #HF list of indices into F + // flip #HF list of whether facet was flipped when added to HF + // + template < + typename DerivedV, + typename DerivedF, + typename DerivedHV, + typename DerivedHF, + typename DerivedJ, + typename Derivedflip> + IGL_INLINE void outer_hull( + const Eigen::PlainObjectBase & V, + const Eigen::PlainObjectBase & F, + Eigen::PlainObjectBase & HV, + Eigen::PlainObjectBase & HF, + Eigen::PlainObjectBase & J, + Eigen::PlainObjectBase & flip); + // Compute the "outer hull" of a potentially non-manifold mesh (V,F) whose + // intersections have been "resolved" (e.g. using `cork` or + // `igl::copyleft::cgal::selfintersect`). The outer hull is defined to be all facets + // (regardless of orientation) for which there exists some path from infinity + // to the face without intersecting any other facets. For solids, this is the + // surface of the solid. In general this includes any thin "wings" or + // "flaps". This implementation largely follows Section 3.6 of "Direct + // repair of self-intersecting meshes" [Attene 2014]. + // + // Note: This doesn't require the input mesh to be piecewise constant + // winding number, but won't handle multiple non-nested connected + // components. + // + // Inputs: + // V #V by 3 list of vertex positions + // F #F by 3 list of triangle indices into V + // Outputs: + // G #G by 3 list of output triangle indices into V + // J #G list of indices into F + // flip #F list of whether facet was added to G **and** flipped orientation + // (false for faces not added to G) + template < + typename DerivedV, + typename DerivedF, + typename DerivedG, + typename DerivedJ, + typename Derivedflip> + IGL_INLINE void outer_hull_legacy( + const Eigen::PlainObjectBase & V, + const Eigen::PlainObjectBase & F, + Eigen::PlainObjectBase & G, + Eigen::PlainObjectBase & J, + Eigen::PlainObjectBase & flip); + } + } +} + +#ifndef IGL_STATIC_LIBRARY +# include "outer_hull.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/peel_outer_hull_layers.cpp b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/peel_outer_hull_layers.cpp new file mode 100644 index 000000000..2af7e7806 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/peel_outer_hull_layers.cpp @@ -0,0 +1,127 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "peel_outer_hull_layers.h" +#include "outer_hull.h" +#include "../../LinSpaced.h" +#include +#include +//#define IGL_PEEL_OUTER_HULL_LAYERS_DEBUG +#ifdef IGL_PEEL_OUTER_HULL_LAYERS_DEBUG +#include "../../writePLY.h" +#include "../../writeDMAT.h" +#include "../../STR.h" +#endif + +template < + typename DerivedV, + typename DerivedF, + typename DerivedI, + typename Derivedflip> +IGL_INLINE size_t igl::copyleft::cgal::peel_outer_hull_layers( + const Eigen::PlainObjectBase & V, + const Eigen::PlainObjectBase & F, + Eigen::PlainObjectBase & I, + Eigen::PlainObjectBase & flip) +{ + using namespace Eigen; + using namespace std; + typedef typename DerivedF::Index Index; + typedef Matrix MatrixXF; + typedef Matrix MatrixXI; + typedef Matrix MatrixXflip; + const Index m = F.rows(); +#ifdef IGL_PEEL_OUTER_HULL_LAYERS_DEBUG + cout<<"peel outer hull layers..."<(m,0,m-1); + // This is O(n * layers) + MatrixXI P(m,1); + Index iter = 0; + while(Fr.size() > 0) + { + assert(Fr.rows() == IM.rows()); + // Compute outer hull of current Fr + MatrixXF Fo; + MatrixXI Jo; + MatrixXflip flipr; +#ifdef IGL_PEEL_OUTER_HULL_LAYERS_DEBUG + { + cout<<"calling outer hull..." << iter < in_outer(Fr.rows(),false); + for(Index g = 0;g +#include +template unsigned long igl::copyleft::cgal::peel_outer_hull_layers, -1, -1, 0, -1, -1>, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template size_t igl::copyleft::cgal::peel_outer_hull_layers, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#ifdef WIN32 +template unsigned __int64 igl::copyleft::cgal::peel_outer_hull_layers,-1,-1,0,-1,-1>,class Eigen::Matrix,class Eigen::Matrix,class Eigen::Matrix >(class Eigen::PlainObjectBase,-1,-1,0,-1,-1> > const &,class Eigen::PlainObjectBase > const &,class Eigen::PlainObjectBase > &,class Eigen::PlainObjectBase > &); +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/peel_outer_hull_layers.h b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/peel_outer_hull_layers.h new file mode 100644 index 000000000..ee2752b29 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/peel_outer_hull_layers.h @@ -0,0 +1,47 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_COPYLEFT_CGAL_PEEL_OUTER_HULL_LAYERS_H +#define IGL_COPYLEFT_CGAL_PEEL_OUTER_HULL_LAYERS_H +#include "../../igl_inline.h" +#include +namespace igl +{ + namespace copyleft + { + namespace cgal + { + // Computes necessary generic information for boolean operations by + // successively "peeling" off the "outer hull" of a mesh (V,F) resulting from + // "resolving" all (self-)intersections. + // + // Inputs: + // V #V by 3 list of vertex positions + // F #F by 3 list of triangle indices into V + // Outputs: + // I #F list of which peel Iation a facet belongs + // flip #F list of whether a facet's orientation was flipped when facet + // "peeled" into its associated outer hull layer. + // Returns number of peels + template < + typename DerivedV, + typename DerivedF, + typename DerivedI, + typename Derivedflip> + IGL_INLINE size_t peel_outer_hull_layers( + const Eigen::PlainObjectBase & V, + const Eigen::PlainObjectBase & F, + Eigen::PlainObjectBase & I, + Eigen::PlainObjectBase & flip); + } + } +} + +#ifndef IGL_STATIC_LIBRARY +# include "peel_outer_hull_layers.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/peel_winding_number_layers.cpp b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/peel_winding_number_layers.cpp new file mode 100644 index 000000000..2bb71a780 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/peel_winding_number_layers.cpp @@ -0,0 +1,33 @@ +#include "peel_winding_number_layers.h" + +#include + +#include "propagate_winding_numbers.h" + +template< +typename DerivedV, +typename DerivedF, +typename DerivedW > +IGL_INLINE size_t igl::copyleft::cgal::peel_winding_number_layers( + const Eigen::PlainObjectBase & V, + const Eigen::PlainObjectBase & F, + Eigen::PlainObjectBase& W) { + const size_t num_faces = F.rows(); + Eigen::VectorXi labels(num_faces); + labels.setZero(); + + Eigen::MatrixXi winding_numbers; + igl::copyleft::cgal::propagate_winding_numbers(V, F, labels, winding_numbers); + assert(winding_numbers.rows() == num_faces); + assert(winding_numbers.cols() == 2); + + int min_w = winding_numbers.minCoeff(); + int max_w = winding_numbers.maxCoeff(); + assert(max_w > min_w); + + W.resize(num_faces, 1); + for (size_t i=0; i + +namespace igl { + namespace copyleft { + namespace cgal { + template< + typename DerivedV, + typename DerivedF, + typename DerivedW > + IGL_INLINE size_t peel_winding_number_layers( + const Eigen::PlainObjectBase & V, + const Eigen::PlainObjectBase & F, + Eigen::PlainObjectBase& W); + } + } +} + +#ifndef IGL_STATIC_LIBRARY +# include "peel_winding_number_layers.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/piecewise_constant_winding_number.cpp b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/piecewise_constant_winding_number.cpp new file mode 100644 index 000000000..0156edbe2 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/piecewise_constant_winding_number.cpp @@ -0,0 +1,27 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "piecewise_constant_winding_number.h" +#include "../../piecewise_constant_winding_number.h" +#include "remesh_self_intersections.h" +#include +#include + +template < typename DerivedV, typename DerivedF> +IGL_INLINE bool igl::copyleft::cgal::piecewise_constant_winding_number( + const Eigen::PlainObjectBase & V, + const Eigen::PlainObjectBase & F) +{ + Eigen::Matrix VV; + Eigen::Matrix FF; + Eigen::Matrix IF; + Eigen::Matrix J; + Eigen::Matrix UIM,IM; + // resolve intersections + remesh_self_intersections(V,F,{false,false,true},VV,FF,IF,J,IM); + return igl::piecewise_constant_winding_number(FF); +} diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/piecewise_constant_winding_number.h b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/piecewise_constant_winding_number.h new file mode 100644 index 000000000..2b93913b3 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/piecewise_constant_winding_number.h @@ -0,0 +1,41 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_COPYLEFT_CGAL_PIECEWISE_CONSTANT_WINDING_NUMBER_H +#define IGL_COPYLEFT_CGAL_PIECEWISE_CONSTANT_WINDING_NUMBER_H +#include "../../igl_inline.h" +#include +#include +namespace igl +{ + namespace copyleft + { + namespace cgal + { + // PIECEWISE_CONSTANT_WINDING_NUMBER Determine if a given mesh induces a + // piecewise constant winding number field: Is this mesh valid input to + // solid set operations. + // + // Inputs: + // V #V by 3 list of mesh vertex positions + // F #F by 3 list of triangle indices into V + // Returns true if the mesh _combinatorially_ induces a piecewise + // constant winding number field. + template < + typename DerivedV, + typename DerivedF> + IGL_INLINE bool piecewise_constant_winding_number( + const Eigen::PlainObjectBase & V, + const Eigen::PlainObjectBase& F); + } + } +} +#ifndef IGL_STATIC_LIBRARY +# include "piecewise_constant_winding_number.cpp" +#endif +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/point_areas.cpp b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/point_areas.cpp new file mode 100644 index 000000000..7b3f9be14 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/point_areas.cpp @@ -0,0 +1,186 @@ +#include "point_areas.h" +#include "delaunay_triangulation.h" + +#include "../../colon.h" +#include "../../slice.h" +#include "../../slice_mask.h" +#include "../../parallel_for.h" + +#include "CGAL/Exact_predicates_inexact_constructions_kernel.h" +#include "CGAL/Triangulation_vertex_base_with_info_2.h" +#include "CGAL/Triangulation_data_structure_2.h" +#include "CGAL/Delaunay_triangulation_2.h" + + + +typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel; +typedef CGAL::Triangulation_vertex_base_with_info_2 Vb; +typedef CGAL::Triangulation_data_structure_2 Tds; +typedef CGAL::Delaunay_triangulation_2 Delaunay; +typedef Kernel::Point_2 Point; + +namespace igl { + namespace copyleft{ + namespace cgal{ + + template + IGL_INLINE void point_areas( + const Eigen::MatrixBase& P, + const Eigen::MatrixBase& I, + const Eigen::MatrixBase& N, + Eigen::PlainObjectBase & A) + { + Eigen::MatrixXd T; + point_areas(P,I,N,A,T); + } + + + template + IGL_INLINE void point_areas( + const Eigen::MatrixBase& P, + const Eigen::MatrixBase& I, + const Eigen::MatrixBase& N, + Eigen::PlainObjectBase & A, + Eigen::PlainObjectBase & T) + { + typedef typename DerivedP::Scalar real; + typedef typename DerivedN::Scalar scalarN; + typedef typename DerivedA::Scalar scalarA; + typedef Eigen::Matrix RowVec3; + typedef Eigen::Matrix RowVec2; + + typedef Eigen::Matrix MatrixP; + typedef Eigen::Matrix MatrixN; + typedef Eigen::Matrix VecotorO; + typedef Eigen::Matrix MatrixI; + + + + const int n = P.rows(); + + assert(P.cols() == 3 && "P must have exactly 3 columns"); + assert(P.rows() == N.rows() + && "P and N must have the same number of rows"); + assert(P.rows() == I.rows() + && "P and I must have the same number of rows"); + + A.setZero(n,1); + T.setZero(n,3); + igl::parallel_for(P.rows(),[&](int i) + { + MatrixI neighbor_index = I.row(i); + MatrixP neighbors; + igl::slice(P,neighbor_index,1,neighbors); + if(N.rows() && neighbors.rows() > 1){ + MatrixN neighbor_normals; + igl::slice(N,neighbor_index,1,neighbor_normals); + Eigen::Matrix poi_normal = neighbor_normals.row(0); + Eigen::Matrix dotprod = + poi_normal(0)*neighbor_normals.col(0) + + poi_normal(1)*neighbor_normals.col(1) + + poi_normal(2)*neighbor_normals.col(2); + Eigen::Array keep = dotprod.array() > 0; + igl::slice_mask(Eigen::MatrixXd(neighbors),keep,1,neighbors); + } + if(neighbors.rows() <= 2){ + A(i) = 0; + } else { + //subtract the mean from neighbors, then take svd, + //the scores will be U*S. This is our pca plane fitting + RowVec3 mean = neighbors.colwise().mean(); + MatrixP mean_centered = neighbors.rowwise() - mean; + Eigen::JacobiSVD svd(mean_centered, + Eigen::ComputeThinU | Eigen::ComputeThinV); + MatrixP scores = svd.matrixU() * svd.singularValues().asDiagonal(); + + T.row(i) = svd.matrixV().col(2).transpose(); + if(T.row(i).dot(N.row(i)) < 0){ + T.row(i) *= -1; + } + + MatrixP plane; + igl::slice(scores,igl::colon(0,scores.rows()-1), + igl::colon(0,1),plane); + + std::vector< std::pair > points; + //This is where we obtain a delaunay triangulation of the points + for(unsigned iter = 0; iter < plane.rows(); iter++){ + points.push_back( std::make_pair( + Point(plane(iter,0),plane(iter,1)), iter ) ); + } + Delaunay triangulation; + triangulation.insert(points.begin(),points.end()); + Eigen::MatrixXi F(triangulation.number_of_faces(),3); + int f_row = 0; + for(Delaunay::Finite_faces_iterator fit = + triangulation.finite_faces_begin(); + fit != triangulation.finite_faces_end(); ++fit) { + Delaunay::Face_handle face = fit; + F.row(f_row) = Eigen::RowVector3i((int)face->vertex(0)->info(), + (int)face->vertex(1)->info(), + (int)face->vertex(2)->info()); + f_row++; + } + + //Here we calculate the voronoi area of the point + scalarA area_accumulator = 0; + for(int f = 0; f < F.rows(); f++){ + int X = -1; + for(int face_iter = 0; face_iter < 3; face_iter++){ + if(F(f,face_iter) == 0){ + X = face_iter; + } + } + if(X >= 0){ + //Triangle XYZ with X being the point we want the area of + int Y = (X+1)%3; + int Z = (X+2)%3; + scalarA x = (plane.row(F(f,Y))-plane.row(F(f,Z))).norm(); + scalarA y = (plane.row(F(f,X))-plane.row(F(f,Z))).norm(); + scalarA z = (plane.row(F(f,Y))-plane.row(F(f,X))).norm(); + scalarA cosX = (z*z + y*y - x*x)/(2*y*z); + scalarA cosY = (z*z + x*x - y*y)/(2*x*z); + scalarA cosZ = (x*x + y*y - z*z)/(2*y*x); + Eigen::Matrix barycentric; + barycentric << x*cosX, y*cosY, z*cosZ; + barycentric /= (barycentric(0)+barycentric(1)+barycentric(2)); + + //TODO: to make numerically stable, reorder so that x≥y≥z: + scalarA full_area = 0.25*std::sqrt( + (x+(y+z))*(z-(x-y))*(z+(x-y))*(x+(y-z))); + Eigen::Matrix partial_area = + barycentric * full_area; + if(cosX < 0){ + area_accumulator += 0.5*full_area; + } else if (cosY < 0 || cosZ < 0){ + area_accumulator += 0.25*full_area; + } else { + area_accumulator += (partial_area(1) + partial_area(2))/2; + } + } + } + + if(std::isfinite(area_accumulator)){ + A(i) = area_accumulator; + } else { + A(i) = 0; + } + } + },1000); + } + } + } +} + + + + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::copyleft::cgal::point_areas, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/point_areas.h b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/point_areas.h new file mode 100644 index 000000000..ad1128f2f --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/point_areas.h @@ -0,0 +1,80 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2018 Gavin Barill +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/ + +#ifndef IGL_POINT_AREAS_H +#define IGL_POINT_AREAS_H +#include "../../igl_inline.h" +#include +namespace igl +{ + namespace copyleft + { + namespace cgal + { + // Given a 3D set of points P, each with a list of k-nearest-neighbours, + // estimate the geodesic voronoi area associated with each point. + // + // The k nearest neighbours may be known from running igl::knn_octree on + // the output data from igl::octree. We reccomend using a k value + // between 15 and 20 inclusive for accurate area estimation. + // + // N is used filter the neighbours, to ensure area estimation only occurs + // using neighbors that are on the same side of the surface (ie for thin + // sheets), as well as to solve the orientation ambiguity of the tangent + // plane normal. + // + // Note: This function *should* be implemented by pre-filtering I, rather + // than filtering in this function using N. In this case, the function + // would only take P and I as input. + // + // Inputs: + // P #P by 3 list of point locations + // I #P by k list of k-nearest-neighbor indices into P + // N #P by 3 list of point normals + // Outputs: + // A #P list of estimated areas + // + // See also: igl::knn + template + IGL_INLINE void point_areas( + const Eigen::MatrixBase& P, + const Eigen::MatrixBase& I, + const Eigen::MatrixBase& N, + Eigen::PlainObjectBase & A); + + // This version can be used to output the tangent plane normal at each + // point. Since we area already fitting a plane to each point's neighbour + // set, the tangent plane normals come "for free" + // + // Inputs: + // P #P by 3 list of point locations + // I #P by k list of k-nearest-neighbor indices into P + // N #P by 3 list of point normals + // Outputs: + // A #P list of estimated areas + // T #P by 3 list of tangent plane normals for each point + template + IGL_INLINE void point_areas( + const Eigen::MatrixBase& P, + const Eigen::MatrixBase& I, + const Eigen::MatrixBase& N, + Eigen::PlainObjectBase & A, + Eigen::PlainObjectBase & T); + + } + } +} + +#ifndef IGL_STATIC_LIBRARY +# include "point_areas.cpp" +#endif + +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/point_mesh_squared_distance.cpp b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/point_mesh_squared_distance.cpp new file mode 100644 index 000000000..e36306991 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/point_mesh_squared_distance.cpp @@ -0,0 +1,142 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "point_mesh_squared_distance.h" +#include "mesh_to_cgal_triangle_list.h" +#include "assign_scalar.h" + +template < + typename Kernel, + typename DerivedP, + typename DerivedV, + typename DerivedF, + typename DerivedsqrD, + typename DerivedI, + typename DerivedC> +IGL_INLINE void igl::copyleft::cgal::point_mesh_squared_distance( + const Eigen::PlainObjectBase & P, + const Eigen::PlainObjectBase & V, + const Eigen::PlainObjectBase & F, + Eigen::PlainObjectBase & sqrD, + Eigen::PlainObjectBase & I, + Eigen::PlainObjectBase & C) +{ + using namespace std; + typedef CGAL::Triangle_3 Triangle_3; + typedef typename std::vector::iterator Iterator; + typedef CGAL::AABB_triangle_primitive Primitive; + typedef CGAL::AABB_traits AABB_triangle_traits; + typedef CGAL::AABB_tree Tree; + Tree tree; + vector T; + point_mesh_squared_distance_precompute(V,F,tree,T); + return point_mesh_squared_distance(P,tree,T,sqrD,I,C); +} + +template +IGL_INLINE void igl::copyleft::cgal::point_mesh_squared_distance_precompute( + const Eigen::PlainObjectBase & V, + const Eigen::PlainObjectBase & F, + CGAL::AABB_tree< + CGAL::AABB_traits >::iterator + > + > + > & tree, + std::vector > & T) +{ + using namespace std; + + typedef CGAL::Triangle_3 Triangle_3; + typedef CGAL::Point_3 Point_3; + typedef typename std::vector::iterator Iterator; + typedef CGAL::AABB_triangle_primitive Primitive; + typedef CGAL::AABB_traits AABB_triangle_traits; + typedef CGAL::AABB_tree Tree; + + // Must be 3D + assert(V.cols() == 3); + // Must be triangles + assert(F.cols() == 3); + + // WTF ALERT!!!! + // + // There's a bug in clang probably or at least in cgal. Without calling this + // line (I guess invoking some compilation from ), clang will vomit + // errors inside CGAL. + // + // http://stackoverflow.com/questions/27748442/is-clangs-c11-support-reliable + T.reserve(0); + + // Make list of cgal triangles + mesh_to_cgal_triangle_list(V,F,T); + tree.clear(); + tree.insert(T.begin(),T.end()); + tree.accelerate_distance_queries(); + // accelerate_distance_queries doesn't seem actually to do _all_ of the + // precomputation. the tree (despite being const) will still do more + // precomputation and reorganizing on the first call of `closest_point` or + // `closest_point_and_primitive`. Therefore, call it once here. + tree.closest_point_and_primitive(Point_3(0,0,0)); +} + +template < + typename Kernel, + typename DerivedP, + typename DerivedsqrD, + typename DerivedI, + typename DerivedC> +IGL_INLINE void igl::copyleft::cgal::point_mesh_squared_distance( + const Eigen::PlainObjectBase & P, + const CGAL::AABB_tree< + CGAL::AABB_traits >::iterator + > + > + > & tree, + const std::vector > & T, + Eigen::PlainObjectBase & sqrD, + Eigen::PlainObjectBase & I, + Eigen::PlainObjectBase & C) +{ + typedef CGAL::Triangle_3 Triangle_3; + typedef typename std::vector::iterator Iterator; + typedef CGAL::AABB_triangle_primitive Primitive; + typedef CGAL::AABB_traits AABB_triangle_traits; + typedef CGAL::AABB_tree Tree; + typedef typename Tree::Point_and_primitive_id Point_and_primitive_id; + typedef CGAL::Point_3 Point_3; + assert(P.cols() == 3); + const int n = P.rows(); + sqrD.resize(n,1); + I.resize(n,1); + C.resize(n,P.cols()); + for(int p = 0;p < n;p++) + { + Point_3 query(P(p,0),P(p,1),P(p,2)); + // Find closest point and primitive id + Point_and_primitive_id pp = tree.closest_point_and_primitive(query); + Point_3 closest_point = pp.first; + assign_scalar(closest_point[0],C(p,0)); + assign_scalar(closest_point[1],C(p,1)); + assign_scalar(closest_point[2],C(p,2)); + assign_scalar((closest_point-query).squared_length(),sqrD(p)); + I(p) = pp.second - T.begin(); + } +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::copyleft::cgal::point_mesh_squared_distance, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase > const&, CGAL::AABB_tree, CGAL::AABB_triangle_primitive, std::vector >, std::allocator > > >::iterator, CGAL::Boolean_tag >, CGAL::Default> > const&, std::vector >, std::allocator > > > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::copyleft::cgal::point_mesh_squared_distance, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::copyleft::cgal::point_mesh_squared_distance, -1, 3, 0, -1, 3>, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, -1, 1, 0, -1, 1>, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::copyleft::cgal::point_mesh_squared_distance_precompute, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, CGAL::AABB_tree, CGAL::AABB_triangle_primitive, std::vector >, std::allocator > > >::iterator, CGAL::Boolean_tag >, CGAL::Default> >&, std::vector >, std::allocator > > >&); +template void igl::copyleft::cgal::point_mesh_squared_distance_precompute, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, CGAL::AABB_tree, CGAL::AABB_triangle_primitive, std::vector >, std::allocator > > >::iterator, CGAL::Boolean_tag >, CGAL::Default> >&, std::vector >, std::allocator > > >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/point_mesh_squared_distance.h b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/point_mesh_squared_distance.h new file mode 100644 index 000000000..b525bddda --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/point_mesh_squared_distance.h @@ -0,0 +1,104 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_COPYLEFT_CGAL_POINT_MESH_SQUARED_DISTANCE_H +#define IGL_COPYLEFT_CGAL_POINT_MESH_SQUARED_DISTANCE_H +#include "../../igl_inline.h" +#include +#include +#include "CGAL_includes.hpp" +namespace igl +{ + namespace copyleft + { + namespace cgal + { + // Compute distances from a set of points P to a triangle mesh (V,F) + // + // Templates: + // Kernal CGAL computation and construction kernel (e.g. + // CGAL::Simple_cartesian) + // Inputs: + // P #P by 3 list of query point positions + // V #V by 3 list of vertex positions + // F #F by 3 list of triangle indices + // Outputs: + // sqrD #P list of smallest squared distances + // I #P list of facet indices corresponding to smallest distances + // C #P by 3 list of closest points + // + // Known bugs: This only computes distances to triangles. So unreferenced + // vertices and degenerate triangles (segments) are ignored. + template < + typename Kernel, + typename DerivedP, + typename DerivedV, + typename DerivedF, + typename DerivedsqrD, + typename DerivedI, + typename DerivedC> + IGL_INLINE void point_mesh_squared_distance( + const Eigen::PlainObjectBase & P, + const Eigen::PlainObjectBase & V, + const Eigen::PlainObjectBase & F, + Eigen::PlainObjectBase & sqrD, + Eigen::PlainObjectBase & I, + Eigen::PlainObjectBase & C); + // Probably can do this in a way that we don't pass around `tree` and `T` + // + // Outputs: + // tree CGAL's AABB tree + // T list of CGAL triangles in order of F (for determining which was found + // in computation) + template < + typename Kernel, + typename DerivedV, + typename DerivedF + > + IGL_INLINE void point_mesh_squared_distance_precompute( + const Eigen::PlainObjectBase & V, + const Eigen::PlainObjectBase & F, + CGAL::AABB_tree< + CGAL::AABB_traits >::iterator + > + > + > & tree, + std::vector > & T); + // Inputs: + // see above + // Outputs: + // see above + template < + typename Kernel, + typename DerivedP, + typename DerivedsqrD, + typename DerivedI, + typename DerivedC> + IGL_INLINE void point_mesh_squared_distance( + const Eigen::PlainObjectBase & P, + const CGAL::AABB_tree< + CGAL::AABB_traits >::iterator + > + > + > & tree, + const std::vector > & T, + Eigen::PlainObjectBase & sqrD, + Eigen::PlainObjectBase & I, + Eigen::PlainObjectBase & C); + } + } +} + +#ifndef IGL_STATIC_LIBRARY +# include "point_mesh_squared_distance.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/point_segment_squared_distance.cpp b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/point_segment_squared_distance.cpp new file mode 100644 index 000000000..257206ae6 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/point_segment_squared_distance.cpp @@ -0,0 +1,41 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "point_segment_squared_distance.h" + +template < typename Kernel> +IGL_INLINE void igl::copyleft::cgal::point_segment_squared_distance( + const CGAL::Point_3 & P1, + const CGAL::Segment_3 & S2, + CGAL::Point_3 & P2, + typename Kernel::FT & d) +{ + if(S2.is_degenerate()) + { + P2 = S2.source(); + d = (P1-P2).squared_length(); + return; + } + // http://stackoverflow.com/a/1501725/148668 + const auto sqr_len = S2.squared_length(); + assert(sqr_len != 0); + const auto & V = S2.source(); + const auto & W = S2.target(); + const auto t = (P1-V).dot(W-V)/sqr_len; + if(t<0) + { + P2 = V; + }else if(t>1) + { + P2 = W; + }else + { + P2 = V + t*(W-V); + } + d = (P1-P2).squared_length(); +} + diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/point_segment_squared_distance.h b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/point_segment_squared_distance.h new file mode 100644 index 000000000..eac628b2a --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/point_segment_squared_distance.h @@ -0,0 +1,44 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_COPYLEFT_CGAL_POINT_SEGMENT_SQUARED_DISTANCE_H +#define IGL_COPYLEFT_CGAL_POINT_SEGMENT_SQUARED_DISTANCE_H +#include "../../igl_inline.h" +#include +#include +namespace igl +{ + namespace copyleft + { + namespace cgal + { + // Given a point P1 and segment S2 find the points on each of closest + // approach and the squared distance thereof. + // + // Inputs: + // P1 point + // S2 segment + // Outputs: + // P2 point on S2 closest to P1 + // d distance betwee P1 and S2 + template < typename Kernel> + IGL_INLINE void point_segment_squared_distance( + const CGAL::Point_3 & P1, + const CGAL::Segment_3 & S2, + CGAL::Point_3 & P2, + typename Kernel::FT & d + ); + + } + } +} +#ifndef IGL_STATIC_LIBRARY +# include "point_segment_squared_distance.cpp" +#endif + +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/point_solid_signed_squared_distance.cpp b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/point_solid_signed_squared_distance.cpp new file mode 100644 index 000000000..7aef2efd1 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/point_solid_signed_squared_distance.cpp @@ -0,0 +1,56 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "point_solid_signed_squared_distance.h" +#include "points_inside_component.h" +#include "point_mesh_squared_distance.h" +#include "../../list_to_matrix.h" +#include "../../slice_mask.h" +#include +#include + +template < + typename DerivedQ, + typename DerivedVB, + typename DerivedFB, + typename DerivedD> +IGL_INLINE void igl::copyleft::cgal::point_solid_signed_squared_distance( + const Eigen::PlainObjectBase & Q, + const Eigen::PlainObjectBase & VB, + const Eigen::PlainObjectBase & FB, + Eigen::PlainObjectBase & D) +{ + // compute unsigned distances + Eigen::VectorXi I; + DerivedVB C; + point_mesh_squared_distance(Q,VB,FB,D,I,C); + // Collect queries that have non-zero distance + Eigen::Array NZ = D.array()!=0; + // Compute sign for non-zero distance queries + DerivedQ QNZ; + slice_mask(Q,NZ,1,QNZ); + Eigen::Array DNZ; + igl::copyleft::cgal::points_inside_component(VB,FB,QNZ,DNZ); + // Apply sign to distances + DerivedD S = DerivedD::Zero(Q.rows(),1); + { + int k = 0; + for(int q = 0;q, -1, 3, 0, -1, 3>, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase, -1, 1, 0, -1, 1> >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/point_solid_signed_squared_distance.h b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/point_solid_signed_squared_distance.h new file mode 100644 index 000000000..845fad133 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/point_solid_signed_squared_distance.h @@ -0,0 +1,48 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_COPYLEFT_CGAL_POINT_SOLID_SIGNED_SQUARED_DISTANCE_H +#define IGL_COPYLEFT_CGAL_POINT_SOLID_SIGNED_SQUARED_DISTANCE_H +#include "../../igl_inline.h" +#include + +namespace igl +{ + namespace copyleft + { + namespace cgal + { + // POINT_SOLID_SIGNED_SQUARED_DISTANCE Given a set of points (Q) and the + // boundary mesh (VB,FB) of a solid (as defined in [Zhou et al. 2016], + // determine the signed squared distance for each point q in Q so that d(q,B) is + // negative if inside and positive if outside. + // + // Inputs: + // Q #Q by 3 list of query point positions + // VB #VB by 3 list of mesh vertex positions of B + // FB #FB by 3 list of mesh triangle indices into VB + // Outputs: + // D + template < + typename DerivedQ, + typename DerivedVB, + typename DerivedFB, + typename DerivedD> + IGL_INLINE void point_solid_signed_squared_distance( + const Eigen::PlainObjectBase & Q, + const Eigen::PlainObjectBase & VB, + const Eigen::PlainObjectBase & FB, + Eigen::PlainObjectBase & D); + } + } +} + +#ifndef IGL_STATIC_LIBRARY +# include "point_solid_signed_squared_distance.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/point_triangle_squared_distance.cpp b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/point_triangle_squared_distance.cpp new file mode 100644 index 000000000..2ea29bc37 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/point_triangle_squared_distance.cpp @@ -0,0 +1,47 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "point_triangle_squared_distance.h" +#include +template < typename Kernel> +IGL_INLINE void point_triangle_squared_distance( + const CGAL::Point_3 & P1, + const CGAL::Triangle_3 & T2, + CGAL::Point_3 & P2, + typename Kernel::FT & d) +{ + assert(!T2.is_degenerate()); + if(T2.has_on(P1)) + { + P2 = P1; + d = 0; + return; + } + const auto proj_1 = T2.supporting_plane().projection(P2); + if(T2.has_on(proj_1)) + { + P2 = proj_1; + d = (proj_1-P1).squared_length(); + return; + } + // closest point must be on the boundary + bool first = true; + // loop over edges + for(int i=0;i<3;i++) + { + CGAL::Point_3 P2i; + typename Kernel::FT di; + const CGAL::Segment_3 si( T2.vertex(i+1), T2.vertex(i+2)); + point_segment_squared_distance(P1,si,P2i,di); + if(first || di < d) + { + first = false; + d = di; + P2 = P2i; + } + } +} diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/point_triangle_squared_distance.h b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/point_triangle_squared_distance.h new file mode 100644 index 000000000..37b63adcb --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/point_triangle_squared_distance.h @@ -0,0 +1,45 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_COPYLEFT_CGAL_POINT_TRIANGLE_SQUARED_DISTANCE_H +#define IGL_COPYLEFT_CGAL_POINT_TRIANGLE_SQUARED_DISTANCE_H +#include "../../igl_inline.h" +#include +#include +namespace igl +{ + namespace copyleft + { + namespace cgal + { + // Given a point P1 and triangle T2 find the points on each of closest + // approach and the squared distance thereof. + // + // Inputs: + // P1 point + // T2 triangle + // Outputs: + // P2 point on T2 closest to P1 + // d distance betwee P1 and T2 + template < typename Kernel> + IGL_INLINE void point_triangle_squared_distance( + const CGAL::Point_3 & P1, + const CGAL::Triangle_3 & T2, + CGAL::Point_3 & P2, + typename Kernel::FT & d + ); + + } + } +} +#ifndef IGL_STATIC_LIBRARY +# include "point_triangle_squared_distance.cpp" +#endif + +#endif + + diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/points_inside_component.cpp b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/points_inside_component.cpp new file mode 100644 index 000000000..1558e130d --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/points_inside_component.cpp @@ -0,0 +1,350 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Qingnan Zhou +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "points_inside_component.h" +#include "../../LinSpaced.h" +#include "order_facets_around_edge.h" +#include "assign_scalar.h" + +#include +#include +#include +#include + +#include +#include +#include +#include + + +namespace igl { + namespace copyleft + { + namespace cgal { + namespace points_inside_component_helper { + typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel; + typedef Kernel::Ray_3 Ray_3; + typedef Kernel::Point_3 Point_3; + typedef Kernel::Vector_3 Vector_3; + typedef Kernel::Triangle_3 Triangle; + typedef Kernel::Plane_3 Plane_3; + typedef std::vector::iterator Iterator; + typedef CGAL::AABB_triangle_primitive Primitive; + typedef CGAL::AABB_traits AABB_triangle_traits; + typedef CGAL::AABB_tree Tree; + + template + void extract_adj_faces( + const Eigen::PlainObjectBase& F, + const Eigen::PlainObjectBase& I, + const size_t s, const size_t d, + std::vector& adj_faces) { + const size_t num_faces = I.rows(); + for (size_t i=0; i + void extract_adj_vertices( + const Eigen::PlainObjectBase& F, + const Eigen::PlainObjectBase& I, + const size_t v, std::vector& adj_vertices) { + std::set unique_adj_vertices; + const size_t num_faces = I.rows(); + for (size_t i=0; i + bool determine_point_edge_orientation( + const Eigen::PlainObjectBase& V, + const Eigen::PlainObjectBase& F, + const Eigen::PlainObjectBase& I, + const Point_3& query, size_t s, size_t d) { + // Algorithm: + // + // Order the adj faces around the edge (s,d) clockwise using + // query point as pivot. (i.e. The first face of the ordering + // is directly after the pivot point, and the last face is + // directly before the pivot.) + // + // The point is outside if the first and last faces of the + // ordering forms a convex angle. This check can be done + // without any construction by looking at the orientation of the + // faces. The angle is convex iff the first face contains (s,d) + // as an edge and the last face contains (d,s) as an edge. + // + // The point is inside if the first and last faces of the + // ordering forms a concave angle. That is the first face + // contains (d,s) as an edge and the last face contains (s,d) as + // an edge. + // + // In the special case of duplicated faces. I.e. multiple faces + // sharing the same 3 corners, but not necessarily the same + // orientation. The ordering will always rank faces containing + // edge (s,d) before faces containing edge (d,s). + // + // Therefore, if there are any duplicates of the first faces, + // the ordering will always choose the one with edge (s,d) if + // possible. The same for the last face. + // + // In the very degenerated case where the first and last face + // are duplicates, but with different orientations, it is + // equally valid to think the angle formed by them is either 0 + // or 360 degrees. By default, 0 degree is used, and thus the + // query point is outside. + + std::vector adj_faces; + extract_adj_faces(F, I, s, d, adj_faces); + const size_t num_adj_faces = adj_faces.size(); + assert(num_adj_faces > 0); + + DerivedV pivot_point(1, 3); + igl::copyleft::cgal::assign_scalar(query.x(), pivot_point(0, 0)); + igl::copyleft::cgal::assign_scalar(query.y(), pivot_point(0, 1)); + igl::copyleft::cgal::assign_scalar(query.z(), pivot_point(0, 2)); + Eigen::VectorXi order; + order_facets_around_edge(V, F, s, d, + adj_faces, pivot_point, order); + assert((size_t)order.size() == num_adj_faces); + if (adj_faces[order[0]] > 0 && + adj_faces[order[num_adj_faces-1] < 0]) { + return true; + } else if (adj_faces[order[0]] < 0 && + adj_faces[order[num_adj_faces-1] > 0]) { + return false; + } else { + throw "The input mesh does not represent a valid volume"; + } + throw "The input mesh does not represent a valid volume"; + return false; + } + + template + bool determine_point_vertex_orientation( + const Eigen::PlainObjectBase& V, + const Eigen::PlainObjectBase& F, + const Eigen::PlainObjectBase& I, + const Point_3& query, size_t s) { + std::vector adj_vertices; + extract_adj_vertices(F, I, s, adj_vertices); + const size_t num_adj_vertices = adj_vertices.size(); + + std::vector adj_points; + for (size_t i=0; i bool{ + size_t positive=0; + size_t negative=0; + size_t coplanar=0; + for (const auto& point : adj_points) { + switch(separator.oriented_side(point)) { + case CGAL::ON_POSITIVE_SIDE: + positive++; + break; + case CGAL::ON_NEGATIVE_SIDE: + negative++; + break; + case CGAL::ON_ORIENTED_BOUNDARY: + coplanar++; + break; + default: + throw "Unknown plane-point orientation"; + } + } + auto query_orientation = separator.oriented_side(query); + bool r = + (positive == 0 && query_orientation == CGAL::POSITIVE) + || + (negative == 0 && query_orientation == CGAL::NEGATIVE); + return r; + }; + + size_t d = std::numeric_limits::max(); + Point_3 p(V(s,0), V(s,1), V(s,2)); + for (size_t i=0; i (size_t)V.rows()) { + // All adj faces are coplanar, use the first edge. + d = adj_vertices[0]; + } + return determine_point_edge_orientation(V, F, I, query, s, d); + } + + template + bool determine_point_face_orientation( + const Eigen::PlainObjectBase& V, + const Eigen::PlainObjectBase& F, + const Eigen::PlainObjectBase& I, + const Point_3& query, size_t fid) { + // Algorithm: A point is on the inside of a face if the + // tetrahedron formed by them is negatively oriented. + + Eigen::Vector3i f = F.row(I(fid, 0)); + const Point_3 v0(V(f[0], 0), V(f[0], 1), V(f[0], 2)); + const Point_3 v1(V(f[1], 0), V(f[1], 1), V(f[1], 2)); + const Point_3 v2(V(f[2], 0), V(f[2], 1), V(f[2], 2)); + auto result = CGAL::orientation(v0, v1, v2, query); + if (result == CGAL::COPLANAR) { + throw "Cannot determine inside/outside because query point lies exactly on the input surface."; + } + return result == CGAL::NEGATIVE; + } + } + } + } +} + +template +IGL_INLINE void igl::copyleft::cgal::points_inside_component( + const Eigen::PlainObjectBase& V, + const Eigen::PlainObjectBase& F, + const Eigen::PlainObjectBase& I, + const Eigen::PlainObjectBase& P, + Eigen::PlainObjectBase& inside) { + using namespace igl::copyleft::cgal::points_inside_component_helper; + if (F.rows() <= 0 || I.rows() <= 0) { + throw "Inside check cannot be done on empty facet component."; + } + + const size_t num_faces = I.rows(); + std::vector triangles; + for (size_t i=0; i ElementType{ + const Eigen::Vector3i f = F.row(I(fid, 0)); + const Point_3 p0(V(f[0], 0), V(f[0], 1), V(f[0], 2)); + const Point_3 p1(V(f[1], 0), V(f[1], 1), V(f[1], 2)); + const Point_3 p2(V(f[2], 0), V(f[2], 1), V(f[2], 2)); + + if (p == p0) { element_index = 0; return VERTEX; } + if (p == p1) { element_index = 1; return VERTEX; } + if (p == p2) { element_index = 2; return VERTEX; } + if (CGAL::collinear(p0, p1, p)) { element_index = 2; return EDGE; } + if (CGAL::collinear(p1, p2, p)) { element_index = 0; return EDGE; } + if (CGAL::collinear(p2, p0, p)) { element_index = 1; return EDGE; } + + element_index = 0; + return FACE; + }; + + const size_t num_queries = P.rows(); + inside.resize(num_queries, 1); + for (size_t i=0; i +IGL_INLINE void igl::copyleft::cgal::points_inside_component( + const Eigen::PlainObjectBase& V, + const Eigen::PlainObjectBase& F, + const Eigen::PlainObjectBase& P, + Eigen::PlainObjectBase& inside) { + Eigen::VectorXi I = igl::LinSpaced(F.rows(), 0, F.rows()-1); + igl::copyleft::cgal::points_inside_component(V, F, I, P, inside); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::copyleft::cgal::points_inside_component, Eigen::Matrix, Eigen::Matrix, -1, 3, 0, -1, 3>, Eigen::Array >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase >&); +template void igl::copyleft::cgal::points_inside_component< Eigen::Matrix, Eigen::Matrix< int, -1, -1, 0, -1, -1>, Eigen::Matrix< int, -1, -1, 0, -1, -1>, Eigen::Matrix, Eigen::Matrix< int, -1, -1, 0, -1, -1> > ( Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&); +template void igl::copyleft::cgal::points_inside_component< Eigen::Matrix, Eigen::Matrix< int, -1, -1, 0, -1, -1>, Eigen::Matrix, Eigen::Matrix< int, -1, -1, 0, -1, -1> > ( Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&); +template void igl::copyleft::cgal::points_inside_component, -1, 3, 0, -1, 3>, Eigen::Matrix, Eigen::Matrix, -1, 3, 0, -1, 3>, Eigen::Matrix >(Eigen::PlainObjectBase, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase >&); +template void igl::copyleft::cgal::points_inside_component, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&); +template void igl::copyleft::cgal::points_inside_component, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&); +template void igl::copyleft::cgal::points_inside_component, -1, -1, 0, -1, -1>, Eigen::Matrix, Eigen::Matrix, -1, -1, 0, -1, -1>, Eigen::Matrix >(Eigen::PlainObjectBase, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/points_inside_component.h b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/points_inside_component.h new file mode 100644 index 000000000..f21354455 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/points_inside_component.h @@ -0,0 +1,71 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Qingnan Zhou +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_COPYLEFT_CGAL_POINTS_INSIDE_COMPONENTS +#define IGL_COPYLEFT_CGAL_POINTS_INSIDE_COMPONENTS + +#include "../../igl_inline.h" +#include +#include + +namespace igl +{ + namespace copyleft + { + namespace cgal { + + // Determine if queries points P are inside of connected facet component + // (V, F, I), where I indicates a subset of facets that forms the + // component. + // + // Precondition: + // The input mesh must be a closed, self-intersection free, + // non-degenerated surface. Queries points must be either inside or + // outside of the mesh (i.e. not on the surface of the mesh). + // + // Inputs: + // V #V by 3 array of vertex positions. + // F #F by 3 array of triangles. + // I #I list of triangle indices to consider. + // P #P by 3 array of query points. + // + // Outputs: + // inside #P list of booleans that is true iff the corresponding + // query point is inside of the mesh. + template< + typename DerivedV, + typename DerivedF, + typename DerivedI, + typename DerivedP, + typename DerivedB> + IGL_INLINE void points_inside_component( + const Eigen::PlainObjectBase& V, + const Eigen::PlainObjectBase& F, + const Eigen::PlainObjectBase& I, + const Eigen::PlainObjectBase& P, + Eigen::PlainObjectBase& inside); + + // Determine if query points P is inside of the mesh (V, F). + // See above for precondition and I/O specs. + template< + typename DerivedV, + typename DerivedF, + typename DerivedP, + typename DerivedB> + IGL_INLINE void points_inside_component( + const Eigen::PlainObjectBase& V, + const Eigen::PlainObjectBase& F, + const Eigen::PlainObjectBase& P, + Eigen::PlainObjectBase& inside); + } + } +} + +#ifndef IGL_STATIC_LIBRARY +#include "points_inside_component.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/polyhedron_to_mesh.cpp b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/polyhedron_to_mesh.cpp new file mode 100644 index 000000000..ba1466e09 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/polyhedron_to_mesh.cpp @@ -0,0 +1,71 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "polyhedron_to_mesh.h" +#include + +template < + typename Polyhedron, + typename DerivedV, + typename DerivedF> +IGL_INLINE void igl::copyleft::cgal::polyhedron_to_mesh( + const Polyhedron & poly, + Eigen::PlainObjectBase & V, + Eigen::PlainObjectBase & F) +{ + using namespace std; + V.resize(poly.size_of_vertices(),3); + F.resize(poly.size_of_facets(),3); + typedef typename Polyhedron::Vertex_const_iterator Vertex_iterator; + std::map vertex_to_index; + { + size_t v = 0; + for( + typename Polyhedron::Vertex_const_iterator p = poly.vertices_begin(); + p != poly.vertices_end(); + p++) + { + V(v,0) = p->point().x(); + V(v,1) = p->point().y(); + V(v,2) = p->point().z(); + vertex_to_index[p] = v; + v++; + } + } + { + size_t f = 0; + for( + typename Polyhedron::Facet_const_iterator facet = poly.facets_begin(); + facet != poly.facets_end(); + ++facet) + { + typename Polyhedron::Halfedge_around_facet_const_circulator he = + facet->facet_begin(); + // Facets in polyhedral surfaces are at least triangles. + assert(CGAL::circulator_size(he) == 3 && "Facets should be triangles"); + size_t c = 0; + do { + //// This is stooopidly slow + // F(f,c) = std::distance(poly.vertices_begin(), he->vertex()); + F(f,c) = vertex_to_index[he->vertex()]; + c++; + } while ( ++he != facet->facet_begin()); + f++; + } + } +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +#include +#include +#include +template void igl::copyleft::cgal::polyhedron_to_mesh >, Eigen::Matrix, Eigen::Matrix >(CGAL::Polyhedron_3 > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::copyleft::cgal::polyhedron_to_mesh >, Eigen::Matrix, Eigen::Matrix >(CGAL::Polyhedron_3 > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::copyleft::cgal::polyhedron_to_mesh,CGAL::Polyhedron_items_with_id_3, CGAL::HalfedgeDS_default, std::allocator >, Eigen::Matrix, Eigen::Matrix >(CGAL::Polyhedron_3,CGAL::Polyhedron_items_with_id_3, CGAL::HalfedgeDS_default, std::allocator > const&,Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/polyhedron_to_mesh.h b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/polyhedron_to_mesh.h new file mode 100644 index 000000000..3f8c66a88 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/polyhedron_to_mesh.h @@ -0,0 +1,43 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_COPYLEFT_CGAL_POLYHEDRON_TO_MESH_H +#define IGL_COPYLEFT_CGAL_POLYHEDRON_TO_MESH_H +#include "../../igl_inline.h" +#include + +namespace igl +{ + namespace copyleft + { + namespace cgal + { + // Convert a CGAL Polyhedron to a mesh (V,F) + // + // Templates: + // Polyhedron CGAL Polyhedron type (e.g. Polyhedron_3) + // Inputs: + // poly cgal polyhedron + // Outputs: + // V #V by 3 list of vertex positions + // F #F by 3 list of triangle indices + template < + typename Polyhedron, + typename DerivedV, + typename DerivedF> + IGL_INLINE void polyhedron_to_mesh( + const Polyhedron & poly, + Eigen::PlainObjectBase & V, + Eigen::PlainObjectBase & F); + } + } +} +#ifndef IGL_STATIC_LIBRARY +# include "polyhedron_to_mesh.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/projected_cdt.cpp b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/projected_cdt.cpp new file mode 100644 index 000000000..f34352c66 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/projected_cdt.cpp @@ -0,0 +1,82 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "projected_cdt.h" +#include "insert_into_cdt.h" +#include "assign_scalar.h" +#include "../../list_to_matrix.h" +template +IGL_INLINE void igl::copyleft::cgal::projected_cdt( + const std::vector & objects, + const CGAL::Plane_3 & P, + std::vector >& vertices, + std::vector >& faces) +{ + typedef CGAL::Triangulation_vertex_base_2 TVB_2; + typedef CGAL::Constrained_triangulation_face_base_2 CTFB_2; + typedef CGAL::Triangulation_data_structure_2 TDS_2; + typedef CGAL::Exact_intersections_tag Itag; + typedef CGAL::Constrained_Delaunay_triangulation_2 CDT_2; + typedef CGAL::Constrained_triangulation_plus_2 CDT_plus_2; + CDT_plus_2 cdt; + for(const auto & obj : objects) insert_into_cdt(obj,P,cdt); + // Read off vertices of the cdt, remembering index + std::map v2i; + size_t count=0; + for ( + auto itr = cdt.finite_vertices_begin(); + itr != cdt.finite_vertices_end(); + itr++) + { + vertices.push_back(P.to_3d(itr->point())); + v2i[itr] = count; + count++; + } + // Read off faces and store index triples + for ( + auto itr = cdt.finite_faces_begin(); + itr != cdt.finite_faces_end(); + itr++) + { + faces.push_back( + { v2i[itr->vertex(0)], v2i[itr->vertex(1)], v2i[itr->vertex(2)] }); + } +} + +template < typename Kernel, typename DerivedV, typename DerivedF> +IGL_INLINE void igl::copyleft::cgal::projected_cdt( + const std::vector & objects, + const CGAL::Plane_3 & P, + Eigen::PlainObjectBase & V, + Eigen::PlainObjectBase & F) +{ + std::vector > vertices; + std::vector > faces; + projected_cdt(objects,P,vertices,faces); + V.resize(vertices.size(),3); + for(int v = 0;v(std::vector > const&, CGAL::Plane_3 const&, std::vector, std::allocator > >&, std::vector >, std::allocator > > >&); +// generated by autoexplicit.sh +template void igl::copyleft::cgal::projected_cdt(std::vector > const&, CGAL::Plane_3 const&, std::vector, std::allocator > >&, std::vector >, std::allocator > > >&); +#include +#ifdef WIN32 +template void igl::copyleft::cgal::projected_cdt(class std::vector> const &, class CGAL::Plane_3 const &, class std::vector, class std::allocator>> &, class std::vector>, class std::allocator>>> &); +template void igl::copyleft::cgal::projected_cdt(class std::vector> const &, class CGAL::Plane_3 const &, class std::vector, class std::allocator>> &, class std::vector>, class std::allocator>>> &); +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/projected_cdt.h b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/projected_cdt.h new file mode 100644 index 000000000..a161cc450 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/projected_cdt.h @@ -0,0 +1,61 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_COPYLEFT_CGAL_PROJECTED_CDT_H +#define IGL_COPYLEFT_CGAL_PROJECTED_CDT_H +#include "../../igl_inline.h" +#include +#include +#include +#include +#include +namespace igl +{ + namespace copyleft + { + namespace cgal + { + // Given a list of objects (e.g., resulting from intersecting a triangle + // with many other triangles), construct a constrained Delaunay + // triangulation on a given plane (P), by inersting constraints for each + // object projected onto that plane. + // + // Inputs: + // objects list of objects. This should lie on the given plane (P), + // otherwise they are added to the cdt _after_ their non-trivial + // projection + // P plane upon which all objects lie and upon which the CDT is + // conducted + // Outputs: + // vertices list of vertices of the CDT mesh _back on the 3D plane_ + // faces list of list of triangle indices into vertices + // + template + IGL_INLINE void projected_cdt( + const std::vector & objects, + const CGAL::Plane_3 & P, + std::vector >& vertices, + std::vector >& faces); + // Outputs: + // V #V by 3 list of vertices of the CDT mesh _back on the 3D plane_, + // **cast** from the number type of Kernel to the number type of + // DerivedV + // F #F by 3 list of triangle indices into V + template < typename Kernel, typename DerivedV, typename DerivedF> + IGL_INLINE void projected_cdt( + const std::vector & objects, + const CGAL::Plane_3 & P, + Eigen::PlainObjectBase & V, + Eigen::PlainObjectBase & F); + } + } +} + +#ifndef IGL_STATIC_LIBRARY +# include "projected_cdt.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/projected_delaunay.cpp b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/projected_delaunay.cpp new file mode 100644 index 000000000..52ea49274 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/projected_delaunay.cpp @@ -0,0 +1,106 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "projected_delaunay.h" +#include "../../REDRUM.h" +#include +#include + +#if CGAL_VERSION_NR < 1040611000 +# warning "CGAL Version < 4.6.1 may result in crashes. Please upgrade CGAL" +#endif + +template +IGL_INLINE void igl::copyleft::cgal::projected_delaunay( + const CGAL::Triangle_3 & A, + const std::vector & A_objects_3, + CGAL::Constrained_triangulation_plus_2< + CGAL::Constrained_Delaunay_triangulation_2< + Kernel, + CGAL::Triangulation_data_structure_2< + CGAL::Triangulation_vertex_base_2, + CGAL::Constrained_triangulation_face_base_2 >, + CGAL::Exact_intersections_tag> > & cdt) +{ + using namespace std; + // 3D Primitives + typedef CGAL::Point_3 Point_3; + typedef CGAL::Segment_3 Segment_3; + typedef CGAL::Triangle_3 Triangle_3; + typedef CGAL::Plane_3 Plane_3; + //typedef CGAL::Tetrahedron_3 Tetrahedron_3; + typedef CGAL::Point_2 Point_2; + //typedef CGAL::Segment_2 Segment_2; + //typedef CGAL::Triangle_2 Triangle_2; + typedef CGAL::Triangulation_vertex_base_2 TVB_2; + typedef CGAL::Constrained_triangulation_face_base_2 CTFB_2; + typedef CGAL::Triangulation_data_structure_2 TDS_2; + typedef CGAL::Exact_intersections_tag Itag; + typedef CGAL::Constrained_Delaunay_triangulation_2 + CDT_2; + typedef CGAL::Constrained_triangulation_plus_2 CDT_plus_2; + + // http://www.cgal.org/Manual/3.2/doc_html/cgal_manual/Triangulation_2/Chapter_main.html#Section_2D_Triangulations_Constrained_Plus + // Plane of triangle A + Plane_3 P(A.vertex(0),A.vertex(1),A.vertex(2)); + // Insert triangle into vertices + typename CDT_plus_2::Vertex_handle corners[3]; + typedef size_t Index; + for(Index i = 0;i<3;i++) + { + const Point_3 & p3 = A.vertex(i); + const Point_2 & p2 = P.to_2d(p3); + typename CDT_plus_2::Vertex_handle corner = cdt.insert(p2); + corners[i] = corner; + } + // Insert triangle edges as constraints + for(Index i = 0;i<3;i++) + { + cdt.insert_constraint( corners[(i+1)%3], corners[(i+2)%3]); + } + // Insert constraints for intersection objects + for( const auto & obj : A_objects_3) + { + if(const Segment_3 *iseg = CGAL::object_cast(&obj)) + { + // Add segment constraint + cdt.insert_constraint(P.to_2d(iseg->vertex(0)),P.to_2d(iseg->vertex(1))); + }else if(const Point_3 *ipoint = CGAL::object_cast(&obj)) + { + // Add point + cdt.insert(P.to_2d(*ipoint)); + } else if(const Triangle_3 *itri = CGAL::object_cast(&obj)) + { + // Add 3 segment constraints + cdt.insert_constraint(P.to_2d(itri->vertex(0)),P.to_2d(itri->vertex(1))); + cdt.insert_constraint(P.to_2d(itri->vertex(1)),P.to_2d(itri->vertex(2))); + cdt.insert_constraint(P.to_2d(itri->vertex(2)),P.to_2d(itri->vertex(0))); + } else if(const std::vector *polyp = + CGAL::object_cast< std::vector >(&obj)) + { + //cerr< & poly = *polyp; + const Index m = poly.size(); + assert(m>=2); + for(Index p = 0;p(CGAL::Triangle_3 const&, std::vector > const&, CGAL::Constrained_triangulation_plus_2 >, CGAL::Constrained_triangulation_face_base_2 > > >, CGAL::Exact_intersections_tag> >&); +template void igl::copyleft::cgal::projected_delaunay(CGAL::Triangle_3 const&, std::vector > const&, CGAL::Constrained_triangulation_plus_2 >, CGAL::Constrained_triangulation_face_base_2 > > >, CGAL::Exact_intersections_tag> >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/projected_delaunay.h b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/projected_delaunay.h new file mode 100644 index 000000000..ee72305cd --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/projected_delaunay.h @@ -0,0 +1,46 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_COPYLEFT_CGAL_PROJECTED_DELAUNAY_H +#define IGL_COPYLEFT_CGAL_PROJECTED_DELAUNAY_H +#include "../../igl_inline.h" +#include "CGAL_includes.hpp" +namespace igl +{ + namespace copyleft + { + namespace cgal + { + // Compute 2D delaunay triangulation of a given 3d triangle and a list of + // intersection objects (points,segments,triangles). CGAL uses an affine + // projection rather than an isometric projection, so we're not guaranteed + // that the 2D delaunay triangulation here will be a delaunay triangulation + // in 3D. + // + // Inputs: + // A triangle in 3D + // A_objects_3 updated list of intersection objects for A + // Outputs: + // cdt Contrained delaunay triangulation in projected 2D plane + template + IGL_INLINE void projected_delaunay( + const CGAL::Triangle_3 & A, + const std::vector & A_objects_3, + CGAL::Constrained_triangulation_plus_2< + CGAL::Constrained_Delaunay_triangulation_2< + Kernel, + CGAL::Triangulation_data_structure_2< + CGAL::Triangulation_vertex_base_2, + CGAL::Constrained_triangulation_face_base_2 >, + CGAL::Exact_intersections_tag> > & cdt); + } + } +} +#ifndef IGL_STATIC_LIBRARY +# include "projected_delaunay.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/propagate_winding_numbers.cpp b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/propagate_winding_numbers.cpp new file mode 100644 index 000000000..7de9d98d2 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/propagate_winding_numbers.cpp @@ -0,0 +1,324 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Qingnan Zhou +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +// +#include "propagate_winding_numbers.h" +#include "../../extract_manifold_patches.h" +#include "../../extract_non_manifold_edge_curves.h" +#include "../../facet_components.h" +#include "../../unique_edge_map.h" +#include "../../piecewise_constant_winding_number.h" +#include "../../writeOBJ.h" +#include "../../writePLY.h" +#include "../../get_seconds.h" +#include "../../LinSpaced.h" +#include "order_facets_around_edge.h" +#include "outer_facet.h" +#include "closest_facet.h" +#include "assign.h" +#include "extract_cells.h" +#include "cell_adjacency.h" + +#include +#include +#include +#include +#include + +//#define PROPAGATE_WINDING_NUMBER_TIMING + +template< + typename DerivedV, + typename DerivedF, + typename DerivedL, + typename DerivedW> +IGL_INLINE bool igl::copyleft::cgal::propagate_winding_numbers( + const Eigen::PlainObjectBase& V, + const Eigen::PlainObjectBase& F, + const Eigen::PlainObjectBase& labels, + Eigen::PlainObjectBase& W) +{ +#ifdef PROPAGATE_WINDING_NUMBER_TIMING + const auto & tictoc = []() -> double + { + static double t_start = igl::get_seconds(); + double diff = igl::get_seconds()-t_start; + t_start += diff; + return diff; + }; + const auto log_time = [&](const std::string& label) -> void { + std::cout << "propagate_winding_num." << label << ": " + << tictoc() << std::endl; + }; + tictoc(); +#endif + + Eigen::MatrixXi E, uE; + Eigen::VectorXi EMAP; + std::vector > uE2E; + igl::unique_edge_map(F, E, uE, EMAP, uE2E); + + Eigen::VectorXi P; + const size_t num_patches = igl::extract_manifold_patches(F, EMAP, uE2E, P); + + DerivedW per_patch_cells; + const size_t num_cells = + igl::copyleft::cgal::extract_cells( + V, F, P, E, uE, uE2E, EMAP, per_patch_cells); +#ifdef PROPAGATE_WINDING_NUMBER_TIMING + log_time("cell_extraction"); +#endif + + return propagate_winding_numbers(V, F, + uE, uE2E, + num_patches, P, + num_cells, per_patch_cells, + labels, W); +} + + +template< + typename DerivedV, + typename DerivedF, + typename DeriveduE, + typename uE2EType, + typename DerivedP, + typename DerivedC, + typename DerivedL, + typename DerivedW> +IGL_INLINE bool igl::copyleft::cgal::propagate_winding_numbers( + const Eigen::PlainObjectBase& V, + const Eigen::PlainObjectBase& F, + const Eigen::PlainObjectBase& uE, + const std::vector >& uE2E, + const size_t num_patches, + const Eigen::PlainObjectBase& P, + const size_t num_cells, + const Eigen::PlainObjectBase& C, + const Eigen::PlainObjectBase& labels, + Eigen::PlainObjectBase& W) +{ +#ifdef PROPAGATE_WINDING_NUMBER_TIMING + const auto & tictoc = []() -> double + { + static double t_start = igl::get_seconds(); + double diff = igl::get_seconds()-t_start; + t_start += diff; + return diff; + }; + const auto log_time = [&](const std::string& label) -> void { + std::cout << "propagate_winding_num." << label << ": " + << tictoc() << std::endl; + }; + tictoc(); +#endif + + bool valid = true; + // https://github.com/libigl/libigl/issues/674 + if (!igl::piecewise_constant_winding_number(F, uE, uE2E)) + { + assert(false && "Input mesh is not PWN"); + std::cerr << "Input mesh is not PWN!" << std::endl; + valid = false; + } + + const size_t num_faces = F.rows(); + typedef std::tuple CellConnection; + std::vector > cell_adj; + igl::copyleft::cgal::cell_adjacency(C, num_cells, cell_adj); +#ifdef PROPAGATE_WINDING_NUMBER_TIMING + log_time("cell_connectivity"); +#endif + + auto save_cell = [&](const std::string& filename, size_t cell_id) -> void{ + std::vector faces; + for (size_t i=0; i std::list { + std::list path; + path.push_back(idx); + while ((size_t)parents[path.back()] != path.back()) { + path.push_back(parents[path.back()]); + } + return path; + }; + for (size_t i=0; i Q; + Q.push(i); + parents[i] = i; + while (!Q.empty()) { + size_t curr_idx = Q.front(); + Q.pop(); + int curr_label = cell_labels[curr_idx]; + for (const auto& neighbor : cell_adj[curr_idx]) { + if (cell_labels[std::get<0>(neighbor)] == 0) + { + cell_labels[std::get<0>(neighbor)] = curr_label * -1; + Q.push(std::get<0>(neighbor)); + parents[std::get<0>(neighbor)] = curr_idx; + } else + { + if (cell_labels[std::get<0>(neighbor)] != curr_label * -1) + { + std::cerr << "Odd cell cycle detected!" << std::endl; + auto path = trace_parents(curr_idx); + path.reverse(); + auto path2 = trace_parents(std::get<0>(neighbor)); + path.insert(path.end(), path2.begin(), path2.end()); + for (auto cell_id : path) + { + std::cout << cell_id << " "; + std::stringstream filename; + filename << "cell_" << cell_id << ".ply"; + save_cell(filename.str(), cell_id); + } + std::cout << std::endl; + valid = false; + } + // Do not fail when odd cycle is detected because the resulting + // integer winding number field, although inconsistent, may still + // be used if the problem region is local and embedded within a + // valid volume. + //assert(cell_labels[std::get<0>(neighbor)] == curr_label * -1); + } + } + } + } + } +#ifdef PROPAGATE_WINDING_NUMBER_TIMING + log_time("odd_cycle_check"); +#endif + } +#endif + + size_t outer_facet; + bool flipped; + Eigen::VectorXi I = igl::LinSpaced(num_faces, 0, num_faces-1); + igl::copyleft::cgal::outer_facet(V, F, I, outer_facet, flipped); +#ifdef PROPAGATE_WINDING_NUMBER_TIMING + log_time("outer_facet"); +#endif + + const size_t outer_patch = P[outer_facet]; + const size_t infinity_cell = C(outer_patch, flipped?1:0); + + Eigen::VectorXi patch_labels(num_patches); + const int INVALID = std::numeric_limits::max(); + patch_labels.setConstant(INVALID); + for (size_t i=0; i Q; + Q.push(infinity_cell); + while (!Q.empty()) { + size_t curr_cell = Q.front(); + Q.pop(); + for (const auto& neighbor : cell_adj[curr_cell]) { + size_t neighbor_cell, patch_idx; + bool direction; + std::tie(neighbor_cell, direction, patch_idx) = neighbor; + if ((per_cell_W.row(neighbor_cell).array() == INVALID).any()) { + per_cell_W.row(neighbor_cell) = per_cell_W.row(curr_cell); + for (size_t i=0; i, -1, -1, 1, -1, -1>, Eigen::Matrix, Eigen::Matrix, unsigned long, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, std::vector >, std::allocator > > > const&, unsigned long, Eigen::PlainObjectBase > const&, unsigned long, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template bool igl::copyleft::cgal::propagate_winding_numbers, -1, -1, 1, -1, -1>, Eigen::Matrix, Eigen::Matrix, unsigned long, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, std::vector >, std::allocator > > > const&, unsigned long, Eigen::PlainObjectBase > const&, unsigned long, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&); +template bool igl::copyleft::cgal::propagate_winding_numbers, -1, -1, 0, -1, -1>, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&); +#ifdef WIN32 +template bool igl::copyleft::cgal::propagate_winding_numbers, -1, -1, 1, -1, -1>, class Eigen::Matrix, class Eigen::Matrix, unsigned __int64, class Eigen::Matrix, class Eigen::Matrix, class Eigen::Matrix, class Eigen::Matrix>(class Eigen::PlainObjectBase, -1, -1, 1, -1, -1>> const &, class Eigen::PlainObjectBase> const &, class Eigen::PlainObjectBase> const &, class std::vector>, class std::allocator>>> const &, unsigned __int64, class Eigen::PlainObjectBase> const &, unsigned __int64, class Eigen::PlainObjectBase> const &, class Eigen::PlainObjectBase> const &, class Eigen::PlainObjectBase> &); +template bool igl::copyleft::cgal::propagate_winding_numbers, -1, -1, 1, -1, -1>, class Eigen::Matrix, class Eigen::Matrix, unsigned __int64, class Eigen::Matrix, class Eigen::Matrix, class Eigen::Matrix, class Eigen::Matrix>(class Eigen::PlainObjectBase, -1, -1, 1, -1, -1>> const &, class Eigen::PlainObjectBase> const &, class Eigen::PlainObjectBase> const &, class std::vector>, class std::allocator>>> const &, unsigned __int64, class Eigen::PlainObjectBase> const &, unsigned __int64, class Eigen::PlainObjectBase> const &, class Eigen::PlainObjectBase> const &, class Eigen::PlainObjectBase> &); +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/propagate_winding_numbers.h b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/propagate_winding_numbers.h new file mode 100644 index 000000000..77d8e7666 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/propagate_winding_numbers.h @@ -0,0 +1,103 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Qingnan Zhou +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +// +#ifndef IGL_COPYLEFT_CGAL_PROPAGATE_WINDING_NUMBERS_H +#define IGL_COPYLEFT_CGAL_PROPAGATE_WINDING_NUMBERS_H +#include "../../igl_inline.h" +#include +#include + +// The following methods compute the winding number on each side of each facet +// or patch of a 3D mesh. The input mesh is valid if it splits the ambient +// space, R^3, into subspaces with constant integer winding numbers. That is +// the input mesh should be closed and for each directed edge the number of +// clockwise facing facets should equal the number of counterclockwise facing +// facets. + +namespace igl +{ + namespace copyleft + { + namespace cgal + { + // TODO: This shouldn't need to be in igl::copyleft::cgal, it should + // instead take as input an index of the ambient cell and the winding + // number vector there. + // + // Compute winding number on each side of the face. The input mesh + // could contain multiple connected components. The input mesh must + // represent the boundary of a valid 3D volume, which means it is + // closed, consistently oriented and induces integer winding numbers. + // + // Inputs: + // V #V by 3 list of vertex positions. + // F #F by 3 list of triangle indices into V. + // labels #F list of facet labels ranging from 0 to k-1. + // Output: + // W #F by k*2 list of winding numbers. ``W(i,j*2)`` is the winding + // number on the positive side of facet ``i`` with respect to the + // facets labeled ``j``. Similarly, ``W(i,j*2+1)`` is the winding + // number on the negative side of facet ``i`` with respect to the + // facets labeled ``j``. + // Returns true iff the input induces a piecewise-constant winding number + // field. + template< + typename DerivedV, + typename DerivedF, + typename DerivedL, + typename DerivedW> + IGL_INLINE bool propagate_winding_numbers( + const Eigen::PlainObjectBase& V, + const Eigen::PlainObjectBase& F, + const Eigen::PlainObjectBase& labels, + Eigen::PlainObjectBase& W); + + // Inputs: + // V #V by 3 list of vertex positions. + // F #F by 3 list of triangle indices into V. + // uE #uE by 2 list of vertex_indices, represents undirected edges. + // uE2E #uE list of lists that maps uE to E. (a one-to-many map) + // num_patches number of patches + // P #F list of patch ids. + // num_cells number of cells + // C #P by 2 list of cell ids on each side of each patch. + // labels #F list of facet labels ranging from 0 to k-1. + // Output: + // W #F by k*2 list of winding numbers. ``W(i,j*2)`` is the winding + // number on the positive side of facet ``i`` with respect to the + // facets labeled ``j``. Similarly, ``W(i,j*2+1)`` is the winding + // number on the negative side of facet ``i`` with respect to the + // facets labeled ``j``. + template< + typename DerivedV, + typename DerivedF, + typename DeriveduE, + typename uE2EType, + typename DerivedP, + typename DerivedC, + typename DerivedL, + typename DerivedW> + IGL_INLINE bool propagate_winding_numbers( + const Eigen::PlainObjectBase& V, + const Eigen::PlainObjectBase& F, + const Eigen::PlainObjectBase& uE, + const std::vector >& uE2E, + const size_t num_patches, + const Eigen::PlainObjectBase& P, + const size_t num_cells, + const Eigen::PlainObjectBase& C, + const Eigen::PlainObjectBase& labels, + Eigen::PlainObjectBase& W); + } + } +} + +#ifndef IGL_STATIC_LIBRARY +# include "propagate_winding_numbers.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/read_triangle_mesh.cpp b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/read_triangle_mesh.cpp new file mode 100644 index 000000000..24ebbb127 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/read_triangle_mesh.cpp @@ -0,0 +1,26 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +#include "read_triangle_mesh.h" +#include "assign.h" +#include "../../read_triangle_mesh.h" + +template +IGL_INLINE bool igl::copyleft::cgal::read_triangle_mesh( + const std::string str, + Eigen::PlainObjectBase& V, + Eigen::PlainObjectBase& F) +{ + Eigen::MatrixXd Vd; + bool ret = igl::read_triangle_mesh(str,Vd,F); + if(ret) + { + assign(Vd,V); + } + return ret; +} diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/read_triangle_mesh.h b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/read_triangle_mesh.h new file mode 100644 index 000000000..c1dae2a22 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/read_triangle_mesh.h @@ -0,0 +1,42 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_COPYLEFT_CGAL_READ_TRIANGLE_MESH_H +#define IGL_COPYLEFT_CGAL_READ_TRIANGLE_MESH_H +#include "../../igl_inline.h" + +#include +namespace igl +{ + namespace copyleft + { + namespace cgal + { + // Simple wrapper, reads floating point precision but assigns to + // DerivedV::Scalar which may be a CGAL type + // + // Inputs: + // str path to file + // Outputs: + // V eigen double matrix #V by 3 + // F eigen int matrix #F by 3 + // Returns true iff success + template + IGL_INLINE bool read_triangle_mesh( + const std::string str, + Eigen::PlainObjectBase& V, + Eigen::PlainObjectBase& F); + } + } +} + +#ifndef IGL_STATIC_LIBRARY +# include "read_triangle_mesh.cpp" +#endif + +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/relabel_small_immersed_cells.cpp b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/relabel_small_immersed_cells.cpp new file mode 100644 index 000000000..993e009ec --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/relabel_small_immersed_cells.cpp @@ -0,0 +1,117 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Qingnan Zhou +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +// + +#include "relabel_small_immersed_cells.h" +#include "../../centroid.h" +#include "assign.h" +#include "cell_adjacency.h" + +#include + +template< + typename DerivedV, + typename DerivedF, + typename DerivedP, + typename DerivedC, + typename FT, + typename DerivedW> +IGL_INLINE void igl::copyleft::cgal::relabel_small_immersed_cells( + const Eigen::PlainObjectBase& V, + const Eigen::PlainObjectBase& F, + const size_t num_patches, + const Eigen::PlainObjectBase& P, + const size_t num_cells, + const Eigen::PlainObjectBase& C, + const FT vol_threashold, + Eigen::PlainObjectBase& W) +{ + const size_t num_vertices = V.rows(); + const size_t num_faces = F.rows(); + typedef std::tuple CellConnection; + std::vector > cell_adj; + igl::copyleft::cgal::cell_adjacency(C, num_cells, cell_adj); + + Eigen::MatrixXd VV; + assign(V,VV); + + auto compute_cell_volume = [&](size_t cell_id) { + std::vector is_involved(num_patches, 0); + for (size_t i=0; i involved_positive_faces; + std::vector involved_negative_faces; + for (size_t i=0; i cell_volumes(num_cells); + for (size_t i=0; i cell_values(num_cells); + for (size_t i=0; i= vol_threashold) continue; + std::set neighbor_values; + const auto neighbors = cell_adj[i]; + for (const auto& entry : neighbors) { + const auto& j = std::get<0>(entry); + neighbor_values.insert(cell_values[j]); + } + // If cell i is immersed, assign its value to be the immersed value. + if (neighbor_values.size() == 1) { + cell_values[i] = *neighbor_values.begin(); + } + } + + for (size_t i=0; i +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +// +#ifndef IGL_RELABEL_SMALL_IMMERSED_CELLS +#define IGL_RELABEL_SMALL_IMMERSED_CELLS + +#include "../../igl_inline.h" +#include +#include + +namespace igl +{ + namespace copyleft + { + namespace cgal + { + // Inputs: + // V #V by 3 list of vertex positions. + // F #F by 3 list of triangle indices into V. + // num_patches number of patches + // P #F list of patch ids. + // num_cells number of cells + // C #P by 2 list of cell ids on each side of each patch. + // vol_threshold Volume threshold, cells smaller than this + // and is completely immersed will be relabeled. + // + // In/Output: + // W #F by 2 cell labels. W(i,0) is the label on the positive side of + // face i, W(i,1) is the label on the negative side of face i. W + // will be modified in place by this method. + template< + typename DerivedV, + typename DerivedF, + typename DerivedP, + typename DerivedC, + typename FT, + typename DerivedW> + IGL_INLINE void relabel_small_immersed_cells( + const Eigen::PlainObjectBase& V, + const Eigen::PlainObjectBase& F, + const size_t num_patches, + const Eigen::PlainObjectBase& P, + const size_t num_cells, + const Eigen::PlainObjectBase& C, + const FT vol_threashold, + Eigen::PlainObjectBase& W); + } + } +} + +#ifndef IGL_STATIC_LIBRARY +# include "relabel_small_immersed_cells.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/remesh_intersections.cpp b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/remesh_intersections.cpp new file mode 100644 index 000000000..019db2eef --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/remesh_intersections.cpp @@ -0,0 +1,541 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Qingnan Zhou +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +// +#include "remesh_intersections.h" +#include "assign_scalar.h" +#include "projected_cdt.h" +#include "../../get_seconds.h" +#include "../../parallel_for.h" +#include "../../LinSpaced.h" +#include "../../unique_rows.h" + +#include +#include +#include +#include +#include + +//#define REMESH_INTERSECTIONS_TIMING + +template < + typename DerivedV, + typename DerivedF, + typename Kernel, + typename DerivedVV, + typename DerivedFF, + typename DerivedJ, + typename DerivedIM> +IGL_INLINE void igl::copyleft::cgal::remesh_intersections( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const std::vector > & T, + const std::map< + typename DerivedF::Index, + std::vector< + std::pair > > & offending, + Eigen::PlainObjectBase & VV, + Eigen::PlainObjectBase & FF, + Eigen::PlainObjectBase & J, + Eigen::PlainObjectBase & IM) +{ + // by default, no stitching + igl::copyleft::cgal::remesh_intersections(V,F,T,offending,false,VV,FF,J,IM); +} + +template < + typename DerivedV, + typename DerivedF, + typename Kernel, + typename DerivedVV, + typename DerivedFF, + typename DerivedJ, + typename DerivedIM> +IGL_INLINE void igl::copyleft::cgal::remesh_intersections( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const std::vector > & T, + const std::map< + typename DerivedF::Index, + std::vector< + std::pair > > & offending, + bool stitch_all, + Eigen::PlainObjectBase & VV, + Eigen::PlainObjectBase & FF, + Eigen::PlainObjectBase & J, + Eigen::PlainObjectBase & IM) +{ + +#ifdef REMESH_INTERSECTIONS_TIMING + const auto & tictoc = []() -> double + { + static double t_start = igl::get_seconds(); + double diff = igl::get_seconds()-t_start; + t_start += diff; + return diff; + }; + const auto log_time = [&](const std::string& label) -> void { + std::cout << "remesh_intersections." << label << ": " + << tictoc() << std::endl; + }; + tictoc(); +#endif + + typedef CGAL::Point_3 Point_3; + typedef CGAL::Segment_3 Segment_3; + typedef CGAL::Plane_3 Plane_3; + typedef CGAL::Triangulation_vertex_base_2 TVB_2; + typedef CGAL::Constrained_triangulation_face_base_2 CTFB_2; + typedef CGAL::Triangulation_data_structure_2 TDS_2; + typedef CGAL::Exact_intersections_tag Itag; + typedef CGAL::Constrained_Delaunay_triangulation_2 + CDT_2; + typedef CGAL::Constrained_triangulation_plus_2 CDT_plus_2; + + typedef typename DerivedF::Index Index; + typedef std::pair Edge; + struct EdgeHash { + size_t operator()(const Edge& e) const { + return (e.first * 805306457) ^ (e.second * 201326611); + } + }; + typedef std::unordered_map, EdgeHash > EdgeMap; + + const size_t num_faces = F.rows(); + const size_t num_base_vertices = V.rows(); + assert(num_faces == T.size()); + + std::vector is_offending(num_faces, false); + for (const auto itr : offending) + { + const auto& fid = itr.first; + is_offending[fid] = true; + } + + // Cluster overlaps so that co-planar clusters are resolved only once + std::unordered_map > intersecting_and_coplanar; + for (const auto itr : offending) + { + const auto& fi = itr.first; + const auto P = T[fi].supporting_plane(); + assert(!P.is_degenerate()); + for (const auto jtr : itr.second) + { + const auto& fj = jtr.first; + const auto& tj = T[fj]; + if (P.has_on(tj[0]) && P.has_on(tj[1]) && P.has_on(tj[2])) + { + auto loc = intersecting_and_coplanar.find(fi); + if (loc == intersecting_and_coplanar.end()) + { + intersecting_and_coplanar[fi] = {fj}; + } else + { + loc->second.push_back(fj); + } + } + } + } +#ifdef REMESH_INTERSECTIONS_TIMING + log_time("overlap_analysis"); +#endif + + std::vector > resolved_faces; + std::vector source_faces; + std::vector new_vertices; + EdgeMap edge_vertices; + // face_vertices: Given a face Index, find vertices inside the face + std::unordered_map> face_vertices; + + // Run constraint Delaunay triangulation on the plane. + // + // Inputs: + // P plane to triangulate upone + // involved_faces #F list of indices into triangle of involved faces + // Outputs: + // vertices #V list of vertex positions of output triangulation + // faces #F list of face indices into vertices of output triangulation + // + auto delaunay_triangulation = [&offending, &T]( + const Plane_3& P, + const std::vector& involved_faces, + std::vector& vertices, + std::vector >& faces) -> void + { + std::vector objects; + + CDT_plus_2 cdt; + // insert each face into a common cdt + for (const auto& fid : involved_faces) + { + const auto itr = offending.find(fid); + const auto& triangle = T[fid]; + objects.push_back(CGAL::make_object(triangle)); + if (itr == offending.end()) + { + continue; + } + for (const auto& index_obj : itr->second) + { + //const auto& ofid = index_obj.first; + const auto& obj = index_obj.second; + objects.push_back(obj); + } + } + projected_cdt(objects,P,vertices,faces); + }; + + // Given p on triangle indexed by ori_f, add point to list of vertices return index of p. + // + // Input: + // p point to search for + // ori_f index of triangle p is corner of + // Returns global index of vertex (dependent on whether stitch_all flag is + // set) + // + auto find_or_append_point = [&]( + const Point_3& p, + const size_t ori_f) -> Index + { + if (stitch_all) + { + // No need to check if p shared by multiple triangles because all shared + // vertices would be merged later on. + const size_t index = num_base_vertices + new_vertices.size(); + new_vertices.push_back(p); + return index; + } else + { + // Stitching triangles according to input connectivity. + // This step is potentially costly. + const auto& triangle = T[ori_f]; + const auto& f = F.row(ori_f).eval(); + + // Check if p is one of the triangle corners. + for (size_t i=0; i<3; i++) + { + if (p == triangle[i]) return f[i]; + } + + // Check if p is on one of the edges. + for (size_t i=0; i<3; i++) { + const Point_3 curr_corner = triangle[i]; + const Point_3 next_corner = triangle[(i+1)%3]; + const Segment_3 edge(curr_corner, next_corner); + if (edge.has_on(p)) { + const Index curr = f[i]; + const Index next = f[(i+1)%3]; + Edge key; + key.first = currsecond) { + if (p == new_vertices[vid - num_base_vertices]) { + return vid; + } + } + const size_t index = num_base_vertices + new_vertices.size(); + new_vertices.push_back(p); + itr->second.push_back(index); + return index; + } + } + } + + // p must be in the middle of the triangle. + auto & existing_face_vertices = face_vertices[ori_f]; + for(const auto vid : existing_face_vertices) { + if (p == new_vertices[vid - num_base_vertices]) { + return vid; + } + } + const size_t index = num_base_vertices + new_vertices.size(); + new_vertices.push_back(p); + existing_face_vertices.push_back(index); + return index; + } + }; + + // Determine the vertex indices for each corner of each output triangle. + // + // Inputs: + // vertices #V list of vertices of cdt + // faces #F list of list of face indices into vertices of cdt + // involved_faces list of involved faces on the plane of cdt + // Side effects: + // - add faces to resolved_faces + // - add corresponding original face to source_faces + // - + auto post_triangulation_process = [&]( + const std::vector& vertices, + const std::vector >& faces, + const std::vector& involved_faces) -> void + { + assert(involved_faces.size() > 0); + // for all faces of the cdt + for (const auto& f : faces) + { + const Point_3& v0 = vertices[f[0]]; + const Point_3& v1 = vertices[f[1]]; + const Point_3& v2 = vertices[f[2]]; + Point_3 center( + (v0[0] + v1[0] + v2[0]) / 3.0, + (v0[1] + v1[1] + v2[1]) / 3.0, + (v0[2] + v1[2] + v2[2]) / 3.0); + if (involved_faces.size() == 1) + { + // If only there is only one involved face, all sub-triangles must + // belong to it and have the correct orientation. + const auto& ori_f = involved_faces[0]; + std::vector corners(3); + corners[0] = find_or_append_point(v0, ori_f); + corners[1] = find_or_append_point(v1, ori_f); + corners[2] = find_or_append_point(v2, ori_f); + resolved_faces.emplace_back(corners); + source_faces.push_back(ori_f); + } else + { + for (const auto& ori_f : involved_faces) + { + const auto& triangle = T[ori_f]; + const Plane_3 P = triangle.supporting_plane(); + if (triangle.has_on(center)) { + std::vector corners(3); + corners[0] = find_or_append_point(v0, ori_f); + corners[1] = find_or_append_point(v1, ori_f); + corners[2] = find_or_append_point(v2, ori_f); + if (CGAL::orientation( + P.to_2d(v0), P.to_2d(v1), P.to_2d(v2)) + == CGAL::RIGHT_TURN) { + std::swap(corners[0], corners[1]); + } + resolved_faces.emplace_back(corners); + source_faces.push_back(ori_f); + } + } + } + } + }; + + // Process un-touched faces. + for (size_t i=0; i processed(num_faces, false); + std::vector > > cdt_inputs; + for (const auto itr : offending) + { + const auto fid = itr.first; + if (processed[fid]) continue; + processed[fid] = true; + + const auto loc = intersecting_and_coplanar.find(fid); + std::vector involved_faces; + if (loc == intersecting_and_coplanar.end()) + { + involved_faces.push_back(fid); + } else + { + std::queue Q; + Q.push(fid); + while (!Q.empty()) + { + const auto index = Q.front(); + involved_faces.push_back(index); + Q.pop(); + + const auto overlapping_faces = intersecting_and_coplanar.find(index); + assert(overlapping_faces != intersecting_and_coplanar.end()); + + for (const auto other_index : overlapping_faces->second) + { + if (processed[other_index]) continue; + processed[other_index] = true; + Q.push(other_index); + } + } + } + + Plane_3 P = T[fid].supporting_plane(); + cdt_inputs.emplace_back(P, involved_faces); + } +#ifdef REMESH_INTERSECTIONS_TIMING + log_time("preprocess"); +#endif + + const size_t num_cdts = cdt_inputs.size(); + std::vector > cdt_vertices(num_cdts); + std::vector > > cdt_faces(num_cdts); + + //// Not clear whether this is safe because of reference counting on Point_3 + //// objects... + //// + //// I tried it and got random segfaults (via MATLAB). Seems this is not + //// safe. + //igl::parallel_for(num_cdts,[&](int i) + for (size_t i=0; i + >(unique_vv.rows(), 0, unique_vv.rows()-1); + }else + { + // Vertices with the same coordinates would be represented by one vertex. + // The IM value of a vertex is the index of the representative vertex. + for (Index v=0; v<(Index)VV_size; v++) { + IM(v) = unique_to_vv[vv_to_unique[v]]; + } + } + +#ifdef REMESH_INTERSECTIONS_TIMING + log_time("store_results"); +#endif +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::copyleft::cgal::remesh_intersections, Eigen::Matrix, CGAL::Epick, Eigen::Matrix, -1, -1, 0, -1, -1>, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, std::vector, std::allocator > > const&, std::map::Index, std::vector::Index, CGAL::Object>, std::allocator::Index, CGAL::Object> > >, std::less::Index>, std::allocator::Index const, std::vector::Index, CGAL::Object>, std::allocator::Index, CGAL::Object> > > > > > const&, bool, Eigen::PlainObjectBase, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::copyleft::cgal::remesh_intersections, Eigen::Matrix, CGAL::Epeck, Eigen::Matrix, -1, -1, 0, -1, -1>, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, std::vector, std::allocator > > const&, std::map::Index, std::vector::Index, CGAL::Object>, std::allocator::Index, CGAL::Object> > >, std::less::Index>, std::allocator::Index const, std::vector::Index, CGAL::Object>, std::allocator::Index, CGAL::Object> > > > > > const&, bool, Eigen::PlainObjectBase, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::copyleft::cgal::remesh_intersections, -1, 3, 0, -1, 3>, Eigen::Matrix, CGAL::Epick, Eigen::Matrix, -1, -1, 1, -1, -1>, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase > const&, std::vector, std::allocator > > const&, std::map::Index, std::vector::Index, CGAL::Object>, std::allocator::Index, CGAL::Object> > >, std::less::Index>, std::allocator::Index const, std::vector::Index, CGAL::Object>, std::allocator::Index, CGAL::Object> > > > > > const&, bool, Eigen::PlainObjectBase, -1, -1, 1, -1, -1> >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::copyleft::cgal::remesh_intersections, -1, 3, 0, -1, 3>, Eigen::Matrix, CGAL::Epeck, Eigen::Matrix, -1, -1, 1, -1, -1>, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase > const&, std::vector, std::allocator > > const&, std::map::Index, std::vector::Index, CGAL::Object>, std::allocator::Index, CGAL::Object> > >, std::less::Index>, std::allocator::Index const, std::vector::Index, CGAL::Object>, std::allocator::Index, CGAL::Object> > > > > > const&, bool, Eigen::PlainObjectBase, -1, -1, 1, -1, -1> >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::copyleft::cgal::remesh_intersections, Eigen::Matrix, CGAL::Epick, Eigen::Matrix, -1, 3, 0, -1, 3>, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, std::vector, std::allocator > > const&, std::map::Index, std::vector::Index, CGAL::Object>, std::allocator::Index, CGAL::Object> > >, std::less::Index>, std::allocator::Index const, std::vector::Index, CGAL::Object>, std::allocator::Index, CGAL::Object> > > > > > const&, bool, Eigen::PlainObjectBase, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::copyleft::cgal::remesh_intersections, -1, -1, 1, -1, -1>, Eigen::Matrix, CGAL::Epick, Eigen::Matrix, -1, -1, 1, -1, -1>, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase > const&, std::vector, std::allocator > > const&, std::map::Index, std::vector::Index, CGAL::Object>, std::allocator::Index, CGAL::Object> > >, std::less::Index>, std::allocator::Index const, std::vector::Index, CGAL::Object>, std::allocator::Index, CGAL::Object> > > > > > const&, bool, Eigen::PlainObjectBase, -1, -1, 1, -1, -1> >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::copyleft::cgal::remesh_intersections, -1, -1, 1, -1, -1>, Eigen::Matrix, CGAL::Epeck, Eigen::Matrix, -1, -1, 1, -1, -1>, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase > const&, std::vector, std::allocator > > const&, std::map::Index, std::vector::Index, CGAL::Object>, std::allocator::Index, CGAL::Object> > >, std::less::Index>, std::allocator::Index const, std::vector::Index, CGAL::Object>, std::allocator::Index, CGAL::Object> > > > > > const&, bool, Eigen::PlainObjectBase, -1, -1, 1, -1, -1> >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::copyleft::cgal::remesh_intersections, -1, 3, 0, -1, 3>, Eigen::Matrix, CGAL::Epick, Eigen::Matrix, -1, -1, 1, -1, -1>, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase > const&, std::vector, std::allocator > > const&, std::map::Index, std::vector::Index, CGAL::Object>, std::allocator::Index, CGAL::Object> > >, std::less::Index>, std::allocator::Index const, std::vector::Index, CGAL::Object>, std::allocator::Index, CGAL::Object> > > > > > const&, bool, Eigen::PlainObjectBase, -1, -1, 1, -1, -1> >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::copyleft::cgal::remesh_intersections, -1, 3, 0, -1, 3>, Eigen::Matrix, CGAL::Epeck, Eigen::Matrix, -1, -1, 1, -1, -1>, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase > const&, std::vector, std::allocator > > const&, std::map::Index, std::vector::Index, CGAL::Object>, std::allocator::Index, CGAL::Object> > >, std::less::Index>, std::allocator::Index const, std::vector::Index, CGAL::Object>, std::allocator::Index, CGAL::Object> > > > > > const&, bool, Eigen::PlainObjectBase, -1, -1, 1, -1, -1> >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::copyleft::cgal::remesh_intersections, Eigen::Matrix, CGAL::Epick, Eigen::Matrix, -1, -1, 0, -1, -1>, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, std::vector, std::allocator > > const&, std::map::Index, std::vector::Index, CGAL::Object>, std::allocator::Index, CGAL::Object> > >, std::less::Index>, std::allocator::Index const, std::vector::Index, CGAL::Object>, std::allocator::Index, CGAL::Object> > > > > > const&, bool, Eigen::PlainObjectBase, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::copyleft::cgal::remesh_intersections, Eigen::Matrix, CGAL::Epeck, Eigen::Matrix, -1, -1, 0, -1, -1>, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, std::vector, std::allocator > > const&, std::map::Index, std::vector::Index, CGAL::Object>, std::allocator::Index, CGAL::Object> > >, std::less::Index>, std::allocator::Index const, std::vector::Index, CGAL::Object>, std::allocator::Index, CGAL::Object> > > > > > const&, bool, Eigen::PlainObjectBase, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::copyleft::cgal::remesh_intersections, Eigen::Matrix, CGAL::Epick, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, std::vector, std::allocator > > const&, std::map::Index, std::vector::Index, CGAL::Object>, std::allocator::Index, CGAL::Object> > >, std::less::Index>, std::allocator::Index const, std::vector::Index, CGAL::Object>, std::allocator::Index, CGAL::Object> > > > > > const&, bool, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::copyleft::cgal::remesh_intersections, Eigen::Matrix, CGAL::Epick, Eigen::Matrix, -1, -1, 0, -1, -1>, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, std::vector, std::allocator > > const&, std::map::Index, std::vector::Index, CGAL::Object>, std::allocator::Index, CGAL::Object> > >, std::less::Index>, std::allocator::Index const, std::vector::Index, CGAL::Object>, std::allocator::Index, CGAL::Object> > > > > > const&, bool, Eigen::PlainObjectBase, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::copyleft::cgal::remesh_intersections, Eigen::Matrix, CGAL::Epick, Eigen::Matrix, -1, -1, 0, -1, -1>, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, std::vector, std::allocator > > const&, std::map::Index, std::vector::Index, CGAL::Object>, std::allocator::Index, CGAL::Object> > >, std::less::Index>, std::allocator::Index const, std::vector::Index, CGAL::Object>, std::allocator::Index, CGAL::Object> > > > > > const&, bool, Eigen::PlainObjectBase, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::copyleft::cgal::remesh_intersections, Eigen::Matrix, CGAL::Epeck, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, std::vector, std::allocator > > const&, std::map::Index, std::vector::Index, CGAL::Object>, std::allocator::Index, CGAL::Object> > >, std::less::Index>, std::allocator::Index const, std::vector::Index, CGAL::Object>, std::allocator::Index, CGAL::Object> > > > > > const&, bool, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::copyleft::cgal::remesh_intersections, Eigen::Matrix, CGAL::Epeck, Eigen::Matrix, -1, -1, 0, -1, -1>, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, std::vector, std::allocator > > const&, std::map::Index, std::vector::Index, CGAL::Object>, std::allocator::Index, CGAL::Object> > >, std::less::Index>, std::allocator::Index const, std::vector::Index, CGAL::Object>, std::allocator::Index, CGAL::Object> > > > > > const&, bool, Eigen::PlainObjectBase, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::copyleft::cgal::remesh_intersections, Eigen::Matrix, CGAL::Epeck, Eigen::Matrix, -1, -1, 0, -1, -1>, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, std::vector, std::allocator > > const&, std::map::Index, std::vector::Index, CGAL::Object>, std::allocator::Index, CGAL::Object> > >, std::less::Index>, std::allocator::Index const, std::vector::Index, CGAL::Object>, std::allocator::Index, CGAL::Object> > > > > > const&, bool, Eigen::PlainObjectBase, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::copyleft::cgal::remesh_intersections, Eigen::Matrix, CGAL::Epick, Eigen::Matrix, -1, -1, 0, -1, -1>, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, std::vector, std::allocator > > const&, std::map::Index, std::vector::Index, CGAL::Object>, std::allocator::Index, CGAL::Object> > >, std::less::Index>, std::allocator::Index const, std::vector::Index, CGAL::Object>, std::allocator::Index, CGAL::Object> > > > > > const&, bool, Eigen::PlainObjectBase, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::copyleft::cgal::remesh_intersections, Eigen::Matrix, CGAL::Epick, Eigen::Matrix, -1, -1, 0, -1, -1>, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, std::vector, std::allocator > > const&, std::map::Index, std::vector::Index, CGAL::Object>, std::allocator::Index, CGAL::Object> > >, std::less::Index>, std::allocator::Index const, std::vector::Index, CGAL::Object>, std::allocator::Index, CGAL::Object> > > > > > const&, bool, Eigen::PlainObjectBase, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::copyleft::cgal::remesh_intersections, Eigen::Matrix, CGAL::Epeck, Eigen::Matrix, -1, -1, 0, -1, -1>, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, std::vector, std::allocator > > const&, std::map::Index, std::vector::Index, CGAL::Object>, std::allocator::Index, CGAL::Object> > >, std::less::Index>, std::allocator::Index const, std::vector::Index, CGAL::Object>, std::allocator::Index, CGAL::Object> > > > > > const&, bool, Eigen::PlainObjectBase, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::copyleft::cgal::remesh_intersections, Eigen::Matrix, CGAL::Epeck, Eigen::Matrix, -1, -1, 0, -1, -1>, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, std::vector, std::allocator > > const&, std::map::Index, std::vector::Index, CGAL::Object>, std::allocator::Index, CGAL::Object> > >, std::less::Index>, std::allocator::Index const, std::vector::Index, CGAL::Object>, std::allocator::Index, CGAL::Object> > > > > > const&, bool, Eigen::PlainObjectBase, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::copyleft::cgal::remesh_intersections, Eigen::Matrix, CGAL::Epick, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, std::vector, std::allocator > > const&, std::map::Index, std::vector::Index, CGAL::Object>, std::allocator::Index, CGAL::Object> > >, std::less::Index>, std::allocator::Index const, std::vector::Index, CGAL::Object>, std::allocator::Index, CGAL::Object> > > > > > const&, bool, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::copyleft::cgal::remesh_intersections, Eigen::Matrix, CGAL::Epick, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, std::vector, std::allocator > > const&, std::map::Index, std::vector::Index, CGAL::Object>, std::allocator::Index, CGAL::Object> > >, std::less::Index>, std::allocator::Index const, std::vector::Index, CGAL::Object>, std::allocator::Index, CGAL::Object> > > > > > const&, bool, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::copyleft::cgal::remesh_intersections, Eigen::Matrix, CGAL::Epick, Eigen::Matrix, -1, 3, 0, -1, 3>, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, std::vector, std::allocator > > const&, std::map::Index, std::vector::Index, CGAL::Object>, std::allocator::Index, CGAL::Object> > >, std::less::Index>, std::allocator::Index const, std::vector::Index, CGAL::Object>, std::allocator::Index, CGAL::Object> > > > > > const&, bool, Eigen::PlainObjectBase, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::copyleft::cgal::remesh_intersections, Eigen::Matrix, CGAL::Epick, Eigen::Matrix, -1, 3, 0, -1, 3>, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, std::vector, std::allocator > > const&, std::map::Index, std::vector::Index, CGAL::Object>, std::allocator::Index, CGAL::Object> > >, std::less::Index>, std::allocator::Index const, std::vector::Index, CGAL::Object>, std::allocator::Index, CGAL::Object> > > > > > const&, bool, Eigen::PlainObjectBase, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::copyleft::cgal::remesh_intersections, Eigen::Matrix, CGAL::Epick, Eigen::Matrix, -1, 3, 0, -1, 3>, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, std::vector, std::allocator > > const&, std::map::Index, std::vector::Index, CGAL::Object>, std::allocator::Index, CGAL::Object> > >, std::less::Index>, std::allocator::Index const, std::vector::Index, CGAL::Object>, std::allocator::Index, CGAL::Object> > > > > > const&, bool, Eigen::PlainObjectBase, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::copyleft::cgal::remesh_intersections, Eigen::Matrix, CGAL::Epeck, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, std::vector, std::allocator > > const&, std::map::Index, std::vector::Index, CGAL::Object>, std::allocator::Index, CGAL::Object> > >, std::less::Index>, std::allocator::Index const, std::vector::Index, CGAL::Object>, std::allocator::Index, CGAL::Object> > > > > > const&, bool, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::copyleft::cgal::remesh_intersections, Eigen::Matrix, CGAL::Epeck, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, std::vector, std::allocator > > const&, std::map::Index, std::vector::Index, CGAL::Object>, std::allocator::Index, CGAL::Object> > >, std::less::Index>, std::allocator::Index const, std::vector::Index, CGAL::Object>, std::allocator::Index, CGAL::Object> > > > > > const&, bool, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::copyleft::cgal::remesh_intersections, Eigen::Matrix, CGAL::Epeck, Eigen::Matrix, -1, 3, 0, -1, 3>, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, std::vector, std::allocator > > const&, std::map::Index, std::vector::Index, CGAL::Object>, std::allocator::Index, CGAL::Object> > >, std::less::Index>, std::allocator::Index const, std::vector::Index, CGAL::Object>, std::allocator::Index, CGAL::Object> > > > > > const&, bool, Eigen::PlainObjectBase, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::copyleft::cgal::remesh_intersections, Eigen::Matrix, CGAL::Epeck, Eigen::Matrix, -1, 3, 0, -1, 3>, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, std::vector, std::allocator > > const&, std::map::Index, std::vector::Index, CGAL::Object>, std::allocator::Index, CGAL::Object> > >, std::less::Index>, std::allocator::Index const, std::vector::Index, CGAL::Object>, std::allocator::Index, CGAL::Object> > > > > > const&, bool, Eigen::PlainObjectBase, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::copyleft::cgal::remesh_intersections, Eigen::Matrix, CGAL::Epeck, Eigen::Matrix, -1, 3, 0, -1, 3>, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, std::vector, std::allocator > > const&, std::map::Index, std::vector::Index, CGAL::Object>, std::allocator::Index, CGAL::Object> > >, std::less::Index>, std::allocator::Index const, std::vector::Index, CGAL::Object>, std::allocator::Index, CGAL::Object> > > > > > const&, bool, Eigen::PlainObjectBase, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::copyleft::cgal::remesh_intersections, -1, 3, 0, -1, 3>, Eigen::Matrix, CGAL::Epick, Eigen::Matrix, -1, -1, 0, -1, -1>, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase > const&, std::vector, std::allocator > > const&, std::map::Index, std::vector::Index, CGAL::Object>, std::allocator::Index, CGAL::Object> > >, std::less::Index>, std::allocator::Index const, std::vector::Index, CGAL::Object>, std::allocator::Index, CGAL::Object> > > > > > const&, bool, Eigen::PlainObjectBase, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::copyleft::cgal::remesh_intersections, -1, 3, 0, -1, 3>, Eigen::Matrix, CGAL::Epick, Eigen::Matrix, -1, -1, 0, -1, -1>, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase > const&, std::vector, std::allocator > > const&, std::map::Index, std::vector::Index, CGAL::Object>, std::allocator::Index, CGAL::Object> > >, std::less::Index>, std::allocator::Index const, std::vector::Index, CGAL::Object>, std::allocator::Index, CGAL::Object> > > > > > const&, bool, Eigen::PlainObjectBase, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::copyleft::cgal::remesh_intersections, -1, 3, 0, -1, 3>, Eigen::Matrix, CGAL::Epeck, Eigen::Matrix, -1, -1, 0, -1, -1>, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase > const&, std::vector, std::allocator > > const&, std::map::Index, std::vector::Index, CGAL::Object>, std::allocator::Index, CGAL::Object> > >, std::less::Index>, std::allocator::Index const, std::vector::Index, CGAL::Object>, std::allocator::Index, CGAL::Object> > > > > > const&, bool, Eigen::PlainObjectBase, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::copyleft::cgal::remesh_intersections, -1, 3, 0, -1, 3>, Eigen::Matrix, CGAL::Epeck, Eigen::Matrix, -1, -1, 0, -1, -1>, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase > const&, std::vector, std::allocator > > const&, std::map::Index, std::vector::Index, CGAL::Object>, std::allocator::Index, CGAL::Object> > >, std::less::Index>, std::allocator::Index const, std::vector::Index, CGAL::Object>, std::allocator::Index, CGAL::Object> > > > > > const&, bool, Eigen::PlainObjectBase, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::copyleft::cgal::remesh_intersections, -1, 3, 0, -1, 3>, Eigen::Matrix, CGAL::Epick, Eigen::Matrix, -1, 3, 0, -1, 3>, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase > const&, std::vector, std::allocator > > const&, std::map::Index, std::vector::Index, CGAL::Object>, std::allocator::Index, CGAL::Object> > >, std::less::Index>, std::allocator::Index const, std::vector::Index, CGAL::Object>, std::allocator::Index, CGAL::Object> > > > > > const&, bool, Eigen::PlainObjectBase, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::copyleft::cgal::remesh_intersections, -1, 3, 0, -1, 3>, Eigen::Matrix, CGAL::Epeck, Eigen::Matrix, -1, 3, 0, -1, 3>, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase > const&, std::vector, std::allocator > > const&, std::map::Index, std::vector::Index, CGAL::Object>, std::allocator::Index, CGAL::Object> > >, std::less::Index>, std::allocator::Index const, std::vector::Index, CGAL::Object>, std::allocator::Index, CGAL::Object> > > > > > const&, bool, Eigen::PlainObjectBase, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::copyleft::cgal::remesh_intersections, 8, 3, 0, 8, 3>, Eigen::Matrix, CGAL::Epick, Eigen::Matrix, -1, -1, 0, -1, -1>, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase, 8, 3, 0, 8, 3> > const&, Eigen::MatrixBase > const&, std::vector, std::allocator > > const&, std::map::Index, std::vector::Index, CGAL::Object>, std::allocator::Index, CGAL::Object> > >, std::less::Index>, std::allocator::Index const, std::vector::Index, CGAL::Object>, std::allocator::Index, CGAL::Object> > > > > > const&, bool, Eigen::PlainObjectBase, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::copyleft::cgal::remesh_intersections, 8, 3, 0, 8, 3>, Eigen::Matrix, CGAL::Epeck, Eigen::Matrix, -1, -1, 0, -1, -1>, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase, 8, 3, 0, 8, 3> > const&, Eigen::MatrixBase > const&, std::vector, std::allocator > > const&, std::map::Index, std::vector::Index, CGAL::Object>, std::allocator::Index, CGAL::Object> > >, std::less::Index>, std::allocator::Index const, std::vector::Index, CGAL::Object>, std::allocator::Index, CGAL::Object> > > > > > const&, bool, Eigen::PlainObjectBase, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::copyleft::cgal::remesh_intersections, Eigen::Matrix, CGAL::Epeck, Eigen::Matrix, -1, 3, 0, -1, 3>, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, std::vector, std::allocator > > const&, std::map::Index, std::vector::Index, CGAL::Object>, std::allocator::Index, CGAL::Object> > >, std::less::Index>, std::allocator::Index const, std::vector::Index, CGAL::Object>, std::allocator::Index, CGAL::Object> > > > > > const&, bool, Eigen::PlainObjectBase, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::copyleft::cgal::remesh_intersections, Eigen::Matrix, CGAL::Epeck, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, std::vector, std::allocator > > const&, std::map::Index, std::vector::Index, CGAL::Object>, std::allocator::Index, CGAL::Object> > >, std::less::Index>, std::allocator::Index const, std::vector::Index, CGAL::Object>, std::allocator::Index, CGAL::Object> > > > > > const&, bool, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::copyleft::cgal::remesh_intersections, Eigen::Matrix, CGAL::Epick, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, std::vector, std::allocator > > const&, std::map::Index, std::vector::Index, CGAL::Object>, std::allocator::Index, CGAL::Object> > >, std::less::Index>, std::allocator::Index const, std::vector::Index, CGAL::Object>, std::allocator::Index, CGAL::Object> > > > > > const&, bool, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#ifdef WIN32 +template void igl::copyleft::cgal::remesh_intersections,class Eigen::Matrix,class CGAL::Epeck,class Eigen::Matrix,-1,-1,0,-1,-1>,class Eigen::Matrix,class Eigen::Matrix<__int64,-1,1,0,-1,1>,class Eigen::Matrix >(class Eigen::MatrixBase > const &,class Eigen::MatrixBase > const &,class std::vector,class std::allocator > > const &,class std::map<__int64,class std::vector,class std::allocator > >,struct std::less<__int64>,class std::allocator,class std::allocator > > > > > const &,bool,class Eigen::PlainObjectBase,-1,-1,0,-1,-1> > &,class Eigen::PlainObjectBase > &,class Eigen::PlainObjectBase > &,class Eigen::PlainObjectBase > &); +template void igl::copyleft::cgal::remesh_intersections,class Eigen::Matrix,class CGAL::Epick,class Eigen::Matrix,-1,-1,0,-1,-1>,class Eigen::Matrix,class Eigen::Matrix<__int64,-1,1,0,-1,1>,class Eigen::Matrix >(class Eigen::MatrixBase > const &,class Eigen::MatrixBase > const &,class std::vector,class std::allocator > > const &,class std::map<__int64,class std::vector,class std::allocator > >,struct std::less<__int64>,class std::allocator,class std::allocator > > > > > const &,bool,class Eigen::PlainObjectBase,-1,-1,0,-1,-1> > &,class Eigen::PlainObjectBase > &,class Eigen::PlainObjectBase > &,class Eigen::PlainObjectBase > &); +template void igl::copyleft::cgal::remesh_intersections, class Eigen::Matrix, class CGAL::Epeck, class Eigen::Matrix, -1, -1, 0, -1, -1>, class Eigen::Matrix, class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>, class Eigen::Matrix>(class Eigen::MatrixBase> const &, class Eigen::MatrixBase> const &, class std::vector, class std::allocator>> const &, class std::map<__int64, class std::vector, class std::allocator>>, struct std::less<__int64>, class std::allocator, class std::allocator>>>>> const &, bool, class Eigen::PlainObjectBase, -1, -1, 0, -1, -1>> &, class Eigen::PlainObjectBase> &, class Eigen::PlainObjectBase> &, class Eigen::PlainObjectBase> &); +template void igl::copyleft::cgal::remesh_intersections, class Eigen::Matrix, class CGAL::Epick, class Eigen::Matrix, -1, -1, 0, -1, -1>, class Eigen::Matrix, class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>, class Eigen::Matrix>(class Eigen::MatrixBase> const &, class Eigen::MatrixBase> const &, class std::vector, class std::allocator>> const &, class std::map<__int64, class std::vector, class std::allocator>>, struct std::less<__int64>, class std::allocator, class std::allocator>>>>> const &, bool, class Eigen::PlainObjectBase, -1, -1, 0, -1, -1>> &, class Eigen::PlainObjectBase> &, class Eigen::PlainObjectBase> &, class Eigen::PlainObjectBase> &); +template void igl::copyleft::cgal::remesh_intersections, -1, 3, 0, -1, 3>, class Eigen::Matrix, class CGAL::Epeck, class Eigen::Matrix, -1, -1, 0, -1, -1>, class Eigen::Matrix, class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>, class Eigen::Matrix>(class Eigen::MatrixBase, -1, 3, 0, -1, 3>> const &, class Eigen::MatrixBase> const &, class std::vector, class std::allocator>> const &, class std::map<__int64, class std::vector, class std::allocator>>, struct std::less<__int64>, class std::allocator, class std::allocator>>>>> const &, bool, class Eigen::PlainObjectBase, -1, -1, 0, -1, -1>> &, class Eigen::PlainObjectBase> &, class Eigen::PlainObjectBase> &, class Eigen::PlainObjectBase> &); +template void igl::copyleft::cgal::remesh_intersections, -1, 3, 0, -1, 3>, class Eigen::Matrix, class CGAL::Epick, class Eigen::Matrix, -1, -1, 0, -1, -1>, class Eigen::Matrix, class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>, class Eigen::Matrix>(class Eigen::MatrixBase, -1, 3, 0, -1, 3>> const &, class Eigen::MatrixBase> const &, class std::vector, class std::allocator>> const &, class std::map<__int64, class std::vector, class std::allocator>>, struct std::less<__int64>, class std::allocator, class std::allocator>>>>> const &, bool, class Eigen::PlainObjectBase, -1, -1, 0, -1, -1>> &, class Eigen::PlainObjectBase> &, class Eigen::PlainObjectBase> &, class Eigen::PlainObjectBase> &); +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/remesh_intersections.h b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/remesh_intersections.h new file mode 100644 index 000000000..2b6a44a57 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/remesh_intersections.h @@ -0,0 +1,94 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Qingnan Zhou +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +// +#ifndef IGL_COPYLEFT_CGAL_REMESH_INTERSECTIONS_H +#define IGL_COPYLEFT_CGAL_REMESH_INTERSECTIONS_H + +#include "../../igl_inline.h" +#include +#include "CGAL_includes.hpp" + +namespace igl +{ + namespace copyleft + { + namespace cgal + { + // Remesh faces according to results of intersection detection and + // construction (e.g. from `igl::copyleft::cgal::intersect_other` or + // `igl::copyleft::cgal::SelfIntersectMesh`) + // + // Inputs: + // V #V by 3 list of vertex positions + // F #F by 3 list of triangle indices into V + // T #F list of cgal triangles + // offending #offending map taking face indices into F to pairs of order + // of first finding and list of intersection objects from all + // intersections + // stitch_all if true, merge all vertices with the same coordinate. + // Outputs: + // VV #VV by 3 list of vertex positions, if stitch_all = false then + // first #V vertices will always be V + // FF #FF by 3 list of triangle indices into V + // IF #intersecting face pairs by 2 list of intersecting face pairs, + // indexing F + // J #FF list of indices into F denoting birth triangle + // IM / stitch_all = true #VV list from 0 to #VV-1 + // \ stitch_all = false #VV list of indices into VV of unique vertices. + // + template < + typename DerivedV, + typename DerivedF, + typename Kernel, + typename DerivedVV, + typename DerivedFF, + typename DerivedJ, + typename DerivedIM> + IGL_INLINE void remesh_intersections( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const std::vector > & T, + const std::map< + typename DerivedF::Index, + std::vector< + std::pair > > & offending, + bool stitch_all, + Eigen::PlainObjectBase & VV, + Eigen::PlainObjectBase & FF, + Eigen::PlainObjectBase & J, + Eigen::PlainObjectBase & IM); + // Same as above except stitch_all is assumed "false" + template < + typename DerivedV, + typename DerivedF, + typename Kernel, + typename DerivedVV, + typename DerivedFF, + typename DerivedJ, + typename DerivedIM> + IGL_INLINE void remesh_intersections( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const std::vector > & T, + const std::map< + typename DerivedF::Index, + std::vector< + std::pair > > & offending, + Eigen::PlainObjectBase & VV, + Eigen::PlainObjectBase & FF, + Eigen::PlainObjectBase & J, + Eigen::PlainObjectBase & IM); + } + } +} + +#ifndef IGL_STATIC_LIBRARY +# include "remesh_intersections.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/remesh_self_intersections.cpp b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/remesh_self_intersections.cpp new file mode 100644 index 000000000..4771e028f --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/remesh_self_intersections.cpp @@ -0,0 +1,112 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "remesh_self_intersections.h" +#include "SelfIntersectMesh.h" +#include "../../C_STR.h" +#include +#include + +template < + typename DerivedV, + typename DerivedF, + typename DerivedVV, + typename DerivedFF, + typename DerivedIF, + typename DerivedJ, + typename DerivedIM> +IGL_INLINE void igl::copyleft::cgal::remesh_self_intersections( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const RemeshSelfIntersectionsParam & params, + Eigen::PlainObjectBase & VV, + Eigen::PlainObjectBase & FF, + Eigen::PlainObjectBase & IF, + Eigen::PlainObjectBase & J, + Eigen::PlainObjectBase & IM) +{ + using namespace std; + if(params.detect_only) + { + //// This is probably a terrible idea, but CGAL is throwing floating point + //// exceptions. + +//#ifdef __APPLE__ +//#define IGL_THROW_FPE 11 +// const auto & throw_fpe = [](int e) +// { +// throw "IGL_THROW_FPE"; +// }; +// signal(SIGFPE,throw_fpe); +//#endif + + typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel; + typedef + SelfIntersectMesh< + Kernel, + DerivedV, + DerivedF, + DerivedVV, + DerivedFF, + DerivedIF, + DerivedJ, + DerivedIM> + SelfIntersectMeshK; + SelfIntersectMeshK SIM(V,F,params,VV,FF,IF,J,IM); + +//#ifdef __APPLE__ +// signal(SIGFPE,SIG_DFL); +//#endif + + }else + { + typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel; + typedef + SelfIntersectMesh< + Kernel, + DerivedV, + DerivedF, + DerivedVV, + DerivedFF, + DerivedIF, + DerivedJ, + DerivedIM> + SelfIntersectMeshK; + SelfIntersectMeshK SIM(V,F,params,VV,FF,IF,J,IM); + } +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::copyleft::cgal::remesh_self_intersections, Eigen::Matrix, Eigen::Matrix, -1, -1, 0, -1, -1>, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, igl::copyleft::cgal::RemeshSelfIntersectionsParam const&, Eigen::PlainObjectBase, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::copyleft::cgal::remesh_self_intersections, -1, 3, 0, -1, 3>, Eigen::Matrix, Eigen::Matrix, -1, -1, 1, -1, -1>, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase > const&, igl::copyleft::cgal::RemeshSelfIntersectionsParam const&, Eigen::PlainObjectBase, -1, -1, 1, -1, -1> >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::copyleft::cgal::remesh_self_intersections, -1, 3, 0, -1, 3>, Eigen::Matrix, Eigen::Matrix, -1, -1, 1, -1, -1>, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase > const&, igl::copyleft::cgal::RemeshSelfIntersectionsParam const&, Eigen::PlainObjectBase, -1, -1, 1, -1, -1> >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::copyleft::cgal::remesh_self_intersections, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, igl::copyleft::cgal::RemeshSelfIntersectionsParam const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::copyleft::cgal::remesh_self_intersections, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, igl::copyleft::cgal::RemeshSelfIntersectionsParam const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::copyleft::cgal::remesh_self_intersections, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, igl::copyleft::cgal::RemeshSelfIntersectionsParam const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::copyleft::cgal::remesh_self_intersections, Eigen::Matrix, Eigen::Matrix, -1, 3, 0, -1, 3>, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, igl::copyleft::cgal::RemeshSelfIntersectionsParam const&, Eigen::PlainObjectBase, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::copyleft::cgal::remesh_self_intersections, Eigen::Matrix, Eigen::Matrix, -1, 3, 0, -1, 3>, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, igl::copyleft::cgal::RemeshSelfIntersectionsParam const&, Eigen::PlainObjectBase, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::copyleft::cgal::remesh_self_intersections, -1, 3, 0, -1, 3>, Eigen::Matrix, Eigen::Matrix, -1, 3, 0, -1, 3>, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase > const&, igl::copyleft::cgal::RemeshSelfIntersectionsParam const&, Eigen::PlainObjectBase, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::copyleft::cgal::remesh_self_intersections, Eigen::Matrix, Eigen::Matrix, -1, 3, 0, -1, 3>, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, igl::copyleft::cgal::RemeshSelfIntersectionsParam const&, Eigen::PlainObjectBase, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::copyleft::cgal::remesh_self_intersections, -1, 3, 0, -1, 3>, Eigen::Matrix, Eigen::Matrix, -1, -1, 0, -1, -1>, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase > const&, igl::copyleft::cgal::RemeshSelfIntersectionsParam const&, Eigen::PlainObjectBase, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::copyleft::cgal::remesh_self_intersections, Eigen::Matrix, Eigen::Matrix, -1, -1, 0, -1, -1>, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, igl::copyleft::cgal::RemeshSelfIntersectionsParam const&, Eigen::PlainObjectBase, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::copyleft::cgal::remesh_self_intersections, Eigen::Matrix, Eigen::Matrix, -1, -1, 0, -1, -1>, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, igl::copyleft::cgal::RemeshSelfIntersectionsParam const&, Eigen::PlainObjectBase, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::copyleft::cgal::remesh_self_intersections, -1, 3, 0, -1, 3>, Eigen::Matrix, Eigen::Matrix, -1, -1, 0, -1, -1>, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase > const&, igl::copyleft::cgal::RemeshSelfIntersectionsParam const&, Eigen::PlainObjectBase, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::copyleft::cgal::remesh_self_intersections, 8, 3, 0, 8, 3>, Eigen::Matrix, Eigen::Matrix, -1, -1, 0, -1, -1>, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase, 8, 3, 0, 8, 3> > const&, Eigen::MatrixBase > const&, igl::copyleft::cgal::RemeshSelfIntersectionsParam const&, Eigen::PlainObjectBase, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::copyleft::cgal::remesh_self_intersections, Eigen::Matrix, Eigen::Matrix, -1, -1, 0, -1, -1>, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, igl::copyleft::cgal::RemeshSelfIntersectionsParam const&, Eigen::PlainObjectBase, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::copyleft::cgal::remesh_self_intersections, Eigen::Matrix, Eigen::Matrix, -1, -1, 0, -1, -1>, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, igl::copyleft::cgal::RemeshSelfIntersectionsParam const&, Eigen::PlainObjectBase, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::copyleft::cgal::remesh_self_intersections, Eigen::Matrix, Eigen::Matrix, -1, -1, 0, -1, -1>, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, igl::copyleft::cgal::RemeshSelfIntersectionsParam const&, Eigen::PlainObjectBase, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::copyleft::cgal::remesh_self_intersections, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, igl::copyleft::cgal::RemeshSelfIntersectionsParam const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#ifdef WIN32 +template void igl::copyleft::cgal::remesh_self_intersections, class Eigen::Matrix, class Eigen::Matrix, -1, -1, 0, -1, -1>, class Eigen::Matrix, class Eigen::Matrix, class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>, class Eigen::Matrix>(class Eigen::MatrixBase> const &, class Eigen::MatrixBase> const &, struct igl::copyleft::cgal::RemeshSelfIntersectionsParam const &, class Eigen::PlainObjectBase, -1, -1, 0, -1, -1>> &, class Eigen::PlainObjectBase> &, class Eigen::PlainObjectBase> &, class Eigen::PlainObjectBase> &, class Eigen::PlainObjectBase> &); +template void igl::copyleft::cgal::remesh_self_intersections, class Eigen::Matrix, class Eigen::Matrix, -1, -1, 0, -1, -1>, class Eigen::Matrix, class Eigen::Matrix, class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>, class Eigen::Matrix >(class Eigen::MatrixBase > const &, class Eigen::MatrixBase > const &, struct igl::copyleft::cgal::RemeshSelfIntersectionsParam const &, class Eigen::PlainObjectBase, -1, -1, 0, -1, -1> > &, class Eigen::PlainObjectBase > &, class Eigen::PlainObjectBase > &, class Eigen::PlainObjectBase > &, class Eigen::PlainObjectBase > &); +template void igl::copyleft::cgal::remesh_self_intersections, -1, 3, 0, -1, 3>, class Eigen::Matrix, class Eigen::Matrix, -1, -1, 0, -1, -1>, class Eigen::Matrix, class Eigen::Matrix, class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>, class Eigen::Matrix>(class Eigen::MatrixBase, -1, 3, 0, -1, 3>> const &, class Eigen::MatrixBase> const &, struct igl::copyleft::cgal::RemeshSelfIntersectionsParam const &, class Eigen::PlainObjectBase, -1, -1, 0, -1, -1>> &, class Eigen::PlainObjectBase> &, class Eigen::PlainObjectBase> &, class Eigen::PlainObjectBase> &, class Eigen::PlainObjectBase> &); +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/remesh_self_intersections.h b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/remesh_self_intersections.h new file mode 100644 index 000000000..e8e8cc492 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/remesh_self_intersections.h @@ -0,0 +1,81 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_COPYLEFT_CGAL_REMESH_SELF_INTERSECTIONS_H +#define IGL_COPYLEFT_CGAL_REMESH_SELF_INTERSECTIONS_H +#include "../../igl_inline.h" +#include "RemeshSelfIntersectionsParam.h" + +#include + +namespace igl +{ + namespace copyleft + { + namespace cgal + { + // Given a triangle mesh (V,F) compute a new mesh (VV,FF) which is the same + // as (V,F) except that any self-intersecting triangles in (V,F) have been + // subdivided (new vertices and face created) so that the self-intersection + // contour lies exactly on edges in (VV,FF). New vertices will appear in + // original faces or on original edges. New vertices on edges are "merged" + // only across original faces sharing that edge. This means that if the input + // triangle mesh is a closed manifold the output will be too. + // + // Inputs: + // V #V by 3 list of vertex positions + // F #F by 3 list of triangle indices into V + // params struct of optional parameters + // Outputs: + // VV #VV by 3 list of vertex positions + // FF #FF by 3 list of triangle indices into VV + // IF #intersecting face pairs by 2 list of intersecting face pairs, + // indexing F + // J #FF list of indices into F denoting birth triangle + // IM #VV list of indices into VV of unique vertices. + // + // Known bugs: If an existing edge in (V,F) lies exactly on another face then + // any resulting additional vertices along that edge may not get properly + // connected so that the output mesh has the same global topology. This is + // because + // + // Example: + // // resolve intersections + // igl::copyleft::cgal::remesh_self_intersections(V,F,params,VV,FF,IF,J,IM); + // // _apply_ duplicate vertex mapping IM to FF + // for_each(FF.data(),FF.data()+FF.size(),[&IM](int & a){a=IM(a);}); + // // remove any vertices now unreferenced after duplicate mapping. + // igl::remove_unreferenced(VV,FF,SV,SF,UIM); + // // Now (SV,SF) is ready to extract outer hull + // igl::copyleft::cgal::outer_hull(SV,SF,G,J,flip); + // + template < + typename DerivedV, + typename DerivedF, + typename DerivedVV, + typename DerivedFF, + typename DerivedIF, + typename DerivedJ, + typename DerivedIM> + IGL_INLINE void remesh_self_intersections( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const RemeshSelfIntersectionsParam & params, + Eigen::PlainObjectBase & VV, + Eigen::PlainObjectBase & FF, + Eigen::PlainObjectBase & IF, + Eigen::PlainObjectBase & J, + Eigen::PlainObjectBase & IM); + } + } +} + +#ifndef IGL_STATIC_LIBRARY +# include "remesh_self_intersections.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/remove_unreferenced.cpp b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/remove_unreferenced.cpp new file mode 100644 index 000000000..03c8864cb --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/remove_unreferenced.cpp @@ -0,0 +1,20 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2017 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "../../remove_unreferenced.h" +#include +#include +#ifdef IGL_STATIC_LIBRARY +#undef IGL_STATIC_LIBRARY +#include "../../remove_unreferenced.cpp" +template void igl::remove_unreferenced, -1, 3, 0, -1, 3>, Eigen::Matrix, Eigen::Matrix, -1, 3, 0, -1, 3>, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::remove_unreferenced, -1, 3, 0, -1, 3>, Eigen::Matrix, Eigen::Matrix, -1, -1, 1, -1, -1>, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase, -1, -1, 1, -1, -1> >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::remove_unreferenced, -1, -1, 0, -1, -1>, Eigen::Matrix, Eigen::Matrix, -1, -1, 0, -1, -1>, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::remove_unreferenced, -1, 3, 0, -1, 3>, Eigen::Matrix, Eigen::Matrix, -1, 4, 0, -1, 4>, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase, -1, 4, 0, -1, 4> >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::remove_unreferenced, -1, -1, 1, -1, -1>, Eigen::Matrix, Eigen::Matrix, -1, -1, 1, -1, -1>, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase, -1, -1, 1, -1, -1> >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::remove_unreferenced, -1, -1, 1, -1, -1>, Eigen::Matrix, Eigen::Matrix, -1, -1, 1, -1, -1>, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase, -1, -1, 1, -1, -1> >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/resolve_intersections.cpp b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/resolve_intersections.cpp new file mode 100644 index 000000000..1cac435af --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/resolve_intersections.cpp @@ -0,0 +1,96 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "resolve_intersections.h" +#include "subdivide_segments.h" +#include "row_to_point.h" +#include "../../unique.h" +#include "../../list_to_matrix.h" +#include +#include +#include +#include +#include + +template < + typename DerivedV, + typename DerivedE, + typename DerivedVI, + typename DerivedEI, + typename DerivedJ, + typename DerivedIM> +IGL_INLINE void igl::copyleft::cgal::resolve_intersections( + const Eigen::PlainObjectBase & V, + const Eigen::PlainObjectBase & E, + Eigen::PlainObjectBase & VI, + Eigen::PlainObjectBase & EI, + Eigen::PlainObjectBase & J, + Eigen::PlainObjectBase & IM) +{ + using namespace Eigen; + using namespace igl; + using namespace std; + // Exact scalar type + typedef CGAL::Epeck K; + typedef K::FT EScalar; + typedef CGAL::Segment_2 Segment_2; + typedef CGAL::Point_2 Point_2; + typedef Matrix MatrixXE; + + // Convert vertex positions to exact kernel + MatrixXE VE(V.rows(),V.cols()); + for(int i = 0;i > steiner(m); + for(int i = 0;i(VE,E(i,0)),row_to_point(VE,E(i,1))); + steiner[i].push_back(si.vertex(0)); + steiner[i].push_back(si.vertex(1)); + for(int j = i+1;j(VE,E(j,0)),row_to_point(VE,E(j,1))); + // do they intersect? + if(CGAL::do_intersect(si,sj)) + { + CGAL::Object result = CGAL::intersection(si,sj); + if(const Point_2 * p = CGAL::object_cast(&result)) + { + steiner[i].push_back(*p); + steiner[j].push_back(*p); + // add intersection point + }else if(const Segment_2 * s = CGAL::object_cast(&result)) + { + // add both endpoints + steiner[i].push_back(s->vertex(0)); + steiner[j].push_back(s->vertex(0)); + steiner[i].push_back(s->vertex(1)); + steiner[j].push_back(s->vertex(1)); + }else + { + assert(false && "Unknown intersection type"); + } + } + } + } + + subdivide_segments(V,E,steiner,VI,EI,J,IM); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::copyleft::cgal::resolve_intersections, Eigen::Matrix, Eigen::Matrix, -1, -1, 0, -1, -1>, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/resolve_intersections.h b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/resolve_intersections.h new file mode 100644 index 000000000..086ef1361 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/resolve_intersections.h @@ -0,0 +1,51 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_COPYLEFT_CGAL_RESOLVE_INTERSECTIONS_H +#define IGL_COPYLEFT_CGAL_RESOLVE_INTERSECTIONS_H +#include "../../igl_inline.h" +#include + +namespace igl +{ + namespace copyleft + { + // RESOLVE_INTERSECTIONS Given a list of possible intersecting segments with + // endpoints, split segments to overlap only at endpoints + // + // Inputs: + // V #V by 2 list of vertex positions + // E #E by 2 list of segment indices into V + // Outputs: + // VI #VI by 2 list of output vertex positions, copies of V are always + // the first #V vertices + // EI #EI by 2 list of segment indices into V, #EI ≥ #E + // J #EI list of indices into E revealing "parent segments" + // IM #VI list of indices into VV of unique vertices. + namespace cgal + { + template < + typename DerivedV, + typename DerivedE, + typename DerivedVI, + typename DerivedEI, + typename DerivedJ, + typename DerivedIM> + IGL_INLINE void resolve_intersections( + const Eigen::PlainObjectBase & V, + const Eigen::PlainObjectBase & E, + Eigen::PlainObjectBase & VI, + Eigen::PlainObjectBase & EI, + Eigen::PlainObjectBase & J, + Eigen::PlainObjectBase & IM); + } + } +} +#ifndef IGL_STATIC_LIBRARY +# include "resolve_intersections.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/row_to_point.cpp b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/row_to_point.cpp new file mode 100644 index 000000000..b6c940c16 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/row_to_point.cpp @@ -0,0 +1,25 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "row_to_point.h" + +template < + typename Kernel, + typename DerivedV> +IGL_INLINE CGAL::Point_2 igl::copyleft::cgal::row_to_point( + const Eigen::PlainObjectBase & V, + const typename DerivedV::Index & i) +{ + return CGAL::Point_2(V(i,0),V(i,1)); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +#include +#include +template CGAL::Point_2 igl::copyleft::cgal::row_to_point, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase, -1, -1, 0, -1, -1> > const&, Eigen::Matrix, -1, -1, 0, -1, -1>::Index const&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/row_to_point.h b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/row_to_point.h new file mode 100644 index 000000000..54e27ad4f --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/row_to_point.h @@ -0,0 +1,38 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_COPYLEFT_CGAL_ROW_TO_POINT_H +#define IGL_COPYLEFT_CGAL_ROW_TO_POINT_H +#include "../../igl_inline.h" +#include +#include +namespace igl +{ + namespace copyleft + { + namespace cgal + { + // Extract a row from V and treat as a 2D cgal point (only first two + // columns of V are used). + // + // Inputs: + // V #V by 2 list of vertex positions + // i row index + // Returns 2D cgal point + template < + typename Kernel, + typename DerivedV> + IGL_INLINE CGAL::Point_2 row_to_point( + const Eigen::PlainObjectBase & V, + const typename DerivedV::Index & i); + } + } +} +#ifndef IGL_STATIC_LIBRARY +# include "row_to_point.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/segment_segment_squared_distance.cpp b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/segment_segment_squared_distance.cpp new file mode 100644 index 000000000..1ca695995 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/segment_segment_squared_distance.cpp @@ -0,0 +1,129 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "segment_segment_squared_distance.h" +#include + +// http://geomalgorithms.com/a07-_distance.html +template < typename Kernel> +IGL_INLINE bool igl::copyleft::cgal::segment_segment_squared_distance( + const CGAL::Segment_3 & S1, + const CGAL::Segment_3 & S2, + CGAL::Point_3 & P1, + CGAL::Point_3 & P2, + typename Kernel::FT & dst) +{ + typedef CGAL::Point_3 Point_3; + typedef CGAL::Vector_3 Vector_3; + typedef typename Kernel::FT EScalar; + if(S1.is_degenerate()) + { + // All points on S1 are the same + P1 = S1.source(); + point_segment_squared_distance(P1,S2,P2,dst); + return true; + }else if(S2.is_degenerate()) + { + assert(!S1.is_degenerate()); + // All points on S2 are the same + P2 = S2.source(); + point_segment_squared_distance(P2,S1,P1,dst); + return true; + } + + assert(!S1.is_degenerate()); + assert(!S2.is_degenerate()); + + Vector_3 u = S1.target() - S1.source(); + Vector_3 v = S2.target() - S2.source(); + Vector_3 w = S1.source() - S2.source(); + + const auto a = u.dot(u); // always >= 0 + const auto b = u.dot(v); + const auto c = v.dot(v); // always >= 0 + const auto d = u.dot(w); + const auto e = v.dot(w); + const auto D = a*c - b*b; // always >= 0 + assert(D>=0); + const auto sc=D, sN=D, sD = D; // sc = sN / sD, default sD = D >= 0 + const auto tc=D, tN=D, tD = D; // tc = tN / tD, default tD = D >= 0 + + bool parallel = false; + // compute the line parameters of the two closest points + if (D==0) + { + // the lines are almost parallel + parallel = true; + sN = 0.0; // force using source point on segment S1 + sD = 1.0; // to prevent possible division by 0.0 later + tN = e; + tD = c; + } else + { + // get the closest points on the infinite lines + sN = (b*e - c*d); + tN = (a*e - b*d); + if (sN < 0.0) + { + // sc < 0 => the s=0 edge is visible + sN = 0.0; + tN = e; + tD = c; + } else if (sN > sD) + { // sc > 1 => the s=1 edge is visible + sN = sD; + tN = e + b; + tD = c; + } + } + + if (tN < 0.0) + { + // tc < 0 => the t=0 edge is visible + tN = 0.0; + // recompute sc for this edge + if (-d < 0.0) + { + sN = 0.0; + }else if (-d > a) + { + sN = sD; + }else + { + sN = -d; + sD = a; + } + }else if (tN > tD) + { + // tc > 1 => the t=1 edge is visible + tN = tD; + // recompute sc for this edge + if ((-d + b) < 0.0) + { + sN = 0; + }else if ((-d + b) > a) + { + sN = sD; + }else + { + sN = (-d + b); + sD = a; + } + } + // finally do the division to get sc and tc + sc = (abs(sN) == 0 ? 0.0 : sN / sD); + tc = (abs(tN) == 0 ? 0.0 : tN / tD); + + // get the difference of the two closest points + P1 = S1.source() + sc*(S1.target()-S1.source()); + P2 = S2.source() + sc*(S2.target()-S2.source()); + Vector_3 dP = w + (sc * u) - (tc * v); // = S1(sc) - S2(tc) + assert(dP == (P1-P2)); + + dst = dP.squared_length(); // return the closest distance + return parallel; +} diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/segment_segment_squared_distance.h b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/segment_segment_squared_distance.h new file mode 100644 index 000000000..5bfbfdcab --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/segment_segment_squared_distance.h @@ -0,0 +1,46 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_COPYLEFT_CGAL_SEGMENT_SEGMENT_SQUARED_DISTANCE_H +#define IGL_COPYLEFT_CGAL_SEGMENT_SEGMENT_SQUARED_DISTANCE_H +#include "../../igl_inline.h" +#include +#include +namespace igl +{ + namespace copyleft + { + namespace cgal + { + // Given two segments S1 and S2 find the points on each of closest + // approach and the squared distance thereof. + // + // Inputs: + // S1 first segment + // S2 second segment + // Outputs: + // P1 point on S1 closest to S2 + // P2 point on S2 closest to S1 + // d distance betwee P1 and S2 + // Returns true if the closest approach is unique. + template < typename Kernel> + IGL_INLINE bool segment_segment_squared_distance( + const CGAL::Segment_3 & S1, + const CGAL::Segment_3 & S2, + CGAL::Point_3 & P1, + CGAL::Point_3 & P2, + typename Kernel::FT & d + ); + + } + } +} +#ifndef IGL_STATIC_LIBRARY +# include "segment_segment_squared_distance.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/signed_distance_isosurface.cpp b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/signed_distance_isosurface.cpp new file mode 100644 index 000000000..eeb6c03c5 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/signed_distance_isosurface.cpp @@ -0,0 +1,138 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "signed_distance_isosurface.h" +#include "point_mesh_squared_distance.h" +#include "complex_to_mesh.h" + +#include "../../AABB.h" +#include "../../per_face_normals.h" +#include "../../per_edge_normals.h" +#include "../../per_vertex_normals.h" +#include "../../centroid.h" +#include "../../WindingNumberAABB.h" + +#include +#include +#include +#include +#include +// Axis-aligned bounding box tree for tet tri intersection +#include +#include +#include +#include + +IGL_INLINE bool igl::copyleft::cgal::signed_distance_isosurface( + const Eigen::MatrixXd & IV, + const Eigen::MatrixXi & IF, + const double level, + const double angle_bound, + const double radius_bound, + const double distance_bound, + const SignedDistanceType sign_type, + Eigen::MatrixXd & V, + Eigen::MatrixXi & F) +{ + using namespace std; + using namespace Eigen; + + // default triangulation for Surface_mesher + typedef CGAL::Surface_mesh_default_triangulation_3 Tr; + // c2t3 + typedef CGAL::Complex_2_in_triangulation_3 C2t3; + typedef Tr::Geom_traits GT;//Kernel + typedef GT::Sphere_3 Sphere_3; + typedef GT::Point_3 Point_3; + typedef GT::FT FT; + typedef std::function Function; + typedef CGAL::Implicit_surface_3 Surface_3; + + AABB tree; + tree.init(IV,IF); + + Eigen::MatrixXd FN,VN,EN; + Eigen::MatrixXi E; + Eigen::VectorXi EMAP; + WindingNumberAABB< Eigen::Vector3d, Eigen::MatrixXd, Eigen::MatrixXi > hier; + switch(sign_type) + { + default: + assert(false && "Unknown SignedDistanceType"); + case SIGNED_DISTANCE_TYPE_UNSIGNED: + // do nothing + break; + case SIGNED_DISTANCE_TYPE_DEFAULT: + case SIGNED_DISTANCE_TYPE_WINDING_NUMBER: + hier.set_mesh(IV,IF); + hier.grow(); + break; + case SIGNED_DISTANCE_TYPE_PSEUDONORMAL: + // "Signed Distance Computation Using the Angle Weighted Pseudonormal" + // [Bærentzen & Aanæs 2005] + per_face_normals(IV,IF,FN); + per_vertex_normals(IV,IF,PER_VERTEX_NORMALS_WEIGHTING_TYPE_ANGLE,FN,VN); + per_edge_normals( + IV,IF,PER_EDGE_NORMALS_WEIGHTING_TYPE_UNIFORM,FN,EN,E,EMAP); + break; + } + + Tr tr; // 3D-Delaunay triangulation + C2t3 c2t3 (tr); // 2D-complex in 3D-Delaunay triangulation + // defining the surface + const auto & IVmax = IV.colwise().maxCoeff(); + const auto & IVmin = IV.colwise().minCoeff(); + const double bbd = (IVmax-IVmin).norm(); + const double r = bbd/2.; + const auto & IVmid = 0.5*(IVmax + IVmin); + // Supposedly the implict needs to evaluate to <0 at cmid... + // http://doc.cgal.org/latest/Surface_mesher/classCGAL_1_1Implicit__surface__3.html + Point_3 cmid(IVmid(0),IVmid(1),IVmid(2)); + Function fun; + switch(sign_type) + { + default: + assert(false && "Unknown SignedDistanceType"); + case SIGNED_DISTANCE_TYPE_UNSIGNED: + fun = + [&tree,&IV,&IF,&level](const Point_3 & q) -> FT + { + int i; + RowVector3d c; + const double sd = tree.squared_distance( + IV,IF,RowVector3d(q.x(),q.y(),q.z()),i,c); + return sd-level; + }; + case SIGNED_DISTANCE_TYPE_DEFAULT: + case SIGNED_DISTANCE_TYPE_WINDING_NUMBER: + fun = + [&tree,&IV,&IF,&hier,&level](const Point_3 & q) -> FT + { + const double sd = signed_distance_winding_number( + tree,IV,IF,hier,Vector3d(q.x(),q.y(),q.z())); + return sd-level; + }; + break; + case SIGNED_DISTANCE_TYPE_PSEUDONORMAL: + fun = [&tree,&IV,&IF,&FN,&VN,&EN,&EMAP,&level](const Point_3 & q) -> FT + { + const double sd = + igl::signed_distance_pseudonormal( + tree,IV,IF,FN,VN,EN,EMAP,RowVector3d(q.x(),q.y(),q.z())); + return sd- level; + }; + break; + } + Sphere_3 bounding_sphere(cmid, (r+level)*(r+level)); + Surface_3 surface(fun,bounding_sphere); + CGAL::Surface_mesh_default_criteria_3 + criteria(angle_bound,radius_bound,distance_bound); + // meshing surface + CGAL::make_surface_mesh(c2t3, surface, criteria, CGAL::Manifold_tag()); + // complex to (V,F) + return igl::copyleft::cgal::complex_to_mesh(c2t3,V,F); +} diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/signed_distance_isosurface.h b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/signed_distance_isosurface.h new file mode 100644 index 000000000..149ea5e3d --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/signed_distance_isosurface.h @@ -0,0 +1,54 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_COPYLEFT_CGAL_SIGNED_DISTANCE_ISOSURFACE_H +#define IGL_COPYLEFT_CGAL_SIGNED_DISTANCE_ISOSURFACE_H +#include "../../igl_inline.h" +#include "../../signed_distance.h" +#include +namespace igl +{ + namespace copyleft + { + namespace cgal + { + // SIGNED_DISTANCE_ISOSURFACE Compute the contour of an iso-level of the + // signed distance field to a given mesh. + // + // Inputs: + // IV #IV by 3 list of input mesh vertex positions + // IF #IF by 3 list of input triangle indices + // level iso-level to contour in world coords, negative is inside. + // angle_bound lower bound on triangle angles (mesh quality) (e.g. 28) + // radius_bound upper bound on triangle size (mesh density?) (e.g. 0.02) + // distance_bound cgal mysterious parameter (mesh density?) (e.g. 0.01) + // sign_type method for computing distance _sign_ (see + // ../signed_distance.h) + // Outputs: + // V #V by 3 list of input mesh vertex positions + // F #F by 3 list of input triangle indices + // + IGL_INLINE bool signed_distance_isosurface( + const Eigen::MatrixXd & IV, + const Eigen::MatrixXi & IF, + const double level, + const double angle_bound, + const double radius_bound, + const double distance_bound, + const SignedDistanceType sign_type, + Eigen::MatrixXd & V, + Eigen::MatrixXi & F); + } + } +} + +#ifndef IGL_STATIC_LIBRARY +# include "signed_distance_isosurface.cpp" +#endif + +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/slice.cpp b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/slice.cpp new file mode 100644 index 000000000..2e274a2f2 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/slice.cpp @@ -0,0 +1,12 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2017 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "../../slice.h" +#ifdef IGL_STATIC_LIBRARY +#undef IGL_STATIC_LIBRARY +#include "../../slice.cpp" +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/slice_mask.cpp b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/slice_mask.cpp new file mode 100644 index 000000000..ec920e0d1 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/slice_mask.cpp @@ -0,0 +1,15 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2017 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "../../slice_mask.h" +#include +#include +#ifdef IGL_STATIC_LIBRARY +#undef IGL_STATIC_LIBRARY +#include "../../slice_mask.cpp" +template void igl::slice_mask, -1, 3, 0, -1, 3>, Eigen::Matrix, -1, 3, 0, -1, 3> >(Eigen::DenseBase, -1, 3, 0, -1, 3> > const&, Eigen::Array const&, int, Eigen::PlainObjectBase, -1, 3, 0, -1, 3> >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/snap_rounding.cpp b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/snap_rounding.cpp new file mode 100644 index 000000000..4eb2a8f45 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/snap_rounding.cpp @@ -0,0 +1,212 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "snap_rounding.h" +#include "resolve_intersections.h" +#include "subdivide_segments.h" +#include "../../remove_unreferenced.h" +#include "../../unique.h" +#include +#include +#include +#include +#include + +template < + typename DerivedV, + typename DerivedE, + typename DerivedVI, + typename DerivedEI, + typename DerivedJ> +IGL_INLINE void igl::copyleft::cgal::snap_rounding( + const Eigen::PlainObjectBase & V, + const Eigen::PlainObjectBase & E, + Eigen::PlainObjectBase & VI, + Eigen::PlainObjectBase & EI, + Eigen::PlainObjectBase & J) +{ + using namespace Eigen; + using namespace igl; + using namespace igl::copyleft::cgal; + using namespace std; + // Exact scalar type + typedef CGAL::Epeck Kernel; + typedef Kernel::FT EScalar; + typedef CGAL::Segment_2 Segment_2; + typedef CGAL::Point_2 Point_2; + typedef CGAL::Vector_2 Vector_2; + typedef Matrix MatrixXE; + // Convert vertex positions to exact kernel + + MatrixXE VE; + { + VectorXi IM; + resolve_intersections(V,E,VE,EI,J,IM); + for_each( + EI.data(), + EI.data()+EI.size(), + [&IM](typename DerivedEI::Scalar& i){i=IM(i);}); + VectorXi _; + remove_unreferenced( MatrixXE(VE), DerivedEI(EI), VE,EI,_); + } + + // find all hot pixels + //// southwest and north east corners + //const RowVector2i SW( + // round(VE.col(0).minCoeff()), + // round(VE.col(1).minCoeff())); + //const RowVector2i NE( + // round(VE.col(0).maxCoeff()), + // round(VE.col(1).maxCoeff())); + + // https://github.com/CGAL/cgal/issues/548 + // Round an exact scalar to the nearest integer. A priori can't just round + // double. Suppose e=0.5+ε but double(e)<0.5 + // + // Inputs: + // e exact number + // Outputs: + // i closest integer + const auto & round = [](const EScalar & e)->int + { + const double d = CGAL::to_double(e); + // get an integer that's near the closest int + int i = std::round(d); + EScalar di_sqr = CGAL::square((e-EScalar(i))); + const auto & search = [&i,&di_sqr,&e](const int dir) + { + while(true) + { + const int j = i+dir; + const EScalar dj_sqr = CGAL::square((e-EScalar(j))); + if(dj_sqr < di_sqr) + { + i = j; + di_sqr = dj_sqr; + }else + { + break; + } + } + }; + // Try to increase/decrease int + search(1); + search(-1); + return i; + }; + vector hot; + for(int i = 0;i _1,_2; + igl::unique(vector(hot),hot,_1,_2); + } + + // find all segments intersecting hot pixels + // split edge at closest point to hot pixel center + vector> steiner(EI.rows()); + // initialize each segment with endpoints + for(int i = 0;i hits; + for(int j = 0;j<4;j++) + { + const Segment_2 & sj = wall[j]; + if(CGAL::do_intersect(si,sj)) + { + CGAL::Object result = CGAL::intersection(si,sj); + if(const Point_2 * p = CGAL::object_cast(&result)) + { + hits.push_back(*p); + }else if(const Segment_2 * s = CGAL::object_cast(&result)) + { + // add both endpoints + hits.push_back(s->vertex(0)); + hits.push_back(s->vertex(1)); + } + } + } + if(hits.size() == 0) + { + continue; + } + // centroid of hits + Vector_2 cen(0,0); + for(const Point_2 & hit : hits) + { + cen = Vector_2(cen.x()+hit.x(), cen.y()+hit.y()); + } + cen = Vector_2(cen.x()/EScalar(hits.size()),cen.y()/EScalar(hits.size())); + const Point_2 rcen(round(cen.x()),round(cen.y())); + // after all of that, don't add as a steiner unless it's going to round + // to h + if(rcen == h) + { + steiner[i].emplace_back(cen.x(),cen.y()); + } + } + } + { + DerivedJ prevJ = J; + VectorXi IM; + subdivide_segments(MatrixXE(VE),MatrixXi(EI),steiner,VE,EI,J,IM); + for_each(J.data(),J.data()+J.size(),[&prevJ](typename DerivedJ::Scalar & j){j=prevJ(j);}); + for_each( + EI.data(), + EI.data()+EI.size(), + [&IM](typename DerivedEI::Scalar& i){i=IM(i);}); + VectorXi _; + remove_unreferenced( MatrixXE(VE), DerivedEI(EI), VE,EI,_); + } + + + VI.resizeLike(VE); + for(int i = 0;i, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/snap_rounding.h b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/snap_rounding.h new file mode 100644 index 000000000..48d2757f1 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/snap_rounding.h @@ -0,0 +1,51 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_COPYLEFT_CGAL_SNAP_ROUNDING_H +#define IGL_COPYLEFT_CGAL_SNAP_ROUNDING_H + +#include "../../igl_inline.h" +#include + +namespace igl +{ + namespace copyleft + { + namespace cgal + { + // SNAP_ROUNDING Snap a list of possible intersecting segments with + // endpoints in any precision to _the_ integer grid. + // + // Inputs: + // V #V by 2 list of vertex positions + // E #E by 2 list of segment indices into V + // Outputs: + // VI #VI by 2 list of output integer vertex positions, rounded copies + // of V are always the first #V vertices + // EI #EI by 2 list of segment indices into V, #EI ≥ #E + // J #EI list of indices into E revealing "parent segments" + template < + typename DerivedV, + typename DerivedE, + typename DerivedVI, + typename DerivedEI, + typename DerivedJ> + IGL_INLINE void snap_rounding( + const Eigen::PlainObjectBase & V, + const Eigen::PlainObjectBase & E, + Eigen::PlainObjectBase & VI, + Eigen::PlainObjectBase & EI, + Eigen::PlainObjectBase & J); + } + } +} + +#ifndef IGL_STATIC_LIBRARY +# include "snap_rounding.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/string_to_mesh_boolean_type.cpp b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/string_to_mesh_boolean_type.cpp new file mode 100644 index 000000000..8ff1a03c4 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/string_to_mesh_boolean_type.cpp @@ -0,0 +1,53 @@ +#include "string_to_mesh_boolean_type.h" +#include +#include +#include + +IGL_INLINE bool igl::copyleft::cgal::string_to_mesh_boolean_type( + const std::string & s, + MeshBooleanType & type) +{ + using namespace std; + string eff_s = s; + transform(eff_s.begin(), eff_s.end(), eff_s.begin(), ::tolower); + const auto & find_any = + [](const vector & haystack, const string & needle)->bool + { + return find(haystack.begin(), haystack.end(), needle) != haystack.end(); + }; + if(find_any({"union","unite","u","∪"},eff_s)) + { + type = MESH_BOOLEAN_TYPE_UNION; + }else if(find_any({"intersect","intersection","i","∩"},eff_s)) + { + type = MESH_BOOLEAN_TYPE_INTERSECT; + }else if( + find_any( + {"minus","subtract","difference","relative complement","m","\\"},eff_s)) + { + type = MESH_BOOLEAN_TYPE_MINUS; + }else if(find_any({"xor","symmetric difference","x","∆"},eff_s)) + { + type = MESH_BOOLEAN_TYPE_XOR; + }else if(find_any({"resolve"},eff_s)) + { + type = MESH_BOOLEAN_TYPE_RESOLVE; + }else + { + return false; + } + return true; +} + +IGL_INLINE igl::MeshBooleanType +igl::copyleft::cgal::string_to_mesh_boolean_type( + const std::string & s) +{ + MeshBooleanType type; +#ifndef NDEBUG + const bool ret = +#endif + string_to_mesh_boolean_type(s,type); + assert(ret && "Unknown MeshBooleanType name"); + return type; +} diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/string_to_mesh_boolean_type.h b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/string_to_mesh_boolean_type.h new file mode 100644 index 000000000..4781099f1 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/string_to_mesh_boolean_type.h @@ -0,0 +1,44 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_COPYLEFT_CGAL_STRING_TO_MESH_BOOLEAN_H +#define IGL_COPYLEFT_CGAL_STRING_TO_MESH_BOOLEAN_H + +#include "../../igl_inline.h" +#include "../../MeshBooleanType.h" +#include + +namespace igl +{ + namespace copyleft + { + namespace cgal + { + // Convert string to boolean type + // + // Inputs: + // s string identifying type, one of the following: + // "union","intersect","minus","xor","resolve" + // Outputs: + // type type of boolean operation + // Returns true only on success + // + IGL_INLINE bool string_to_mesh_boolean_type( + const std::string & s, + MeshBooleanType & type); + // Returns type without error handling + IGL_INLINE MeshBooleanType string_to_mesh_boolean_type( + const std::string & s); + } + } +} + +#ifndef IGL_STATIC_LIBRARY +# include "string_to_mesh_boolean_type.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/subdivide_segments.cpp b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/subdivide_segments.cpp new file mode 100644 index 000000000..ccfe04b1c --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/subdivide_segments.cpp @@ -0,0 +1,142 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "subdivide_segments.h" +#include "row_to_point.h" +#include "assign_scalar.h" +#include "../../unique.h" +#include "../../list_to_matrix.h" +#include +#include +#include +#include +#include + +template < + typename DerivedV, + typename DerivedE, + typename Kernel, + typename DerivedVI, + typename DerivedEI, + typename DerivedJ, + typename DerivedIM> +IGL_INLINE void igl::copyleft::cgal::subdivide_segments( + const Eigen::PlainObjectBase & V, + const Eigen::PlainObjectBase & E, + const std::vector > > & _steiner, + Eigen::PlainObjectBase & VI, + Eigen::PlainObjectBase & EI, + Eigen::PlainObjectBase & J, + Eigen::PlainObjectBase & IM) +{ + using namespace Eigen; + using namespace igl; + using namespace std; + + // Exact scalar type + typedef Kernel K; + typedef typename Kernel::FT EScalar; + typedef CGAL::Segment_2 Segment_2; + typedef CGAL::Point_2 Point_2; + typedef Matrix MatrixXE; + + // non-const copy + std::vector > > steiner = _steiner; + + // Convert vertex positions to exact kernel + MatrixXE VE(V.rows(),V.cols()); + for(int i = 0;i S; + std::vector > vEI; + std::vector vJ; + for(int i = 0;i(VE,E(i,0)); + std::sort( + steiner[i].begin(), + steiner[i].end(), + [&s](const Point_2 & A, const Point_2 & B)->bool + { + return (A-s).squared_length() < (B-s).squared_length(); + }); + } + // remove duplicates + steiner[i].erase( + std::unique(steiner[i].begin(), steiner[i].end()), + steiner[i].end()); + { + int s = E(i,0); + // legs to each steiner in order + for(int j = 1;j vVES,_1; + for(int i = 0;i(VE,i)); + } + vVES.insert(vVES.end(),S.begin(),S.end()); + std::vector vA,vIM; + igl::unique(vVES,_1,vA,vIM); + // Push indices back into vVES + for_each(vIM.data(),vIM.data()+vIM.size(),[&vA](size_t & i){i=vA[i];}); + list_to_matrix(vIM,IM); + } +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::copyleft::cgal::subdivide_segments, Eigen::Matrix, CGAL::Epeck, Eigen::Matrix, -1, -1, 0, -1, -1>, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, std::vector, std::allocator > >, std::allocator, std::allocator > > > > const&, Eigen::PlainObjectBase, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::copyleft::cgal::subdivide_segments, -1, -1, 0, -1, -1>, Eigen::Matrix, CGAL::Epeck, Eigen::Matrix, -1, -1, 0, -1, -1>, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase > const&, std::vector, std::allocator > >, std::allocator, std::allocator > > > > const&, Eigen::PlainObjectBase, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/subdivide_segments.h b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/subdivide_segments.h new file mode 100644 index 000000000..cd7d41a00 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/subdivide_segments.h @@ -0,0 +1,56 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_COPYLEFT_CGAL_SUBDIVIDE_SEGMENTS_H +#define IGL_COPYLEFT_CGAL_SUBDIVIDE_SEGMENTS_H +#include "../../igl_inline.h" +#include +#include +#include +#include +namespace igl +{ + namespace copyleft + { + namespace cgal + { + // Insert steiner points to subdivide a given set of line segments + // + // Inputs: + // V #V by 2 list of vertex positions + // E #E by 2 list of segment indices into V + // steiner #E list of lists of unsorted steiner points (including + // endpoints) along the #E original segments + // Outputs: + // VI #VI by 2 list of output vertex positions, copies of V are always + // the first #V vertices + // EI #EI by 2 list of segment indices into V, #EI ≥ #E + // J #EI list of indices into E revealing "parent segments" + // IM #VI list of indices into VV of unique vertices. + template < + typename DerivedV, + typename DerivedE, + typename Kernel, + typename DerivedVI, + typename DerivedEI, + typename DerivedJ, + typename DerivedIM> + IGL_INLINE void subdivide_segments( + const Eigen::PlainObjectBase & V, + const Eigen::PlainObjectBase & E, + const std::vector > > & steiner, + Eigen::PlainObjectBase & VI, + Eigen::PlainObjectBase & EI, + Eigen::PlainObjectBase & J, + Eigen::PlainObjectBase & IM); + } + } +} +#ifndef IGL_STATIC_LIBRARY +# include "subdivide_segments.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/submesh_aabb_tree.cpp b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/submesh_aabb_tree.cpp new file mode 100644 index 000000000..4351ec0a9 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/submesh_aabb_tree.cpp @@ -0,0 +1,58 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "submesh_aabb_tree.h" +#include + +template< + typename DerivedV, + typename DerivedF, + typename DerivedI, + typename Kernel> +IGL_INLINE void igl::copyleft::cgal::submesh_aabb_tree( + const Eigen::PlainObjectBase& V, + const Eigen::PlainObjectBase& F, + const Eigen::PlainObjectBase& I, + CGAL::AABB_tree< + CGAL::AABB_traits< + Kernel, + CGAL::AABB_triangle_primitive< + Kernel, typename std::vector< + typename Kernel::Triangle_3 >::iterator > > > & tree, + std::vector & triangles, + std::vector & in_I) +{ + in_I.resize(F.rows(), false); + const size_t num_faces = I.rows(); + for (size_t i=0; i, -1, -1, 1, -1, -1>, Eigen::Matrix, Eigen::Matrix, CGAL::Epeck>(Eigen::PlainObjectBase, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, CGAL::AABB_tree >::iterator, CGAL::Boolean_tag > > >&, std::vector >&, std::vector >&); +// generated by autoexplicit.sh +template void igl::copyleft::cgal::submesh_aabb_tree, -1, -1, 1, -1, -1>, Eigen::Matrix, Eigen::Matrix, CGAL::Epeck>(Eigen::PlainObjectBase, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, CGAL::AABB_tree >::iterator, CGAL::Boolean_tag > > >&, std::vector >&, std::vector >&); +template void igl::copyleft::cgal::submesh_aabb_tree, -1, -1, 0, -1, -1>, Eigen::Matrix, Eigen::Matrix, CGAL::Epeck>(Eigen::PlainObjectBase, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, CGAL::AABB_tree >::iterator, CGAL::Boolean_tag > > >&, std::vector >&, std::vector >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/submesh_aabb_tree.h b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/submesh_aabb_tree.h new file mode 100644 index 000000000..eec9c030f --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/submesh_aabb_tree.h @@ -0,0 +1,64 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +// +#ifndef IGL_COPYLET_CGAL_SUBMESH_AABB_TREE_H +#define IGL_COPYLET_CGAL_SUBMESH_AABB_TREE_H + +#include "../../igl_inline.h" +#include +#include + +#include +#include +#include +#include +#include + +namespace igl +{ + namespace copyleft + { + namespace cgal + { + // Build an AABB tree for a submesh indicated by a face selection list I + // of a full mesh (V,F) + // + // Inputs: + // V #V by 3 array of vertices. + // F #F by 3 array of faces. + // I #I list of triangle indices to consider. + // Outputs: + // tree aabb containing triangles of (V,F(I,:)) + // triangles #I list of cgal triangles + // in_I #F list of whether in submesh + template< + typename DerivedV, + typename DerivedF, + typename DerivedI, + typename Kernel> + IGL_INLINE void submesh_aabb_tree( + const Eigen::PlainObjectBase& V, + const Eigen::PlainObjectBase& F, + const Eigen::PlainObjectBase& I, + CGAL::AABB_tree< + CGAL::AABB_traits< + Kernel, + CGAL::AABB_triangle_primitive< + Kernel, typename std::vector< + typename Kernel::Triangle_3 >::iterator > > > & tree, + std::vector & triangles, + std::vector & in_I); + } + } +} + +#ifndef IGL_STATIC_LIBRARY +# include "submesh_aabb_tree.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/triangle_triangle_squared_distance.cpp b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/triangle_triangle_squared_distance.cpp new file mode 100644 index 000000000..0c512f800 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/triangle_triangle_squared_distance.cpp @@ -0,0 +1,114 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "triangle_triangle_squared_distance.h" +#include "point_triangle_squared_distance.h" +#include +#include +#include + +template < typename Kernel> +IGL_INLINE bool igl::copyleft::cgal::triangle_triangle_squared_distance( + const CGAL::Triangle_3 & T1, + const CGAL::Triangle_3 & T2, + CGAL::Point_3 & P1, + CGAL::Point_3 & P2, + typename Kernel::FT & d) +{ + typedef CGAL::Point_3 Point_3; + typedef CGAL::Vector_3 Vector_3; + typedef CGAL::Triangle_3 Triangle_3; + typedef CGAL::Segment_3 Segment_3; + typedef typename Kernel::FT EScalar; + assert(!T1.is_degenerate()); + assert(!T2.is_degenerate()); + + bool unique = true; + if(CGAL::do_intersect(T1,T2)) + { + // intersecting triangles have zero (squared) distance + CGAL::Object result = CGAL::intersection(T1,T2); + // Some point on the intersection result + CGAL::Point_3 Q; + if(const Point_3 * p = CGAL::object_cast(&result)) + { + Q = *p; + }else if(const Segment_3 * s = CGAL::object_cast(&result)) + { + unique = false; + Q = s->source(); + }else if(const Triangle_3 *itri = CGAL::object_cast(&result)) + { + Q = s->vertex(0); + unique = false; + }else if(const std::vector *polyp = + CGAL::object_cast< std::vector >(&result)) + { + assert(polyp->size() > 0 && "intersection poly should not be empty"); + Q = polyp[0]; + unique = false; + }else + { + assert(false && "Unknown intersection result"); + } + P1 = Q; + P2 = Q; + d = 0; + return unique; + } + // triangles do not intersect: the points of closest approach must be on the + // boundary of one of the triangles + d = std::numeric_limits::infinity(); + const auto & vertices_face = [&unique]( + const Triangle_3 & T1, + const Triangle_3 & T2, + Point_3 & P1, + Point_3 & P2, + EScalar & d) + { + for(int i = 0;i<3;i++) + { + const Point_3 vi = T1.vertex(i); + Point_3 P2i; + EScalar di; + point_triangle_squared_distance(vi,T2,P2i,di); + if(di +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_COPYLEFT_CGAL_TRIANGLE_TRIANGLE_SQUARED_DISTANCE_H +#define IGL_COPYLEFT_CGAL_TRIANGLE_TRIANGLE_SQUARED_DISTANCE_H +#include "../../igl_inline.h" +#include +#include +namespace igl +{ + namespace copyleft + { + namespace cgal + { + // Given two triangles T1 and T2 find the points on each of closest + // approach and the squared distance thereof. + // + // Inputs: + // T1 first triangle + // T2 second triangle + // Outputs: + // P1 point on T1 closest to T2 + // P2 point on T2 closest to T1 + // d distance betwee P1 and T2 + // Returns true if the closest approach is unique. + template < typename Kernel> + IGL_INLINE bool triangle_triangle_squared_distance( + const CGAL::Triangle_3 & T1, + const CGAL::Triangle_3 & T2, + CGAL::Point_3 & P1, + CGAL::Point_3 & P2, + typename Kernel::FT & d); + } + } +} +#ifndef IGL_STATIC_LIBRARY +# include "triangle_triangle_squared_distance.cpp" +#endif + +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/trim_with_solid.cpp b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/trim_with_solid.cpp new file mode 100644 index 000000000..1e67da71e --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/trim_with_solid.cpp @@ -0,0 +1,105 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "trim_with_solid.h" +#include "assign.h" +#include "intersect_other.h" +#include "point_solid_signed_squared_distance.h" + +#include "../../extract_manifold_patches.h" +#include "../../list_to_matrix.h" +#include "../../remove_unreferenced.h" +#include "../../slice_mask.h" + +#include + +#include + +template < + typename DerivedVA, + typename DerivedFA, + typename DerivedVB, + typename DerivedFB, + typename DerivedV, + typename DerivedF, + typename DerivedD, + typename DerivedJ> +IGL_INLINE void igl::copyleft::cgal::trim_with_solid( + const Eigen::PlainObjectBase & VA, + const Eigen::PlainObjectBase & FA, + const Eigen::PlainObjectBase & VB, + const Eigen::PlainObjectBase & FB, + Eigen::PlainObjectBase & Vd, + Eigen::PlainObjectBase & F, + Eigen::PlainObjectBase & D, + Eigen::PlainObjectBase & J) +{ + // resolve intersections using exact representation + typedef Eigen::Matrix MatrixX3E; + typedef Eigen::Matrix VectorXE; + typedef Eigen::Matrix RowVector3E; + MatrixX3E V; + Eigen::MatrixXi _1; + Eigen::VectorXi _2; + // Intersect A and B meshes and stitch together new faces + igl::copyleft::cgal::intersect_other( + VA,FA,VB,FB,{false,false,true},_1,V,F,J,_2); + // Partition result into manifold patches + Eigen::VectorXi P; + const size_t num_patches = igl::extract_manifold_patches(F,P); + // only keep faces from A + Eigen::Matrix A = J.array()< FA.rows(); + igl::slice_mask(Eigen::MatrixXi(F),A,1,F); + igl::slice_mask(Eigen::VectorXi(P),A,1,P); + igl::slice_mask(Eigen::VectorXi(J),A,1,J); + // Aggregate representative query points for each patch + std::vector flag(num_patches); + std::vector > vQ; + Eigen::VectorXi P2Q(num_patches); + for(int f = 0;f q = { + (V(F(f,0),0)+ V(F(f,1),0)+ V(F(f,2),0))/3., + (V(F(f,0),1)+ V(F(f,1),1)+ V(F(f,2),1))/3., + (V(F(f,0),2)+ V(F(f,1),2)+ V(F(f,2),2))/3.}; + vQ.emplace_back(q); + flag[p] = true; + } + } + MatrixX3E Q; + igl::list_to_matrix(vQ,Q); + VectorXE SP; + point_solid_signed_squared_distance(Q,VB,FB,SP); + Eigen::Matrix DP = SP.array()>0; + // distribute flag to all faces + D.resize(F.rows()); + for(int f = 0;f, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix + >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, + Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, + Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/trim_with_solid.h b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/trim_with_solid.h new file mode 100644 index 000000000..aa45d80f7 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/trim_with_solid.h @@ -0,0 +1,63 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_COPYLEFT_CGAL_TRIM_WITH_SOLID_H +#define IGL_COPYLEFT_CGAL_TRIM_WITH_SOLID_H + +#include "../../igl_inline.h" +#include + +namespace igl +{ + namespace copyleft + { + namespace cgal + { + // TRIM_WITH_SOLID Given an arbitrary mesh (VA,FA) and the boundary mesh + // (VB,FB) of a solid (as defined in [Zhou et al. 2016]), Resolve intersections + // between A and B subdividing faces of A so that intersections with B exists + // only along edges and vertices (and coplanar faces). Then determine whether + // each of these faces is inside or outside of B. This can be used to extract + // the part of A inside or outside of B. + // + // Inputs: + // VA #VA by 3 list of mesh vertex positions of A + // FA #FA by 3 list of mesh triangle indices into VA + // VB #VB by 3 list of mesh vertex positions of B + // FB #FB by 3 list of mesh triangle indices into VB + // Outputs: + // V #V by 3 list of mesh vertex positions of output + // F #F by 3 list of mesh triangle indices into V + // D #F list of bools whether face is inside B + // J #F list of indices into FA revealing birth parent + // + template < + typename DerivedVA, + typename DerivedFA, + typename DerivedVB, + typename DerivedFB, + typename DerivedV, + typename DerivedF, + typename DerivedD, + typename DerivedJ> + IGL_INLINE void trim_with_solid( + const Eigen::PlainObjectBase & VA, + const Eigen::PlainObjectBase & FA, + const Eigen::PlainObjectBase & VB, + const Eigen::PlainObjectBase & FB, + Eigen::PlainObjectBase & Vd, + Eigen::PlainObjectBase & F, + Eigen::PlainObjectBase & D, + Eigen::PlainObjectBase & J); + } + } +} + +#ifndef IGL_STATIC_LIBRARY +# include "trim_with_solid.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/unique.cpp b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/unique.cpp new file mode 100644 index 000000000..9ebf98f30 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/unique.cpp @@ -0,0 +1,15 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2017 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "../../unique.h" +#include +#include +#ifdef IGL_STATIC_LIBRARY +#undef IGL_STATIC_LIBRARY +#include "../../unique.cpp" +template void igl::unique >(std::vector, std::allocator > > const&, std::vector, std::allocator > >&, std::vector >&, std::vector >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/unique_rows.cpp b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/unique_rows.cpp new file mode 100644 index 000000000..e4d946f77 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/unique_rows.cpp @@ -0,0 +1,18 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2017 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "../../unique_rows.h" +#include +#include +#ifdef IGL_STATIC_LIBRARY +#undef IGL_STATIC_LIBRARY +#include "../../unique_rows.cpp" +template void igl::unique_rows, -1, -1, 0, -1, -1>, Eigen::Matrix, -1, -1, 0, -1, -1>, Eigen::Matrix, Eigen::Matrix >(Eigen::DenseBase, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::unique_rows, -1, -1, 1, -1, -1>, Eigen::Matrix, -1, -1, 1, -1, -1>, Eigen::Matrix, Eigen::Matrix >(Eigen::DenseBase, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase, -1, -1, 1, -1, -1> >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::unique_rows, -1, 3, 0, -1, 3>, Eigen::Matrix, -1, 3, 0, -1, 3>, Eigen::Matrix, Eigen::Matrix >(Eigen::DenseBase, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/wire_mesh.cpp b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/wire_mesh.cpp new file mode 100644 index 000000000..5e3bf9bf3 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/wire_mesh.cpp @@ -0,0 +1,254 @@ +#include "wire_mesh.h" + +#include "../../list_to_matrix.h" +#include "../../slice.h" +#include "../../PI.h" +#include "convex_hull.h" +#include "coplanar.h" +#include "mesh_boolean.h" +#include +#include + +template < + typename DerivedWV, + typename DerivedWE, + typename Derivedth, + typename DerivedV, + typename DerivedF, + typename DerivedJ> +IGL_INLINE void igl::copyleft::cgal::wire_mesh( + const Eigen::MatrixBase & WV, + const Eigen::MatrixBase & WE, + const Eigen::MatrixBase & th, + const int poly_size, + const bool solid, + Eigen::PlainObjectBase & V, + Eigen::PlainObjectBase & F, + Eigen::PlainObjectBase & J) +{ + assert((th.size()==1 || th.size()==WE.rows()) && + "th should be scalar or size of WE"); + + typedef typename DerivedWV::Scalar Scalar; + // Canonical polygon to place at each endpoint + typedef Eigen::Matrix MatrixX3S; + MatrixX3S PV(poly_size,3); + for(int p =0;p > > A(WV.rows()); + // Inputs: + // e index of edge + // c index of endpoint [0,1] + // p index of polygon vertex + // Returns index of corresponding vertex in V + const auto index = + [&PV,&WV](const int e, const int c, const int p)->int + { + return WV.rows() + e*2*PV.rows() + PV.rows()*c + p; + }; + const auto unindex = + [&PV,&WV](int v, int & e, int & c, int & p) + { + assert(v>=WV.rows()); + v = v-WV.rows(); + e = v/(2*PV.rows()); + v = v-e*(2*PV.rows()); + c = v/(PV.rows()); + v = v-c*(PV.rows()); + p = v; + }; + + // Count each vertex's indicident edges. + std::vector nedges(WV.rows(), 0); + for(int e = 0;e RowVector3S; + const RowVector3S ev = WV.row(WE(e,1))-WV.row(WE(e,0)); + const Scalar len = ev.norm(); + // Unit edge vector + const RowVector3S uv = ev.normalized(); + Eigen::Quaternion q; + q = q.FromTwoVectors(RowVector3S(0,0,1),uv); + // loop over polygon vertices + for(int p = 0;p 1); + // Move to endpoint, offset by amount + V.row(index(e,c,p)) = + qp+WV.row(WE(e,c)) + dist*dir*uv; + } + } + } + + std::vector > vF; + std::vector vJ; + const auto append_hull = + [&V,&vF,&vJ,&unindex,&WV](const Eigen::VectorXi & I, const int j) + { + MatrixX3S Vv; + igl::slice(V,I,1,Vv); + if(coplanar(Vv)) + { + return; + } + Eigen::MatrixXi Fv; + convex_hull(Vv,Fv); + for(int f = 0;f face(I(Fv(f,0)), I(Fv(f,1)), I(Fv(f,2))); + //const bool on_vertex = (face +IGL_INLINE void igl::copyleft::cgal::wire_mesh( + const Eigen::MatrixBase & WV, + const Eigen::MatrixBase & WE, + const double th, + const int poly_size, + const bool solid, + Eigen::PlainObjectBase & V, + Eigen::PlainObjectBase & F, + Eigen::PlainObjectBase & J) +{ + return wire_mesh( + WV,WE,(Eigen::VectorXd(1,1)< +IGL_INLINE void igl::copyleft::cgal::wire_mesh( + const Eigen::MatrixBase & WV, + const Eigen::MatrixBase & WE, + const double th, + const int poly_size, + Eigen::PlainObjectBase & V, + Eigen::PlainObjectBase & F, + Eigen::PlainObjectBase & J) +{ + return wire_mesh(WV,WE,th,poly_size,true,V,F,J); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +template void igl::copyleft::cgal::wire_mesh, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, double, int, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cgal/wire_mesh.h b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/wire_mesh.h new file mode 100644 index 000000000..f88bc9edd --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cgal/wire_mesh.h @@ -0,0 +1,83 @@ +#ifndef IGL_COPYLEFT_CGAL_WIRE_MESH_H +#define IGL_COPYLEFT_CGAL_WIRE_MESH_H +#include "../../igl_inline.h" +#include +namespace igl +{ + namespace copyleft + { + namespace cgal + { + // Construct a "wire" or "wireframe" or "strut" surface mesh, given a + // one-dimensional network of straight edges. + // + // Inputs: + // WV #WV by 3 list of vertex positions + // WE #WE by 2 list of edge indices into WV + // th #WE diameter thicknesses of wire edges + // poly_size number of sides on each wire (e.g., 4 would produce wires by + // connecting rectangular prisms). + // solid whether to resolve self-intersections to + // create a "solid" output mesh (cf., [Zhou et al. 2016] + // Outputs: + // V #V by 3 list of output vertices + // F #F by 3 list of output triangle indices into V + // J #F list of indices into [0,#WV+#WE) revealing "birth simplex" of + // output faces J(j) < #WV means the face corresponds to the J(j)th + // vertex in WV. J(j) >= #WV means the face corresponds to the + // (J(j)-#WV)th edge in WE. + template < + typename DerivedWV, + typename DerivedWE, + typename Derivedth, + typename DerivedV, + typename DerivedF, + typename DerivedJ> + IGL_INLINE void wire_mesh( + const Eigen::MatrixBase & WV, + const Eigen::MatrixBase & WE, + const Eigen::MatrixBase & th, + const int poly_size, + const bool solid, + Eigen::PlainObjectBase & V, + Eigen::PlainObjectBase & F, + Eigen::PlainObjectBase & J); + template < + typename DerivedWV, + typename DerivedWE, + typename DerivedV, + typename DerivedF, + typename DerivedJ> + IGL_INLINE void wire_mesh( + const Eigen::MatrixBase & WV, + const Eigen::MatrixBase & WE, + const double th, + const int poly_size, + const bool solid, + Eigen::PlainObjectBase & V, + Eigen::PlainObjectBase & F, + Eigen::PlainObjectBase & J); + // Default with solid=true + template < + typename DerivedWV, + typename DerivedWE, + typename DerivedV, + typename DerivedF, + typename DerivedJ> + IGL_INLINE void wire_mesh( + const Eigen::MatrixBase & WV, + const Eigen::MatrixBase & WE, + const double th, + const int poly_size, + Eigen::PlainObjectBase & V, + Eigen::PlainObjectBase & F, + Eigen::PlainObjectBase & J); + + } + } +} + +#ifndef IGL_STATIC_LIBRARY +# include "wire_mesh.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/comiso/frame_field.cpp b/src/external/libigl-2.3.0/include/igl/copyleft/comiso/frame_field.cpp new file mode 100644 index 000000000..c3549eeff --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/comiso/frame_field.cpp @@ -0,0 +1,688 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Daniele Panozzo +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "frame_field.h" + +#include +#include +#include +#include +#include + +namespace igl +{ +namespace copyleft +{ +namespace comiso +{ + +class FrameInterpolator +{ +public: + // Init + IGL_INLINE FrameInterpolator(const Eigen::MatrixXd& _V, const Eigen::MatrixXi& _F); + IGL_INLINE ~FrameInterpolator(); + + // Reset constraints (at least one constraint must be present or solve will fail) + IGL_INLINE void resetConstraints(); + + IGL_INLINE void setConstraint(const int fid, const Eigen::VectorXd& v); + + IGL_INLINE void interpolateSymmetric(); + + // Generate the frame field + IGL_INLINE void solve(); + + // Convert the frame field in the canonical representation + IGL_INLINE void frame2canonical(const Eigen::MatrixXd& TP, const Eigen::RowVectorXd& v, double& theta, Eigen::VectorXd& S); + + // Convert the canonical representation in a frame field + IGL_INLINE void canonical2frame(const Eigen::MatrixXd& TP, const double theta, const Eigen::VectorXd& S, Eigen::RowVectorXd& v); + + IGL_INLINE Eigen::MatrixXd getFieldPerFace(); + + IGL_INLINE void PolarDecomposition(Eigen::MatrixXd V, Eigen::MatrixXd& U, Eigen::MatrixXd& P); + + // Symmetric + Eigen::MatrixXd S; + std::vector S_c; + + // ------------------------------------------------- + + // Face Topology + Eigen::MatrixXi TT, TTi; + + // Two faces are consistent if their representative vector are taken modulo PI + std::vector edge_consistency; + Eigen::MatrixXi edge_consistency_TT; + +private: + IGL_INLINE double mod2pi(double d); + IGL_INLINE double modpi2(double d); + IGL_INLINE double modpi(double d); + + // Convert a direction on the tangent space into an angle + IGL_INLINE double vector2theta(const Eigen::MatrixXd& TP, const Eigen::RowVectorXd& v); + + // Convert an angle in a vector in the tangent space + IGL_INLINE Eigen::RowVectorXd theta2vector(const Eigen::MatrixXd& TP, const double theta); + + // Interpolate the cross field (theta) + IGL_INLINE void interpolateCross(); + + // Compute difference between reference frames + IGL_INLINE void computek(); + + // Compute edge consistency + IGL_INLINE void compute_edge_consistency(); + + // Cross field direction + Eigen::VectorXd thetas; + std::vector thetas_c; + + // Edge Topology + Eigen::MatrixXi EV, FE, EF; + std::vector isBorderEdge; + + // Angle between two reference frames + // R(k) * t0 = t1 + Eigen::VectorXd k; + + // Mesh + Eigen::MatrixXd V; + Eigen::MatrixXi F; + + // Normals per face + Eigen::MatrixXd N; + + // Reference frame per triangle + std::vector TPs; + +}; + +FrameInterpolator::FrameInterpolator(const Eigen::MatrixXd& _V, const Eigen::MatrixXi& _F) +{ + using namespace std; + using namespace Eigen; + + V = _V; + F = _F; + + assert(V.rows() > 0); + assert(F.rows() > 0); + + + // Generate topological relations + igl::triangle_triangle_adjacency(F,TT,TTi); + igl::edge_topology(V,F, EV, FE, EF); + + // Flag border edges + isBorderEdge.resize(EV.rows()); + for(unsigned i=0; i 3*(igl::PI/4.0); + + // Copy it into edge_consistency_TT + int i1 = -1; + int i2 = -1; + for (unsigned i=0; i<3; ++i) + { + if (TT(fid0,i) == fid1) + i1 = i; + if (TT(fid1,i) == fid0) + i2 = i; + } + assert(i1 != -1); + assert(i2 != -1); + + edge_consistency_TT(fid0,i1) = edge_consistency[eid]; + edge_consistency_TT(fid1,i2) = edge_consistency[eid]; + } + } +} + +void FrameInterpolator::computek() +{ + using namespace std; + using namespace Eigen; + + k.resize(EF.rows()); + + // For every non-border edge + for (unsigned eid=0; eid(); + + assert(tmp(0) - ref1(0) < (0.000001)); + assert(tmp(1) - ref1(1) < (0.000001)); + + k[eid] = ktemp; + } + } + +} + + + void FrameInterpolator::frame2canonical(const Eigen::MatrixXd& TP, const Eigen::RowVectorXd& v, double& theta, Eigen::VectorXd& S_v) +{ + using namespace std; + using namespace Eigen; + + RowVectorXd v0 = v.segment<3>(0); + RowVectorXd v1 = v.segment<3>(3); + + // Project onto the tangent plane + Vector2d vp0 = TP * v0.transpose(); + Vector2d vp1 = TP * v1.transpose(); + + // Assemble matrix + MatrixXd M(2,2); + M << vp0, vp1; + + if (M.determinant() < 0) + M.col(1) = -M.col(1); + + assert(M.determinant() > 0); + + // cerr << "M: " << M << endl; + + MatrixXd R,S; + PolarDecomposition(M,R,S); + + // Finally, express the cross field as an angle + theta = atan2(R(1,0),R(0,0)); + + MatrixXd R2(2,2); + R2 << cos(theta), -sin(theta), sin(theta), cos(theta); + + assert((R2-R).norm() < 10e-8); + + // Convert into rotation invariant form + S = R * S * R.inverse(); + + // Copy in vector form + S_v = VectorXd(3); + S_v << S(0,0), S(0,1), S(1,1); +} + + void FrameInterpolator::canonical2frame(const Eigen::MatrixXd& TP, const double theta, const Eigen::VectorXd& S_v, Eigen::RowVectorXd& v) +{ + using namespace std; + using namespace Eigen; + + assert(S_v.size() == 3); + + MatrixXd S_temp(2,2); + S_temp << S_v(0), S_v(1), S_v(1), S_v(2); + + // Convert angle in vector in the tangent plane + // Vector2d vp(cos(theta),sin(theta)); + + // First reconstruct R + MatrixXd R(2,2); + + R << cos(theta), -sin(theta), sin(theta), cos(theta); + + // Rotation invariant reconstruction + MatrixXd M = S_temp * R; + + Vector2d vp0(M(0,0),M(1,0)); + Vector2d vp1(M(0,1),M(1,1)); + + // Unproject the vectors + RowVectorXd v0 = vp0.transpose() * TP; + RowVectorXd v1 = vp1.transpose() * TP; + + v.resize(6); + v << v0, v1; +} + +void FrameInterpolator::solve() +{ + interpolateCross(); + interpolateSymmetric(); +} + +void FrameInterpolator::interpolateSymmetric() +{ + using namespace std; + using namespace Eigen; + + // Generate uniform Laplacian matrix + typedef Eigen::Triplet triplet; + std::vector triplets; + + // Variables are stacked as x1,y1,z1,x2,y2,z2 + triplets.reserve(3*4*F.rows()); + + MatrixXd b = MatrixXd::Zero(3*F.rows(),1); + + // Build L and b + for (unsigned eid=0; eid L(3*F.rows(),3*F.rows()); + L.setFromTriplets(triplets.begin(), triplets.end()); + + triplets.clear(); + + // Add soft constraints + double w = 100000; + for (unsigned fid=0; fid < F.rows(); ++fid) + { + if (S_c[fid]) + { + for (unsigned i=0;i<3;++i) + { + triplets.push_back(triplet(3*fid + i,3*fid + i,w)); + b(3*fid + i) += w*S(fid,i); + } + } + } + + SparseMatrix soft(3*F.rows(),3*F.rows()); + soft.setFromTriplets(triplets.begin(), triplets.end()); + + SparseMatrix M; + + M = L + soft; + + // Solve Lx = b; + + SparseLU > solver; + + solver.compute(M); + + if(solver.info()!=Success) + { + std::cerr << "LU failed - frame_interpolator.cpp" << std::endl; + assert(0); + } + + MatrixXd x; + x = solver.solve(b); + + if(solver.info()!=Success) + { + std::cerr << "Linear solve failed - frame_interpolator.cpp" << std::endl; + assert(0); + } + + S = MatrixXd::Zero(F.rows(),3); + + // Copy back the result + for (unsigned i=0;i svd(V,Eigen::ComputeFullU | Eigen::ComputeFullV); + + U = svd.matrixU() * svd.matrixV().transpose(); + P = svd.matrixV() * svd.singularValues().asDiagonal() * svd.matrixV().transpose(); +} + +} +} +} + +IGL_INLINE void igl::copyleft::comiso::frame_field( + const Eigen::MatrixXd& V, + const Eigen::MatrixXi& F, + const Eigen::VectorXi& b, + const Eigen::MatrixXd& bc1, + const Eigen::MatrixXd& bc2, + Eigen::MatrixXd& FF1, + Eigen::MatrixXd& FF2 + ) + +{ + using namespace std; + using namespace Eigen; + + assert(b.size() > 0); + + // Init Solver + FrameInterpolator field(V,F); + + for (unsigned i=0; i +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_COMISO_FRAMEFIELD_H +#define IGL_COMISO_FRAMEFIELD_H + +#include +#include +#include +#include + +namespace igl +{ +namespace copyleft +{ +namespace comiso +{ +// Generate a piecewise-constant frame-field field from a sparse set of constraints on faces +// using the algorithm proposed in: +// Frame Fields: Anisotropic and Non-Orthogonal Cross Fields +// Daniele Panozzo, Enrico Puppo, Marco Tarini, Olga Sorkine-Hornung, +// ACM Transactions on Graphics (SIGGRAPH, 2014) +// +// Inputs: +// V #V by 3 list of mesh vertex coordinates +// F #F by 3 list of mesh faces (must be triangles) +// b #B by 1 list of constrained face indices +// bc1 #B by 3 list of the constrained first representative vector of the frame field (up to permutation and sign) +// bc2 #B by 3 list of the constrained second representative vector of the frame field (up to permutation and sign) +// +// Outputs: +// FF1 #F by 3 the first representative vector of the frame field (up to permutation and sign) +// FF2 #F by 3 the second representative vector of the frame field (up to permutation and sign) +// +// TODO: it now supports only soft constraints, should be extended to support both hard and soft constraints +IGL_INLINE void frame_field( + const Eigen::MatrixXd& V, + const Eigen::MatrixXi& F, + const Eigen::VectorXi& b, + const Eigen::MatrixXd& bc1, + const Eigen::MatrixXd& bc2, + Eigen::MatrixXd& FF1, + Eigen::MatrixXd& FF2 + ); +} +} +} + +#ifndef IGL_STATIC_LIBRARY +# include "frame_field.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/comiso/miq.cpp b/src/external/libigl-2.3.0/include/igl/copyleft/comiso/miq.cpp new file mode 100644 index 000000000..5adde4416 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/comiso/miq.cpp @@ -0,0 +1,1543 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Daniele Panozzo , Olga Diamanti , Kevin Walliman +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +#include "miq.h" +#include "../../local_basis.h" +#include "../../triangle_triangle_adjacency.h" +#include "../../cut_mesh.h" +#include "../../LinSpaced.h" + +// includes for VertexIndexing +#include "../../HalfEdgeIterator.h" +#include "../../is_border_vertex.h" +#include "../../vertex_triangle_adjacency.h" + +// includes for PoissonSolver +#include "../../slice_into.h" +#include "../../grad.h" +#include "../../cotmatrix.h" +#include "../../doublearea.h" +#include +#include +#include +#include + +// +#include "igl/cross_field_mismatch.h" +#include "../../comb_frame_field.h" +#include "../../comb_cross_field.h" +#include "../../cut_mesh_from_singularities.h" +#include "../../find_cross_field_singularities.h" +#include "../../compute_frame_field_bisectors.h" +#include "../../rotate_vectors.h" + +#ifndef NDEBUG +#include +#endif +#include +#include "../../matlab_format.h" + +#define DEBUGPRINT 0 + + +namespace igl { +namespace copyleft { +namespace comiso { + struct SeamInfo + { + int v0,v0p; + unsigned int integerVar; + int mismatch; + + IGL_INLINE SeamInfo(int _v0, + int _v0p, + int _mismatch, + unsigned int _integerVar); + + IGL_INLINE SeamInfo(const SeamInfo &S1); + }; + + struct MeshSystemInfo + { + MeshSystemInfo() + { + num_vert_variables = 0; + num_integer_cuts = 0; + } + ////number of vertices variables + unsigned int num_vert_variables; + ///num of integer for cuts + unsigned int num_integer_cuts; + ///this are used for drawing purposes + std::vector edgeSeamInfo; + }; + + + template + class VertexIndexing + { + public: + // Input: + const Eigen::PlainObjectBase &V; + const Eigen::PlainObjectBase &F; + const Eigen::PlainObjectBase &Vcut; + const Eigen::PlainObjectBase &Fcut; + const Eigen::PlainObjectBase &TT; + const Eigen::PlainObjectBase &TTi; + + const Eigen::Matrix &mismatch; + const Eigen::Matrix &singular; // bool + const Eigen::Matrix &seams; // 3 bool + + + ///this handle for mesh TODO: move with the other global variables + MeshSystemInfo systemInfo; + + IGL_INLINE VertexIndexing(const Eigen::PlainObjectBase &_V, + const Eigen::PlainObjectBase &_F, + const Eigen::PlainObjectBase &_Vcut, + const Eigen::PlainObjectBase &_Fcut, + const Eigen::PlainObjectBase &_TT, + const Eigen::PlainObjectBase &_TTi, + const Eigen::Matrix &_mismatch, + const Eigen::Matrix &_singular, + const Eigen::Matrix &_seams + ); + + // provide information about every vertex per seam + IGL_INLINE void initSeamInfo(); + + + private: + struct VertexInfo{ + int v; // vertex index (according to V) + int f0, k0; // face and local edge information of the edge that connects this vertex to the previous vertex (previous in the vector) + int f1, k1; // face and local edge information of the other face corresponding to the same edge + VertexInfo(int _v, int _f0, int _k0, int _f1, int _k1) : + v(_v), f0(_f0), k0(_k0), f1(_f1), k1(_k1){} + bool operator==(VertexInfo const& other){ + return other.v == v; + } + }; + + IGL_INLINE void getSeamInfo(int f0, + int f1, + int indexE, + int &v0, int &v1, + int &v0p, int &v1p, + int &_mismatch); + + IGL_INLINE std::vector > getVerticesPerSeam(); + }; + + + template + class PoissonSolver + { + private: + + // Penalization term for integer variables used in mixedIntegerSolve + const double PENALIZATION = 0.000001; + + public: + IGL_INLINE void solvePoisson(Eigen::VectorXd stiffness, + double gradientSize = 0.1, + double gridResolution = 1., + bool directRound = true, + unsigned int localIter = 0, + bool doRound = true, + bool singularityRound = true, + const std::vector &roundVertices = std::vector(), + const std::vector> &hardFeatures = std::vector >()); + + IGL_INLINE PoissonSolver(const Eigen::PlainObjectBase &_V, + const Eigen::PlainObjectBase &_F, + const Eigen::PlainObjectBase &_Vcut, + const Eigen::PlainObjectBase &_Fcut, + const Eigen::PlainObjectBase &_TT, + const Eigen::PlainObjectBase &_TTi, + const Eigen::PlainObjectBase &_PD1, + const Eigen::PlainObjectBase &_PD2, + const Eigen::Matrix&_singular, + const MeshSystemInfo &_systemInfo + ); + + const Eigen::PlainObjectBase &V; + const Eigen::PlainObjectBase &F; + const Eigen::PlainObjectBase &Vcut; + const Eigen::PlainObjectBase &Fcut; + const Eigen::PlainObjectBase &TT; + const Eigen::PlainObjectBase &TTi; + const Eigen::PlainObjectBase &PD1; + const Eigen::PlainObjectBase &PD2; + const Eigen::Matrix &singular; // bool + + const MeshSystemInfo &systemInfo; + + // Internal: + Eigen::VectorXd Handle_Stiffness; + std::vector > VF; + std::vector > VFi; + Eigen::MatrixXd UV; // this is probably useless + + // Output: + // per wedge UV coordinates, 6 coordinates (1 face) per row + Eigen::MatrixXd WUV; + // per vertex UV coordinates, Vcut.rows() x 2 + Eigen::MatrixXd UV_out; + + // Matrices + Eigen::SparseMatrix Lhs; + Eigen::SparseMatrix Constraints; + Eigen::VectorXd rhs; + Eigen::VectorXd constraints_rhs; + ///vector of unknowns + std::vector< double > X; + + ////REAL PART + ///number of fixed vertex + unsigned int n_fixed_vars; + + ///the number of REAL variables for vertices + unsigned int n_vert_vars; + + ///total number of variables of the system, + ///do not consider constraints, but consider integer vars + unsigned int num_total_vars; + + //////INTEGER PART + ///the total number of integer variables + unsigned int n_integer_vars; + + ///CONSTRAINT PART + ///number of cuts constraints + unsigned int num_cut_constraint; + + // number of user-defined constraints + unsigned int num_userdefined_constraint; + + ///total number of constraints equations + unsigned int num_constraint_equations; + + ///vector of blocked vertices + std::vector Hard_constraints; + + ///vector of indexes to round + std::vector ids_to_round; + + ///vector of indexes to round + std::vector > userdefined_constraints; + + ///boolean that is true if rounding to integer is needed + bool integer_rounding; + + ///START COMMON MATH FUNCTIONS + ///return the complex encoding the rotation + ///for a given mismatch interval + IGL_INLINE std::complex getRotationComplex(int interval); + ///END COMMON MATH FUNCTIONS + + ///START FIXING VERTICES + ///set a given vertex as fixed + IGL_INLINE void addFixedVertex(int v); + + ///find vertex to fix in case we're using + ///a vector field NB: multiple components not handled + IGL_INLINE void findFixedVertField(); + + ///find hard constraint depending if using or not + ///a vector field + IGL_INLINE void findFixedVert(); + + IGL_INLINE int getFirstVertexIndex(int v); + + ///fix the vertices which are flagged as fixed + IGL_INLINE void fixBlockedVertex(); + ///END FIXING VERTICES + + ///HANDLING SINGULARITY + //set the singularity round to integer location + IGL_INLINE void addSingularityRound(); + + IGL_INLINE void addToRoundVertices(std::vector ids); + + ///START GENERIC SYSTEM FUNCTIONS + //build the Laplacian matrix cycling over all range maps + //and over all faces + IGL_INLINE void buildLaplacianMatrix(double vfscale = 1); + + ///find different sized of the system + IGL_INLINE void findSizes(); + + IGL_INLINE void allocateSystem(); + + ///intitialize the whole matrix + IGL_INLINE void initMatrix(); + + ///map back coordinates after that + ///the system has been solved + IGL_INLINE void mapCoords(); + ///END GENERIC SYSTEM FUNCTIONS + + ///set the constraints for the inter-range cuts + IGL_INLINE void buildSeamConstraintsExplicitTranslation(); + + ///set the constraints for the inter-range cuts + IGL_INLINE void buildUserDefinedConstraints(); + + ///call of the mixed integer solver + IGL_INLINE void mixedIntegerSolve(double coneGridRes = 1, + bool directRound = true, + unsigned int localIter = 0); + + IGL_INLINE void clearUserConstraint(); + + IGL_INLINE void addSharpEdgeConstraint(int fid, int vid); + + }; + + template + class MIQ_class + { + private: + const Eigen::PlainObjectBase &V; + const Eigen::PlainObjectBase &F; + DerivedV Vcut; + DerivedF Fcut; + Eigen::MatrixXd UV_out; + DerivedF FUV_out; + + // internal + DerivedF TT; + DerivedF TTi; + + // Stiffness per face + Eigen::VectorXd stiffnessVector; + DerivedV B1, B2, B3; + + public: + IGL_INLINE MIQ_class(const Eigen::PlainObjectBase &V_, + const Eigen::PlainObjectBase &F_, + const Eigen::PlainObjectBase &PD1_combed, + const Eigen::PlainObjectBase &PD2_combed, + const Eigen::Matrix &mismatch, + const Eigen::Matrix &singular, + const Eigen::Matrix &seams, + Eigen::PlainObjectBase &UV, + Eigen::PlainObjectBase &FUV, + double gradientSize = 30.0, + double stiffness = 5.0, + bool directRound = false, + unsigned int iter = 5, + unsigned int localIter = 5, + bool doRound = true, + bool singularityRound = true, + std::vector roundVertices = std::vector(), + std::vector > hardFeatures = std::vector >()); + + + IGL_INLINE void extractUV(Eigen::PlainObjectBase &UV_out, + Eigen::PlainObjectBase &FUV_out); + + private: + IGL_INLINE int NumFlips(const Eigen::MatrixXd& WUV); + + IGL_INLINE double Distortion(int f, double h, const Eigen::MatrixXd& WUV); + + IGL_INLINE double LaplaceDistortion(int f, double h, const Eigen::MatrixXd& WUV); + + IGL_INLINE bool updateStiffeningJacobianDistorsion(double grad_size, const Eigen::MatrixXd& WUV); + + IGL_INLINE bool IsFlipped(const Eigen::Vector2d &uv0, + const Eigen::Vector2d &uv1, + const Eigen::Vector2d &uv2); + + IGL_INLINE bool IsFlipped(int i, const Eigen::MatrixXd& WUV); + + }; +}; +}; +} + +IGL_INLINE igl::copyleft::comiso::SeamInfo::SeamInfo(int _v0, + int _v0p, + int _mismatch, + unsigned int _integerVar) +{ + v0=_v0; + v0p=_v0p; + integerVar=_integerVar; + mismatch=_mismatch; +} + +IGL_INLINE igl::copyleft::comiso::SeamInfo::SeamInfo(const SeamInfo &S1) +{ + v0=S1.v0; + v0p=S1.v0p; + integerVar=S1.integerVar; + mismatch=S1.mismatch; +} + + +template +IGL_INLINE igl::copyleft::comiso::VertexIndexing::VertexIndexing(const Eigen::PlainObjectBase &_V, + const Eigen::PlainObjectBase &_F, + const Eigen::PlainObjectBase &_Vcut, + const Eigen::PlainObjectBase &_Fcut, + const Eigen::PlainObjectBase &_TT, + const Eigen::PlainObjectBase &_TTi, + const Eigen::Matrix &_mismatch, + const Eigen::Matrix &_singular, + const Eigen::Matrix &_seams + ): +V(_V), +F(_F), +Vcut(_Vcut), +Fcut(_Fcut), +TT(_TT), +TTi(_TTi), +mismatch(_mismatch), +singular(_singular), +seams(_seams) +{ + #ifdef DEBUG_PRINT + cerr< +IGL_INLINE void igl::copyleft::comiso::VertexIndexing::getSeamInfo(const int f0, + const int f1, + const int indexE, + int &v0, int &v1, + int &v0p, int &v1p, + int &_mismatch) +{ + int edgef0 = indexE; + v0 = Fcut(f0,edgef0); + v1 = Fcut(f0,(edgef0+1)%3); + ////get the index on opposite side + assert(TT(f0,edgef0) == f1); + int edgef1 = TTi(f0,edgef0); + v1p = Fcut(f1,edgef1); + v0p = Fcut(f1,(edgef1+1)%3); + + _mismatch = mismatch(f0,edgef0); + assert(F(f0,edgef0) == F(f1,((edgef1+1)%3))); + assert(F(f0,((edgef0+1)%3)) == F(f1,edgef1)); +} + +template +IGL_INLINE std::vector::VertexInfo> > igl::copyleft::comiso::VertexIndexing::getVerticesPerSeam() +{ + // Return value + std::vector >verticesPerSeam; + + // for every vertex, keep track of their adjacent vertices on seams. + // regular vertices have two neighbors on a seam, start- and endvertices may have any other numbers of neighbors (e.g. 1 or 3) + std::vector > VVSeam(V.rows()); + Eigen::MatrixXi F_hit = Eigen::MatrixXi::Zero(F.rows(), 3); + for (unsigned int f=0; f startVertexIndices; + std::vector isStartVertex(V.rows()); + for (unsigned int i=0;isize(); + + // explore every seam to which this vertex is a start vertex + // note: a vertex can never be a start vertex and a regular vertex simultaneously + for (size_t j = 0; j < neighborSize; j++) + { + std::vector thisSeam; // temporary container + + // Create vertexInfo struct for start vertex + VertexInfo startVertex = VertexInfo(element, -1, -1, -1, -1);// -1 values are arbitrary (will never be used) + VertexInfo currentVertex = startVertex; + // Add start vertex to the seam + thisSeam.push_back(currentVertex); + + // advance on the seam + auto currentVertexNeighbors = startVertexNeighbors; + auto nextVertex = currentVertexNeighbors->front(); + currentVertexNeighbors->pop_front(); + + // bogus initialization due to lack of def. constructor + VertexInfo prevVertex = startVertex; + while (true) + { + // move to the next vertex + prevVertex = currentVertex; + currentVertex = nextVertex; + currentVertexNeighbors = &VVSeam[nextVertex.v]; + + // add current vertex to this seam + thisSeam.push_back(currentVertex); + + // remove the previous vertex + auto it = std::find(currentVertexNeighbors->begin(), currentVertexNeighbors->end(), prevVertex); + assert(it != currentVertexNeighbors->end()); + currentVertexNeighbors->erase(it); + + if (currentVertexNeighbors->size() == 1 && !isStartVertex[currentVertex.v]) + { + nextVertex = currentVertexNeighbors->front(); + currentVertexNeighbors->pop_front(); + } + else + break; + } + verticesPerSeam.push_back(thisSeam); + } + } + + return verticesPerSeam; +} + +template +IGL_INLINE void igl::copyleft::comiso::VertexIndexing::initSeamInfo() +{ + auto verticesPerSeam = getVerticesPerSeam(); + systemInfo.edgeSeamInfo.clear(); + unsigned int integerVar = 0; + // Loop over each seam + for(auto seam : verticesPerSeam){ + //choose initial side of the seam such that the start vertex corresponds to Fcut(f, k) and the end vertex corresponds to Fcut(f, (k+1)%3) and not vice versa. + int priorVertexIdx; + if(seam.size() > 2){ + auto v1 = seam[1]; + auto v2 = seam[2]; + if(Fcut(v1.f0, (v1.k0+1) % 3) == Fcut(v2.f0, v2.k0) || Fcut(v1.f0, (v1.k0+1) % 3) == Fcut(v2.f1, v2.k1)){ + priorVertexIdx = Fcut(v1.f0, v1.k0); + } + else{ + priorVertexIdx = Fcut(v1.f1, v1.k1); + assert(Fcut(v1.f1, (v1.k1+1) % 3) == Fcut(v2.f0, v2.k0) || Fcut(v1.f1, (v1.k1+1) % 3) == Fcut(v2.f1, v2.k1)); + } + } + else{ + auto v1 = seam[1]; + priorVertexIdx = Fcut(v1.f0, v1.k0); + } + + // Loop over each vertex of the seam + for(auto it=seam.begin()+1; it != seam.end(); ++it){ + auto vertex = *it; + // choose the correct side of the seam + int f,k,ff; + if(priorVertexIdx == Fcut(vertex.f0, vertex.k0)){ + f = vertex.f0; ff = vertex.f1; + k = vertex.k0; + } + else{ + f = vertex.f1; ff = vertex.f0; + k = vertex.k1; + assert(priorVertexIdx == Fcut(vertex.f1, vertex.k1)); + } + + int vtx0,vtx0p,vtx1,vtx1p; + int MM; + getSeamInfo(f, ff, k, vtx0, vtx1, vtx0p, vtx1p, MM); + systemInfo.edgeSeamInfo.push_back(SeamInfo(vtx0,vtx0p,MM,integerVar)); + if(it == seam.end() -1){ + systemInfo.edgeSeamInfo.push_back(SeamInfo(vtx1,vtx1p,MM,integerVar)); + } + priorVertexIdx = vtx1; + } + // use the same integer for each seam + integerVar++; + } + systemInfo.num_integer_cuts = integerVar; + +#ifndef NDEBUG + int totalNVerticesOnSeams = 0; + for(auto const & seam : verticesPerSeam){ + totalNVerticesOnSeams += seam.size(); + } + assert(systemInfo.edgeSeamInfo.size() == totalNVerticesOnSeams); +#endif +} + + + +template +IGL_INLINE void igl::copyleft::comiso::PoissonSolver::solvePoisson(Eigen::VectorXd stiffness, + double gradientSize, + double gridResolution, + bool directRound, + unsigned int localIter, + bool doRound, + bool singularityRound, + const std::vector &roundVertices, + const std::vector> &hardFeatures) +{ + Handle_Stiffness = stiffness; + + //initialization of flags and data structures + integer_rounding=doRound; + + ids_to_round.clear(); + + clearUserConstraint(); + // copy the user constraints number + for (const auto & element : hardFeatures) + { + addSharpEdgeConstraint(element[0], element[1]); + } + + ///Initializing Matrix + clock_t t0 = clock(); + + ///initialize the matrix ALLOCATING SPACE + initMatrix(); + if (DEBUGPRINT) + printf("\n ALLOCATED THE MATRIX \n"); + + ///build the Laplacian system + buildLaplacianMatrix(gradientSize); + + // add seam constraints + buildSeamConstraintsExplicitTranslation(); + + // add user defined constraints + buildUserDefinedConstraints(); + + ////add the Lagrange multiplier + fixBlockedVertex(); + + if (DEBUGPRINT) + printf("\n BUILT THE MATRIX \n"); + + if (integer_rounding) + addToRoundVertices(roundVertices); + + if (singularityRound) + addSingularityRound(); + + clock_t t1 = clock(); + if (DEBUGPRINT) printf("\n time:%ld \n",t1-t0); + if (DEBUGPRINT) printf("\n SOLVING \n"); + + mixedIntegerSolve(gridResolution, directRound, localIter); + + clock_t t2 = clock(); + if (DEBUGPRINT) printf("\n time:%ld \n",t2-t1); + if (DEBUGPRINT) printf("\n ASSIGNING COORDS \n"); + + mapCoords(); + + clock_t t3 = clock(); + if (DEBUGPRINT) printf("\n time:%ld \n",t3-t2); + if (DEBUGPRINT) printf("\n FINISHED \n"); +} + +template +IGL_INLINE igl::copyleft::comiso::PoissonSolver +::PoissonSolver(const Eigen::PlainObjectBase &_V, + const Eigen::PlainObjectBase &_F, + const Eigen::PlainObjectBase &_Vcut, + const Eigen::PlainObjectBase &_Fcut, + const Eigen::PlainObjectBase &_TT, + const Eigen::PlainObjectBase &_TTi, + const Eigen::PlainObjectBase &_PD1, + const Eigen::PlainObjectBase &_PD2, + const Eigen::Matrix&_singular, + const MeshSystemInfo &_systemInfo +): +V(_V), +F(_F), +Vcut(_Vcut), +Fcut(_Fcut), +TT(_TT), +TTi(_TTi), +PD1(_PD1), +PD2(_PD2), +singular(_singular), +systemInfo(_systemInfo) +{ + n_fixed_vars = 0; + n_vert_vars = 0; + num_total_vars = 0; + n_integer_vars = 0; + num_cut_constraint = 0; + num_userdefined_constraint = 0; + num_constraint_equations = 0; + integer_rounding = false; + UV = Eigen::MatrixXd(V.rows(),2); + WUV = Eigen::MatrixXd(F.rows(),6); + UV_out = Eigen::MatrixXd(Vcut.rows(),2); + igl::vertex_triangle_adjacency(V,F,VF,VFi); +} + +///START COMMON MATH FUNCTIONS +///return the complex encoding the rotation +///for a given mismatch interval +template +IGL_INLINE std::complex igl::copyleft::comiso::PoissonSolver::getRotationComplex( + int interval) +{ + assert((interval>=0)&&(interval<4)); + + switch(interval) + { + case 0:return {1,0}; + case 1:return {0,1}; + case 2: return {-1,0}; + default:return {0,-1}; + } +} + +///END COMMON MATH FUNCTIONS + +///START FIXING VERTICES +///set a given vertex as fixed +template +IGL_INLINE void igl::copyleft::comiso::PoissonSolver::addFixedVertex(int v) +{ + n_fixed_vars++; + Hard_constraints.push_back(v); +} + +///find vertex to fix in case we're using +///a vector field NB: multiple components not handled +template +IGL_INLINE void igl::copyleft::comiso::PoissonSolver::findFixedVertField() +{ + Hard_constraints.clear(); + + n_fixed_vars=0; + //fix the first singularity + for (unsigned int v=0;v +IGL_INLINE void igl::copyleft::comiso::PoissonSolver::findFixedVert() +{ + Hard_constraints.clear(); + findFixedVertField(); +} + +template +IGL_INLINE int igl::copyleft::comiso::PoissonSolver::getFirstVertexIndex(int v) +{ + return Fcut(VF[v][0],VFi[v][0]); +} + +///fix the vertices which are flagged as fixed +template +IGL_INLINE void igl::copyleft::comiso::PoissonSolver::fixBlockedVertex() +{ + int offset_row = num_cut_constraint*2; + + unsigned int constr_num = 0; + for (unsigned int i=0;ivertex_index[0]; + int index = getFirstVertexIndex(v); + + ///multiply times 2 because of uv + int indexvert = index*2; + + ///find the first free row to add the constraint + int indexRow = offset_row + constr_num * 2; + int indexCol = indexRow; + + ///add fixing constraint LHS + Constraints.coeffRef(indexRow, indexvert) += 1; + Constraints.coeffRef(indexRow+1,indexvert+1) += 1; + + ///add fixing constraint RHS + constraints_rhs[indexCol] = UV(v,0); + constraints_rhs[indexCol+1] = UV(v,1); + + constr_num++; + } + assert(constr_num==n_fixed_vars); +} +///END FIXING VERTICES + +///HANDLING SINGULARITY +//set the singularity round to integer location +template +IGL_INLINE void igl::copyleft::comiso::PoissonSolver::addSingularityRound() +{ + for (unsigned int v=0;v +IGL_INLINE void igl::copyleft::comiso::PoissonSolver::addToRoundVertices(std::vector ids) +{ + for(auto index : ids) + { + if (index < 0 || index >= V.rows()) + std::cerr << "WARNING: Ignored round vertex constraint, vertex " << index << " does not exist in the mesh." << std::endl; + int index0 = getFirstVertexIndex(index); + ids_to_round.push_back( index0 * 2 ); + ids_to_round.push_back((index0 * 2)+1); + } +} + +///START GENERIC SYSTEM FUNCTIONS +template +IGL_INLINE void igl::copyleft::comiso::PoissonSolver::buildLaplacianMatrix(double vfscale) +{ + Eigen::VectorXi idx = igl::LinSpaced(Vcut.rows(), 0, 2*Vcut.rows()-2); + Eigen::VectorXi idx2 = igl::LinSpaced(Vcut.rows(), 1, 2*Vcut.rows()-1); + + // get gradient matrix + Eigen::SparseMatrix G(Fcut.rows() * 3, Vcut.rows()); + igl::grad(Vcut, Fcut, G); + + // get triangle weights + Eigen::VectorXd dblA(Fcut.rows()); + igl::doublearea(Vcut, Fcut, dblA); + + // compute intermediate result + Eigen::SparseMatrix G2; + G2 = G.transpose() * dblA.replicate<3,1>().asDiagonal() * Handle_Stiffness.replicate<3,1>().asDiagonal(); + + /// Compute LHS + Eigen::SparseMatrix Cotmatrix; + Cotmatrix = 0.5 * G2 * G; + igl::slice_into(Cotmatrix, idx, idx, Lhs); + igl::slice_into(Cotmatrix, idx2, idx2, Lhs); + + /// Compute RHS + // reshape nrosy vectors + const Eigen::MatrixXd u = Eigen::Map(PD1.data(),Fcut.rows()*3,1); // this mimics a reshape at the cost of a copy. + const Eigen::MatrixXd v = Eigen::Map(PD2.data(),Fcut.rows()*3,1); // this mimics a reshape at the cost of a copy. + + // multiply with weights + Eigen::VectorXd rhs1 = G2 * u * 0.5 * vfscale; + Eigen::VectorXd rhs2 = -G2 * v * 0.5 * vfscale; + igl::slice_into(rhs1, idx, 1, rhs); + igl::slice_into(rhs2, idx2, 1, rhs); +} + +///find different sized of the system +template +IGL_INLINE void igl::copyleft::comiso::PoissonSolver::findSizes() +{ + ///find the vertex that need to be fixed + findFixedVert(); + + ///REAL PART + n_vert_vars = systemInfo.num_vert_variables; + + ///INTEGER PART + ///the total number of integer variables + n_integer_vars = systemInfo.num_integer_cuts; + + ///CONSTRAINT PART + num_cut_constraint = systemInfo.edgeSeamInfo.size(); + + num_constraint_equations = num_cut_constraint * 2 + n_fixed_vars * 2 + num_userdefined_constraint; + + ///total variable of the system + num_total_vars = (n_vert_vars+n_integer_vars) * 2; + + ///initialize matrix size + + if (DEBUGPRINT) printf("\n*** SYSTEM VARIABLES *** \n"); + if (DEBUGPRINT) printf("* NUM REAL VERTEX VARIABLES %ud \n",n_vert_vars); + + if (DEBUGPRINT) printf("\n*** INTEGER VARIABLES *** \n"); + if (DEBUGPRINT) printf("* NUM INTEGER VARIABLES %ud \n",n_integer_vars); + + if (DEBUGPRINT) printf("\n*** CONSTRAINTS *** \n "); + if (DEBUGPRINT) printf("* NUM FIXED CONSTRAINTS %ud\n",n_fixed_vars); + if (DEBUGPRINT) printf("* NUM CUTS CONSTRAINTS %ud\n",num_cut_constraint); + if (DEBUGPRINT) printf("* NUM USER DEFINED CONSTRAINTS %ud\n",num_userdefined_constraint); + + if (DEBUGPRINT) printf("\n*** TOTAL SIZE *** \n"); + if (DEBUGPRINT) printf("* TOTAL VARIABLE SIZE (WITH INTEGER TRASL) %ud \n",num_total_vars); + if (DEBUGPRINT) printf("* TOTAL CONSTRAINTS %ud \n",num_constraint_equations); +} + +template +IGL_INLINE void igl::copyleft::comiso::PoissonSolver::allocateSystem() +{ + Lhs.resize(n_vert_vars * 2, n_vert_vars * 2); + Constraints.resize(num_constraint_equations, num_total_vars); + rhs.resize(n_vert_vars * 2); + constraints_rhs.resize(num_constraint_equations); + + printf("\n INITIALIZED SPARSE MATRIX OF %ud x %ud \n",n_vert_vars*2, n_vert_vars*2); + printf("\n INITIALIZED SPARSE MATRIX OF %ud x %ud \n",num_constraint_equations, num_total_vars); + printf("\n INITIALIZED VECTOR OF %ud x 1 \n",n_vert_vars*2); + printf("\n INITIALIZED VECTOR OF %ud x 1 \n",num_constraint_equations); +} + +///intitialize the whole matrix +template +IGL_INLINE void igl::copyleft::comiso::PoissonSolver::initMatrix() +{ + findSizes(); + allocateSystem(); +} + +///map back coordinates after that +///the system has been solved +template +IGL_INLINE void igl::copyleft::comiso::PoissonSolver::mapCoords() +{ + ///map coords to faces + for (unsigned int f=0;f +IGL_INLINE void igl::copyleft::comiso::PoissonSolver::buildSeamConstraintsExplicitTranslation() +{ + ///current constraint row + int constr_row = 0; + + for (unsigned int i=0; i rot = getRotationComplex(interval); + + ///get the integer variable + unsigned int integerVar = n_vert_vars + systemInfo.edgeSeamInfo[i].integerVar; + + if (integer_rounding) + { + ids_to_round.push_back(integerVar*2); + ids_to_round.push_back(integerVar*2+1); + } + + // cross boundary compatibility conditions + Constraints.coeffRef(constr_row, 2*p0) += rot.real(); + Constraints.coeffRef(constr_row, 2*p0+1) += -rot.imag(); + Constraints.coeffRef(constr_row+1, 2*p0) += rot.imag(); + Constraints.coeffRef(constr_row+1, 2*p0+1) += rot.real(); + + Constraints.coeffRef(constr_row, 2*p0p) += -1; + Constraints.coeffRef(constr_row+1, 2*p0p+1) += -1; + + Constraints.coeffRef(constr_row, 2*integerVar) += 1; + Constraints.coeffRef(constr_row+1, 2*integerVar+1) += 1; + + constraints_rhs[constr_row] = 0; + constraints_rhs[constr_row+1] = 0; + + constr_row += 2; + } + +} + +///set the constraints for the inter-range cuts +template +IGL_INLINE void igl::copyleft::comiso::PoissonSolver::buildUserDefinedConstraints() +{ + /// the user defined constraints are at the end + unsigned int constr_row = num_cut_constraint*2 + n_fixed_vars*2; + + assert(num_userdefined_constraint == userdefined_constraints.size()); + + for (unsigned int i = 0; i < num_userdefined_constraint; i++) + { + for (unsigned int j = 0; j < userdefined_constraints[i].size()-1; ++j) + { + Constraints.coeffRef(constr_row, j) = userdefined_constraints[i][j]; + } + + constraints_rhs[constr_row] = userdefined_constraints[i][userdefined_constraints[i].size()-1]; + constr_row +=1; + } +} + +///call of the mixed integer solver +template +IGL_INLINE void igl::copyleft::comiso::PoissonSolver::mixedIntegerSolve(double coneGridRes, + bool directRound, + unsigned int localIter) +{ + X = std::vector((n_vert_vars+n_integer_vars)*2); + if (DEBUGPRINT) + printf("\n ALLOCATED X \n"); + + ///variables part + const int sizeMatrix = (n_vert_vars + n_integer_vars) * 2; + const int scalarSize = n_vert_vars * 2; + + ///matrix A + gmm::col_matrix< gmm::wsvector< double > > A(sizeMatrix,sizeMatrix); // lhs matrix variables + + ///constraints part + int CsizeX = num_constraint_equations; + int CsizeY = sizeMatrix+1; + gmm::row_matrix< gmm::wsvector< double > > C(CsizeX,CsizeY); // constraints + + if (DEBUGPRINT) + printf("\n ALLOCATED QMM STRUCTURES \n"); + + std::vector B(sizeMatrix,0); // rhs + + if (DEBUGPRINT) + printf("\n ALLOCATED RHS STRUCTURES \n"); + + //// copy LHS + for (int k=0; k < Lhs.outerSize(); ++k){ + for (Eigen::SparseMatrix::InnerIterator it(Lhs,k); it; ++it){ + int row = it.row(); + int col = it.col(); + A(row, col) += it.value(); + } + } + //// copy Constraints + for (int k=0; k < Constraints.outerSize(); ++k){ + for (Eigen::SparseMatrix::InnerIterator it(Constraints,k); it; ++it){ + int row = it.row(); + int col = it.col(); + C(row, col) += it.value(); + } + } + + if (DEBUGPRINT) + printf("\n SET %d INTEGER VALUES \n",n_integer_vars); + + int offline_index = scalarSize; + for(unsigned int i = 0; i < n_integer_vars*2; ++i) + { + int index=offline_index+i; + A(index, index) = PENALIZATION; + } + + if (DEBUGPRINT) + printf("\n SET RHS \n"); + + // copy RHS + for(unsigned int i = 0; i < scalarSize; ++i) + { + B[i] = rhs[i] * coneGridRes; + } + + // copy constraint RHS + if (DEBUGPRINT) + printf("\n SET %d CONSTRAINTS \n",num_constraint_equations); + + for(unsigned int i = 0; i < num_constraint_equations; ++i) + { + C(i, sizeMatrix) = -constraints_rhs[i] * coneGridRes; + } + + COMISO::ConstrainedSolver solver; + + solver.misolver().set_local_iters(localIter); + + solver.misolver().set_direct_rounding(directRound); + + std::sort(ids_to_round.begin(),ids_to_round.end()); + auto new_end=std::unique(ids_to_round.begin(),ids_to_round.end()); + long int dist = distance(ids_to_round.begin(),new_end); + ids_to_round.resize(dist); + + solver.solve( C, A, X, B, ids_to_round, 0.0, false, false); +} + +template +IGL_INLINE void igl::copyleft::comiso::PoissonSolver::clearUserConstraint() +{ + num_userdefined_constraint = 0; + userdefined_constraints.clear(); +} + +template +IGL_INLINE void igl::copyleft::comiso::PoissonSolver::addSharpEdgeConstraint(int fid, int vid) +{ + // prepare constraint + std::vector c(systemInfo.num_vert_variables*2 + 1, 0); + + int v1 = Fcut(fid,vid); + int v2 = Fcut(fid,(vid+1)%3); + + Eigen::Matrix e = Vcut.row(v2) - Vcut.row(v1); + e = e.normalized(); + + double d1 = fabs(e.dot(PD1.row(fid).normalized())); + double d2 = fabs(e.dot(PD2.row(fid).normalized())); + + int offset = 0; + + if (d1>d2) + offset = 1; + + ids_to_round.push_back((v1 * 2) + offset); + ids_to_round.push_back((v2 * 2) + offset); + + // add constraint + c[(v1 * 2) + offset] = 1; + c[(v2 * 2) + offset] = -1; + + // add to the user-defined constraints + num_userdefined_constraint++; + userdefined_constraints.push_back(c); + +} + + + +template +IGL_INLINE igl::copyleft::comiso::MIQ_class::MIQ_class( + const Eigen::PlainObjectBase &V_, + const Eigen::PlainObjectBase &F_, + const Eigen::PlainObjectBase &PD1_combed, + const Eigen::PlainObjectBase &PD2_combed, + const Eigen::Matrix &mismatch, + const Eigen::Matrix &singular, + const Eigen::Matrix &seams, + Eigen::PlainObjectBase &UV, + Eigen::PlainObjectBase &FUV, + double gradientSize, + double stiffness, + bool directRound, + unsigned int iter, + unsigned int localIter, + bool doRound, + bool singularityRound, + std::vector roundVertices, + std::vector > hardFeatures): +V(V_), +F(F_) +{ + igl::cut_mesh(V, F, seams, Vcut, Fcut); + + igl::local_basis(V,F,B1,B2,B3); + igl::triangle_triangle_adjacency(F,TT,TTi); + + // Prepare indexing for the linear system + VertexIndexing VInd(V, F, Vcut, Fcut, TT, TTi, mismatch, singular, seams); + + VInd.initSeamInfo(); + + // Assemble the system and solve + PoissonSolver PSolver(V, + F, + Vcut, + Fcut, + TT, + TTi, + PD1_combed, + PD2_combed, + singular, + VInd.systemInfo); + stiffnessVector = Eigen::VectorXd::Constant(F.rows(),1); + + + if (iter > 0) // do stiffening + { + for (unsigned int i=0;i +IGL_INLINE void igl::copyleft::comiso::MIQ_class::extractUV(Eigen::PlainObjectBase &UV_out, + Eigen::PlainObjectBase &FUV_out) +{ + UV_out = this->UV_out; + FUV_out = this->FUV_out; +} + +template +IGL_INLINE int igl::copyleft::comiso::MIQ_class::NumFlips(const Eigen::MatrixXd& WUV) +{ + int numFl=0; + for (unsigned int i=0;i +IGL_INLINE double igl::copyleft::comiso::MIQ_class::Distortion(int f, double h, const Eigen::MatrixXd& WUV) +{ + assert(h > 0); + + Eigen::Vector2d uv0,uv1,uv2; + + uv0 << WUV(f,0), WUV(f,1); + uv1 << WUV(f,2), WUV(f,3); + uv2 << WUV(f,4), WUV(f,5); + + Eigen::Matrix p0 = Vcut.row(Fcut(f,0)); + Eigen::Matrix p1 = Vcut.row(Fcut(f,1)); + Eigen::Matrix p2 = Vcut.row(Fcut(f,2)); + + Eigen::Matrix norm = (p1 - p0).cross(p2 - p0); + double area2 = norm.norm(); + double area2_inv = 1.0 / area2; + norm *= area2_inv; + + if (area2 > 0) + { + // Singular values of the Jacobian + Eigen::Matrix neg_t0 = norm.cross(p2 - p1); + Eigen::Matrix neg_t1 = norm.cross(p0 - p2); + Eigen::Matrix neg_t2 = norm.cross(p1 - p0); + + Eigen::Matrix diffu = (neg_t0 * uv0(0) +neg_t1 *uv1(0) + neg_t2 * uv2(0) )*area2_inv; + Eigen::Matrix diffv = (neg_t0 * uv0(1) + neg_t1*uv1(1) + neg_t2*uv2(1) )*area2_inv; + + // first fundamental form + double I00 = diffu.dot(diffu); // guaranteed non-neg + double I01 = diffu.dot(diffv); // I01 = I10 + double I11 = diffv.dot(diffv); // guaranteed non-neg + + // eigenvalues of a 2x2 matrix + // [a00 a01] + // [a10 a11] + // 1/2 * [ (a00 + a11) +/- sqrt((a00 - a11)^2 + 4 a01 a10) ] + double trI = I00 + I11; // guaranteed non-neg + double diffDiag = I00 - I11; // guaranteed non-neg + double sqrtDet = sqrt(std::max(0.0, diffDiag*diffDiag + + 4 * I01 * I01)); // guaranteed non-neg + double sig1 = 0.5 * (trI + sqrtDet); // higher singular value + double sig2 = 0.5 * (trI - sqrtDet); // lower singular value + + // Avoid sig2 < 0 due to numerical error + if (fabs(sig2) < 1.0e-8) + sig2 = 0; + + assert(sig1 >= 0); + assert(sig2 >= 0); + + if (sig2 < 0) { + printf("Distortion will be NaN! sig1^2 is negative (%lg)\n", + sig2); + } + + // The singular values of the Jacobian are the sqrts of the + // eigenvalues of the first fundamental form. + sig1 = sqrt(sig1); + sig2 = sqrt(sig2); + + // distortion + double tao = IsFlipped(f,WUV) ? -1 : 1; + double factor = tao / h; + double lam = fabs(factor * sig1 - 1) + fabs(factor * sig2 - 1); + return lam; + } + else { + return 10; // something "large" + } +} + +//////////////////////////////////////////////////////////////////////////// +// Approximate the distortion Laplacian using a uniform Laplacian on +// the dual mesh: +// ___________ +// \-1 / \-1 / +// \ / 3 \ / +// \-----/ +// \-1 / +// \ / +// +// @param[in] f facet on which to compute distortion Laplacian +// @param[in] h scaling factor applied to cross field +// @return distortion Laplacian for f +/////////////////////////////////////////////////////////////////////////// +template +IGL_INLINE double igl::copyleft::comiso::MIQ_class::LaplaceDistortion(const int f, double h, const Eigen::MatrixXd& WUV) +{ + double mydist = Distortion(f, h, WUV); + double lapl=0; + for (int i=0;i<3;i++) + { + if (TT(f,i) != -1) + lapl += (mydist - Distortion(TT(f,i), h, WUV)); + } + return lapl; +} + +template +IGL_INLINE bool igl::copyleft::comiso::MIQ_class::updateStiffeningJacobianDistorsion(double grad_size, const Eigen::MatrixXd& WUV) +{ + bool flipped = NumFlips(WUV)>0; + + if (!flipped) + return false; + + double maxL=0; + double maxD=0; + + if (flipped) + { + const double c = 1.0; + const double d = 5.0; + + for (unsigned int i = 0; i < Fcut.rows(); ++i) + { + double dist=Distortion(i,grad_size,WUV); + if (dist > maxD) + maxD=dist; + + double absLap=fabs(LaplaceDistortion(i, grad_size,WUV)); + if (absLap > maxL) + maxL = absLap; + + double stiffDelta = std::min(c * absLap, d); + + stiffnessVector[i]+=stiffDelta; + } + } + printf("Maximum Distorsion %4.4f \n",maxD); + printf("Maximum Laplacian %4.4f \n",maxL); + return flipped; +} + +template +IGL_INLINE bool igl::copyleft::comiso::MIQ_class::IsFlipped(const Eigen::Vector2d &uv0, + const Eigen::Vector2d &uv1, + const Eigen::Vector2d &uv2) +{ + Eigen::Vector2d e0 = (uv1-uv0); + Eigen::Vector2d e1 = (uv2-uv0); + + double Area = e0(0)*e1(1) - e0(1)*e1(0); + return (Area<=0); +} + +template +IGL_INLINE bool igl::copyleft::comiso::MIQ_class::IsFlipped( + const int i, const Eigen::MatrixXd& WUV) +{ + Eigen::Vector2d uv0,uv1,uv2; + uv0 << WUV(i,0), WUV(i,1); + uv1 << WUV(i,2), WUV(i,3); + uv2 << WUV(i,4), WUV(i,5); + + return (IsFlipped(uv0,uv1,uv2)); +} + + + + +template +IGL_INLINE void igl::copyleft::comiso::miq( + const Eigen::PlainObjectBase &V, + const Eigen::PlainObjectBase &F, + const Eigen::PlainObjectBase &PD1_combed, + const Eigen::PlainObjectBase &PD2_combed, + const Eigen::Matrix &mismatch, + const Eigen::Matrix &singular, + const Eigen::Matrix &seams, + Eigen::PlainObjectBase &UV, + Eigen::PlainObjectBase &FUV, + double gradientSize, + double stiffness, + bool directRound, + unsigned int iter, + unsigned int localIter, + bool doRound, + bool singularityRound, + const std::vector &roundVertices, + const std::vector> &hardFeatures) +{ + gradientSize = gradientSize/(V.colwise().maxCoeff()-V.colwise().minCoeff()).norm(); + + igl::copyleft::comiso::MIQ_class miq(V, + F, + PD1_combed, + PD2_combed, + mismatch, + singular, + seams, + UV, + FUV, + gradientSize, + stiffness, + directRound, + iter, + localIter, + doRound, + singularityRound, + roundVertices, + hardFeatures); + + miq.extractUV(UV,FUV); +} + +template +IGL_INLINE void igl::copyleft::comiso::miq( + const Eigen::PlainObjectBase &V, + const Eigen::PlainObjectBase &F, + const Eigen::PlainObjectBase &PD1, + const Eigen::PlainObjectBase &PD2, + Eigen::PlainObjectBase &UV, + Eigen::PlainObjectBase &FUV, + double gradientSize, + double stiffness, + bool directRound, + unsigned int iter, + unsigned int localIter, + bool doRound, + bool singularityRound, + const std::vector &roundVertices, + const std::vector> &hardFeatures) +{ + + DerivedV BIS1, BIS2; + igl::compute_frame_field_bisectors(V, F, PD1, PD2, BIS1, BIS2); + + DerivedV BIS1_combed, BIS2_combed; + igl::comb_cross_field(V, F, BIS1, BIS2, BIS1_combed, BIS2_combed); + + DerivedF Handle_MMatch; + igl::cross_field_mismatch(V, F, BIS1_combed, BIS2_combed, true, Handle_MMatch); + + Eigen::Matrix isSingularity, singularityIndex; + igl::find_cross_field_singularities(V, F, Handle_MMatch, isSingularity, singularityIndex); + + Eigen::Matrix Handle_Seams; + igl::cut_mesh_from_singularities(V, F, Handle_MMatch, Handle_Seams); + + DerivedV PD1_combed, PD2_combed; + igl::comb_frame_field(V, F, PD1, PD2, BIS1_combed, BIS2_combed, PD1_combed, PD2_combed); + + igl::copyleft::comiso::miq(V, + F, + PD1_combed, + PD2_combed, + Handle_MMatch, + isSingularity, + Handle_Seams, + UV, + FUV, + gradientSize, + stiffness, + directRound, + iter, + localIter, + doRound, + singularityRound, + roundVertices, + hardFeatures); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +template void igl::copyleft::comiso::miq, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase > const &, Eigen::PlainObjectBase > const &, Eigen::PlainObjectBase > const &, Eigen::PlainObjectBase > const &, Eigen::PlainObjectBase > &, Eigen::PlainObjectBase > &, double, double, bool, unsigned int, unsigned int, bool, bool, const std::vector &, const std::vector> &); +template void igl::copyleft::comiso::miq, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase > const &, Eigen::PlainObjectBase > const &, Eigen::PlainObjectBase > const &, Eigen::PlainObjectBase > const &, Eigen::Matrix const &, Eigen::Matrix const &, Eigen::Matrix const &, Eigen::PlainObjectBase > &, Eigen::PlainObjectBase > &, double, double, bool, unsigned int, unsigned int, bool, bool, const std::vector &, const std::vector> &); +template void igl::copyleft::comiso::miq, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase > const &, Eigen::PlainObjectBase > const &, Eigen::PlainObjectBase > const &, Eigen::PlainObjectBase > const &, Eigen::PlainObjectBase > &, Eigen::PlainObjectBase > &, double, double, bool, unsigned int, unsigned int, bool, bool, const std::vector &, const std::vector> &); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/comiso/miq.h b/src/external/libigl-2.3.0/include/igl/copyleft/comiso/miq.h new file mode 100644 index 000000000..80b4db9c1 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/comiso/miq.h @@ -0,0 +1,124 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Daniele Panozzo , Olga Diamanti , Kevin Walliman +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_COMISO_MIQ_H +#define IGL_COMISO_MIQ_H +#include "../../igl_inline.h" +#include +#include + +namespace igl +{ + namespace copyleft + { + namespace comiso + { + // Global seamless parametrization aligned with a given per-face Jacobian (PD1, PD2). + // The algorithm is based on + // "Mixed-Integer Quadrangulation" by D. Bommes, H. Zimmer, L. Kobbelt + // ACM SIGGRAPH 2009, Article No. 77 (http://dl.acm.org/citation.cfm?id=1531383) + // We thank Nico Pietroni for providing a reference implementation of MIQ + // on which our code is based. + + // Limitations: + // - Due to the way of handling of hardFeatures the algorithm may fail in difficult cases. + // - Meshes with boundaries are not hendled properly i.e., jagged edges along the boundary are possible + + // Input: + // V #V by 3 list of mesh vertex 3D positions + // F #F by 3 list of faces indices in V + // PD1 #V by 3 first line of the Jacobian per triangle + // PD2 #V by 3 second line of the Jacobian per triangle + // (optional, if empty it will be a vector in the tangent plane orthogonal to PD1) + // gradientSize global scaling for the gradient (controls the quads resolution) + // stiffness weight for the stiffness iterations (Reserved but not used!) + // directRound greedily round all integer variables at once (greatly improves optimization speed but lowers quality) + // iter stiffness iterations (0 = no stiffness) + // localIter number of local iterations for the integer rounding + // doRound enables the integer rounding (disabling it could be useful for debugging) + // singularityRound set true/false to decide if the singularities' coordinates should be rounded to the nearest integers + // roundVertices id of additional vertices that should be snapped to integer coordinates + // hardFeatures #H by 2 list of pairs of vertices that belongs to edges that should be snapped to integer coordinates + // + // Output: + // UV #UV by 2 list of vertices in 2D + // FUV #FUV by 3 list of face indices in UV + // + template + IGL_INLINE void miq( + const Eigen::PlainObjectBase &V, + const Eigen::PlainObjectBase &F, + const Eigen::PlainObjectBase &PD1, + const Eigen::PlainObjectBase &PD2, + Eigen::PlainObjectBase &UV, + Eigen::PlainObjectBase &FUV, + double gradientSize = 30.0, + double stiffness = 5.0, + bool directRound = false, + unsigned int iter = 5, + unsigned int localIter = 5, + bool doRound = true, + bool singularityRound = true, + const std::vector &roundVertices = std::vector(), + const std::vector> &hardFeatures = std::vector >()); + + // Helper function that allows to directly provided pre-combed bisectors for an already cut mesh + + // Input: + // V #V by 3 list of mesh vertex 3D positions + // F #F by 3 list of faces indices in V + + // Additional Input: + // PD1_combed #F by 3 first combed Jacobian + // PD2_combed #F by 3 second combed Jacobian + // mismatch #F by 3 list of per-corner integer PI/2 rotations + // singular #V list of flag that denotes if a vertex is singular or not + // seams #F by 3 list of per-corner flag that denotes seams + + // Input: + // gradientSize global scaling for the gradient (controls the quads resolution) + // stiffness weight for the stiffness iterations (Reserved but not used!) + // directRound greedily round all integer variables at once (greatly improves optimization speed but lowers quality) + // iter stiffness iterations (0 = no stiffness) + // localIter number of local iterations for the integer rounding + // doRound enables the integer rounding (disabling it could be useful for debugging) + // singularityRound set true/false to decide if the singularities' coordinates should be rounded to the nearest integers + // roundVertices id of additional vertices that should be snapped to integer coordinates + // hardFeatures #H by 2 list of pairs of vertices that belongs to edges that should be snapped to integer coordinates + + // Output: + // UV #UV by 2 list of vertices in 2D + // FUV #FUV by 3 list of face indices in UV + // + template + IGL_INLINE void miq( + const Eigen::PlainObjectBase &V, + const Eigen::PlainObjectBase &F, + const Eigen::PlainObjectBase &PD1_combed, + const Eigen::PlainObjectBase &PD2_combed, + const Eigen::Matrix &mismatch, + const Eigen::Matrix &singular, + const Eigen::Matrix &seams, + Eigen::PlainObjectBase &UV, + Eigen::PlainObjectBase &FUV, + double gradientSize = 30.0, + double stiffness = 5.0, + bool directRound = false, + unsigned int iter = 5, + unsigned int localIter = 5, + bool doRound = true, + bool singularityRound = true, + const std::vector &roundVertices = std::vector(), + const std::vector> &hardFeatures = std::vector >()); + }; +}; +}; +#ifndef IGL_STATIC_LIBRARY +#include "miq.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/comiso/nrosy.cpp b/src/external/libigl-2.3.0/include/igl/copyleft/comiso/nrosy.cpp new file mode 100644 index 000000000..1b2c4d74e --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/comiso/nrosy.cpp @@ -0,0 +1,783 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Daniele Panozzo +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +#include "nrosy.h" + +#include +#include +#include +#include + +#include +#include "../../PI.h" + +#include +#include +#include +#include + +#include +#include +#include +#include + +namespace igl +{ +namespace copyleft +{ + +namespace comiso +{ +class NRosyField +{ +public: + // Init + IGL_INLINE NRosyField(const Eigen::MatrixXd& _V, const Eigen::MatrixXi& _F); + + // Generate the N-rosy field + // N degree of the rosy field + // round separately: round the integer variables one at a time, slower but higher quality + IGL_INLINE void solve(int N = 4); + + // Set a hard constraint on fid + // fid: face id + // v: direction to fix (in 3d) + IGL_INLINE void setConstraintHard(int fid, const Eigen::Vector3d& v); + + // Set a soft constraint on fid + // fid: face id + // w: weight of the soft constraint, clipped between 0 and 1 + // v: direction to fix (in 3d) + IGL_INLINE void setConstraintSoft(int fid, double w, const Eigen::Vector3d& v); + + // Set the ratio between smoothness and soft constraints (0 -> smoothness only, 1 -> soft constr only) + IGL_INLINE void setSoftAlpha(double alpha); + + // Reset constraints (at least one constraint must be present or solve will fail) + IGL_INLINE void resetConstraints(); + + // Return the current field + IGL_INLINE Eigen::MatrixXd getFieldPerFace(); + + // Compute singularity indexes + IGL_INLINE void findCones(int N); + + // Return the singularities + IGL_INLINE Eigen::VectorXd getSingularityIndexPerVertex(); + +private: + // Compute angle differences between reference frames + IGL_INLINE void computek(); + + // Remove useless matchings + IGL_INLINE void reduceSpace(); + + // Prepare the system matrix + IGL_INLINE void prepareSystemMatrix(int N); + + // Solve with roundings using CoMIso + IGL_INLINE void solveRoundings(); + + // Convert a vector in 3d to an angle wrt the local reference system + IGL_INLINE double convert3DtoLocal(unsigned fid, const Eigen::Vector3d& v); + + // Convert an angle wrt the local reference system to a 3d vector + IGL_INLINE Eigen::Vector3d convertLocalto3D(unsigned fid, double a); + + // Compute the per vertex angle defect + IGL_INLINE Eigen::VectorXd angleDefect(); + + // Temporary variable for the field + Eigen::VectorXd angles; + + // Hard constraints + Eigen::VectorXd hard; + std::vector isHard; + + // Soft constraints + Eigen::VectorXd soft; + Eigen::VectorXd wSoft; + double softAlpha; + + // Face Topology + Eigen::MatrixXi TT, TTi; + + // Edge Topology + Eigen::MatrixXi EV, FE, EF; + std::vector isBorderEdge; + + // Per Edge information + // Angle between two reference frames + Eigen::VectorXd k; + + // Jumps + Eigen::VectorXi p; + std::vector pFixed; + + // Mesh + Eigen::MatrixXd V; + Eigen::MatrixXi F; + + // Normals per face + Eigen::MatrixXd N; + + // Singularity index + Eigen::VectorXd singularityIndex; + + // Reference frame per triangle + std::vector TPs; + + // System stuff + Eigen::SparseMatrix A; + Eigen::VectorXd b; + Eigen::VectorXi tag_t; + Eigen::VectorXi tag_p; + +}; + +} // NAMESPACE COMISO +} // NAMESPACE COPYLEFT +} // NAMESPACE IGL + +igl::copyleft::comiso::NRosyField::NRosyField(const Eigen::MatrixXd& _V, const Eigen::MatrixXi& _F) +{ + V = _V; + F = _F; + + assert(V.rows() > 0); + assert(F.rows() > 0); + + // Generate topological relations + igl::triangle_triangle_adjacency(F,TT,TTi); + igl::edge_topology(V,F, EV, FE, EF); + + // Flag border edges + isBorderEdge.resize(EV.rows()); + for(unsigned i=0; i= 0 && alpha < 1); + softAlpha = alpha; +} + + +void igl::copyleft::comiso::NRosyField::prepareSystemMatrix(const int N) +{ + double Nd = N; + + // Minimize the MIQ energy + // Energy on edge ij is + // (t_i - t_j + kij + pij*(2*pi/N))^2 + // Partial derivatives: + // t_i: 2 ( t_i - t_j + kij + pij*(2*pi/N)) = 0 + // t_j: 2 (-t_i + t_j - kij - pij*(2*pi/N)) = 0 + // pij: 4pi/N ( t_i - t_j + kij + pij*(2*pi/N)) = 0 + // + // t_i t_j pij kij + // t_i [ 2 -2 4pi/N 2 ] + // t_j [ -2 2 -4pi/N -2 ] + // pij [ 4pi/N -4pi/N 2*(2pi/N)^2 4pi/N ] + + // Count and tag the variables + tag_t = Eigen::VectorXi::Constant(F.rows(),-1); + std::vector id_t; + size_t count = 0; + for(unsigned i=0; i id_p; + for(unsigned i=0; i > T; + T.reserve(3 * 4 * count_p); + + for(auto eid : id_p) + { + int i = EF(eid, 0); + int j = EF(eid, 1); + bool isFixed_i = isHard[i]; + bool isFixed_j = isHard[j]; + bool isFixed_p = pFixed[eid]; + int row; + // (i)-th row: t_i [ 2 -2 4pi/N 2 ] + if (!isFixed_i) + { + row = tag_t[i]; + T.emplace_back(row, tag_t[i], 2); + if (isFixed_j) + b(row) += 2 * hard[j]; + else + T.emplace_back(row, tag_t[j], -2); + if (isFixed_p) + b(row) += -((4. * igl::PI) / Nd) * p[eid]; + else + T.emplace_back(row, tag_p[eid], ((4. * igl::PI) / Nd)); + b(row) += -2 * k[eid]; + assert(hard[i] == hard[i]); + assert(hard[j] == hard[j]); + assert(p[eid] == p[eid]); + assert(k[eid] == k[eid]); + assert(b(row) == b(row)); + } + // (j)+1 -th row: t_j [ -2 2 -4pi/N -2 ] + if (!isFixed_j) + { + row = tag_t[j]; + T.emplace_back(row, tag_t[j], 2); + if (isFixed_i) + b(row) += 2 * hard[i]; + else + T.emplace_back(row, tag_t[i], -2); + if (isFixed_p) + b(row) += ((4. * igl::PI) / Nd) * p[eid]; + else + T.emplace_back(row, tag_p[eid], -((4. * igl::PI) / Nd)); + b(row) += 2 * k[eid]; + assert(k[eid] == k[eid]); + assert(b(row) == b(row)); + } + // (r*3)+2 -th row: pij [ 4pi/N -4pi/N 2*(2pi/N)^2 4pi/N ] + if (!isFixed_p) + { + row = tag_p[eid]; + T.emplace_back(row, tag_p[eid], (2. * pow(((2. * igl::PI) / Nd), 2))); + if (isFixed_i) + b(row) += -(4. * igl::PI) / Nd * hard[i]; + else + T.emplace_back(row, tag_t[i], (4. * igl::PI) / Nd); + if (isFixed_j) + b(row) += (4. * igl::PI) / Nd * hard[j]; + else + T.emplace_back(row,tag_t[j], -(4. * igl::PI) / Nd); + b(row) += - (4 * igl::PI)/Nd * k[eid]; + assert(k[eid] == k[eid]); + assert(b(row) == b(row)); + } + } + + A.resize(count_t + count_p, count_t + count_p); + A.setFromTriplets(T.begin(), T.end()); + + // Soft constraints + bool addSoft = false; + + for(unsigned i=0; i > TSoft; + TSoft.reserve(2 * count_p); + + for(unsigned i=0; i ASoft(count_t + count_p, count_t + count_p); + ASoft.setFromTriplets(TSoft.begin(), TSoft.end()); + + A = (1.0 - softAlpha) * A + softAlpha * ASoft; + b = b * (1.0 - softAlpha) + bSoft * softAlpha; + } +} + +void igl::copyleft::comiso::NRosyField::solveRoundings() +{ + unsigned n = A.rows(); + + gmm::col_matrix< gmm::wsvector< double > > gmm_A(n, n); + std::vector gmm_b(n); + std::vector ids_to_round; + std::vector x(n); + + // Copy A + for (int k=0; k::InnerIterator it(A, k); it; ++it) + { + gmm_A(it.row(),it.col()) += it.value(); + } + + // Copy b + for(unsigned int i = 0; i < n;++i) + gmm_b[i] = b[i]; + + // Set variables to round + ids_to_round.clear(); + for(unsigned i=0; i > gmm_C(0, n); + + COMISO::ConstrainedSolver cs; + cs.solve(gmm_C, gmm_A, x, gmm_b, ids_to_round, 0.0, false, true); + + // Copy the result back + for(unsigned i=0; i igl::PI) + ktemp -= 2*igl::PI; + + // just to be sure, rotate ref0 using angle ktemp... + Eigen::MatrixXd R2(2,2); + R2 << std::cos(-ktemp), -std::sin(-ktemp), std::sin(-ktemp), std::cos(-ktemp); + + tmp = R2*ref0.head<2>(); + + assert(tmp(0) - ref1(0) < 1e-10); + assert(tmp(1) - ref1(1) < 1e-10); + + k[eid] = ktemp; + } + } + +} + +void igl::copyleft::comiso::NRosyField::reduceSpace() +{ + // All variables are free in the beginning + for(unsigned int i = 0; i < EV.rows(); ++i) + pFixed[i] = false; + + std::vector visited(EV.rows(), false); + std::vector starting(EV.rows(), false); + + std::queue q; + for(unsigned int i = 0; i < F.rows(); ++i) + if (isHard[i] || wSoft[i] != 0) + { + q.push(i); + starting[i] = true; + } + + // Reduce the search space (see MI paper) + while (!q.empty()) + { + int c = q.front(); + q.pop(); + + visited[c] = true; + for(int i=0; i<3; ++i) + { + int eid = FE(c,i); + int fid = TT(c,i); + + // skip borders + if (fid != -1) + { + assert((EF(eid,0) == c && EF(eid,1) == fid) || (EF(eid,1) == c && EF(eid,0) == fid)); + // for every neighbouring face + if (!visited[fid] && !starting[fid]) + { + pFixed[eid] = true; + p[eid] = 0; + visited[fid] = true; + q.push(fid); + } + } + else + { + // fix borders + pFixed[eid] = true; + p[eid] = 0; + } + } + } + + // Force matchings between fixed faces + for(unsigned int i = 0; i < F.rows();++i) + { + if (isHard[i]) + { + for(unsigned int j = 0; j < 3; ++j) + { + int fid = TT(i,j); + if ((fid!=-1) && (isHard[fid])) + { + // i and fid are adjacent and fixed + int eid = FE(i,j); + int fid0 = EF(eid,0); + int fid1 = EF(eid,1); + + pFixed[eid] = true; + p[eid] = (int)std::round(2.0 / igl::PI * (hard(fid1) - hard(fid0) - k(eid))); + } + } + } + } +} + +double igl::copyleft::comiso::NRosyField::convert3DtoLocal(unsigned fid, const Eigen::Vector3d& v) +{ + // Project onto the tangent plane + Eigen::Vector2d vp = TPs[fid] * v; + + // Convert to angle + return std::atan2(vp(1), vp(0)); +} + +Eigen::Vector3d igl::copyleft::comiso::NRosyField::convertLocalto3D(unsigned fid, double a) +{ + Eigen::Vector2d vp(std::cos(a), std::sin(a)); + return vp.transpose() * TPs[fid]; +} + +Eigen::VectorXd igl::copyleft::comiso::NRosyField::angleDefect() +{ + Eigen::VectorXd A = Eigen::VectorXd::Constant(V.rows(), 2*igl::PI); + + for (unsigned int i = 0; i < F.rows(); ++i) + { + for (int j = 0; j < 3; ++j) + { + Eigen::VectorXd a = V.row(F(i,(j+1)%3)) - V.row(F(i,j)); + Eigen::VectorXd b = V.row(F(i,(j+2)%3)) - V.row(F(i,j)); + double t = a.transpose() * b; + if(a.norm() > 0. && b.norm() > 0.) + t /= (a.norm() * b.norm()); + else + throw std::runtime_error("igl::copyleft::comiso::NRosyField::angleDefect: Division by zero!"); + A(F(i, j)) -= std::acos(std::max(std::min(t, 1.), -1.)); + } + } + + return A; +} + +void igl::copyleft::comiso::NRosyField::findCones(int N) +{ + // Compute I0, see http://www.graphics.rwth-aachen.de/media/papers/bommes_zimmer_2009_siggraph_011.pdf for details + + singularityIndex = Eigen::VectorXd::Zero(V.rows()); + + // first the k + for (unsigned i = 0; i < EV.rows(); ++i) + { + if (!isBorderEdge[i]) + { + singularityIndex(EV(i, 0)) += k(i); + singularityIndex(EV(i, 1)) -= k(i); + } + } + + // then the A + Eigen::VectorXd A = angleDefect(); + singularityIndex += A; + // normalize + singularityIndex /= (2 * igl::PI); + + // round to integer (remove numerical noise) + for (unsigned i = 0; i < singularityIndex.size(); ++i) + singularityIndex(i) = round(singularityIndex(i)); + + for (unsigned i = 0; i < EV.rows(); ++i) + { + if (!isBorderEdge[i]) + { + singularityIndex(EV(i, 0)) += double(p(i)) / double(N); + singularityIndex(EV(i, 1)) -= double(p(i)) / double(N); + } + } + + // Clear the vertices on the edges + for (unsigned i = 0; i < EV.rows(); ++i) + { + if (isBorderEdge[i]) + { + singularityIndex(EV(i,0)) = 0; + singularityIndex(EV(i,1)) = 0; + } + } +} + +Eigen::VectorXd igl::copyleft::comiso::NRosyField::getSingularityIndexPerVertex() +{ + return singularityIndex; +} + +IGL_INLINE void igl::copyleft::comiso::nrosy( + const Eigen::MatrixXd& V, + const Eigen::MatrixXi& F, + const Eigen::VectorXi& b, + const Eigen::MatrixXd& bc, + const Eigen::VectorXi& b_soft, + const Eigen::VectorXd& w_soft, + const Eigen::MatrixXd& bc_soft, + const int N, + const double soft, + Eigen::MatrixXd& R, + Eigen::VectorXd& S + ) +{ + // Init solver + igl::copyleft::comiso::NRosyField solver(V, F); + + // Add hard constraints + for (unsigned i = 0; i < b.size(); ++i) + solver.setConstraintHard(b(i), bc.row(i)); + + // Add soft constraints + for (unsigned i = 0; i < b_soft.size(); ++i) + solver.setConstraintSoft(b_soft(i), w_soft(i), bc_soft.row(i)); + + // Set the soft constraints global weight + solver.setSoftAlpha(soft); + + // Interpolate + solver.solve(N); + + // Copy the result back + R = solver.getFieldPerFace(); + + // Extract singularity indices + S = solver.getSingularityIndexPerVertex(); +} + + +IGL_INLINE void igl::copyleft::comiso::nrosy( + const Eigen::MatrixXd& V, + const Eigen::MatrixXi& F, + const Eigen::VectorXi& b, + const Eigen::MatrixXd& bc, + const int N, + Eigen::MatrixXd& R, + Eigen::VectorXd& S + ) +{ + // Init solver + igl::copyleft::comiso::NRosyField solver(V, F); + + // Add hard constraints + for (unsigned i= 0; i < b.size(); ++i) + solver.setConstraintHard(b(i), bc.row(i)); + + // Interpolate + solver.solve(N); + + // Copy the result back + R = solver.getFieldPerFace(); + + // Extract singularity indices + S = solver.getSingularityIndexPerVertex(); +} diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/comiso/nrosy.h b/src/external/libigl-2.3.0/include/igl/copyleft/comiso/nrosy.h new file mode 100644 index 000000000..0de0ea343 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/comiso/nrosy.h @@ -0,0 +1,70 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Daniele Panozzo +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_COMISO_NROSY_H +#define IGL_COMISO_NROSY_H + +#include +#include +#include "../../igl_inline.h" + +namespace igl +{ + namespace copyleft + { + namespace comiso + { + // Generate a N-RoSy field from a sparse set of constraints + // + // Inputs: + // V #V by 3 list of mesh vertex coordinates + // F #F by 3 list of mesh faces (must be triangles) + // b #B by 1 list of constrained face indices + // bc #B by 3 list of representative vectors for the constrained + // faces + // b_soft #S by 1 b for soft constraints + // w_soft #S by 1 weight for the soft constraints (0-1) + // bc_soft #S by 3 bc for soft constraints + // N the degree of the N-RoSy vector field + // soft the strength of the soft constraints w.r.t. smoothness + // (0 -> smoothness only, 1->constraints only) + // Outputs: + // R #F by 3 the representative vectors of the interpolated field + // S #V by 1 the singularity index for each vertex (0 = regular) + IGL_INLINE void nrosy( + const Eigen::MatrixXd& V, + const Eigen::MatrixXi& F, + const Eigen::VectorXi& b, + const Eigen::MatrixXd& bc, + const Eigen::VectorXi& b_soft, + const Eigen::VectorXd& w_soft, + const Eigen::MatrixXd& bc_soft, + int N, + double soft, + Eigen::MatrixXd& R, + Eigen::VectorXd& S + ); + //wrapper for the case without soft constraints + IGL_INLINE void nrosy( + const Eigen::MatrixXd& V, + const Eigen::MatrixXi& F, + const Eigen::VectorXi& b, + const Eigen::MatrixXd& bc, + int N, + Eigen::MatrixXd& R, + Eigen::VectorXd& S + ); + + } +} +} + +#ifndef IGL_STATIC_LIBRARY +# include "nrosy.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cork/from_cork_mesh.cpp b/src/external/libigl-2.3.0/include/igl/copyleft/cork/from_cork_mesh.cpp new file mode 100644 index 000000000..964263111 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cork/from_cork_mesh.cpp @@ -0,0 +1,41 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "from_cork_mesh.h" + +template < + typename DerivedV, + typename DerivedF> +IGL_INLINE void igl::copyleft::cork::from_cork_mesh( + const CorkTriMesh & mesh, + Eigen::PlainObjectBase & V, + Eigen::PlainObjectBase & F) +{ + using namespace std; + F.resize(mesh.n_triangles,3); + V.resize(mesh.n_vertices,3); + for(size_t v = 0;v, Eigen::Matrix >(CorkTriMesh const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::copyleft::cork::from_cork_mesh, Eigen::Matrix >(CorkTriMesh const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cork/from_cork_mesh.h b/src/external/libigl-2.3.0/include/igl/copyleft/cork/from_cork_mesh.h new file mode 100644 index 000000000..a2fef28c1 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cork/from_cork_mesh.h @@ -0,0 +1,39 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_COPYLEFT_CORK_FROM_CORK_MESH_H +#define IGL_COPYLEFT_CORK_FROM_CORK_MESH_H +#include "../../igl_inline.h" +#include +#include +namespace igl +{ + namespace copyleft + { + namespace cork + { + // Convert cork's triangle mesh representation to a (V,F) mesh. + // + // Inputs: + // mesh cork representation of mesh + // Outputs: + // V #V by 3 list of vertex positions + // F #F by 3 list of triangle indices into V + template < + typename DerivedV, + typename DerivedF> + IGL_INLINE void from_cork_mesh( + const CorkTriMesh & mesh, + Eigen::PlainObjectBase & V, + Eigen::PlainObjectBase & F); + } + } +} +#ifndef IGL_STATIC_LIBRARY +# include "from_cork_mesh.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cork/mesh_boolean.cpp b/src/external/libigl-2.3.0/include/igl/copyleft/cork/mesh_boolean.cpp new file mode 100644 index 000000000..61ed4a6ad --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cork/mesh_boolean.cpp @@ -0,0 +1,99 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "mesh_boolean.h" +#include "to_cork_mesh.h" +#include "from_cork_mesh.h" + +template < + typename DerivedVA, + typename DerivedFA, + typename DerivedVB, + typename DerivedFB, + typename DerivedVC, + typename DerivedFC> +IGL_INLINE void igl::copyleft::cork::mesh_boolean( + const Eigen::PlainObjectBase & VA, + const Eigen::PlainObjectBase & FA, + const Eigen::PlainObjectBase & VB, + const Eigen::PlainObjectBase & FB, + const MeshBooleanType & type, + Eigen::PlainObjectBase & VC, + Eigen::PlainObjectBase & FC) +{ + CorkTriMesh A,B,C; + // pointer to output so it's easy to redirect on degenerate cases + CorkTriMesh *ret = &C; + to_cork_mesh(VA,FA,A); + to_cork_mesh(VB,FB,B); + switch(type) + { + case MESH_BOOLEAN_TYPE_UNION: + if(A.n_triangles == 0) + { + ret = &B; + }else if(B.n_triangles == 0) + { + ret = &A; + }else + { + computeUnion(A,B,ret); + } + break; + case MESH_BOOLEAN_TYPE_INTERSECT: + if(A.n_triangles == 0 || B.n_triangles == 0) + { + ret->n_triangles = 0; + ret->n_vertices = 0; + }else + { + computeIntersection(A,B,ret); + } + break; + case MESH_BOOLEAN_TYPE_MINUS: + if(A.n_triangles == 0) + { + ret->n_triangles = 0; + ret->n_vertices = 0; + }else if(B.n_triangles == 0) + { + ret = &A; + }else + { + computeDifference(A,B,ret); + } + break; + case MESH_BOOLEAN_TYPE_XOR: + if(A.n_triangles == 0) + { + ret = &B; + }else if(B.n_triangles == 0) + { + ret = &A; + }else + { + computeSymmetricDifference(A,B,&C); + } + break; + case MESH_BOOLEAN_TYPE_RESOLVE: + resolveIntersections(A,B,&C); + break; + default: + assert(false && "Unknown type"); + return; + } + from_cork_mesh(*ret,VC,FC); + freeCorkTriMesh(&A); + freeCorkTriMesh(&B); + freeCorkTriMesh(&C); +} +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +template void igl::copyleft::cork::mesh_boolean, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, MeshBooleanType const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::copyleft::cork::mesh_boolean, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, igl::MeshBooleanType const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cork/mesh_boolean.h b/src/external/libigl-2.3.0/include/igl/copyleft/cork/mesh_boolean.h new file mode 100644 index 000000000..db2589284 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cork/mesh_boolean.h @@ -0,0 +1,55 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_COPYLEFT_CORK_MESH_BOOLEAN_H +#define IGL_COPYLEFT_CORK_MESH_BOOLEAN_H +#include "../../MeshBooleanType.h" +#include "../../igl_inline.h" +#include +#include // for consistent uint + +namespace igl +{ + namespace copyleft + { + namespace cork + { + // Compute a boolean operation on two input meshes using the cork library. + // + // Inputs: + // VA #VA by 3 list of vertex positions of first mesh + // FA #FA by 3 list of triangle indices into VA + // VB #VB by 3 list of vertex positions of second mesh + // FB #FB by 3 list of triangle indices into VB + // type of boolean operation see MeshBooleanType.h + // Outputs: + // VC #VC by 3 list of vertex positions of output mesh + // FC #FC by 3 list of triangle indices into VC + template < + typename DerivedVA, + typename DerivedFA, + typename DerivedVB, + typename DerivedFB, + typename DerivedVC, + typename DerivedFC> + IGL_INLINE void mesh_boolean( + const Eigen::PlainObjectBase & VA, + const Eigen::PlainObjectBase & FA, + const Eigen::PlainObjectBase & VB, + const Eigen::PlainObjectBase & FB, + const MeshBooleanType & type, + Eigen::PlainObjectBase & VC, + Eigen::PlainObjectBase & FC); + } + } +} + +#ifndef IGL_STATIC_LIBRARY +# include "mesh_boolean.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cork/to_cork_mesh.cpp b/src/external/libigl-2.3.0/include/igl/copyleft/cork/to_cork_mesh.cpp new file mode 100644 index 000000000..845f8cb67 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cork/to_cork_mesh.cpp @@ -0,0 +1,43 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "to_cork_mesh.h" +template < + typename DerivedV, + typename DerivedF> +IGL_INLINE void igl::copyleft::cork::to_cork_mesh( + const Eigen::PlainObjectBase & V, + const Eigen::PlainObjectBase & F, + CorkTriMesh & mesh) +{ + using namespace std; + assert((F.cols() == 0 || F.cols() == 3) && "Facets should be triangles."); + assert((V.cols() == 0 || V.cols() == 3) && "Vertices should be in 3D."); + mesh.n_triangles = F.rows(); + mesh.n_vertices = V.rows(); + mesh.vertices = new float[mesh.n_vertices*3]; + mesh.triangles = new uint[mesh.n_triangles*3]; + for(size_t v = 0;v, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, CorkTriMesh&); +template void igl::copyleft::cork::to_cork_mesh, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, CorkTriMesh&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/cork/to_cork_mesh.h b/src/external/libigl-2.3.0/include/igl/copyleft/cork/to_cork_mesh.h new file mode 100644 index 000000000..b034e357f --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/cork/to_cork_mesh.h @@ -0,0 +1,39 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_COPYLEFT_CORK_TO_CORK_MESH_H +#define IGL_COPYLEFT_CORK_TO_CORK_MESH_H +#include "../../igl_inline.h" +#include +#include +namespace igl +{ + namespace copyleft + { + namespace cork + { + // Convert a (V,F) mesh to a cork's triangle mesh representation. + // + // Inputs: + // V #V by 3 list of vertex positions + // F #F by 3 list of triangle indices into V + // Outputs: + // mesh cork representation of mesh + template < + typename DerivedV, + typename DerivedF> + IGL_INLINE void to_cork_mesh( + const Eigen::PlainObjectBase & V, + const Eigen::PlainObjectBase & F, + CorkTriMesh & mesh); + } + } +} +#ifndef IGL_STATIC_LIBRARY +# include "to_cork_mesh.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/marching_cubes.cpp b/src/external/libigl-2.3.0/include/igl/copyleft/marching_cubes.cpp new file mode 100644 index 000000000..b6364aee5 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/marching_cubes.cpp @@ -0,0 +1,551 @@ +/*===========================================================================*\ + * * + * IsoEx * + * Copyright (C) 2002 by Computer Graphics Group, RWTH Aachen * + * www.rwth-graphics.de * + * * + *---------------------------------------------------------------------------* + * * + * License * + * * + * This library is free software; you can redistribute it and/or modify it * + * under the terms of the GNU Library General Public License as published * + * by the Free Software Foundation, version 2. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * + * * + \*===========================================================================*/ + +#include "marching_cubes.h" +#include "marching_cubes_tables.h" + +#include + + +extern const int edgeTable[256]; +extern const int triTable[256][2][17]; +extern const int polyTable[8][16]; + + +template +class MarchingCubes +{ + struct EdgeKey + { + EdgeKey(unsigned i0, unsigned i1) : i0_(i0), i1_(i1) {} + + bool operator==(const EdgeKey& _rhs) const + { + return i0_ == _rhs.i0_ && i1_ == _rhs.i1_; + } + + unsigned i0_, i1_; + }; + + struct EdgeHash + { + std::size_t operator()(const EdgeKey& key) const { + std::size_t seed = 0; + seed ^= key.i0_ + 0x9e3779b9 + (seed<<6) + (seed>>2); // Copied from boost::hash_combine + seed ^= key.i1_ + 0x9e3779b9 + (seed<<6) + (seed>>2); + return std::hash()(seed); + } + }; + + typedef std::unordered_map MyMap; + typedef typename MyMap::const_iterator MyMapIterator; + +public: + // Dense index grid version + MarchingCubes(const Eigen::MatrixBase &values, + const Eigen::MatrixBase &points, + const unsigned x_res, + const unsigned y_res, + const unsigned z_res, + const double isovalue, + Eigen::PlainObjectBase &vertices, + Eigen::PlainObjectBase &faces) + { + assert(values.cols() == 1); + assert(points.cols() == 3); + + if(x_res <2 || y_res<2 ||z_res<2) + return; + faces.resize(10000,3); + int num_faces = 0; + + vertices.resize(10000,3); + int num_vertices = 0; + + unsigned n_cubes = (x_res-1) * (y_res-1) * (z_res-1); + assert(unsigned(points.rows()) == x_res * y_res * z_res); + + unsigned int offsets_[8]; + offsets_[0] = 0; + offsets_[1] = 1; + offsets_[2] = 1 + x_res; + offsets_[3] = x_res; + offsets_[4] = x_res*y_res; + offsets_[5] = 1 + x_res*y_res; + offsets_[6] = 1 + x_res + x_res*y_res; + offsets_[7] = x_res + x_res*y_res; + + for (unsigned cube_it =0 ; cube_it < n_cubes; ++cube_it) + { + unsigned corner[8]; + // get point indices of corner vertices + for (int i=0; i<8; ++i) + { + // get cube coordinates + unsigned int _idx = cube_it; + unsigned int X(x_res-1), Y(y_res-1); + unsigned int x = _idx % X; _idx /= X; + unsigned int y = _idx % Y; _idx /= Y; + unsigned int z = _idx; + // transform to point coordinates + _idx = x + y*x_res + z*x_res*y_res; + // add offset + corner[i] = _idx + offsets_[i]; + } + add_cube(values,points,isovalue,corner,vertices,num_vertices,faces,num_faces,edge2vertex); + } + vertices.conservativeResize(num_vertices, Eigen::NoChange); + faces.conservativeResize(num_faces, Eigen::NoChange); + } + + // Sparse index grid version + MarchingCubes(const Eigen::MatrixBase &values, + const Eigen::MatrixBase &points, + const Eigen::MatrixBase &cubes, + const double isovalue, + Eigen::PlainObjectBase &vertices, + Eigen::PlainObjectBase &faces) + { + assert(values.cols() == 1); + assert(points.cols() == 3); + assert(cubes.cols() == 8); + + if(cubes.rows() == 0) + { + return; + } + + faces.resize(10000,3); + int num_faces = 0; + + vertices.resize(10000,3); + int num_vertices = 0; + + + unsigned n_cubes = cubes.rows(); + + for (unsigned cube_it =0 ; cube_it < n_cubes; ++cube_it) + { + typedef Eigen::Matrix CubeIndexVector; + + CubeIndexVector corner = cubes.row(cube_it); + add_cube(values,points,isovalue,corner.data(),vertices,num_vertices,faces,num_faces,edge2vertex); + } + vertices.conservativeResize(num_vertices, Eigen::NoChange); + faces.conservativeResize(num_faces, Eigen::NoChange); + } + + // Dense index grid function version + template + MarchingCubes( + const std::function< DerivedValue(const DerivedPoint & ) > & value_fun, + const Eigen::MatrixBase &points, + const unsigned x_res, + const unsigned y_res, + const unsigned z_res, + const double isovalue, + Eigen::PlainObjectBase &vertices, + Eigen::PlainObjectBase &faces) + { + assert(points.cols() == 3); + + if(x_res <2 || y_res<2 ||z_res<2) + return; + faces.resize(10000,3); + int num_faces = 0; + + vertices.resize(10000,3); + int num_vertices = 0; + + unsigned n_cubes = (x_res-1) * (y_res-1) * (z_res-1); + assert(unsigned(points.rows()) == x_res * y_res * z_res); + + unsigned int offsets_[8]; + offsets_[0] = 0; + offsets_[1] = 1; + offsets_[2] = 1 + x_res; + offsets_[3] = x_res; + offsets_[4] = x_res*y_res; + offsets_[5] = 1 + x_res*y_res; + offsets_[6] = 1 + x_res + x_res*y_res; + offsets_[7] = x_res + x_res*y_res; + + for (unsigned cube_it =0 ; cube_it < n_cubes; ++cube_it) + { + unsigned corner[8]; + // get point indices of corner vertices + for (int i=0; i<8; ++i) + { + // get cube coordinates + unsigned int _idx = cube_it; + unsigned int X(x_res-1), Y(y_res-1); + unsigned int x = _idx % X; _idx /= X; + unsigned int y = _idx % Y; _idx /= Y; + unsigned int z = _idx; + // transform to point coordinates + _idx = x + y*x_res + z*x_res*y_res; + // add offset + corner[i] = _idx + offsets_[i]; + } + add_cube(value_fun,points,isovalue,corner,vertices,num_vertices,faces,num_faces,edge2vertex); + } + vertices.conservativeResize(num_vertices, Eigen::NoChange); + faces.conservativeResize(num_faces, Eigen::NoChange); + } + + template + static void add_cube( + const Eigen::MatrixBase &values, + const Eigen::MatrixBase &points, + const double isovalue, + const CubeIndexType corner[], + Eigen::PlainObjectBase &vertices, + int &num_vertices, + Eigen::PlainObjectBase &faces, + int & num_faces, + MyMap &edge2vertex) + { + typedef typename DerivedFaces::Scalar SampleScalar; + SampleScalar samples[12]; + unsigned char cubetype(0); + + // determine cube type + for (int i=0; i<8; ++i) + { + if (values(corner[i]) > isovalue) + { + cubetype |= (1< faces.rows()) + { + faces.conservativeResize(faces.rows()+10000, Eigen::NoChange); + } + faces.row(num_faces-1) << + samples[triTable[cubetype][0][i ]], + samples[triTable[cubetype][0][i+1]], + samples[triTable[cubetype][0][i+2]]; + } + }; + + template + static void add_cube( + const std::function< DerivedValue(const DerivedPoint & ) > & value_fun, + const Eigen::MatrixBase &points, + const double isovalue, + const CubeIndexType corner[], + Eigen::PlainObjectBase &vertices, + int &num_vertices, + Eigen::PlainObjectBase &faces, + int & num_faces, + MyMap &edge2vertex) + { + typedef typename DerivedFaces::Scalar SampleScalar; + SampleScalar samples[12]; + unsigned char cubetype(0); + + // determine cube type + for (int i=0; i<8; ++i) + { + if (value_fun(points.row(corner[i])) > isovalue) + { + cubetype |= (1< faces.rows()) + { + faces.conservativeResize(faces.rows()+10000, Eigen::NoChange); + } + faces.row(num_faces-1) << + samples[triTable[cubetype][0][i ]], + samples[triTable[cubetype][0][i+1]], + samples[triTable[cubetype][0][i+2]]; + } + }; + + static typename DerivedFaces::Scalar add_vertex( + const Eigen::MatrixBase &values, + const Eigen::MatrixBase &points, + const double isovalue, + unsigned int i0, + unsigned int i1, + Eigen::PlainObjectBase &vertices, + int &num_vertices, + MyMap &edge2vertex) + { + // find vertex if it has been computed already + MyMapIterator it = edge2vertex.find(EdgeKey(i0, i1)); + if (it != edge2vertex.end()) + { + return it->second; + } + + // generate new vertex + const Eigen::Matrix & p0 = points.row(i0); + const Eigen::Matrix & p1 = points.row(i1); + typename DerivedValues::Scalar s0 = fabs(values(i0)-isovalue); + typename DerivedValues::Scalar s1 = fabs(values(i1)-isovalue); + typename DerivedValues::Scalar t = s0 / (s0+s1); + num_vertices++; + if (num_vertices > vertices.rows()) + { + vertices.conservativeResize(vertices.rows()+10000, Eigen::NoChange); + } + // + // Linear interpolation based on linearly interpolating values + vertices.row(num_vertices-1) = ((1.0f-t)*p0 + t*p1).template cast(); + edge2vertex[EdgeKey(i0, i1)] = num_vertices-1; + return num_vertices-1; + } + + template + static typename DerivedFaces::Scalar add_vertex( + const std::function< DerivedValue(const DerivedPoint & ) > & value_fun, + const Eigen::MatrixBase &points, + const double isovalue, + unsigned int i0, + unsigned int i1, + Eigen::PlainObjectBase &vertices, + int &num_vertices, + MyMap &edge2vertex) + { + // find vertex if it has been computed already + MyMapIterator it = edge2vertex.find(EdgeKey(i0, i1)); + if (it != edge2vertex.end()) + { + return it->second; + } + num_vertices++; + if (num_vertices > vertices.rows()) + { + vertices.conservativeResize(vertices.rows()+10000, Eigen::NoChange); + } + + // generate new vertex + typedef Eigen::Matrix RowVector3S; + const RowVector3S & p0 = points.row(i0); + const RowVector3S & p1 = points.row(i1); + // Linear interpolation based on linearly interpolating values + //typename DerivedValues::Scalar s0 = fabs(value_fun(points.row(i0))-isovalue); + //typename DerivedValues::Scalar s1 = fabs(value_fun(points.row(i1))-isovalue); + //typename DerivedValues::Scalar t = s0 / (s0+s1); + const DerivedValue v1 = value_fun(p1); + double t0 = (v1>isovalue)?0:1; + double t1 = (v1>isovalue)?1:0; + double t; + for(int j = 0;j<10;j++) + { + t = 0.5*(t0+t1); + const double val = value_fun( ((1.0f-t)*p0 + t*p1) ); + if( val > isovalue ) + { + t1 = t; + }else + { + t0 = t; + } + } + vertices.row(num_vertices-1) = ((1.0f-t)*p0 + t*p1).template cast(); + + edge2vertex[EdgeKey(i0, i1)] = num_vertices-1; + return num_vertices-1; + } + + // maps an edge to the sample vertex generated on it + MyMap edge2vertex; +}; + + +template +IGL_INLINE void igl::copyleft::marching_cubes( + const Eigen::MatrixBase &values, + const Eigen::MatrixBase &points, + const unsigned x_res, + const unsigned y_res, + const unsigned z_res, + const double isovalue, + Eigen::PlainObjectBase &vertices, + Eigen::PlainObjectBase &faces) +{ + typedef Eigen::MatrixXi Shim; /* DerivedIndices shim type is unused in this instantiation*/ + MarchingCubes + mc(values, points, x_res, y_res, z_res, isovalue, vertices, faces); +} + +template < + typename DerivedValue, + typename DerivedPoint, + typename DerivedPoints, + typename DerivedVertices, + typename DerivedFaces> +IGL_INLINE void igl::copyleft::marching_cubes( + const std::function< DerivedValue(const DerivedPoint & ) > & value_fun, + const Eigen::MatrixBase &points, + const unsigned x_res, + const unsigned y_res, + const unsigned z_res, + const double isovalue, + Eigen::PlainObjectBase &vertices, + Eigen::PlainObjectBase &faces) +{ + MarchingCubes< + Eigen::Matrix, /* unnecessary */ + DerivedPoints, DerivedVertices, + Eigen::Matrix, /* unnecessary */ + DerivedFaces> mc(value_fun, points, x_res, y_res, z_res, isovalue, vertices, faces); +} + +template +IGL_INLINE void igl::copyleft::marching_cubes( + const Eigen::MatrixBase &values, + const Eigen::MatrixBase &points, + const unsigned x_res, + const unsigned y_res, + const unsigned z_res, + Eigen::PlainObjectBase &vertices, + Eigen::PlainObjectBase &faces) +{ + typedef Eigen::MatrixXi Shim; /* DerivedIndices shim type is unused in this instantiation*/ + MarchingCubes + mc(values, points, x_res, y_res, z_res, 0.0 /*isovalue*/, vertices, faces); +} + +template +IGL_INLINE void igl::copyleft::marching_cubes( + const Eigen::MatrixBase& values, + const Eigen::MatrixBase& points, + const Eigen::MatrixBase& indices, + const double isovalue, + Eigen::PlainObjectBase& vertices, + Eigen::PlainObjectBase &faces) +{ + MarchingCubes mc(values, points, indices, isovalue, vertices, faces); +} + +template +IGL_INLINE void igl::copyleft::marching_cubes( + const Eigen::MatrixBase &values, + const Eigen::MatrixBase &points, + const Eigen::MatrixBase & indices, + Eigen::PlainObjectBase &vertices, + Eigen::PlainObjectBase &faces) +{ + MarchingCubes mc(values, points, indices, 0.0 /*isovalue*/, vertices, faces); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::copyleft::marching_cubes, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, unsigned int, unsigned int, unsigned int, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::copyleft::marching_cubes, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, unsigned int, unsigned int, unsigned int, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::copyleft::marching_cubes, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, unsigned int, unsigned int, unsigned int, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::copyleft::marching_cubes, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, unsigned int, unsigned int, unsigned int, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::copyleft::marching_cubes, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, unsigned int, unsigned int, unsigned int, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::copyleft::marching_cubes, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, unsigned int, unsigned int, unsigned int, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::copyleft::marching_cubes, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(const Eigen::MatrixBase >&, const Eigen::MatrixBase >&, const Eigen::MatrixBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::copyleft::marching_cubes, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(const Eigen::MatrixBase >&, const Eigen::MatrixBase >&, const Eigen::MatrixBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::copyleft::marching_cubes, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(const Eigen::MatrixBase >&, const Eigen::MatrixBase >&, const Eigen::MatrixBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::copyleft::marching_cubes, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(const Eigen::MatrixBase >&, const Eigen::MatrixBase >&, const Eigen::MatrixBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::copyleft::marching_cubes, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(const Eigen::MatrixBase >&, const Eigen::MatrixBase >&, const Eigen::MatrixBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::copyleft::marching_cubes,Eigen::Matrix,Eigen::Matrix,Eigen::Matrix,Eigen::Matrix >(const Eigen::MatrixBase >&,const Eigen::MatrixBase >&,const Eigen::MatrixBase >&,Eigen::PlainObjectBase >&,Eigen::PlainObjectBase >&); +template void igl::copyleft::marching_cubes,Eigen::Matrix,Eigen::Matrix,Eigen::Matrix,Eigen::Matrix >(const Eigen::MatrixBase >&,const Eigen::MatrixBase >&,const Eigen::MatrixBase >&,Eigen::PlainObjectBase >&,Eigen::PlainObjectBase >&); +template void igl::copyleft::marching_cubes,Eigen::Matrix,Eigen::Matrix,Eigen::Matrix,Eigen::Matrix >(const Eigen::MatrixBase >&,const Eigen::MatrixBase >&,const Eigen::MatrixBase >&,Eigen::PlainObjectBase >&,Eigen::PlainObjectBase >&); +template void igl::copyleft::marching_cubes, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::copyleft::marching_cubes, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, unsigned int, unsigned int, unsigned int, double, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/marching_cubes.h b/src/external/libigl-2.3.0/include/igl/copyleft/marching_cubes.h new file mode 100644 index 000000000..985eb3ac8 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/marching_cubes.h @@ -0,0 +1,128 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_COPYLEFT_MARCHINGCUBES_H +#define IGL_COPYLEFT_MARCHINGCUBES_H +#include "../igl_inline.h" + +#include +namespace igl +{ + namespace copyleft + { + // marching_cubes( values, points, x_res, y_res, z_res, isovalue, vertices, faces ) + // + // performs marching cubes reconstruction on a grid defined by values, and + // points, and generates a mesh defined by vertices and faces + // + // Input: + // values #number_of_grid_points x 1 array -- the scalar values of an + // implicit function defined on the grid points (<0 in the inside of the + // surface, 0 on the border, >0 outside) + // points #number_of_grid_points x 3 array -- 3-D positions of the grid + // points, ordered in x,y,z order: + // points[index] = the point at (x,y,z) where : + // x = (index % (xres -1), + // y = (index / (xres-1)) %(yres-1), + // z = index / (xres -1) / (yres -1) ). + // where x,y,z index x, y, z dimensions + // i.e. index = x + y*xres + z*xres*yres + // xres resolutions of the grid in x dimension + // yres resolutions of the grid in y dimension + // zres resolutions of the grid in z dimension + // isovalue the isovalue of the surface to reconstruct + // Output: + // vertices #V by 3 list of mesh vertex positions + // faces #F by 3 list of mesh triangle indices + // + // See also: igl::marching_cubes + template + IGL_INLINE void marching_cubes( + const Eigen::MatrixBase &values, + const Eigen::MatrixBase &points, + const unsigned x_res, + const unsigned y_res, + const unsigned z_res, + const double isovalue, + Eigen::PlainObjectBase &vertices, + Eigen::PlainObjectBase &faces); + template < + typename DerivedValue, + typename DerivedPoint, + typename DerivedPoints, + typename DerivedVertices, + typename DerivedFaces> + IGL_INLINE void marching_cubes( + const std::function< DerivedValue(const DerivedPoint & ) > & value_fun, + const Eigen::MatrixBase &points, + const unsigned x_res, + const unsigned y_res, + const unsigned z_res, + const double isovalue, + Eigen::PlainObjectBase &vertices, + Eigen::PlainObjectBase &faces); + + // Overload of the above function where the isovalue defaults to 0.0 + template + IGL_INLINE void marching_cubes( + const Eigen::MatrixBase &values, + const Eigen::MatrixBase &points, + const unsigned x_res, + const unsigned y_res, + const unsigned z_res, + Eigen::PlainObjectBase &vertices, + Eigen::PlainObjectBase &faces); + + + + // marching_cubes( values, points, indices, vertices, faces ) + // + // Perform marching cubes reconstruction on the sparse grid cells defined by (indices, points). + // The indices parameter is an nx8 dense array of index values into the points and values arrays. + // Each row of indices represents a cube for which to generate vertices and faces over. + // + // Input: + // values #number_of_grid_points x 1 array -- the scalar values of an + // implicit function defined on the grid points (<0 in the inside of the + // surface, 0 on the border, >0 outside) + // points #number_of_grid_points x 3 array -- 3-D positions of the grid + // points, ordered in x,y,z order: + // indices #cubes x 8 array -- one row for each cube where each value is + // the index of a vertex in points and a scalar in values. + // i.e. points[indices[i, j]] = the position of the j'th vertex of the i'th cube + // Output: + // vertices #V by 3 list of mesh vertex positions + // faces #F by 3 list of mesh triangle indices + // Note: The winding direction of the cube indices will affect the output winding of the faces + // + template + IGL_INLINE void marching_cubes( + const Eigen::MatrixBase &values, + const Eigen::MatrixBase &points, + const Eigen::MatrixBase &indices, + const double isovalue, + Eigen::PlainObjectBase &vertices, + Eigen::PlainObjectBase &faces); + + // Overload of the above function where the isovalue defaults to 0.0 + template + IGL_INLINE void marching_cubes( + const Eigen::MatrixBase &values, + const Eigen::MatrixBase &points, + const Eigen::MatrixBase &indices, + Eigen::PlainObjectBase &vertices, + Eigen::PlainObjectBase &faces); + + } + +} + +#ifndef IGL_STATIC_LIBRARY +# include "marching_cubes.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/marching_cubes_tables.h b/src/external/libigl-2.3.0/include/igl/copyleft/marching_cubes_tables.h new file mode 100644 index 000000000..4bba533c3 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/marching_cubes_tables.h @@ -0,0 +1,917 @@ +/*===========================================================================*\ + * * + * IsoEx * + * Copyright (C) 2002 by Computer Graphics Group, RWTH Aachen * + * www.rwth-graphics.de * + * * + *---------------------------------------------------------------------------* + * * + * License * + * * + * This library is free software; you can redistribute it and/or modify it * + * under the terms of the GNU Library General Public License as published * + * by the Free Software Foundation, version 2. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * + * * + \*===========================================================================*/ + +//============================================================================= +#ifndef IGL_ISOEX_MC_TABLES_HH +#define IGL_ISOEX_MC_TABLES_HH +//============================================================================= + + +//int edgeTable[256]; +//int triTable[256][2][17]; +//int polyTable[8][16]; + +const int edgeTable[256]= +{ + 0x0 , 0x109, 0x203, 0x30a, 0x406, 0x50f, 0x605, 0x70c, + 0x80c, 0x905, 0xa0f, 0xb06, 0xc0a, 0xd03, 0xe09, 0xf00, + 0x190, 0x99 , 0x393, 0x29a, 0x596, 0x49f, 0x795, 0x69c, + 0x99c, 0x895, 0xb9f, 0xa96, 0xd9a, 0xc93, 0xf99, 0xe90, + 0x230, 0x339, 0x33 , 0x13a, 0x636, 0x73f, 0x435, 0x53c, + 0xa3c, 0xb35, 0x83f, 0x936, 0xe3a, 0xf33, 0xc39, 0xd30, + 0x3a0, 0x2a9, 0x1a3, 0xaa , 0x7a6, 0x6af, 0x5a5, 0x4ac, + 0xbac, 0xaa5, 0x9af, 0x8a6, 0xfaa, 0xea3, 0xda9, 0xca0, + 0x460, 0x569, 0x663, 0x76a, 0x66 , 0x16f, 0x265, 0x36c, + 0xc6c, 0xd65, 0xe6f, 0xf66, 0x86a, 0x963, 0xa69, 0xb60, + 0x5f0, 0x4f9, 0x7f3, 0x6fa, 0x1f6, 0xff , 0x3f5, 0x2fc, + 0xdfc, 0xcf5, 0xfff, 0xef6, 0x9fa, 0x8f3, 0xbf9, 0xaf0, + 0x650, 0x759, 0x453, 0x55a, 0x256, 0x35f, 0x55 , 0x15c, + 0xe5c, 0xf55, 0xc5f, 0xd56, 0xa5a, 0xb53, 0x859, 0x950, + 0x7c0, 0x6c9, 0x5c3, 0x4ca, 0x3c6, 0x2cf, 0x1c5, 0xcc , + 0xfcc, 0xec5, 0xdcf, 0xcc6, 0xbca, 0xac3, 0x9c9, 0x8c0, + 0x8c0, 0x9c9, 0xac3, 0xbca, 0xcc6, 0xdcf, 0xec5, 0xfcc, + 0xcc , 0x1c5, 0x2cf, 0x3c6, 0x4ca, 0x5c3, 0x6c9, 0x7c0, + 0x950, 0x859, 0xb53, 0xa5a, 0xd56, 0xc5f, 0xf55, 0xe5c, + 0x15c, 0x55 , 0x35f, 0x256, 0x55a, 0x453, 0x759, 0x650, + 0xaf0, 0xbf9, 0x8f3, 0x9fa, 0xef6, 0xfff, 0xcf5, 0xdfc, + 0x2fc, 0x3f5, 0xff , 0x1f6, 0x6fa, 0x7f3, 0x4f9, 0x5f0, + 0xb60, 0xa69, 0x963, 0x86a, 0xf66, 0xe6f, 0xd65, 0xc6c, + 0x36c, 0x265, 0x16f, 0x66 , 0x76a, 0x663, 0x569, 0x460, + 0xca0, 0xda9, 0xea3, 0xfaa, 0x8a6, 0x9af, 0xaa5, 0xbac, + 0x4ac, 0x5a5, 0x6af, 0x7a6, 0xaa , 0x1a3, 0x2a9, 0x3a0, + 0xd30, 0xc39, 0xf33, 0xe3a, 0x936, 0x83f, 0xb35, 0xa3c, + 0x53c, 0x435, 0x73f, 0x636, 0x13a, 0x33 , 0x339, 0x230, + 0xe90, 0xf99, 0xc93, 0xd9a, 0xa96, 0xb9f, 0x895, 0x99c, + 0x69c, 0x795, 0x49f, 0x596, 0x29a, 0x393, 0x99 , 0x190, + 0xf00, 0xe09, 0xd03, 0xc0a, 0xb06, 0xa0f, 0x905, 0x80c, + 0x70c, 0x605, 0x50f, 0x406, 0x30a, 0x203, 0x109, 0x0 +}; + + +//----------------------------------------------------------------------------- + + +const int triTable[256][2][17] = +{{{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + { 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 3, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{0, 1, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 3, 0, 1, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{1, 8, 3, 9, 8, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 4, 1, 9, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 3, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{0, 8, 3, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {2, 3, 3, 0, 8, 3, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{9, 2, 10, 0, 2, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 4, 2, 10, 9, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{2, 8, 3, 2, 10, 8, 10, 9, 8, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 5, 10, 9, 8, 3, 2 , -1,-1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 3, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{0, 11, 2, 8, 11, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 4, 0, 8, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + /* 10 */ + {{1, 9, 0, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {2, 3, 3, 1, 9, 0, 2, 3,11, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{1, 11, 2, 1, 9, 11, 9, 8, 11, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 5, 9, 8, 11, 2, 1,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{3, 10, 1, 11, 10, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 4, 3, 11,10, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{0, 10, 1, 0, 8, 10, 8, 11, 10, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 5, 8, 11, 10, 1, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{3, 9, 0, 3, 11, 9, 11, 10, 9, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 5, 11,10, 9, 0, 3, -1,-1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + /* 15 */ + {{9, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 4, 8, 11, 10, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 3, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{4, 3, 0, 7, 3, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 4, 4, 7, 3, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{0, 1, 9, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {2, 3, 3, 0, 1, 9, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{4, 1, 9, 4, 7, 1, 7, 3, 1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 5, 7, 3, 1, 9, 4, -1,-1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + /* 20 */ + {{1, 2, 10, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {2, 3, 3, 1, 2,10, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{3, 4, 7, 3, 0, 4, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1}, + {2, 4, 3, 3, 0, 4, 7, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1}}, + + {{9, 2, 10, 9, 0, 2, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1}, + {2, 4, 3, 2,10, 9, 0, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1}}, + + {{2, 10, 9, 2, 9, 7, 2, 7, 3, 7, 9, 4, -1, -1, -1, -1, -1}, + {1, 6, 7, 3, 2,10, 9, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{8, 4, 7, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {2, 3, 3, 8, 4, 7, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1}}, + + /* 25 */ + {{11, 4, 7, 11, 2, 4, 2, 0, 4, -1, -1, -1, -1, -1, -1, -1, -1}, + { 1, 5, 2, 0, 4, 7,11,-1,-1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{9, 0, 1, 8, 4, 7, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1}, + {3, 3, 3, 3, 9, 0, 1, 8, 4, 7, 2, 3, 11, -1, -1, -1, -1}}, + + {{4, 7, 11, 9, 4, 11, 9, 11, 2, 9, 2, 1, -1, -1, -1, -1, -1}, + {2, 4, 4, 2, 1, 9, 11, 11,9,4,7, -1, -1, -1, -1, -1 ,-1}}, + + {{3, 10, 1, 3, 11, 10, 7, 8, 4, -1, -1, -1, -1, -1, -1, -1, -1}, + {2, 4, 3, 3, 11,10, 1, 7, 8, 4, -1, -1, -1, -1, -1, -1, -1}}, + + {{1, 11, 10, 1, 4, 11, 1, 0, 4, 7, 11, 4, -1, -1, -1, -1, -1}, + {1, 6, 1, 0, 4, 7,11,10, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + /* 30 */ + {{4, 7, 8, 9, 0, 11, 9, 11, 10, 11, 0, 3, -1, -1, -1, -1, -1}, + {2, 3, 5, 4, 7, 8, 0, 3, 11, 10, 9, -1, -1, -1, -1, -1, -1}}, + + {{4, 7, 11, 4, 11, 9, 9, 11, 10, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 5, 4, 7,11,10, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 3, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{9, 5, 4, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {2, 3, 3, 9, 5, 4, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{0, 5, 4, 1, 5, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 4, 0, 1, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + /* 35 */ + {{8, 5, 4, 8, 3, 5, 3, 1, 5, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 5, 3, 1, 5, 4, 8,-1,-1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{1, 2, 10, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {2, 3, 3, 1, 2,10, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{3, 0, 8, 1, 2, 10, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1, -1}, + {3, 3, 3, 3, 3, 0, 8, 1, 2, 10, 4, 9, 5, -1, -1, -1, -1}}, + + {{5, 2, 10, 5, 4, 2, 4, 0, 2, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 5, 4, 0, 2,10, 5,-1,-1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{2, 10, 5, 3, 2, 5, 3, 5, 4, 3, 4, 8, -1, -1, -1, -1, -1}, + {2, 4, 4, 2, 10, 5, 3, 4, 8, 3, 5, -1, -1, -1, -1, -1, -1}}, + + /* 40 */ + {{9, 5, 4, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {2, 3, 3, 9, 5, 4, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{0, 11, 2, 0, 8, 11, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1, -1}, + {2, 4, 3, 0, 8, 11, 2, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1}}, + + {{0, 5, 4, 0, 1, 5, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1}, + {2, 4, 3, 0, 1, 5, 4, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1}}, + + {{2, 1, 5, 2, 5, 8, 2, 8, 11, 4, 8, 5, -1, -1, -1, -1, -1}, + {1, 6, 2, 1, 5, 4, 8,11, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{10, 3, 11, 10, 1, 3, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1}, + { 2, 4, 3, 3,11,10, 1, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1}}, + + /* 45 */ + {{4, 9, 5, 0, 8, 1, 8, 10, 1, 8, 11, 10, -1, -1, -1, -1, -1}, + {2, 3, 5, 4, 9, 5, 1, 0, 8,11, 10, -1, -1, -1, -1, -1, -1}}, + + {{5, 4, 0, 5, 0, 11, 5, 11, 10, 11, 0, 3, -1, -1, -1, -1, -1}, + {1, 6, 5, 4, 0, 3,11, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{5, 4, 8, 5, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 5, 5, 4, 8, 11, 10,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{9, 7, 8, 5, 7, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 4, 7, 8, 9, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{9, 3, 0, 9, 5, 3, 5, 7, 3, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 5, 5, 7, 3, 0, 9,-1,-1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + /* 50 */ + {{0, 7, 8, 0, 1, 7, 1, 5, 7, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 5, 1, 5, 7, 8, 0,-1,-1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{1, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 4, 3, 1, 5, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{9, 7, 8, 9, 5, 7, 10, 1, 2, -1, -1, -1, -1, -1, -1, -1, -1}, + {2, 4, 3, 7, 8, 9, 5,10, 1, 2, -1, -1, -1, -1, -1, -1, -1}}, + + {{10, 1, 2, 9, 5, 0, 5, 3, 0, 5, 7, 3, -1, -1, -1, -1, -1}, + { 2, 3, 5,10, 1, 2, 0, 9, 5, 7, 3,-1, -1, -1, -1, -1, -1}}, + + {{8, 0, 2, 8, 2, 5, 8, 5, 7, 10, 5, 2, -1, -1, -1, -1, -1}, + {1, 6, 2,10, 5, 7, 8, 0,-1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + /* 55 */ + {{2, 10, 5, 2, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 5, 2,10, 5, 7, 3,-1,-1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{7, 9, 5, 7, 8, 9, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1}, + {2, 4, 3, 7, 8, 9, 5, 3,11, 2, -1, -1, -1, -1, -1, -1, -1}}, + + {{9, 5, 7, 9, 7, 2, 9, 2, 0, 2, 7, 11, -1, -1, -1, -1, -1}, + {1, 6, 2, 0, 9, 5, 7,11, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{2, 3, 11, 0, 1, 8, 1, 7, 8, 1, 5, 7, -1, -1, -1, -1, -1}, + {2, 3, 5, 2, 3,11, 8, 0, 1, 5, 7, -1, -1, -1, -1, -1, -1}}, + + {{11, 2, 1, 11, 1, 7, 7, 1, 5, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 5,11, 2, 1, 5, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + /* 60 */ + {{9, 5, 8, 8, 5, 7, 10, 1, 3, 10, 3, 11, -1, -1, -1, -1, -1}, + {2, 4, 4, 3,11, 10, 1, 5, 7, 8, 9, -1, -1, -1, -1, -1, -1}}, + + {{5, 7, 0, 5, 0, 9, 7, 11, 0, 1, 0, 10, 11, 10, 0, -1, -1}, + {1, 7, 5, 7, 11,10, 1, 0, 9, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{11, 10, 0, 11, 0, 3, 10, 5, 0, 8, 0, 7, 5, 7, 0, -1, -1}, + {1, 7, 11,10,5, 7, 8, 0,3, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{11, 10, 5, 7, 11, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + { 1, 4, 5, 7, 11,10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + { 1, 3,10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + /* 65 */ + {{0, 8, 3, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {2, 3, 3, 0, 8, 3, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{9, 0, 1, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {2, 3, 3, 9, 0, 1, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{1, 8, 3, 1, 9, 8, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1}, + {2, 4, 3, 1, 9, 8, 3, 5,10, 6, -1, -1, -1, -1, -1, -1, -1}}, + + {{1, 6, 5, 2, 6, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 4, 1, 2, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{1, 6, 5, 1, 2, 6, 3, 0, 8, -1, -1, -1, -1, -1, -1, -1, -1}, + {2, 4, 3, 1, 2, 6, 5, 3, 0, 8, -1, -1, -1, -1, -1, -1, -1}}, + + /* 70 */ + {{9, 6, 5, 9, 0, 6, 0, 2, 6, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 5, 0, 2, 6, 5, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{5, 9, 8, 5, 8, 2, 5, 2, 6, 3, 2, 8, -1, -1, -1, -1, -1}, + {1, 6, 2, 6, 5, 9, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{2, 3, 11, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {2, 3, 3, 2, 3,11, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{11, 0, 8, 11, 2, 0, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1}, + { 2, 4, 3, 0, 8, 11, 2, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1}}, + + {{0, 1, 9, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1}, + {3, 3, 3, 3, 0, 1, 9, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1}}, + + /* 75 */ + {{5, 10, 6, 1, 9, 2, 9, 11, 2, 9, 8, 11, -1, -1, -1, -1, -1}, + {2, 3, 5, 5,10, 6, 2, 1, 9, 8,11, -1, -1, -1, -1, -1, -1}}, + + {{6, 3, 11, 6, 5, 3, 5, 1, 3, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 5, 5, 1, 3, 11,6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{0, 8, 11, 0, 11, 5, 0, 5, 1, 5, 11, 6, -1, -1, -1, -1, -1}, + {1, 6, 5, 1, 0, 8,11, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{3, 11, 6, 0, 3, 6, 0, 6, 5, 0, 5, 9, -1, -1, -1, -1, -1}, + {2, 4, 4, 3, 11, 6, 0, 5, 9, 0, 6, -1, -1, -1, -1}}, + + {{6, 5, 9, 6, 9, 11, 11, 9, 8, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 5, 6, 5, 9, 8, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + /* 80 */ + {{5, 10, 6, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {2, 3, 3, 5,10, 6, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{4, 3, 0, 4, 7, 3, 6, 5, 10, -1, -1, -1, -1, -1, -1, -1, -1}, + {2, 4, 3, 4, 7, 3, 0, 6, 5, 10, -1, -1, -1, -1, -1, -1, -1}}, + + {{1, 9, 0, 5, 10, 6, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1}, + {3, 3, 3, 3, 1, 9, 0, 5,10, 6, 8, 4, 7, -1, -1, -1, -1}}, + + {{10, 6, 5, 1, 9, 7, 1, 7, 3, 7, 9, 4, -1, -1, -1, -1, -1}, + { 2, 3, 5,10, 6, 5, 9, 4, 7, 3, 1,-1, -1, -1, -1, -1, -1}}, + + {{6, 1, 2, 6, 5, 1, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1}, + {2, 4, 3, 1, 2, 6, 5, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1}}, + + /* 85 */ + {{1, 2, 5, 5, 2, 6, 3, 0, 4, 3, 4, 7, -1, -1, -1, -1, -1}, + {2, 4, 4, 2, 6, 5, 1, 3, 0, 4, 7, -1, -1, -1, -1, -1, -1}}, + + {{8, 4, 7, 9, 0, 5, 0, 6, 5, 0, 2, 6, -1, -1, -1, -1, -1}, + {2, 3, 5, 8, 4, 7, 5, 9, 0, 2, 6, -1, -1, -1, -1, -1, -1}}, + + {{7, 3, 9, 7, 9, 4, 3, 2, 9, 5, 9, 6, 2, 6, 9, -1, -1}, + {1, 7, 7, 3, 2, 6, 5, 9, 4,-1, -1, -1, -1, -1, -1, -1, -1}}, + + {{3, 11, 2, 7, 8, 4, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1}, + {3, 3, 3, 3, 3,11, 2, 7, 8, 4, 10, 6, 5, -1, -1, -1, -1}}, + + {{5, 10, 6, 4, 7, 2, 4, 2, 0, 2, 7, 11, -1, -1, -1, -1, -1}, + {2, 3, 5, 5,10, 6, 7,11, 2, 0, 4, -1, -1, -1, -1, -1, -1}}, + + /* 90 */ + {{0, 1, 9, 4, 7, 8, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1, -1}, + {4, 3, 3, 3, 3, 0, 1, 9, 4, 7, 8, 2, 3, 11, 5, 10, 6}}, + + {{9, 2, 1, 9, 11, 2, 9, 4, 11, 7, 11, 4, 5, 10, 6, -1, -1}, + {3, 4, 4, 3, 2, 1, 9,11, 4, 7, 11, 9, 5, 10, 6, -1, -1}}, + + {{8, 4, 7, 3, 11, 5, 3, 5, 1, 5, 11, 6, -1, -1, -1, -1, -1}, + {2, 3, 5, 8, 4, 7, 11, 6, 5, 1, 3, -1, -1, -1, -1, -1, -1}}, + + {{5, 1, 11, 5, 11, 6, 1, 0, 11, 7, 11, 4, 0, 4, 11, -1, -1}, + {1, 7, 5, 1, 0, 4, 7,11, 6, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{0, 5, 9, 0, 6, 5, 0, 3, 6, 11, 6, 3, 8, 4, 7, -1, -1}, + {3, 4, 4, 3, 0, 6, 5, 9, 3, 11, 6, 0, 8, 4, 7, -1, -1}}, + + /* 95 */ + {{6, 5, 9, 6, 9, 11, 4, 7, 9, 7, 11, 9, -1, -1, -1, -1, -1}, + {2, 4, 4, 9, 4, 7, 11, 6, 5, 9, 11,-1, -1, -1, -1, -1, -1}}, + + {{10, 4, 9, 6, 4, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + { 1, 4, 4, 9, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{4, 10, 6, 4, 9, 10, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1}, + {2, 4, 3, 4, 9,10, 6, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1}}, + + {{10, 0, 1, 10, 6, 0, 6, 4, 0, -1, -1, -1, -1, -1, -1, -1, -1}, + { 1, 5, 6, 4, 0, 1, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{8, 3, 1, 8, 1, 6, 8, 6, 4, 6, 1, 10, -1, -1, -1, -1, -1}, + {1, 6, 1,10, 6, 4, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + /* 100 */ + {{1, 4, 9, 1, 2, 4, 2, 6, 4, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 5, 2, 6, 4, 9, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{3, 0, 8, 1, 2, 9, 2, 4, 9, 2, 6, 4, -1, -1, -1, -1, -1}, + {2, 3, 5, 3, 0, 8, 9, 1, 2, 6, 4, -1, -1, -1, -1, -1, -1}}, + + {{0, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 4, 2, 6, 4, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{8, 3, 2, 8, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 5, 8, 3, 2, 6, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{10, 4, 9, 10, 6, 4, 11, 2, 3, -1, -1, -1, -1, -1, -1, -1, -1}, + { 2, 4, 3, 10, 6, 4, 9,11, 2, 3, -1, -1, -1, -1, -1, -1, -1}}, + + /* 105 */ + {{0, 8, 2, 2, 8, 11, 4, 9, 10, 4, 10, 6, -1, -1, -1, -1, -1}, + {2, 4, 4, 2, 11, 8, 0, 10, 6, 4, 9, -1, -1, -1, -1, -1, -1}}, + + {{3, 11, 2, 0, 1, 6, 0, 6, 4, 6, 1, 10, -1, -1, -1, -1, -1}, + {2, 3, 5, 3,11, 2, 1, 10,6, 4, 0, -1, -1, -1, -1, -1, -1}}, + + {{6, 4, 1, 6, 1, 10, 4, 8, 1, 2, 1, 11, 8, 11, 1, -1, -1}, + {1, 7, 6, 4, 8,11, 2, 1,10, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{9, 6, 4, 9, 3, 6, 9, 1, 3, 11, 6, 3, -1, -1, -1, -1, -1}, + {1, 6, 3,11, 6, 4, 9, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{8, 11, 1, 8, 1, 0, 11, 6, 1, 9, 1, 4, 6, 4, 1, -1, -1}, + {1, 7, 8,11, 6, 4, 9, 1, 0, -1, -1, -1, -1, -1, -1, -1, -1}}, + + /* 110 */ + {{3, 11, 6, 3, 6, 0, 0, 6, 4, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 5, 3,11, 6, 4, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{6, 4, 8, 11, 6, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 4, 8, 11, 6, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{7, 10, 6, 7, 8, 10, 8, 9, 10, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 5, 8, 9,10, 6, 7,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{0, 7, 3, 0, 10, 7, 0, 9, 10, 6, 7, 10, -1, -1, -1, -1, -1}, + {1, 6, 0, 9, 10, 6, 7, 3, -1,-1,-1, -1, -1, -1, -1, -1, -1}}, + + {{10, 6, 7, 1, 10, 7, 1, 7, 8, 1, 8, 0, -1, -1, -1, -1, -1}, + { 2, 4, 4, 8, 0, 1, 7, 10, 6, 7, 1,-1, -1, -1, -1, -1, -1}}, + + /* 115 */ + {{10, 6, 7, 10, 7, 1, 1, 7, 3, -1, -1, -1, -1, -1, -1, -1, -1}, + { 1, 5, 10, 6, 7, 3, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{1, 2, 6, 1, 6, 8, 1, 8, 9, 8, 6, 7, -1, -1, -1, -1, -1}, + {1, 6, 1, 2, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{2, 6, 9, 2, 9, 1, 6, 7, 9, 0, 9, 3, 7, 3, 9, -1, -1}, + {1, 7, 2, 6, 7, 3, 0, 9, 1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{7, 8, 0, 7, 0, 6, 6, 0, 2, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 5, 7, 8, 0, 2, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{7, 3, 2, 6, 7, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 4, 7, 3, 2, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + /* 120 */ + {{2, 3, 11, 10, 6, 8, 10, 8, 9, 8, 6, 7, -1, -1, -1, -1, -1}, + {2, 3, 5, 2, 3,11, 6, 7, 8, 9,10, -1, -1, -1, -1, -1, -1}}, + + {{2, 0, 7, 2, 7, 11, 0, 9, 7, 6, 7, 10, 9, 10, 7, -1, -1}, + {1, 7, 2, 0, 9,10,6, 7, 11, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{1, 8, 0, 1, 7, 8, 1, 10, 7, 6, 7, 10, 2, 3, 11, -1, -1}, + {3, 4, 4, 3, 8, 0, 1, 7, 10, 6, 7, 1, 11, 2, 3, -1, -1}}, + + {{11, 2, 1, 11, 1, 7, 10, 6, 1, 6, 7, 1, -1, -1, -1, -1, -1}, + { 2, 4, 4, 11, 2, 1,7, 1, 10, 6, 7,-1, -1, -1, -1, -1, -1}}, + + {{8, 9, 6, 8, 6, 7, 9, 1, 6, 11, 6, 3, 1, 3, 6, -1, -1}, + {1, 7, 8, 9, 1, 3, 11, 6, 7,-1, -1, -1, -1, -1, -1, -1, -1}}, + + /* 125 */ + {{0, 9, 1, 11, 6, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {2, 3, 3, 0, 9, 1, 11, 6, 7, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{7, 8, 0, 7, 0, 6, 3, 11, 0, 11, 6, 0, -1, -1, -1, -1, -1}, + {2, 4, 4, 0, 3,11, 6, 7, 8, 0, 6, -1, -1, -1, -1, -1, -1}}, + + {{7, 11, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 3, 7, 11, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 3, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{3, 0, 8, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {2, 3, 3, 3, 0, 8, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1}}, + + /* 130 */ + {{0, 1, 9, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {2, 3, 3, 0, 1, 9, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{8, 1, 9, 8, 3, 1, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1}, + {2, 4, 3, 1, 9, 8, 3,11, 7, 6, -1, -1, -1, -1, -1, -1, -1}}, + + {{10, 1, 2, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + { 2, 3, 3,10, 1, 2, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{1, 2, 10, 3, 0, 8, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1, -1}, + {3, 3, 3, 3, 1, 2,10, 3, 0, 8, 6, 11, 7, -1, -1, -1, -1}}, + + {{2, 9, 0, 2, 10, 9, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1, -1}, + {2, 4, 3, 2, 10, 9, 0, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1}}, + + /* 135 */ + {{6, 11, 7, 2, 10, 3, 10, 8, 3, 10, 9, 8, -1, -1, -1, -1, -1}, + {2, 3, 5, 6, 11, 7, 3, 2,10, 9, 8, -1, -1, -1, -1, -1, -1}}, + + {{7, 2, 3, 6, 2, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 4, 2, 3, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{7, 0, 8, 7, 6, 0, 6, 2, 0, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 5, 6, 2, 0, 8, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{2, 7, 6, 2, 3, 7, 0, 1, 9, -1, -1, -1, -1, -1, -1, -1, -1}, + {2, 4, 3, 2, 3, 7, 6, 0, 1, 9, -1, -1, -1, -1, -1, -1, -1}}, + + {{1, 6, 2, 1, 8, 6, 1, 9, 8, 8, 7, 6, -1, -1, -1, -1, -1}, + {1, 6, 6, 2, 1, 9, 8, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + /* 140 */ + {{10, 7, 6, 10, 1, 7, 1, 3, 7, -1, -1, -1, -1, -1, -1, -1, -1}, + { 1, 5, 1, 3, 7, 6,10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{10, 7, 6, 1, 7, 10, 1, 8, 7, 1, 0, 8, -1, -1, -1, -1, -1}, + { 2, 4, 4, 10, 1, 7, 6, 8, 7, 1, 0,-1, -1, -1, -1, -1, -1}}, + + {{0, 3, 7, 0, 7, 10, 0, 10, 9, 6, 10, 7, -1, -1, -1, -1, -1}, + {1, 6,10, 9, 0, 3, 7, 6,-1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{7, 6, 10, 7, 10, 8, 8, 10, 9, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 5, 7, 6, 10, 9, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{6, 8, 4, 11, 8, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 4, 6, 11, 8, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + /* 145 */ + {{3, 6, 11, 3, 0, 6, 0, 4, 6, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 5, 0, 4, 6,11, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{8, 6, 11, 8, 4, 6, 9, 0, 1, -1, -1, -1, -1, -1, -1, -1, -1}, + {2, 4, 3, 6,11, 8, 4, 9, 0, 1, -1, -1, -1, -1, -1, -1, -1}}, + + {{9, 4, 6, 9, 6, 3, 9, 3, 1, 11, 3, 6, -1, -1, -1, -1, -1}, + {1, 6, 6,11, 3, 1, 9, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{6, 8, 4, 6, 11, 8, 2, 10, 1, -1, -1, -1, -1, -1, -1, -1, -1}, + {2, 4, 3, 6, 11, 8, 4, 2, 10, 1, -1, -1, -1, -1, -1, -1, -1}}, + + {{1, 2, 10, 3, 0, 11, 0, 6, 11, 0, 4, 6, -1, -1, -1, -1, -1}, + {2, 3, 5, 1, 2, 10,11, 3,0,4, 6, -1, -1, -1, -1, -1, -1}}, + + /* 150 */ + {{4, 11, 8, 4, 6, 11, 0, 2, 9, 2, 10, 9, -1, -1, -1, -1, -1}, + {2, 4, 4, 4, 6, 11, 8, 2,10, 9, 0, -1, -1, -1, -1, -1, -1}}, + + {{10, 9, 3, 10, 3, 2, 9, 4, 3, 11, 3, 6, 4, 6, 3, -1, -1}, + {1, 7, 10,9, 4, 6, 11, 3, 2, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{8, 2, 3, 8, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 5, 4, 6, 2, 3, 8,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{0, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 4, 4, 6, 2, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{1, 9, 0, 2, 3, 4, 2, 4, 6, 4, 3, 8, -1, -1, -1, -1, -1}, + {2, 3, 5, 1, 9, 0, 3, 8, 4, 6, 2, -1, -1, -1, -1, -1, -1}}, + + /* 155 */ + {{1, 9, 4, 1, 4, 2, 2, 4, 6, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 5, 1, 9, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{8, 1, 3, 8, 6, 1, 8, 4, 6, 6, 10, 1, -1, -1, -1, -1, -1}, + {1, 6, 1, 3, 8, 4, 6,10, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{10, 1, 0, 10, 0, 6, 6, 0, 4, -1, -1, -1, -1, -1, -1, -1, -1}, + { 1, 5,10, 1,0,4,6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{4, 6, 3, 4, 3, 8, 6, 10, 3, 0, 3, 9, 10, 9, 3, -1, -1}, + {1, 7, 4, 6, 10, 9, 0,3, 8, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{10, 9, 4, 6, 10, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + { 1, 4, 4, 6, 10, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + /* 160 */ + {{4, 9, 5, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {2, 3, 3, 4, 9, 5, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{0, 8, 3, 4, 9, 5, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1}, + {3, 3, 3, 3, 0, 8, 3, 4, 9, 5, 11, 7, 6, -1, -1, -1, -1}}, + + {{5, 0, 1, 5, 4, 0, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1}, + {2, 4, 3, 0, 1, 5, 4, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1}}, + + {{11, 7, 6, 8, 3, 4, 3, 5, 4, 3, 1, 5, -1, -1, -1, -1, -1}, + { 2, 3, 5,11, 7, 6, 4, 8, 3, 1, 5,-1, -1, -1, -1, -1, -1}}, + + {{9, 5, 4, 10, 1, 2, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1}, + {3, 3, 3, 3, 9, 5, 4,10, 1, 2, 7, 6, 11, -1, -1, -1, -1}}, + + /* 165 */ + {{6, 11, 7, 1, 2, 10, 0, 8, 3, 4, 9, 5, -1, -1, -1, -1, -1}, + {4, 3, 3, 3, 3, 6,11, 7, 1, 2,10, 0, 8, 3, 4, 9, 5}}, + + {{7, 6, 11, 5, 4, 10, 4, 2, 10, 4, 0, 2, -1, -1, -1, -1, -1}, + {2, 3, 5, 7, 6, 11, 10, 5, 4, 0, 2,-1, -1, -1, -1, -1, -1}}, + + {{3, 4, 8, 3, 5, 4, 3, 2, 5, 10, 5, 2, 11, 7, 6, -1, -1}, + {3, 4, 4, 3, 5, 3, 2,10, 4, 8, 3, 5, 6, 11, 7, 6, -1}}, + + {{7, 2, 3, 7, 6, 2, 5, 4, 9, -1, -1, -1, -1, -1, -1, -1, -1}, + {2, 4, 3, 2, 3, 7, 6, 5, 4, 9, -1, -1, -1, -1, -1, -1, -1}}, + + {{9, 5, 4, 0, 8, 6, 0, 6, 2, 6, 8, 7, -1, -1, -1, -1, -1}, + {2, 3, 5, 9, 5, 4, 8, 7, 6, 2, 0, -1, -1, -1, -1, -1, -1}}, + + /* 170 */ + {{3, 6, 2, 3, 7, 6, 1, 5, 0, 5, 4, 0, -1, -1, -1, -1, -1}, + {2, 4, 4, 3, 7, 6, 2, 0, 1, 5, 4, -1, -1, -1, -1, -1, -1}}, + + {{6, 2, 8, 6, 8, 7, 2, 1, 8, 4, 8, 5, 1, 5, 8, -1, -1}, + {1, 7, 6, 2, 1, 5, 4, 8, 7,-1, -1, -1, -1, -1, -1, -1, -1}}, + + {{9, 5, 4, 10, 1, 6, 1, 7, 6, 1, 3, 7, -1, -1, -1, -1, -1}, + {2, 3, 5, 9, 5, 4, 6,10, 1, 3, 7,-1, -1, -1, -1, -1, -1}}, + + {{1, 6, 10, 1, 7, 6, 1, 0, 7, 8, 7, 0, 9, 5, 4, -1, -1}, + {3, 4, 4, 3, 0, 8, 7, 1, 6, 10, 1, 7, 9, 5, 4, -1, -1}}, + + {{4, 0, 10, 4, 10, 5, 0, 3, 10, 6, 10, 7, 3, 7, 10, -1, -1}, + {1, 7, 4, 0, 3, 7, 6, 10, 5, -1, -1, -1, -1, -1, -1, -1, -1}}, + + /* 175 */ + {{7, 6, 10, 7, 10, 8, 5, 4, 10, 4, 8, 10, -1, -1, -1, -1, -1}, + {2, 4, 4, 4, 8, 10, 5, 7, 6,10, 8, -1, -1, -1, -1, -1, -1}}, + + {{6, 9, 5, 6, 11, 9, 11, 8, 9, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 5,11, 8, 9, 5, 6,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{3, 6, 11, 0, 6, 3, 0, 5, 6, 0, 9, 5, -1, -1, -1, -1, -1}, + {2, 4, 4, 0, 9, 5, 6, 6,11, 3, 0, -1, -1, -1, -1, -1, -1}}, + + {{0, 11, 8, 0, 5, 11, 0, 1, 5, 5, 6, 11, -1, -1, -1, -1, -1}, + {1, 6, 0, 1, 5, 6,11, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{6, 11, 3, 6, 3, 5, 5, 3, 1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 5, 6,11, 3, 1, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + /*180 */ + {{1, 2, 10, 9, 5, 11, 9, 11, 8, 11, 5, 6, -1, -1, -1, -1, -1}, + {2, 3, 5, 1, 2, 10, 5, 6,11, 8, 9, -1, -1, -1, -1, -1, -1}}, + + {{0, 11, 3, 0, 6, 11, 0, 9, 6, 5, 6, 9, 1, 2, 10, -1, -1}, + {3, 4, 4, 3, 11, 3,0, 6, 9, 5, 6, 0, 2, 10, 1, 2, 10}}, + + {{11, 8, 5, 11, 5, 6, 8, 0, 5, 10, 5, 2, 0, 2, 5, -1, -1}, + { 1, 7,11, 8, 0, 2,10, 5, 6,-1, -1, -1, -1, -1, -1, -1, -1}}, + + {{6, 11, 3, 6, 3, 5, 2, 10, 3, 10, 5, 3, -1, -1, -1, -1, -1}, + {2, 4, 4, 6,11, 3, 5, 10, 5, 3, 2, -1, -1, -1, -1, -1, -1}}, + + {{5, 8, 9, 5, 2, 8, 5, 6, 2, 3, 8, 2, -1, -1, -1, -1, -1}, + {1, 6, 2, 3, 8, 9, 5, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + /* 185 */ + {{9, 5, 6, 9, 6, 0, 0, 6, 2, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 5, 9, 5, 6, 2, 0,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{1, 5, 8, 1, 8, 0, 5, 6, 8, 3, 8, 2, 6, 2, 8, -1, -1}, + {1, 7, 1, 5, 6, 2, 3, 8, 0, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{1, 5, 6, 2, 1, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 4, 1, 5, 6, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{1, 3, 6, 1, 6, 10, 3, 8, 6, 5, 6, 9, 8, 9, 6, -1, -1}, + {1, 7, 1, 3, 8, 9, 5, 6,10, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{10, 1, 0, 10, 0, 6, 9, 5, 0, 5, 6, 0, -1, -1, -1, -1, -1}, + { 2, 4, 4, 5, 6, 0, 9, 10, 1, 0, 6, -1, -1, -1, -1, -1, -1}}, + + /* 190 */ + {{0, 3, 8, 5, 6, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {2, 3, 3, 0, 3, 8, 5, 6, 10, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{10, 5, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + { 1, 3,10, 5, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{11, 5, 10, 7, 5, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + { 1, 4, 5,10, 11, 7,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{11, 5, 10, 11, 7, 5, 8, 3, 0, -1, -1, -1, -1, -1, -1, -1, -1}, + { 2, 4, 3, 5,10,11, 7, 8, 3, 0, -1, -1, -1, -1, -1, -1, -1}}, + + {{5, 11, 7, 5, 10, 11, 1, 9, 0, -1, -1, -1, -1, -1, -1, -1, -1}, + { 2, 4, 3, 5, 10, 11, 7, 1, 9, 0, -1, -1, -1, -1, -1, -1, -1}}, + + /* 195 */ + {{10, 7, 5, 10, 11, 7, 9, 8, 1, 8, 3, 1, -1, -1, -1, -1, -1}, + { 2, 4, 4, 10, 11, 7, 5, 1, 9, 8, 3, -1, -1, -1, -1, -1, -1}}, + + {{11, 1, 2, 11, 7, 1, 7, 5, 1, -1, -1, -1, -1, -1, -1, -1, -1}, + { 1, 5, 7, 5, 1, 2,11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{0, 8, 3, 1, 2, 7, 1, 7, 5, 7, 2, 11, -1, -1, -1, -1, -1}, + {2, 3, 5, 0, 8, 3, 2,11, 7, 5,1, -1, -1, -1, -1, -1, -1}}, + + {{9, 7, 5, 9, 2, 7, 9, 0, 2, 2, 11, 7, -1, -1, -1, -1, -1}, + {1, 6, 2,11, 7, 5, 9, 0,-1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{7, 5, 2, 7, 2, 11, 5, 9, 2, 3, 2, 8, 9, 8, 2, -1, -1}, + {1, 7, 7, 5, 9, 8, 3, 2,11,-1, -1, -1, -1, -1, -1, -1, -1}}, + + /* 200 */ + {{2, 5, 10, 2, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 5, 3, 7, 5,10, 2,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{8, 2, 0, 8, 5, 2, 8, 7, 5, 10, 2, 5, -1, -1, -1, -1, -1}, + {1, 6, 5,10, 2, 0, 8, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{9, 0, 1, 5, 10, 3, 5, 3, 7, 3, 10, 2, -1, -1, -1, -1, -1}, + {2, 3, 5, 9, 0, 1, 10, 2, 3, 7, 5, -1, -1, -1, -1, -1, -1}}, + + {{9, 8, 2, 9, 2, 1, 8, 7, 2, 10, 2, 5, 7, 5, 2, -1, -1}, + {1, 7, 9, 8, 7, 5,10, 2, 1,-1, -1, -1, -1, -1, -1, -1, -1}}, + + {{1, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 4, 3, 7, 5, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + /* 205 */ + {{0, 8, 7, 0, 7, 1, 1, 7, 5, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 5, 0, 8, 7, 5, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{9, 0, 3, 9, 3, 5, 5, 3, 7, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 5, 9, 0, 3, 7, 5,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{9, 8, 7, 5, 9, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 4, 7, 5, 9, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{5, 8, 4, 5, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 5, 10,11, 8, 4, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{5, 0, 4, 5, 11, 0, 5, 10, 11, 11, 3, 0, -1, -1, -1, -1, -1}, + {1, 6, 0, 4, 5,10,11, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + /* 210 */ + {{0, 1, 9, 8, 4, 10, 8, 10, 11, 10, 4, 5, -1, -1, -1, -1, -1}, + {2, 3, 5, 0, 1, 9, 4, 5, 10, 11, 8, -1, -1, -1, -1, -1, -1}}, + + {{10, 11, 4, 10, 4, 5, 11, 3, 4, 9, 4, 1, 3, 1, 4, -1, -1}, + { 1, 7,10, 11, 3, 1, 9,4, 5,-1, -1, -1, -1, -1, -1, -1}}, + + {{2, 5, 1, 2, 8, 5, 2, 11, 8, 4, 5, 8, -1, -1, -1, -1, -1}, + {1, 6, 2,11, 8, 4, 5, 1,-1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{0, 4, 11, 0, 11, 3, 4, 5, 11, 2, 11, 1, 5, 1, 11, -1, -1}, + {1, 7, 0, 4, 5, 1, 2, 11, 3,-1, -1, -1, -1, -1, -1, -1, -1}}, + + {{0, 2, 5, 0, 5, 9, 2, 11, 5, 4, 5, 8, 11, 8, 5, -1, -1}, + {1, 7, 0, 2,11, 8, 4, 5, 9, -1, -1, -1, -1, -1, -1, -1, -1}}, + + /* 215 */ + {{9, 4, 5, 2, 11, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {2, 3, 3, 9, 4, 5, 2, 11, 3, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{2, 5, 10, 3, 5, 2, 3, 4, 5, 3, 8, 4, -1, -1, -1, -1, -1}, + {2, 4, 4, 2, 3, 5, 10, 4, 5, 3, 8,-1, -1, -1, -1, -1, -1}}, + + {{5, 10, 2, 5, 2, 4, 4, 2, 0, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 5, 5,10, 2, 0, 4,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{3, 10, 2, 3, 5, 10, 3, 8, 5, 4, 5, 8, 0, 1, 9, -1, -1}, + {3, 4, 4, 3, 3, 5, 10, 2, 8, 4, 5, 3, 0, 1, 9, -1, -1}}, + + {{5, 10, 2, 5, 2, 4, 1, 9, 2, 9, 4, 2, -1, -1, -1, -1, -1}, + {1, 6,10, 2, 1, 9, 4, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + /* 220 */ + {{8, 4, 5, 8, 5, 3, 3, 5, 1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 5, 8, 4, 5, 1, 3,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{0, 4, 5, 1, 0, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 4, 0, 4, 5, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{8, 4, 5, 8, 5, 3, 9, 0, 5, 0, 3, 5, -1, -1, -1, -1, -1}, + {2, 4, 4, 0, 3, 5, 9, 8, 4, 5, 3, -1, -1, -1, -1, -1, -1}}, + + {{9, 4, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 3, 9, 4, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{4, 11, 7, 4, 9, 11, 9, 10, 11, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 5, 9,10, 11, 7, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + /* 225 */ + {{0, 8, 3, 4, 9, 7, 9, 11, 7, 9, 10, 11, -1, -1, -1, -1, -1}, + {2, 3, 5, 0, 8, 3, 7, 4, 9, 10, 11, -1, -1, -1, -1, -1, -1}}, + + {{1, 10, 11, 1, 11, 4, 1, 4, 0, 7, 4, 11, -1, -1, -1, -1, -1}, + {1, 6, 1, 10,11, 7, 4, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{3, 1, 4, 3, 4, 8, 1, 10, 4, 7, 4, 11, 10, 11, 4, -1, -1}, + {1, 7, 3, 1,10,11, 7, 4, 8, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{4, 11, 7, 9, 11, 4, 9, 2, 11, 9, 1, 2, -1, -1, -1, -1, -1}, + {2, 4, 4, 2, 11, 9, 1, 4, 9, 11, 7, -1, -1, -1, -1, -1, -1}}, + + {{9, 7, 4, 9, 11, 7, 9, 1, 11, 2, 11, 1, 0, 8, 3, -1, -1}, + {3, 4, 4, 3, 1, 2, 11, 9, 7, 4, 9,11, 8, 3, 0, 8, 3}}, + + /* 230 */ + {{11, 7, 4, 11, 4, 2, 2, 4, 0, -1, -1, -1, -1, -1, -1, -1, -1}, + { 1, 5, 11, 7, 4, 0, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{11, 7, 4, 11, 4, 2, 8, 3, 4, 3, 2, 4, -1, -1, -1, -1, -1}, + { 2, 4, 4, 11, 7, 4, 2, 3, 2, 4, 8,-1, -1, -1, -1, -1, -1}}, + + {{2, 9, 10, 2, 7, 9, 2, 3, 7, 7, 4, 9, -1, -1, -1, -1, -1}, + {1, 6, 2, 3, 7, 4, 9,10, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{9, 10, 7, 9, 7, 4, 10, 2, 7, 8, 7, 0, 2, 0, 7, -1, -1}, + {1, 7, 9,10, 2, 0, 8, 7, 4,-1, -1, -1, -1, -1, -1, -1, -1}}, + + {{3, 7, 10, 3, 10, 2, 7, 4, 10, 1, 10, 0, 4, 0, 10, -1, -1}, + {1, 7, 3, 7, 4, 0, 1,10, 2, -1, -1, -1, -1, -1, -1, -1, -1}}, + + /* 235 */ + {{1, 10, 2, 8, 7, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {2, 3, 3, 1,10, 2, 8, 7, 4, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{4, 9, 1, 4, 1, 7, 7, 1, 3, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 5, 4, 9, 1, 3, 7,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{4, 9, 1, 4, 1, 7, 0, 8, 1, 8, 7, 1, -1, -1, -1, -1, -1}, + {2, 4, 4, 8, 7, 1, 0, 4, 9, 1, 7, -1, -1, -1, -1, -1, -1}}, + + {{4, 0, 3, 7, 4, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 4, 3, 7, 4, 0,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{4, 8, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 3, 4, 8, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + /* 240 */ + {{9, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 4, 8, 9, 10,11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{3, 0, 9, 3, 9, 11, 11, 9, 10, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 5, 3, 0, 9, 10, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{0, 1, 10, 0, 10, 8, 8, 10, 11, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 5, 0, 1, 10,11, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{3, 1, 10, 11, 3, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 4, 3, 1,10, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{1, 2, 11, 1, 11, 9, 9, 11, 8, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 5, 1, 2, 11, 8, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + /* 245 */ + {{3, 0, 9, 3, 9, 11, 1, 2, 9, 2, 11, 9, -1, -1, -1, -1, -1}, + {2, 4, 4, 2,11, 9, 1, 3, 0, 9, 11, -1, -1, -1, -1, -1,-1}}, + + {{0, 2, 11, 8, 0, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 4, 0, 2,11, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{3, 2, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 3, 3, 2, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{2, 3, 8, 2, 8, 10, 10, 8, 9, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 5, 2, 3, 8, 9, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{9, 10, 2, 0, 9, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 4, 2, 0, 9,10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + /* 250 */ + {{2, 3, 8, 2, 8, 10, 0, 1, 8, 1, 10, 8, -1, -1, -1, -1, -1}, + {2, 4, 4, 2, 3, 8, 10, 1, 10, 8, 0, -1, -1, -1, -1, -1, -1}}, + + {{1, 10, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 3, 1, 10, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{1, 3, 8, 9, 1, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 4, 1, 3, 8, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{0, 9, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 3, 0, 9, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{0, 3, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 3, 0, 3, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + + {{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + { 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}} +}; + + +//----------------------------------------------------------------------------- + + +const int polyTable[8][16] = +{ + {-1}, + {-1}, + {-1}, + {0, 1, 2, -1}, + {0, 1, 2, 2, 3, 0, -1}, + {0, 1, 2, 0, 2, 4, 4, 2, 3, -1}, + {0, 1, 2, 2, 3, 4, 4, 5, 0, 0, 2, 4, -1}, + {0, 1, 5, 0, 5, 6, 1, 2, 5, 4, 5, 3, 2, 3, 5, -1} +}; + + +//============================================================================= + + +//============================================================================= +#endif // ISOEX_MC_TABLES_HH defined +//============================================================================= diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/opengl2/render_to_tga.cpp b/src/external/libigl-2.3.0/include/igl/copyleft/opengl2/render_to_tga.cpp new file mode 100644 index 000000000..452eade7c --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/opengl2/render_to_tga.cpp @@ -0,0 +1,88 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "render_to_tga.h" +#include "tga.h" + +#include "../../opengl2/gl.h" + +#include + +IGL_INLINE bool igl::opengl::render_to_tga( + const std::string tga_file, + const int width, + const int height, + const bool alpha) +{ + + size_t components = 3; + GLenum format = GL_BGR; + if(alpha) + { + format = GL_BGRA; + components = 4; + } + GLubyte * cmap = NULL; + + // OpenGL by default tries to read data in multiples of 4, if our data is + // only RGB or BGR and the width is not divible by 4 then we need to alert + // opengl + if((width % 4) != 0 && + (format == GL_RGB || + format == GL_BGR)) + { + glPixelStorei(GL_PACK_ALIGNMENT, 1); + } + GLubyte *pixels; + pixels = (unsigned char *) malloc (width * height * components); + glReadPixels( + 0, + 0, + width, + height, + format, + GL_UNSIGNED_BYTE, + pixels); + + // set up generic image struct + gliGenericImage * genericImage; + genericImage = (gliGenericImage*) malloc(sizeof(gliGenericImage)); + genericImage->width = width; + genericImage->height = height; + genericImage->format = format; + genericImage->components = components; + genericImage->pixels = pixels; + // CMAP is not supported, but we need to put something here + genericImage->cmapEntries = 0; + genericImage->cmapFormat = GL_BGR; + genericImage->cmap = cmap; + + // write pixels to tga file + FILE * imgFile; + // "-" as output file name is code for write to stdout + if(tga_file.compare("-") == 0) + { + imgFile = stdout; + }else{ + imgFile = fopen(tga_file.c_str(),"w"); + if(NULL==imgFile) + { + printf("IOError: %s could not be opened...\n",tga_file.c_str()); + free(genericImage); + return false; + } + } + + writeTGA(genericImage,imgFile); + + free(genericImage); + return fclose(imgFile) == 0; +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/opengl2/render_to_tga.h b/src/external/libigl-2.3.0/include/igl/copyleft/opengl2/render_to_tga.h new file mode 100644 index 000000000..d792c1e31 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/opengl2/render_to_tga.h @@ -0,0 +1,38 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_OPENGL_RENDER_TO_TGA_H +#define IGL_OPENGL_RENDER_TO_TGA_H +#include "../../igl_inline.h" +#include + +namespace igl +{ + namespace opengl + { + // Render current open GL image to .tga file + // Inputs: + // tga_file path to output .tga file + // width width of scene and resulting image + // height height of scene and resulting image + /// alpha whether to include alpha channel + // Returns true only if no errors occurred + // + // See also: png/render_to_png which is slower but writes .png files + IGL_INLINE bool render_to_tga( + const std::string tga_file, + const int width, + const int height, + const bool alpha); + } +} + +#ifndef IGL_STATIC_LIBRARY +# include "render_to_tga.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/opengl2/texture_from_tga.cpp b/src/external/libigl-2.3.0/include/igl/copyleft/opengl2/texture_from_tga.cpp new file mode 100644 index 000000000..717a6734c --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/opengl2/texture_from_tga.cpp @@ -0,0 +1,68 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "texture_from_tga.h" +#include "tga.h" +#include + +IGL_INLINE bool igl::opengl::texture_from_tga(const std::string tga_file, GLuint & id) +{ + using namespace std; + + // read pixels to tga file + FILE * imgFile; + // "-" as input file name is code for read from stdin + imgFile = fopen(tga_file.c_str(),"r"); + if(NULL==imgFile) + { + printf("IOError: %s could not be opened...",tga_file.c_str()); + return false; + } + + // gliReadTGA annoyingly uses char * instead of const char * + size_t len = tga_file.length(); + char* tga_file_char = new char [ len + 1 ]; + strcpy( tga_file_char, tga_file.c_str() ); + // read image + gliGenericImage* img = gliReadTGA(imgFile, tga_file_char, 0, 0); + // clean up filename buffer + delete[] tga_file_char; + fclose( imgFile ); + + // set up texture mapping parameters and generate texture id + glGenTextures(1,&id); + glBindTexture(GL_TEXTURE_2D, id); + // Texture parameters + float empty[] = {1.0f,1.0f,1.0f,0.0f}; + glTexParameterfv(GL_TEXTURE_2D,GL_TEXTURE_BORDER_COLOR,empty); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); + //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, + // GL_LINEAR_MIPMAP_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, + GL_LINEAR); + + // OpenGL by default tries to read data in multiples of 4, if our data is + // only RGB or BGR and the width is not divible by 4 then we need to alert + // opengl + if((img->width % 4) != 0 && + (img->format == GL_RGB || + img->format == GL_BGR)) + { + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + } + + // Load texture + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, img->width, + img->height, 0, img->format, GL_UNSIGNED_BYTE, + img->pixels); + return id; +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/opengl2/texture_from_tga.h b/src/external/libigl-2.3.0/include/igl/copyleft/opengl2/texture_from_tga.h new file mode 100644 index 000000000..8a5f704c7 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/opengl2/texture_from_tga.h @@ -0,0 +1,33 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_OPENGL_TEXTURE_FROM_TGA_H +#define IGL_OPENGL_TEXTURE_FROM_TGA_H +#include "../../igl_inline.h" +#include "../../opengl2/gl.h" +#include + +namespace igl +{ + namespace opengl + { + // Read an image from a .tga file and use it as a texture + // + // Input: + // tga_file path to .tga file + // Output: + // id of generated openGL texture + // Returns true on success, false on failure + IGL_INLINE bool texture_from_tga(const std::string tga_file, GLuint & id); + } +} + +#ifndef IGL_STATIC_LIBRARY +# include "texture_from_tga.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/opengl2/tga.cpp b/src/external/libigl-2.3.0/include/igl/copyleft/opengl2/tga.cpp new file mode 100644 index 000000000..9fedbf228 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/opengl2/tga.cpp @@ -0,0 +1,550 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// WARNING +// +// THIS DOES NOT DEAL WITH VERTICALLY FLIPPED DATA CORRECTLY +// +//////////////////////////////////////////////////////////////////////////////// + +/* This file is derived from (actually an earlier version of)... */ + +/* The GIMP -- an image manipulation program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * $Id: tga.cpp,v 1.1.2.5 2007-05-10 02:10:07 elif Exp $ + * TrueVision Targa loading and saving file filter for the Gimp. + * Targa code Copyright (C) 1997 Raphael FRANCOIS and Gordon Matzigkeit + * + * The Targa reading and writing code was written from scratch by + * Raphael FRANCOIS and Gordon Matzigkeit + * based on the TrueVision TGA File Format + * Specification, Version 2.0: + * + * + * + * It does not contain any code written for other TGA file loaders. + * Not even the RLE handling. ;) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "tga.h" +#include "../../opengl2/glext.h" +#include +#include +#include +#include + +static char error[256]; +static unsigned int _verbose = 0; +static int totbytes = 0; + +typedef struct { + unsigned char *statebuf; + int statelen; + int laststate; +} RLEstate; + +IGL_INLINE static int +std_fread(RLEstate * /*rleInfo*/, unsigned char *buf, size_t datasize, size_t nelems, FILE *fp) +{ + if (_verbose > 1) { + totbytes += nelems * datasize; + printf("TGA: std_fread %d (total %d)\n", + (int)(nelems * datasize), totbytes); + } + return fread(buf, datasize, nelems, fp); +} + +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) + +#define RLE_PACKETSIZE 0x80 + +/* Decode a bufferful of file. */ +IGL_INLINE static int +rle_fread(RLEstate *rleInfo, unsigned char *vbuf, size_t datasize, size_t nelems, FILE *fp) +{ + + unsigned char *buf = vbuf; + int j, k; + int buflen, count, bytes, curbytes; + unsigned char *p; + + /* Scale the buffer length. */ + buflen = nelems * datasize; + + j = 0; + curbytes = totbytes; + while (j < buflen) { + if (rleInfo->laststate < rleInfo->statelen) { + /* Copy bytes from our previously decoded buffer. */ + bytes = MIN(buflen - j, rleInfo->statelen - rleInfo->laststate); + memcpy(buf + j, rleInfo->statebuf + rleInfo->laststate, bytes); + j += bytes; + rleInfo->laststate += bytes; + + /* If we used up all of our state bytes, then reset them. */ + if (rleInfo->laststate >= rleInfo->statelen) { + rleInfo->laststate = 0; + rleInfo->statelen = 0; + } + + /* If we filled the buffer, then exit the loop. */ + if (j >= buflen) break; + } + + /* Decode the next packet. */ + count = fgetc(fp); + if (count == EOF) { + if (_verbose) printf("TGA: hit EOF while looking for count\n"); + return j / datasize; + } + + /* Scale the byte length to the size of the data. */ + bytes = ((count & ~RLE_PACKETSIZE) + 1) * datasize; + + if (j + bytes <= buflen) { + /* We can copy directly into the image buffer. */ + p = buf + j; + } else { +#ifdef PROFILE + printf("TGA: needed to use statebuf for %d bytes\n", buflen - j); +#endif + /* Allocate the state buffer if we haven't already. */ + if (!rleInfo->statebuf) { + rleInfo->statebuf = (unsigned char *) malloc(RLE_PACKETSIZE * datasize); + } + p = rleInfo->statebuf; + } + + if (count & RLE_PACKETSIZE) { + /* Fill the buffer with the next value. */ + if (fread(p, datasize, 1, fp) != 1) { + if (_verbose) { + printf("TGA: EOF while reading %d/%d element RLE packet\n", + bytes, (int)datasize); + } + return j / datasize; + } + + /* Optimized case for single-byte encoded data. */ + if (datasize == 1) { + memset(p + 1, *p, bytes - 1); + } else { + for (k = datasize; k < bytes; k += datasize) { + memcpy(p + k, p, datasize); + } + } + } else { + /* Read in the buffer. */ + if (fread(p, bytes, 1, fp) != 1) { + if (_verbose) { + printf("TGA: EOF while reading %d/%d element raw packet\n", + bytes, (int)datasize); + } + return j / datasize; + } + } + + if (_verbose > 1) { + totbytes += bytes; + if (_verbose > 2) { + printf("TGA: %s packet %d/%d\n", + (count & RLE_PACKETSIZE) ? "RLE" : "raw", + bytes, totbytes); + } + } + + /* We may need to copy bytes from the state buffer. */ + if (p == rleInfo->statebuf) { + rleInfo->statelen = bytes; + } else { + j += bytes; + } + } + + if (_verbose > 1) { + printf("TGA: rle_fread %d/%d (total %d)\n", + (int) ( nelems * datasize), totbytes - curbytes, totbytes); + } + return nelems; +} + +IGL_INLINE igl::opengl::gliGenericImage * +igl::opengl::gliReadTGA(FILE *fp, char *name, int /*hflip*/, int vflip) +{ + igl::opengl::TgaHeader tgaHeader; + igl::opengl::TgaFooter tgaFooter; + char horzrev, vertrev; + int width, height, bpp; + int start, end, dir; + int i, j, k; + int pelbytes, wbytes; + GLenum format; + int components; + RLEstate rleRec; + RLEstate *rleInfo; + int rle; + int index, colors, length; + GLubyte *cmap, *pixels, *data; + int (*myfread)(RLEstate *rleInfo, unsigned char*, size_t, size_t, FILE*); + igl::opengl::gliGenericImage *genericImage; + + /* Check the footer. */ + if (fseek(fp, 0L - sizeof(tgaFooter), SEEK_END) + || fread(&tgaFooter, sizeof(tgaFooter), 1, fp) != 1) { + sprintf(error, "TGA: Cannot read footer from \"%s\"", name); + if (_verbose) printf("%s\n", error); + return NULL; + } + + /* Check the signature. */ + if (memcmp(tgaFooter.signature, TGA_SIGNATURE, + sizeof(tgaFooter.signature)) == 0) { + if (_verbose) printf("TGA: found New TGA\n"); + } else { + if (_verbose) printf("TGA: found Original TGA\n"); + } + + if (fseek(fp, 0, SEEK_SET) || + fread(&tgaHeader, sizeof(tgaHeader), 1, fp) != 1) { + sprintf(error, "TGA: Cannot read header from \"%s\"", name); + if (_verbose) printf("%s\n", error); + return NULL; + } + + if (_verbose && tgaHeader.idLength) { + char *idString = (char*) malloc(tgaHeader.idLength); + + if (fread(idString, tgaHeader.idLength, 1, fp) != 1) { + sprintf(error, "TGA: Cannot read ID field in \"%s\"", name); + printf("%s\n", error); + } else { + printf("TGA: ID field: \"%*s\"\n", tgaHeader.idLength, idString); + } + free(idString); + } else { + /* Skip the image ID field. */ + if (tgaHeader.idLength && fseek(fp, tgaHeader.idLength, SEEK_CUR)) { + sprintf(error, "TGA: Cannot skip ID field in \"%s\"", name); + if (_verbose) printf("%s\n", error); + return NULL; + } + } + + /* Reassemble the multi-byte values correctly, regardless of + host endianness. */ + width = (tgaHeader.widthHi << 8) | tgaHeader.widthLo; + height = (tgaHeader.heightHi << 8) | tgaHeader.heightLo; + bpp = tgaHeader.bpp; + if (_verbose) { + printf("TGA: width=%d, height=%d, bpp=%d\n", width, height, bpp); + } + + horzrev = tgaHeader.descriptor & TGA_DESC_HORIZONTAL; + vertrev = tgaHeader.descriptor & TGA_DESC_VERTICAL; + //vertrev=0; + +// // JASON - we can force this stuff if we want +// if( hflip ) +// horzrev = 1; + if( vflip ) + vertrev = 1; + + if (_verbose && horzrev) printf("TGA: horizontal reversed\n"); + if (_verbose && vertrev) printf("TGA: vertical reversed\n"); + + rle = 0; + switch (tgaHeader.imageType) { + case TGA_TYPE_MAPPED_RLE: + rle = 1; + if (_verbose) printf("TGA: run-length encoded\n"); + case TGA_TYPE_MAPPED: + /* Test for alpha channel. */ + format = GL_COLOR_INDEX; + components = 1; + if (_verbose) { + printf("TGA: %d bit indexed image (%d bit palette)\n", + tgaHeader.colorMapSize, bpp); + } + break; + + case TGA_TYPE_GRAY_RLE: + rle = 1; + if (_verbose) printf("TGA: run-length encoded\n"); + case TGA_TYPE_GRAY: + format = GL_LUMINANCE; + components = 1; + if (_verbose) printf("TGA: %d bit grayscale image\n", bpp); + break; + + case TGA_TYPE_COLOR_RLE: + rle = 1; + if (_verbose) printf("TGA: run-length encoded\n"); + case TGA_TYPE_COLOR: + /* Test for alpha channel. */ + if (bpp == 32) { + format = GL_BGRA_EXT; + components = 4; + if (_verbose) { + printf("TGA: %d bit color image with alpha channel\n", bpp); + } + } else { + format = GL_BGR_EXT; + components = 3; + if (_verbose) printf("TGA: %d bit color image\n", bpp); + } + break; + + default: + sprintf(error, + "TGA: unrecognized image type %d\n", tgaHeader.imageType); + if (_verbose) printf("%s\n", error); + return NULL; + } + + if ((format == GL_BGRA_EXT && bpp != 32) || + (format == GL_BGR_EXT && bpp != 24) || + ((format == GL_LUMINANCE || format == GL_COLOR_INDEX) && bpp != 8)) { + /* FIXME: We haven't implemented bit-packed fields yet. */ + fprintf(stderr, "bpp %d, format %x\n", bpp, (unsigned int)format); + sprintf(error, "TGA: channel sizes other than 8 bits are unimplemented"); + if (_verbose) printf("%s\n", error); + return NULL; + } + + /* Check that we have a color map only when we need it. */ + if (format == GL_COLOR_INDEX) { + if (tgaHeader.colorMapType != 1) { + sprintf(error, "TGA: indexed image has invalid color map type %d\n", + tgaHeader.colorMapType); + if (_verbose) printf("%s\n", error); + return NULL; + } + } else if (tgaHeader.colorMapType != 0) { + sprintf(error, "TGA: non-indexed image has invalid color map type %d\n", + tgaHeader.colorMapType); + if (_verbose) printf("%s\n", error); + return NULL; + } + + if (tgaHeader.colorMapType == 1) { + /* We need to read in the colormap. */ + index = (tgaHeader.colorMapIndexHi << 8) | tgaHeader.colorMapIndexLo; + length = (tgaHeader.colorMapLengthHi << 8) | tgaHeader.colorMapLengthLo; + + if (_verbose) { + printf("TGA: reading color map (%d + %d) * (%d / 8)\n", + index, length, tgaHeader.colorMapSize); + } + if (length == 0) { + sprintf(error, "TGA: invalid color map length %d", length); + if (_verbose) printf("%s\n", error); + return NULL; + } + if (tgaHeader.colorMapSize != 24) { + /* We haven't implemented bit-packed fields yet. */ + sprintf(error, "TGA: channel sizes other than 8 bits are unimplemented"); + if (_verbose) printf("%s\n", error); + return NULL; + } + + pelbytes = tgaHeader.colorMapSize / 8; + colors = length + index; + cmap = (GLubyte*)malloc (colors * pelbytes); + + /* Zero the entries up to the beginning of the map. */ + memset(cmap, 0, index * pelbytes); + + /* Read in the rest of the colormap. */ + if (fread(cmap, pelbytes, length, fp) != (size_t) length) { + sprintf(error, "TGA: error reading colormap (ftell == %ld)\n", + ftell (fp)); + if (_verbose) printf("%s\n", error); + free(cmap); + return NULL; + } + + if (pelbytes >= 3) { + /* Rearrange the colors from BGR to RGB. */ + int tmp; + for (j = index; j < length * pelbytes; j += pelbytes) { + tmp = cmap[j]; + cmap[j] = cmap[j + 2]; + cmap[j + 2] = tmp; + } + } + } else { + colors = 0; + cmap = NULL; + } + + /* Allocate the data. */ + pelbytes = bpp / 8; + pixels = (unsigned char *) malloc (width * height * pelbytes); + + if (rle) { + rleRec.statebuf = 0; + rleRec.statelen = 0; + rleRec.laststate = 0; + rleInfo = &rleRec; + myfread = rle_fread; + } else { + rleInfo = NULL; + myfread = std_fread; + } + + wbytes = width * pelbytes; + + if (vertrev) { + start = 0; + end = height; + dir = 1; + } else { + /* We need to reverse loading order of rows. */ + start = height-1; + end = -1; + dir = -1; + } + + for (i = start; i != end; i += dir) { + data = pixels + i*wbytes; + + /* Suck in the data one row at a time. */ + if (myfread(rleInfo, data, pelbytes, width, fp) != width) { + /* Probably premature end of file. */ + if (_verbose) { + printf ("TGA: error reading (ftell == %ld, width=%d)\n", + ftell(fp), width); + } + return NULL; + } + + if (horzrev) { + /* We need to mirror row horizontally. */ + for (j = 0; j < width/2; j++) { + GLubyte tmp; + + for (k = 0; k < pelbytes; k++) { + tmp = data[j*pelbytes+k]; + data[j*pelbytes+k] = data[(width-j-1)*pelbytes+k]; + data[(width-j-1)*pelbytes+k] = tmp; + } + } + } + } + + if (rle) { + free(rleInfo->statebuf); + } + + if (fgetc (fp) != EOF) { + if (_verbose) printf ("TGA: too much input data, ignoring extra...\n"); + } + + genericImage = (igl::opengl::gliGenericImage*) malloc(sizeof(igl::opengl::gliGenericImage)); + genericImage->width = width; + genericImage->height = height; + genericImage->format = format; + genericImage->components = components; + genericImage->cmapEntries = colors; + genericImage->cmapFormat = GL_BGR_EXT; // XXX fix me + genericImage->cmap = cmap; + genericImage->pixels = pixels; + + return genericImage; +} + +IGL_INLINE int igl::opengl::gli_verbose(int new_verbose) +{ + _verbose = new_verbose; + return _verbose; +} + + + +// added 10/2005, Denis Zorin +// a very simple TGA output, supporting +// uncompressed luminance RGB and RGBA +// G22.2270 students: this is C (no C++) +// so this is not the style I would encourage +// you to use; I used it for consistency +// with the rest of the code in this file + + +// fixed header values for the subset of TGA we use for writing +unsigned char TGAHeaderColor[12] = + { 0,// 0 ID length = no id + 0,// 1 color map type = no color map + 2,// 2 image type = uncompressed true color + 0, 0, 0, 0, 0,// color map spec = empty + 0, 0, // x origin of image + 0, 0 // y origin of image + }; + +unsigned char TGAHeaderBW[12] = + { 0,// 0 ID length = no id + 0,// 1 color map type = no color map + 3,// 3 image type = uncompressed black and white + 0, 0, 0, 0, 0,// color map spec = empty + 0, 0, // x origin of image + 0, 0 // y origin of image + }; + +// this makes sure that +// image size is written in correct format +// and byte order (least first) +IGL_INLINE void write16bit(int n, FILE* fp) { + unsigned char bytes[] = { static_cast(n % 256), static_cast(n / 256) }; + fwrite(bytes, 2, sizeof(unsigned char),fp); +} + + + +IGL_INLINE void igl::opengl::writeTGA( igl::opengl::gliGenericImage* image, FILE *fp) { + + assert(!image->cmap); // we do not deal with color map images + + if(image->components == 3 || image->components == 4) + fwrite(TGAHeaderColor, 12, sizeof(unsigned char),fp); + else { + if(image->components == 1 ) + fwrite(TGAHeaderBW, 12, sizeof(unsigned char),fp); + else { fprintf(stderr,"Supported component number: 1,3 or 4\n"); exit(1); } + } + + write16bit(image->width,fp); + write16bit(image->height,fp); + switch (image->components ) { + case 1: + putc(8,fp); + break; + case 3: + putc(24,fp); + break; + case 4: + putc(32,fp); + break; + default: fprintf(stderr,"Supported component number: 1,3 or 4\n"); exit(1); + }; + + if(image-> components == 4) + putc(0x04,fp); // bottom left image (0x00) + 8 bit alpha (0x4) + else + putc(0x00,fp); + + fwrite(image->pixels, image->height*image->width*image->components, sizeof(char),fp); +} + diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/opengl2/tga.h b/src/external/libigl-2.3.0/include/igl/copyleft/opengl2/tga.h new file mode 100644 index 000000000..bb2ef5568 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/opengl2/tga.h @@ -0,0 +1,106 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_OPENGL_TGA_H +#define IGL_OPENGL_TGA_H +#include "../../igl_inline.h" + +#include "../../opengl2/gl.h" +// See license in tga.cpp +/* tga.h - interface for TrueVision (TGA) image file loader */ +#include +#ifdef _WIN32 +#include +#endif + +namespace igl +{ +namespace opengl +{ + +typedef struct { + + GLsizei width; + GLsizei height; + GLint components; + GLenum format; + + GLsizei cmapEntries; + GLenum cmapFormat; + GLubyte *cmap; + + GLubyte *pixels; + +} gliGenericImage; + +typedef struct { + unsigned char idLength; + unsigned char colorMapType; + + /* The image type. */ +#define TGA_TYPE_MAPPED 1 +#define TGA_TYPE_COLOR 2 +#define TGA_TYPE_GRAY 3 +#define TGA_TYPE_MAPPED_RLE 9 +#define TGA_TYPE_COLOR_RLE 10 +#define TGA_TYPE_GRAY_RLE 11 + unsigned char imageType; + + /* Color Map Specification. */ + /* We need to separately specify high and low bytes to avoid endianness + and alignment problems. */ + unsigned char colorMapIndexLo, colorMapIndexHi; + unsigned char colorMapLengthLo, colorMapLengthHi; + unsigned char colorMapSize; + + /* Image Specification. */ + unsigned char xOriginLo, xOriginHi; + unsigned char yOriginLo, yOriginHi; + + unsigned char widthLo, widthHi; + unsigned char heightLo, heightHi; + + unsigned char bpp; + + /* Image descriptor. + 3-0: attribute bpp + 4: left-to-right ordering + 5: top-to-bottom ordering + 7-6: zero + */ +#define TGA_DESC_ABITS 0x0f +#define TGA_DESC_HORIZONTAL 0x10 +#define TGA_DESC_VERTICAL 0x20 + unsigned char descriptor; + +} TgaHeader; + +typedef struct { + unsigned int extensionAreaOffset; + unsigned int developerDirectoryOffset; +#define TGA_SIGNATURE "TRUEVISION-XFILE" + char signature[16]; + char dot; + char null; +} TgaFooter; + +IGL_INLINE extern gliGenericImage *gliReadTGA(FILE *fp, char *name, int hflip, int vflip); +IGL_INLINE int gli_verbose(int new_verbose); +IGL_INLINE extern int gliVerbose(int newVerbose); + +IGL_INLINE void writeTGA( gliGenericImage* image, FILE *fp); + + + +} // end of igl namespace +} + +#ifndef IGL_STATIC_LIBRARY +# include "tga.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/progressive_hulls.cpp b/src/external/libigl-2.3.0/include/igl/copyleft/progressive_hulls.cpp new file mode 100644 index 000000000..44738c8b2 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/progressive_hulls.cpp @@ -0,0 +1,31 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "progressive_hulls.h" +#include "progressive_hulls_cost_and_placement.h" +#include "../decimate.h" +#include "../max_faces_stopping_condition.h" +IGL_INLINE bool igl::copyleft::progressive_hulls( + const Eigen::MatrixXd & V, + const Eigen::MatrixXi & F, + const size_t max_m, + Eigen::MatrixXd & U, + Eigen::MatrixXi & G, + Eigen::VectorXi & J) +{ + int m = F.rows(); + Eigen::VectorXi I; + return decimate( + V, + F, + progressive_hulls_cost_and_placement, + max_faces_stopping_condition(m,(const int)m,max_m), + U, + G, + J, + I); +} diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/progressive_hulls.h b/src/external/libigl-2.3.0/include/igl/copyleft/progressive_hulls.h new file mode 100644 index 000000000..54e0580a0 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/progressive_hulls.h @@ -0,0 +1,43 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_COPYLEFT_PROGRESSIVE_HULLS_H +#define IGL_COPYLEFT_PROGRESSIVE_HULLS_H +#include "../igl_inline.h" +#include + +namespace igl +{ + namespace copyleft + { + // Assumes (V,F) is a closed manifold mesh + // Collapses edges until desired number of faces is achieved but ensures + // that new vertices are placed outside all previous meshes as per + // "progressive hulls" in "Silhouette clipping" [Sander et al. 2000]. + // + // Inputs: + // V #V by dim list of vertex positions + // F #F by 3 list of face indices into V. + // max_m desired number of output faces + // Outputs: + // U #U by dim list of output vertex posistions (can be same ref as V) + // G #G by 3 list of output face indices into U (can be same ref as G) + // J #G list of indices into F of birth faces + // Returns true if m was reached (otherwise #G > m) + IGL_INLINE bool progressive_hulls( + const Eigen::MatrixXd & V, + const Eigen::MatrixXi & F, + const size_t max_m, + Eigen::MatrixXd & U, + Eigen::MatrixXi & G, + Eigen::VectorXi & J); + } +} +#ifndef IGL_STATIC_LIBRARY +# include "progressive_hulls.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/progressive_hulls_cost_and_placement.cpp b/src/external/libigl-2.3.0/include/igl/copyleft/progressive_hulls_cost_and_placement.cpp new file mode 100644 index 000000000..6bd916906 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/progressive_hulls_cost_and_placement.cpp @@ -0,0 +1,107 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "progressive_hulls_cost_and_placement.h" +#include "quadprog.h" +#include "../unique.h" +#include "../circulation.h" +#include +#include +#include + +IGL_INLINE void igl::copyleft::progressive_hulls_cost_and_placement( + const int e, + const Eigen::MatrixXd & V, + const Eigen::MatrixXi & F, + const Eigen::MatrixXi & E, + const Eigen::VectorXi & EMAP, + const Eigen::MatrixXi & EF, + const Eigen::MatrixXi & EI, + double & cost, + Eigen::RowVectorXd & p) +{ + using namespace Eigen; + using namespace std; + // Controls the amount of quadratic energy to add (too small will introduce + // instabilities and flaps) + const double w = 0.1; + + assert(V.cols() == 3 && "V.cols() should be 3"); + // Gather list of unique face neighbors + vector Nall = circulation(e, true,EMAP,EF,EI); + vector Nother= circulation(e,false,EMAP,EF,EI); + Nall.insert(Nall.end(),Nother.begin(),Nother.end()); + vector N; + igl::unique(Nall,N); + // Gather: + // A #N by 3 normals scaled by area, + // D #N determinants of matrix formed by points as columns + // B #N point on plane dot normal + MatrixXd A(N.size(),3); + VectorXd D(N.size()); + VectorXd B(N.size()); + //cout<<"N=["; + for(int i = 0;i= B + // A x - B >=0 + // This is annoyingly necessary. Seems the solver is letting some garbage + // slip by. + success = success && ((A*x-B).minCoeff()>-1e-10); + if(success) + { + p = x.transpose(); + //assert(cost>=0 && "Cost should be positive"); + }else + { + cost = std::numeric_limits::infinity(); + //VectorXi NM; + //igl::list_to_matrix(N,NM); + //cout< +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_COPYLEFT_PROGRESSIVE_HULLS_COST_AND_PLACEMENT_H +#define IGL_COPYLEFT_PROGRESSIVE_HULLS_COST_AND_PLACEMENT_H +#include +#include "../igl_inline.h" +namespace igl +{ + namespace copyleft + { + // A "cost and placement" compatible with `igl::decimate` implementing the + // "progressive hulls" algorithm in "Silhouette clipping" [Sander et al. + // 2000]. This implementation fixes an issue that the original linear + // program becomes unstable for flat patches by introducing a small + // quadratic energy term pulling the collapsed edge toward its midpoint. + // This function is not really meant to be called directly but rather + // passed to `igl::decimate` as a handle. + // + // Inputs: + // e index of edge to be collapsed + // V #V by 3 list of vertex positions + // F #F by 3 list of faces indices into V + // E #E by 3 list of edges indices into V + // EMAP #F*3 list of indices into E, mapping each directed edge to unique + // unique edge in E + // EF #E by 2 list of edge flaps, EF(e,0)=f means e=(i-->j) is the edge of + // F(f,:) opposite the vth corner, where EI(e,0)=v. Similarly EF(e,1) " + // e=(j->i) + // EI #E by 2 list of edge flap corners (see above). + // Outputs: + // cost cost of collapsing edge e + // p position to place collapsed vertex + // + IGL_INLINE void progressive_hulls_cost_and_placement( + const int e, + const Eigen::MatrixXd & V, + const Eigen::MatrixXi & F, + const Eigen::MatrixXi & E, + const Eigen::VectorXi & EMAP, + const Eigen::MatrixXi & EF, + const Eigen::MatrixXi & EI, + double & cost, + Eigen::RowVectorXd & p); + } +} +#ifndef IGL_STATIC_LIBRARY +# include "progressive_hulls_cost_and_placement.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/quadprog.cpp b/src/external/libigl-2.3.0/include/igl/copyleft/quadprog.cpp new file mode 100644 index 000000000..7ee417e81 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/quadprog.cpp @@ -0,0 +1,618 @@ +#include "quadprog.h" +#include "../matlab_format.h" +#include +#include +#include +/* + FILE eiquadprog.hh + + NOTE: this is a modified of uQuadProg++ package, working with Eigen data structures. + uQuadProg++ is itself a port made by Angelo Furfaro of QuadProg++ originally developed by + Luca Di Gaspero, working with ublas data structures. + + The quadprog_solve() function implements the algorithm of Goldfarb and Idnani + for the solution of a (convex) Quadratic Programming problem +by means of a dual method. + +The problem is in the form: + +min 0.5 * x G x + g0 x +s.t. + CE^T x + ce0 = 0 + CI^T x + ci0 >= 0 + + The matrix and vectors dimensions are as follows: + G: n * n + g0: n + + CE: n * p + ce0: p + + CI: n * m + ci0: m + + x: n + + The function will return the cost of the solution written in the x vector or + std::numeric_limits::infinity() if the problem is infeasible. In the latter case + the value of the x vector is not correct. + + References: D. Goldfarb, A. Idnani. A numerically stable dual method for solving + strictly convex quadratic programs. Mathematical Programming 27 (1983) pp. 1-33. + + Notes: + 1. pay attention in setting up the vectors ce0 and ci0. + If the constraints of your problem are specified in the form + A^T x = b and C^T x >= d, then you should set ce0 = -b and ci0 = -d. + 2. The matrix G is modified within the function since it is used to compute + the G = L^T L cholesky factorization for further computations inside the function. + If you need the original matrix G you should make a copy of it and pass the copy + to the function. + + + The author will be grateful if the researchers using this software will + acknowledge the contribution of this modified function and of Di Gaspero's + original version in their research papers. + + +LICENSE + +Copyright (2010) Gael Guennebaud +Copyright (2008) Angelo Furfaro +Copyright (2006) Luca Di Gaspero + + +This file is a porting of QuadProg++ routine, originally developed +by Luca Di Gaspero, exploiting uBlas data structures for vectors and +matrices instead of native C++ array. + +uquadprog is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +uquadprog is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with uquadprog; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +#include + +IGL_INLINE bool igl::copyleft::quadprog( + const Eigen::MatrixXd & G, + const Eigen::VectorXd & g0, + const Eigen::MatrixXd & CE, + const Eigen::VectorXd & ce0, + const Eigen::MatrixXd & CI, + const Eigen::VectorXd & ci0, + Eigen::VectorXd& x) +{ + using namespace Eigen; + typedef double Scalar; + + + const auto print_ivector= [](const char* name, const Eigen::MatrixXi & A, int n) + { + std::cout<Scalar + { + Scalar a1, b1, t; + a1 = std::abs(a); + b1 = std::abs(b); + if (a1 > b1) + { + t = (b1 / a1); + return a1 * std::sqrt(1.0 + t * t); + } + else + if (b1 > a1) + { + t = (a1 / b1); + return b1 * std::sqrt(1.0 + t * t); + } + return a1 * std::sqrt(2.0); + }; + const auto compute_d = [](VectorXd &d, const MatrixXd& J, const VectorXd& np) + { + d = J.adjoint() * np; + }; + + const auto update_z = + [](VectorXd& z, const MatrixXd& J, const VectorXd& d, int iq) + { + z = J.rightCols(z.size()-iq) * d.tail(d.size()-iq); + }; + + const auto update_r = + [](const MatrixXd& R, VectorXd& r, const VectorXd& d, int iq) + { + r.head(iq) = + R.topLeftCorner(iq,iq).triangularView().solve(d.head(iq)); + }; + + const auto add_constraint = [&distance]( + MatrixXd& R, + MatrixXd& J, + VectorXd& d, + int& iq, + double& R_norm)->bool + { + int n=J.rows(); +#ifdef TRACE_SOLVER + std::cerr << "Add constraint " << iq << '/'; +#endif + int j, k; + double cc, ss, h, t1, t2, xny; + + /* we have to find the Givens rotation which will reduce the element + d(j) to zero. + if it is already zero we don't have to do anything, except of + decreasing j */ + for (j = n - 1; j >= iq + 1; j--) + { + /* The Givens rotation is done with the matrix (cc cs, cs -cc). + If cc is one, then element (j) of d is zero compared with element + (j - 1). Hence we don't have to do anything. + If cc is zero, then we just have to switch column (j) and column (j - 1) + of J. Since we only switch columns in J, we have to be careful how we + update d depending on the sign of gs. + Otherwise we have to apply the Givens rotation to these columns. + The i - 1 element of d has to be updated to h. */ + cc = d(j - 1); + ss = d(j); + h = distance(cc, ss); + if (h == 0.0) + continue; + d(j) = 0.0; + ss = ss / h; + cc = cc / h; + if (cc < 0.0) + { + cc = -cc; + ss = -ss; + d(j - 1) = -h; + } + else + d(j - 1) = h; + xny = ss / (1.0 + cc); + for (k = 0; k < n; k++) + { + t1 = J(k,j - 1); + t2 = J(k,j); + J(k,j - 1) = t1 * cc + t2 * ss; + J(k,j) = xny * (t1 + J(k,j - 1)) - t2; + } + } + /* update the number of constraints added*/ + iq++; + /* To update R we have to put the iq components of the d vector + into column iq - 1 of R + */ + R.col(iq-1).head(iq) = d.head(iq); +#ifdef TRACE_SOLVER + std::cerr << iq << std::endl; +#endif + + if (std::abs(d(iq - 1)) <= std::numeric_limits::epsilon() * R_norm) + { + // problem degenerate + return false; + } + R_norm = std::max(R_norm, std::abs(d(iq - 1))); + return true; + }; + + const auto delete_constraint = [&distance]( + MatrixXd& R, + MatrixXd& J, + VectorXi& A, + VectorXd& u, + int p, + int& iq, + int l) + { + int n = R.rows(); +#ifdef TRACE_SOLVER + std::cerr << "Delete constraint " << l << ' ' << iq; +#endif + int i, j, k, qq; + double cc, ss, h, xny, t1, t2; + + /* Find the index qq for active constraint l to be removed */ + for (i = p; i < iq; i++) + if (A(i) == l) + { + qq = i; + break; + } + + /* remove the constraint from the active set and the duals */ + for (i = qq; i < iq - 1; i++) + { + A(i) = A(i + 1); + u(i) = u(i + 1); + R.col(i) = R.col(i+1); + } + + A(iq - 1) = A(iq); + u(iq - 1) = u(iq); + A(iq) = 0; + u(iq) = 0.0; + for (j = 0; j < iq; j++) + R(j,iq - 1) = 0.0; + /* constraint has been fully removed */ + iq--; +#ifdef TRACE_SOLVER + std::cerr << '/' << iq << std::endl; +#endif + + if (iq == 0) + return; + + for (j = qq; j < iq; j++) + { + cc = R(j,j); + ss = R(j + 1,j); + h = distance(cc, ss); + if (h == 0.0) + continue; + cc = cc / h; + ss = ss / h; + R(j + 1,j) = 0.0; + if (cc < 0.0) + { + R(j,j) = -h; + cc = -cc; + ss = -ss; + } + else + R(j,j) = h; + + xny = ss / (1.0 + cc); + for (k = j + 1; k < iq; k++) + { + t1 = R(j,k); + t2 = R(j + 1,k); + R(j,k) = t1 * cc + t2 * ss; + R(j + 1,k) = xny * (t1 + R(j,k)) - t2; + } + for (k = 0; k < n; k++) + { + t1 = J(k,j); + t2 = J(k,j + 1); + J(k,j) = t1 * cc + t2 * ss; + J(k,j + 1) = xny * (J(k,j) + t1) - t2; + } + } + }; + + int i, k, l; /* indices */ + int ip, me, mi; + int n=g0.size(); int p=ce0.size(); int m=ci0.size(); + MatrixXd R(G.rows(),G.cols()), J(G.rows(),G.cols()); + + LLT chol(G.cols()); + + VectorXd s(m+p), z(n), r(m + p), d(n), np(n), u(m + p); + VectorXd x_old(n), u_old(m + p); + double f_value, psi, c1, c2, sum, ss, R_norm; + const double inf = std::numeric_limits::infinity(); + double t, t1, t2; /* t is the step length, which is the minimum of the partial step length t1 + * and the full step length t2 */ + VectorXi A(m + p), A_old(m + p), iai(m + p); + int q; + int iq, iter = 0; + std::vector iaexcl(m + p); + + me = p; /* number of equality constraints */ + mi = m; /* number of inequality constraints */ + q = 0; /* size of the active set A (containing the indices of the active constraints) */ + + /* + * Preprocessing phase + */ + + /* compute the trace of the original matrix G */ + c1 = G.trace(); + + /* decompose the matrix G in the form LL^T */ + chol.compute(G); + + /* initialize the matrix R */ + d.setZero(); + R.setZero(); + R_norm = 1.0; /* this variable will hold the norm of the matrix R */ + + /* compute the inverse of the factorized matrix G^-1, this is the initial value for H */ + // J = L^-T + J.setIdentity(); + J = chol.matrixU().solve(J); + c2 = J.trace(); +#ifdef TRACE_SOLVER + print_matrix("J", J, n); +#endif + + /* c1 * c2 is an estimate for cond(G) */ + + /* + * Find the unconstrained minimizer of the quadratic form 0.5 * x G x + g0 x + * this is a feasible point in the dual space + * x = G^-1 * g0 + */ + x = chol.solve(g0); + x = -x; + /* and compute the current solution value */ + f_value = 0.5 * g0.dot(x); +#ifdef TRACE_SOLVER + std::cerr << "Unconstrained solution: " << f_value << std::endl; + print_vector("x", x, n); +#endif + + /* Add equality constraints to the working set A */ + iq = 0; + for (i = 0; i < me; i++) + { + np = CE.col(i); + compute_d(d, J, np); + update_z(z, J, d, iq); + update_r(R, r, d, iq); +#ifdef TRACE_SOLVER + print_matrix("R", R, iq); + print_vector("z", z, n); + print_vector("r", r, iq); + print_vector("d", d, n); +#endif + + /* compute full step length t2: i.e., the minimum step in primal space s.t. the contraint + becomes feasible */ + t2 = 0.0; + if (std::abs(z.dot(z)) > std::numeric_limits::epsilon()) // i.e. z != 0 + t2 = (-np.dot(x) - ce0(i)) / z.dot(np); + + x += t2 * z; + + /* set u = u+ */ + u(iq) = t2; + u.head(iq) -= t2 * r.head(iq); + + /* compute the new solution value */ + f_value += 0.5 * (t2 * t2) * z.dot(np); + A(i) = -i - 1; + + if (!add_constraint(R, J, d, iq, R_norm)) + { + // FIXME: it should raise an error + // Equality constraints are linearly dependent + return false; + } + } + + /* set iai = K \ A */ + for (i = 0; i < mi; i++) + iai(i) = i; + +l1: iter++; +#ifdef TRACE_SOLVER + print_vector("x", x, n); +#endif + /* step 1: choose a violated constraint */ + for (i = me; i < iq; i++) + { + ip = A(i); + iai(ip) = -1; + } + + /* compute s(x) = ci^T * x + ci0 for all elements of K \ A */ + ss = 0.0; + psi = 0.0; /* this value will contain the sum of all infeasibilities */ + ip = 0; /* ip will be the index of the chosen violated constraint */ + for (i = 0; i < mi; i++) + { + iaexcl[i] = true; + sum = CI.col(i).dot(x) + ci0(i); + s(i) = sum; + psi += std::min(0.0, sum); + } +#ifdef TRACE_SOLVER + print_vector("s", s, mi); +#endif + + + if (std::abs(psi) <= mi * std::numeric_limits::epsilon() * c1 * c2* 100.0) + { + /* numerically there are not infeasibilities anymore */ + q = iq; + return true; + } + + /* save old values for u, x and A */ + u_old.head(iq) = u.head(iq); + A_old.head(iq) = A.head(iq); + x_old = x; + +l2: /* Step 2: check for feasibility and determine a new S-pair */ + for (i = 0; i < mi; i++) + { + if (s(i) < ss && iai(i) != -1 && iaexcl[i]) + { + ss = s(i); + ip = i; + } + } + if (ss >= 0.0) + { + q = iq; + return true; + } + + /* set np = n(ip) */ + np = CI.col(ip); + /* set u = (u 0)^T */ + u(iq) = 0.0; + /* add ip to the active set A */ + A(iq) = ip; + +#ifdef TRACE_SOLVER + std::cerr << "Trying with constraint " << ip << std::endl; + print_vector("np", np, n); +#endif + +l2a:/* Step 2a: determine step direction */ + /* compute z = H np: the step direction in the primal space (through J, see the paper) */ + compute_d(d, J, np); + update_z(z, J, d, iq); + /* compute N* np (if q > 0): the negative of the step direction in the dual space */ + update_r(R, r, d, iq); +#ifdef TRACE_SOLVER + std::cerr << "Step direction z" << std::endl; + print_vector("z", z, n); + print_vector("r", r, iq + 1); + print_vector("u", u, iq + 1); + print_vector("d", d, n); + print_ivector("A", A, iq + 1); +#endif + + /* Step 2b: compute step length */ + l = 0; + /* Compute t1: partial step length (maximum step in dual space without violating dual feasibility */ + t1 = inf; /* +inf */ + /* find the index l s.t. it reaches the minimum of u+(x) / r */ + for (k = me; k < iq; k++) + { + double tmp; + if (r(k) > 0.0 && ((tmp = u(k) / r(k)) < t1) ) + { + t1 = tmp; + l = A(k); + } + } + /* Compute t2: full step length (minimum step in primal space such that the constraint ip becomes feasible */ + if (std::abs(z.dot(z)) > std::numeric_limits::epsilon()) // i.e. z != 0 + t2 = -s(ip) / z.dot(np); + else + t2 = inf; /* +inf */ + + /* the step is chosen as the minimum of t1 and t2 */ + t = std::min(t1, t2); +#ifdef TRACE_SOLVER + std::cerr << "Step sizes: " << t << " (t1 = " << t1 << ", t2 = " << t2 << ") "; +#endif + + /* Step 2c: determine new S-pair and take step: */ + + /* case (i): no step in primal or dual space */ + if (t >= inf) + { + /* QPP is infeasible */ + // FIXME: unbounded to raise + q = iq; + return false; + } + /* case (ii): step in dual space */ + if (t2 >= inf) + { + /* set u = u + t * [-r 1) and drop constraint l from the active set A */ + u.head(iq) -= t * r.head(iq); + u(iq) += t; + iai(l) = l; + delete_constraint(R, J, A, u, p, iq, l); +#ifdef TRACE_SOLVER + std::cerr << " in dual space: " + << f_value << std::endl; + print_vector("x", x, n); + print_vector("z", z, n); + print_ivector("A", A, iq + 1); +#endif + goto l2a; + } + + /* case (iii): step in primal and dual space */ + + x += t * z; + /* update the solution value */ + f_value += t * z.dot(np) * (0.5 * t + u(iq)); + + u.head(iq) -= t * r.head(iq); + u(iq) += t; +#ifdef TRACE_SOLVER + std::cerr << " in both spaces: " + << f_value << std::endl; + print_vector("x", x, n); + print_vector("u", u, iq + 1); + print_vector("r", r, iq + 1); + print_ivector("A", A, iq + 1); +#endif + + if (t == t2) + { +#ifdef TRACE_SOLVER + std::cerr << "Full step has taken " << t << std::endl; + print_vector("x", x, n); +#endif + /* full step has taken */ + /* add constraint ip to the active set*/ + if (!add_constraint(R, J, d, iq, R_norm)) + { + iaexcl[ip] = false; + delete_constraint(R, J, A, u, p, iq, ip); +#ifdef TRACE_SOLVER + print_matrix("R", R, n); + print_ivector("A", A, iq); +#endif + for (i = 0; i < m; i++) + iai(i) = i; + for (i = 0; i < iq; i++) + { + A(i) = A_old(i); + iai(A(i)) = -1; + u(i) = u_old(i); + } + x = x_old; + goto l2; /* go to step 2 */ + } + else + iai(ip) = -1; +#ifdef TRACE_SOLVER + print_matrix("R", R, n); + print_ivector("A", A, iq); +#endif + goto l1; + } + + /* a patial step has taken */ +#ifdef TRACE_SOLVER + std::cerr << "Partial step has taken " << t << std::endl; + print_vector("x", x, n); +#endif + /* drop constraint l */ + iai(l) = l; + delete_constraint(R, J, A, u, p, iq, l); +#ifdef TRACE_SOLVER + print_matrix("R", R, n); + print_ivector("A", A, iq); +#endif + + s(ip) = CI.col(ip).dot(x) + ci0(ip); + +#ifdef TRACE_SOLVER + print_vector("s", s, mi); +#endif + goto l2a; +} diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/quadprog.h b/src/external/libigl-2.3.0/include/igl/copyleft/quadprog.h new file mode 100644 index 000000000..f054bbdba --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/quadprog.h @@ -0,0 +1,48 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_COPYLEFT_QUADPROG_H +#define IGL_COPYLEFT_QUADPROG_H + +#include "../igl_inline.h" +#include +namespace igl +{ + namespace copyleft + { + // Solve a (dense) quadratric program of the form: + // + // min 0.5 x G x + g0 x + // s.t. CE' x + ce0 = 0 + // and CI' x + ci0 >= 0 + // + // Inputs: + // G #x by #x matrix of quadratic coefficients + // g0 #x vector of linear coefficients + // CE #x by #CE list of linear equality coefficients + // ce0 #CE list of linear equality right-hand sides + // CI #x by #CI list of linear equality coefficients + // ci0 #CI list of linear equality right-hand sides + // Outputs: + // x #x vector of solution values + // Returns true iff success + IGL_INLINE bool quadprog( + const Eigen::MatrixXd & G, + const Eigen::VectorXd & g0, + const Eigen::MatrixXd & CE, + const Eigen::VectorXd & ce0, + const Eigen::MatrixXd & CI, + const Eigen::VectorXd & ci0, + Eigen::VectorXd& x); + } +} + +#ifndef IGL_STATIC_LIBRARY +# include "quadprog.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/tetgen/README b/src/external/libigl-2.3.0/include/igl/copyleft/tetgen/README new file mode 100644 index 000000000..0315b6c11 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/tetgen/README @@ -0,0 +1,7 @@ +IGL interface to tetgen library + +Dependencies: + tetgen + +Travel to $IGL/external/tetgen and issue: + make -f Makefile.igl tetlib diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/tetgen/cdt.cpp b/src/external/libigl-2.3.0/include/igl/copyleft/tetgen/cdt.cpp new file mode 100644 index 000000000..f2602dd66 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/tetgen/cdt.cpp @@ -0,0 +1,64 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "cdt.h" +#include "../../bounding_box.h" +#include "tetrahedralize.h" + +template < + typename DerivedV, + typename DerivedF, + typename DerivedTV, + typename DerivedTT, + typename DerivedTF> +IGL_INLINE bool igl::copyleft::tetgen::cdt( + const Eigen::PlainObjectBase& V, + const Eigen::PlainObjectBase& F, + const CDTParam & param, + Eigen::PlainObjectBase& TV, + Eigen::PlainObjectBase& TT, + Eigen::PlainObjectBase& TF) +{ + using namespace Eigen; + using namespace std; + // Effective input mesh + DerivedV U; + DerivedF G; + if(param.use_bounding_box) + { + // Construct bounding box mesh + DerivedV BV; + DerivedF BF; + bounding_box(V,BV,BF); + // scale bounding box + const RowVector3d mid = + (BV.colwise().minCoeff() + BV.colwise().maxCoeff()).eval()*0.5; + BV.rowwise() -= mid; + assert(param.bounding_box_scale >= 1.); + BV.array() *= param.bounding_box_scale; + BV.rowwise() += mid; + // Append bounding box to mesh + U.resize(V.rows()+BV.rows(),V.cols()); + U<, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, igl::copyleft::tetgen::CDTParam const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/tetgen/cdt.h b/src/external/libigl-2.3.0/include/igl/copyleft/tetgen/cdt.h new file mode 100644 index 000000000..e59a28029 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/tetgen/cdt.h @@ -0,0 +1,72 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_COPYLEFT_TETGEN_CDT_H +#define IGL_COPYLEFT_TETGEN_CDT_H +#include "../../igl_inline.h" + +#include +#include +#ifndef TETLIBRARY +# define TETLIBRARY +#endif +#include "tetgen.h" // Defined REAL + +namespace igl +{ + namespace copyleft + { + namespace tetgen + { + struct CDTParam + { + // Tetgen can compute mesh of convex hull of input (i.e. "c") but often + // chokes. One workaround is to force it to mesh the entire bounding box. + // {false} + bool use_bounding_box = false; + // Scale the bounding box a bit so that vertices near it do not give tetgen + // problems. {1.01} + double bounding_box_scale = 1.01; + // Flags to tetgen. Do not include the "c" flag here! {"Y"} + std::string flags = "Y"; + }; + // Create a constrained delaunay tessellation containing convex hull of the + // given **non-selfintersecting** mesh. + // + // Inputs: + // V #V by 3 list of input mesh vertices + // F #F by 3 list of input mesh facets + // param see above + // TV #TV by 3 list of output mesh vertices (V come first) + // TT #TT by 3 list of tetrahedra indices into TV. + // TF #TF by 3 list of facets from F potentially subdivided. + // + template < + typename DerivedV, + typename DerivedF, + typename DerivedTV, + typename DerivedTT, + typename DerivedTF> + IGL_INLINE bool cdt( + const Eigen::PlainObjectBase& V, + const Eigen::PlainObjectBase& F, + const CDTParam & param, + Eigen::PlainObjectBase& TV, + Eigen::PlainObjectBase& TT, + Eigen::PlainObjectBase& TF); + } + } +} + + +#ifndef IGL_STATIC_LIBRARY +# include "cdt.cpp" +#endif + +#endif + + diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/tetgen/mesh_to_tetgenio.cpp b/src/external/libigl-2.3.0/include/igl/copyleft/tetgen/mesh_to_tetgenio.cpp new file mode 100644 index 000000000..7376ec816 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/tetgen/mesh_to_tetgenio.cpp @@ -0,0 +1,166 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "mesh_to_tetgenio.h" + +// IGL includes +#include "../../matrix_to_list.h" + +// STL includes +#include + + +IGL_INLINE bool igl::copyleft::tetgen::mesh_to_tetgenio( + const std::vector > & V, + const std::vector > & F, + const std::vector > & H, + const std::vector > & R, + tetgenio & in) +{ + using namespace std; + in.firstnumber = 0; + in.numberofpoints = V.size(); + in.pointlist = new REAL[in.numberofpoints * 3]; + //loop over points + for(size_t i = 0; i < (size_t)V.size(); i++) + { + assert(V[i].size() == 3); + in.pointlist[i*3+0] = V[i][0]; + in.pointlist[i*3+1] = V[i][1]; + in.pointlist[i*3+2] = V[i][2]; + } + in.numberoffacets = F.size(); + in.facetlist = new tetgenio::facet[in.numberoffacets]; + in.facetmarkerlist = new int[in.numberoffacets]; + + // loop over face + for(size_t i = 0;i < (size_t)F.size(); i++) + { + in.facetmarkerlist[i] = i; + tetgenio::facet * f = &in.facetlist[i]; + f->numberofpolygons = 1; + f->polygonlist = new tetgenio::polygon[f->numberofpolygons]; + f->numberofholes = 0; + f->holelist = NULL; + tetgenio::polygon * p = &f->polygonlist[0]; + p->numberofvertices = F[i].size(); + p->vertexlist = new int[p->numberofvertices]; + // loop around face + for(int j = 0;j < (int)F[i].size(); j++) + { + p->vertexlist[j] = F[i][j]; + } + } + + in.numberofholes = H.size(); + in.holelist = new double[3 * in.numberofholes]; + // loop over holes + for(size_t holeID = 0, nHoles = H.size(); holeID < nHoles; holeID++) + { + in.holelist[holeID * 3 + 0] = H[holeID][0]; + in.holelist[holeID * 3 + 1] = H[holeID][1]; + in.holelist[holeID * 3 + 2] = H[holeID][2]; + } + + in.numberofregions = R.size(); + in.regionlist = new REAL[ 5 * in.numberofregions]; + // loop over regions + for(size_t regionID = 0, nRegions = R.size(); regionID < nRegions; regionID++) + { + in.regionlist[regionID * 5 + 0] = R[regionID][0]; + in.regionlist[regionID * 5 + 1] = R[regionID][1]; + in.regionlist[regionID * 5 + 2] = R[regionID][2]; + in.regionlist[regionID * 5 + 3] = R[regionID][3]; + in.regionlist[regionID * 5 + 4] = R[regionID][4]; + } + + return true; + +} + +template +IGL_INLINE bool igl::copyleft::tetgen::mesh_to_tetgenio( + const Eigen::PlainObjectBase& V, + const Eigen::PlainObjectBase& F, + const Eigen::PlainObjectBase& H, + const Eigen::PlainObjectBase& R, + tetgenio & in) +{ + using namespace std; + vector > vV, vH, vR; + vector > vF; + matrix_to_list(V,vV); + matrix_to_list(F,vF); + matrix_to_list(H, vH); + matrix_to_list(R, vR); + return mesh_to_tetgenio(vV,vF,vH,vR,in); +} + + +IGL_INLINE bool igl::copyleft::tetgen::mesh_to_tetgenio( + const std::vector > & V, + const std::vector > & F, + tetgenio & in) +{ + using namespace std; + // all indices start from 0 + in.firstnumber = 0; + + in.numberofpoints = V.size(); + in.pointlist = new REAL[in.numberofpoints * 3]; + // loop over points + for(int i = 0; i < (int)V.size(); i++) + { + assert(V[i].size() == 3); + in.pointlist[i*3+0] = V[i][0]; + in.pointlist[i*3+1] = V[i][1]; + in.pointlist[i*3+2] = V[i][2]; + } + + in.numberoffacets = F.size(); + in.facetlist = new tetgenio::facet[in.numberoffacets]; + in.facetmarkerlist = new int[in.numberoffacets]; + + // loop over face + for(int i = 0;i < (int)F.size(); i++) + { + in.facetmarkerlist[i] = i; + tetgenio::facet * f = &in.facetlist[i]; + f->numberofpolygons = 1; + f->polygonlist = new tetgenio::polygon[f->numberofpolygons]; + f->numberofholes = 0; + f->holelist = NULL; + tetgenio::polygon * p = &f->polygonlist[0]; + p->numberofvertices = F[i].size(); + p->vertexlist = new int[p->numberofvertices]; + // loop around face + for(int j = 0;j < (int)F[i].size(); j++) + { + p->vertexlist[j] = F[i][j]; + } + } + return true; +} + +template +IGL_INLINE bool igl::copyleft::tetgen::mesh_to_tetgenio( + const Eigen::PlainObjectBase& V, + const Eigen::PlainObjectBase& F, + tetgenio & in) +{ + using namespace std; + vector > vV; + vector > vF; + matrix_to_list(V,vV); + matrix_to_list(F,vF); + return mesh_to_tetgenio(vV,vF,in); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +template bool igl::copyleft::tetgen::mesh_to_tetgenio, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, tetgenio&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/tetgen/mesh_to_tetgenio.h b/src/external/libigl-2.3.0/include/igl/copyleft/tetgen/mesh_to_tetgenio.h new file mode 100644 index 000000000..23e00e947 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/tetgen/mesh_to_tetgenio.h @@ -0,0 +1,87 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_COPYLEFT_TETGEN_MESH_TO_TETGENIO_H +#define IGL_COPYLEFT_TETGEN_MESH_TO_TETGENIO_H +#include "../../igl_inline.h" + +#ifndef TETLIBRARY +# define TETLIBRARY +#endif +#include "tetgen.h" // Defined tetgenio, REAL +#include +#include + +namespace igl +{ + namespace copyleft + { + namespace tetgen + { + // Load a vertex list and face list into a tetgenio object + // Inputs: + // V #V by 3 vertex position list + // F #F list of polygon face indices into V (0-indexed) + // Outputs: + // in tetgenio input object + // Returns true on success, false on error + IGL_INLINE bool mesh_to_tetgenio( + const std::vector > & V, + const std::vector > & F, + tetgenio & in); + + // Wrapper with Eigen types + // Templates: + // DerivedV real-value: i.e. from MatrixXd + // DerivedF integer-value: i.e. from MatrixXi + template + IGL_INLINE bool mesh_to_tetgenio( + const Eigen::PlainObjectBase& V, + const Eigen::PlainObjectBase& F, + tetgenio & in); + + + // Load a vertex list and face list into a tetgenio object + // Inputs: + // V #V by 3 vertex position list + // F #F list of polygon face indices into V (0-indexed) + // H #H list of seed point inside each hole + // R #R list of seed point inside each region + // Outputs: + // in tetgenio input object + // Returns true on success, false on error + IGL_INLINE bool mesh_to_tetgenio( + const std::vector > & V, + const std::vector > & F, + const std::vector > & H, + const std::vector > & R, + tetgenio & in); + + + // Wrapper with Eigen types + // Templates: + // DerivedV real-value: i.e. from MatrixXd + // DerivedF integer-value: i.e. from MatrixXi + // DerivedH real-value + // DerivedR real-value + template + IGL_INLINE bool mesh_to_tetgenio( + const Eigen::PlainObjectBase& V, + const Eigen::PlainObjectBase& F, + const Eigen::PlainObjectBase& H, + const Eigen::PlainObjectBase& R, + tetgenio& in); + } + } +} + + +#ifndef IGL_STATIC_LIBRARY +# include "mesh_to_tetgenio.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/tetgen/mesh_with_skeleton.cpp b/src/external/libigl-2.3.0/include/igl/copyleft/tetgen/mesh_with_skeleton.cpp new file mode 100644 index 000000000..5c920b36d --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/tetgen/mesh_with_skeleton.cpp @@ -0,0 +1,102 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "mesh_with_skeleton.h" +#include "tetrahedralize.h" + +#include "../../sample_edges.h" +#include "../../cat.h" + +#include +// Default settings pq2Y tell tetgen to mesh interior of triangle mesh and +// to produce a graded tet mesh +const static std::string DEFAULT_TETGEN_FLAGS = "pq2Y"; + +IGL_INLINE bool igl::copyleft::tetgen::mesh_with_skeleton( + const Eigen::MatrixXd & V, + const Eigen::MatrixXi & F, + const Eigen::MatrixXd & C, + const Eigen::VectorXi & /*P*/, + const Eigen::MatrixXi & BE, + const Eigen::MatrixXi & CE, + const int samples_per_bone, + const std::string & tetgen_flags, + Eigen::MatrixXd & VV, + Eigen::MatrixXi & TT, + Eigen::MatrixXi & FF) +{ + using namespace Eigen; + using namespace std; + const string eff_tetgen_flags = + (tetgen_flags.length() == 0?DEFAULT_TETGEN_FLAGS:tetgen_flags); + // Collect all edges that need samples: + MatrixXi BECE = cat(1,BE,CE); + MatrixXd S; + // Sample each edge with 10 samples. (Choice of 10 doesn't seem to matter so + // much, but could under some circumstances) + sample_edges(C,BECE,samples_per_bone,S); + // Vertices we'll constrain tet mesh to meet + MatrixXd VS = cat(1,V,S); + // Use tetgen to mesh the interior of surface, this assumes surface: + // * has no holes + // * has no non-manifold edges or vertices + // * has consistent orientation + // * has no self-intersections + // * has no 0-volume pieces + cerr<<"tetgen begin()"< +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_COPYLEFT_TETGEN_MESH_WITH_SKELETON_H +#define IGL_COPYLEFT_TETGEN_MESH_WITH_SKELETON_H +#include "../../igl_inline.h" +#include +#include + +namespace igl +{ + namespace copyleft + { + namespace tetgen + { + // Mesh the interior of a given surface with tetrahedra which are graded + // (tend to be small near the surface and large inside) and conform to the + // given handles and samplings thereof. + // + // Inputs: + // V #V by 3 list of mesh vertex positions + // F #F by 3 list of triangle indices + // C #C by 3 list of vertex positions + // P #P list of point handle indices + // BE #BE by 2 list of bone-edge indices + // CE #CE by 2 list of cage-edge indices + // samples_per_bone #samples to add per bone + // tetgen_flags flags to pass to tetgen {""-->"pq2Y"} otherwise you're on + // your own and it's your funeral if you pass nonsense flags + // Outputs: + // VV #VV by 3 list of tet-mesh vertex positions + // TT #TT by 4 list of tetrahedra indices + // FF #FF by 3 list of surface triangle indices + // Returns true only on success + IGL_INLINE bool mesh_with_skeleton( + const Eigen::MatrixXd & V, + const Eigen::MatrixXi & F, + const Eigen::MatrixXd & C, + const Eigen::VectorXi & /*P*/, + const Eigen::MatrixXi & BE, + const Eigen::MatrixXi & CE, + const int samples_per_bone, + const std::string & tetgen_flags, + Eigen::MatrixXd & VV, + Eigen::MatrixXi & TT, + Eigen::MatrixXi & FF); + // Wrapper using default tetgen_flags + IGL_INLINE bool mesh_with_skeleton( + const Eigen::MatrixXd & V, + const Eigen::MatrixXi & F, + const Eigen::MatrixXd & C, + const Eigen::VectorXi & /*P*/, + const Eigen::MatrixXi & BE, + const Eigen::MatrixXi & CE, + const int samples_per_bone, + Eigen::MatrixXd & VV, + Eigen::MatrixXi & TT, + Eigen::MatrixXi & FF); + } + } +} + + +#ifndef IGL_STATIC_LIBRARY +# include "mesh_with_skeleton.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/tetgen/read_into_tetgenio.cpp b/src/external/libigl-2.3.0/include/igl/copyleft/tetgen/read_into_tetgenio.cpp new file mode 100644 index 000000000..506c5e4ba --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/tetgen/read_into_tetgenio.cpp @@ -0,0 +1,74 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "read_into_tetgenio.h" +#include "mesh_to_tetgenio.h" + +// IGL includes +#include "../../pathinfo.h" +#ifndef IGL_NO_EIGEN +# define IGL_NO_EIGEN_WAS_NOT_ALREADY_DEFINED +# define IGL_NO_EIGEN +#endif +// Include igl headers without including Eigen +#include "../../readOBJ.h" +#ifdef IGL_NO_EIGEN_WAS_NOT_ALREADY_DEFINED +# undef IGL_NO_EIGEN +#endif + +// STL includes +#include +#include +#include + +IGL_INLINE bool igl::copyleft::tetgen::read_into_tetgenio( + const std::string & path, + tetgenio & in) +{ + using namespace std; + // get file extension + string dirname,basename,ext,filename; + pathinfo(path,dirname,basename,ext,filename); + // convert to lower case for easy comparison + transform(ext.begin(), ext.end(), ext.begin(), ::tolower); + bool success = false; + + char basename_char[1024]; + strcpy(basename_char,basename.c_str()); + + if(ext == "obj") + { + // read obj into vertex list and face list + vector > V,TC,N; + vector > F,FTC,FN; + success = readOBJ(path,V,TC,N,F,FTC,FN); + success &= mesh_to_tetgenio(V,F,in); + }else if(ext == "off") + { + success = in.load_off(basename_char); + }else if(ext == "node") + { + success = in.load_node(basename_char); + }else + { + if(ext.length() > 0) + { + cerr<<"^read_into_tetgenio Warning: Unsupported extension ("< +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_COPYLEFT_TETGEN_READ_INTO_TETGENIO_H +#define IGL_COPYLEFT_TETGEN_READ_INTO_TETGENIO_H +#include "../../igl_inline.h" + +#include +#ifndef TETLIBRARY +#define TETLIBRARY +#endif +#include "tetgen.h" // Defined tetgenio, REAL + +namespace igl +{ + namespace copyleft + { + namespace tetgen + { + // Read a mesh or point set into tetgenio (input object for calling + // tetgen). Many file formats are already supported by tetgen: + // .off + // .ply + // .node + // .ply + // .medit + // .vtk + // etc. + // Notably it does not support .obj which is loaded by hand here (also + // demonstrating how to load points/faces programmatically) + // + // If the file extension is not recognized the filename is assumed to be + // the basename of a collection describe a tetmesh, (of which at least + // the .node file must exist): + // [filename].node + // [filename].ele + // [filename].face + // [filename].edge + // [filename].vol + // + // Inputs: + // path path to file or basename to files + // Outputs: + // in tetgenio input object + // Returns true on success, false on error + IGL_INLINE bool read_into_tetgenio( + const std::string & path, + tetgenio & in); + } + } +} + + +#ifndef IGL_STATIC_LIBRARY +# include "read_into_tetgenio.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/tetgen/tetgenio_to_tetmesh.cpp b/src/external/libigl-2.3.0/include/igl/copyleft/tetgen/tetgenio_to_tetmesh.cpp new file mode 100644 index 000000000..aba87da83 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/tetgen/tetgenio_to_tetmesh.cpp @@ -0,0 +1,280 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "tetgenio_to_tetmesh.h" + +// IGL includes +#include "../../list_to_matrix.h" + +// STL includes +#include + +IGL_INLINE bool igl::copyleft::tetgen::tetgenio_to_tetmesh( + const tetgenio & out, + std::vector > & V, + std::vector > & T, + std::vector > & F) +{ + using namespace std; + // process points + if(out.pointlist == NULL) + { + cerr<<"^tetgenio_to_tetmesh Error: point list is NULL\n"<(3)); + // loop over points + for(int i = 0;i < out.numberofpoints; i++) + { + V[i][0] = out.pointlist[i*3+0]; + V[i][1] = out.pointlist[i*3+1]; + V[i][2] = out.pointlist[i*3+2]; + } + + + // process tets + if(out.tetrahedronlist == NULL) + { + cerr<<"^tetgenio_to_tetmesh Error: tet list is NULL\n"<(out.numberofcorners)); + int min_index = 1e7; + int max_index = -1e7; + // loop over tetrahedra + for(int i = 0; i < out.numberoftetrahedra; i++) + { + for(int j = 0; j index ? index : min_index); + max_index = (max_index < index ? index : max_index); + } + } + assert(min_index >= 0); + assert(max_index >= 0); + assert(max_index < (int)V.size()); + + // When would this not be 4? + F.clear(); + // loop over tetrahedra + for(int i = 0; i < out.numberoftrifaces; i++) + { + if (out.trifacemarkerlist && out.trifacemarkerlist[i] >= 0) + { + vector face(3); + for(int j = 0; j<3; j++) + { + face[j] = out.trifacelist[i * 3 + j]; + } + F.push_back(face); + } + } + + return true; +} + +template +IGL_INLINE bool igl::copyleft::tetgen::tetgenio_to_tetmesh( + const tetgenio & out, + Eigen::PlainObjectBase& V, + Eigen::PlainObjectBase& T) +{ + Eigen::Matrix F; + return tetgenio_to_tetmesh(out,V,T,F); +} + +template +IGL_INLINE bool igl::copyleft::tetgen::tetgenio_to_tetmesh( + const tetgenio & out, + Eigen::PlainObjectBase& V, + Eigen::PlainObjectBase& T, + Eigen::PlainObjectBase& F) +{ + using namespace std; + vector > vV; + vector > vT; + vector > vF; + bool success = tetgenio_to_tetmesh(out,vV,vT,vF); + if(!success) + { + return false; + } + bool V_rect = list_to_matrix(vV,V); + if(!V_rect) + { + // igl::list_to_matrix(vV,V) already printed error message to std err + return false; + } + bool T_rect = list_to_matrix(vT,T); + if(!T_rect) + { + // igl::list_to_matrix(vT,T) already printed error message to std err + return false; + } + bool F_rect = list_to_matrix(vF,F); + if(!F_rect) + { + return false; + } + + return true; +} + +IGL_INLINE bool igl::copyleft::tetgen::tetgenio_to_tetmesh( + const tetgenio & out, + std::vector > & V, + std::vector > & T) +{ + std::vector > F; + return tetgenio_to_tetmesh(out,V,T,F); +} + +IGL_INLINE bool igl::copyleft::tetgen::tetgenio_to_tetmesh( + const tetgenio & out, + std::vector > & V, + std::vector > & T, + std::vector > & F, + std::vector >& R, + std::vector >& N, + std::vector >& PT, + std::vector >& FT, + size_t & nR ) +{ + using namespace std; + // process points + if(out.pointlist == NULL) + { + cerr<<"^tetgenio_to_tetmesh Error: point list is NULL\n"<(3)); + // loop over points + for(int i = 0;i < out.numberofpoints; i++) + { + V[i][0] = out.pointlist[i*3+0]; + V[i][1] = out.pointlist[i*3+1]; + V[i][2] = out.pointlist[i*3+2]; + } + + // process tets + if(out.tetrahedronlist == NULL) + { + cerr<<"^tetgenio_to_tetmesh Error: tet list is NULL\n"<(out.numberofcorners)); + int min_index = 1e7; + int max_index = -1e7; + // loop over tetrahedra + for(int i = 0; i < out.numberoftetrahedra; i++) + { + for(int j = 0; j index ? index : min_index); + max_index = (max_index < index ? index : max_index); + } + } + + assert(min_index >= 0); + assert(max_index >= 0); + assert(max_index < (int)V.size()); + + // When would this not be 4? + F.clear(); + // loop over tetrahedra + for(int i = 0; i < out.numberoftrifaces; i++) + { + if(out.trifacemarkerlist[i]>=0) + { + vector face(3); + for(int j = 0; j<3; j++) + { + face[j] = out.trifacelist[i * 3 + j]; + } + F.push_back(face); + } + } + + if(out.tetrahedronattributelist) + { + R.resize(out.numberoftetrahedra, vector(1)); + unordered_map hashUniqueRegions; + for(size_t i = 0; i < out.numberoftetrahedra; i++) + { + R[i][0] = out.tetrahedronattributelist[i]; + hashUniqueRegions[R[i][0]] = i; + } + // extract region marks + nR = hashUniqueRegions.size(); + }else + { + R.clear(); + nR = 0; + } + + // extract neighbor list + if(out.neighborlist) + { + N.resize(out.numberoftetrahedra, vector(4)); + for (size_t i = 0; i < out.numberoftetrahedra; i++) + { + for (size_t j = 0; j < 4; j++) + N[i][j] = out.neighborlist[i * 4 + j]; + } + }else + { + N.clear(); + } + + // extract point 2 tetrahedron list + if(out.point2tetlist) + { + PT.resize(out.numberofpoints, vector(1)); + for (size_t i = 0; i < out.numberofpoints; i++) + { + PT[i][0] = out.point2tetlist[i]; + } + }else + { + PT.clear(); + } + + //extract face to tetrahedron list + if(out.face2tetlist) + { + FT.resize(out.numberoftrifaces, vector(2)); + int triface; + for (size_t i = 0; i < out.numberoftrifaces; i++) + { + for (size_t j = 0; j < 2; j++) + { + FT[i][j] = out.face2tetlist[0]; + } + } + }else + { + FT.clear(); + } + + return true; +} + + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +template bool igl::copyleft::tetgen::tetgenio_to_tetmesh, Eigen::Matrix >(tetgenio const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/tetgen/tetgenio_to_tetmesh.h b/src/external/libigl-2.3.0/include/igl/copyleft/tetgen/tetgenio_to_tetmesh.h new file mode 100644 index 000000000..0d1c523e1 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/tetgen/tetgenio_to_tetmesh.h @@ -0,0 +1,94 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_COPYLEFT_TETGEN_TETGENIO_TO_TETMESH_H +#define IGL_COPYLEFT_TETGEN_TETGENIO_TO_TETMESH_H +#include "../../igl_inline.h" + +#ifndef TETLIBRARY +#define TETLIBRARY +#endif +#include "tetgen.h" // Defined tetgenio, REAL +#include +#include +#include +namespace igl +{ + namespace copyleft + { + namespace tetgen + { + // Extract a tetrahedral mesh from a tetgenio object + // Inputs: + // out tetgenio output object + // Outputs: + // V #V by 3 vertex position list + // T #T by 4 list of tetrahedra indices into V + // F #F by 3 list of marked facets + // Returns true on success, false on error + IGL_INLINE bool tetgenio_to_tetmesh( + const tetgenio & out, + std::vector > & V, + std::vector > & T, + std::vector > & F); + + IGL_INLINE bool tetgenio_to_tetmesh( + const tetgenio & out, + std::vector > & V, + std::vector > & T); + + // Wrapper with Eigen types + // Templates: + // DerivedV real-value: i.e. from MatrixXd + // DerivedT integer-value: i.e. from MatrixXi + template + IGL_INLINE bool tetgenio_to_tetmesh( + const tetgenio & out, + Eigen::PlainObjectBase& V, + Eigen::PlainObjectBase& T, + Eigen::PlainObjectBase& F); + + template + IGL_INLINE bool tetgenio_to_tetmesh( + const tetgenio & out, + Eigen::PlainObjectBase& V, + Eigen::PlainObjectBase& T); + + // Extract a tetrahedral mesh from a tetgenio object + // Inputs: + // out tetgenio output object + // Outputs: + // V #V by 3 vertex position list + // T #T by 4 list of tetrahedra indices into V + // F #F by 3 list of marked facets + // R #T list of region IDs for tetrahedra + // N #T by 2 list of neighbors for each tetrahedron + // PT #V list of incident tetrahedron for each vertex + // FT #F by 2 list of tetrahedra sharing each face + // nR number of regions in output mesh + // Returns true on success, false on error + IGL_INLINE bool tetgenio_to_tetmesh( + const tetgenio & out, + std::vector > & V, + std::vector > & T, + std::vector > & F, + std::vector > & R,// region marks for tetrahedrons + std::vector > &N, // neighborlist per tet + std::vector > &PT, // Point to tet list per point + std::vector > &FT, // face to tet list + size_t & nR); // number of regions + + } + } +} + + +#ifndef IGL_STATIC_LIBRARY +# include "tetgenio_to_tetmesh.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/tetgen/tetrahedralize.cpp b/src/external/libigl-2.3.0/include/igl/copyleft/tetgen/tetrahedralize.cpp new file mode 100644 index 000000000..c5f6eb29d --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/tetgen/tetrahedralize.cpp @@ -0,0 +1,346 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "tetrahedralize.h" +#include "mesh_to_tetgenio.h" +#include "tetgenio_to_tetmesh.h" + +// IGL includes +#include "../../matrix_to_list.h" +#include "../../list_to_matrix.h" +#include "../../boundary_facets.h" + +// STL includes +#include +#include + +IGL_INLINE int igl::copyleft::tetgen::tetrahedralize( + const std::vector > & V, + const std::vector > & F, + const std::string switches, + std::vector > & TV, + std::vector > & TT, + std::vector > & TF) +{ + using namespace std; + tetgenio in,out; + bool success; + success = mesh_to_tetgenio(V,F,in); + if(!success) + { + return -1; + } + try + { + char * cswitches = new char[switches.size() + 1]; + std::strcpy(cswitches,switches.c_str()); + ::tetrahedralize(cswitches,&in, &out); + delete[] cswitches; + }catch(int e) + { + cerr<<"^"<<__FUNCTION__<<": TETGEN CRASHED... KABOOOM!!!"< +IGL_INLINE int igl::copyleft::tetgen::tetrahedralize( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + const std::string switches, + Eigen::PlainObjectBase& TV, + Eigen::PlainObjectBase& TT, + Eigen::PlainObjectBase& TF) +{ + using namespace std; + vector > vV,vTV; + vector > vF,vTT,vTF; + matrix_to_list(V,vV); + matrix_to_list(F,vF); + int e = tetrahedralize(vV,vF,switches,vTV,vTT,vTF); + if(e == 0) + { + bool TV_rect = list_to_matrix(vTV,TV); + if(!TV_rect) + { + return 3; + } + bool TT_rect = list_to_matrix(vTT,TT); + if(!TT_rect) + { + return 3; + } + bool TF_rect = list_to_matrix(vTF,TF); + if(!TF_rect) + { + return 3; + } + } + return e; +} + +template < + typename DerivedV, + typename DerivedF, + typename DerivedVM, + typename DerivedFM, + typename DerivedTV, + typename DerivedTT, + typename DerivedTF, + typename DerivedTM> +IGL_INLINE int igl::copyleft::tetgen::tetrahedralize( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + const Eigen::MatrixBase& VM, + const Eigen::MatrixBase& FM, + const std::string switches, + Eigen::PlainObjectBase& TV, + Eigen::PlainObjectBase& TT, + Eigen::PlainObjectBase& TF, + Eigen::PlainObjectBase& TM) +{ + using namespace std; + vector > vV,vTV; + vector > vF,vTT,vTF; + vector vTM; + + matrix_to_list(V,vV); + matrix_to_list(F,vF); + vector vVM = matrix_to_list(VM); + vector vFM = matrix_to_list(FM); + int e = tetrahedralize(vV,vF,vVM,vFM,switches,vTV,vTT,vTF,vTM); + if(e == 0) + { + bool TV_rect = list_to_matrix(vTV,TV); + if(!TV_rect) + { + return false; + } + bool TT_rect = list_to_matrix(vTT,TT); + if(!TT_rect) + { + return false; + } + bool TF_rect = list_to_matrix(vTF,TF); + if(!TF_rect) + { + return false; + } + bool TM_rect = list_to_matrix(vTM,TM); + if(!TM_rect) + { + return false; + } + } + return e; +} + +IGL_INLINE int igl::copyleft::tetgen::tetrahedralize( + const std::vector > & V, + const std::vector > & F, + const std::vector & VM, + const std::vector & FM, + const std::string switches, + std::vector > & TV, + std::vector > & TT, + std::vector > & TF, + std::vector & TM) +{ + using namespace std; + tetgenio in,out; + bool success; + success = mesh_to_tetgenio(V,F,in); + if(!success) + { + return -1; + } + in.pointmarkerlist = new int[VM.size()]; + for (int i = 0; i < VM.size(); ++i) { + in.pointmarkerlist[i] = VM[i]; + } + // These have already been created in mesh_to_tetgenio. + // Reset them here. + for (int i = 0; i < FM.size(); ++i) { + in.facetmarkerlist[i] = FM[i]; + } + try + { + char * cswitches = new char[switches.size() + 1]; + std::strcpy(cswitches,switches.c_str()); + ::tetrahedralize(cswitches,&in, &out); + delete[] cswitches; + }catch(int e) + { + cerr<<"^"<<__FUNCTION__<<": TETGEN CRASHED... KABOOOM!!!"< > & V, + const std::vector > & F, + const std::vector > & H, + const std::vector > & R, + const std::string switches, + std::vector > & TV, + std::vector > & TT, + std::vector > & TF, + std::vector > &TR, + std::vector > & TN, + std::vector > & PT, + std::vector > & FT, + size_t & numRegions) +{ + using namespace std; + tetgenio in,out; + bool success; + success = mesh_to_tetgenio(V, F, H, R, in); + if(!success) + { + return -1; + } + try + { + char * cswitches = new char[switches.size() + 1]; + strcpy(cswitches, switches.c_str()); + + ::tetrahedralize(cswitches, &in, &out); + delete[] cswitches; +}catch(int e) + { + cerr <<"^"<<__FUNCTION__<<": TETGEN CRASHED...KABOOM!!"< +IGL_INLINE int igl::copyleft::tetgen::tetrahedralize( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + const Eigen::MatrixBase& H, + const Eigen::MatrixBase& R, + const std::string switches, + Eigen::PlainObjectBase& TV, + Eigen::PlainObjectBase& TT, + Eigen::PlainObjectBase& TF, + Eigen::PlainObjectBase& TR, + Eigen::PlainObjectBase& TN, + Eigen::PlainObjectBase& PT, + Eigen::PlainObjectBase& FT, + size_t & numRegions) +{ + using namespace std; + vector > vV, vH, vR, vTV, vTR; + vector > vF,vTT,vTF, vTN, vPT, vFT; + matrix_to_list(V,vV); + matrix_to_list(F,vF); + matrix_to_list(H, vH); + matrix_to_list(R, vR); + + int e = tetrahedralize(vV,vF,vH,vR,switches,vTV,vTT,vTF,vTR,vTN,vPT,vFT, numRegions); + + if(e == 0) + { + bool TV_rect = list_to_matrix(vTV,TV); + if(!TV_rect) + { + return 3; + } + bool TT_rect = list_to_matrix(vTT,TT); + if(!TT_rect) + { + return 3; + } + bool TF_rect = list_to_matrix(vTF,TF); + if(!TF_rect) + { + return 3; + } + bool TR_rect = list_to_matrix(vTR, TR); + if(!TR_rect) + { + return 3; + } + bool TN_rect = list_to_matrix(vTN, TN); + if(!TN_rect) + { + return 3; + } + bool PT_rect = list_to_matrix(vPT, PT); + if(!PT_rect) + { + return 3; + } + bool FT_rect = list_to_matrix(vFT, FT); + if(!FT_rect) + { + return 3; + } + } + return e; +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +template int igl::copyleft::tetgen::tetrahedralize, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, std::basic_string, std::allocator >, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template int igl::copyleft::tetgen::tetrahedralize,Eigen::Matrix,Eigen::Matrix,Eigen::Matrix,Eigen::Matrix,Eigen::Matrix,Eigen::Matrix,Eigen::Matrix >(const Eigen::MatrixBase > &,const Eigen::MatrixBase > &,const Eigen::MatrixBase > &,const Eigen::MatrixBase > &,const std::basic_string, std::allocator >,Eigen::PlainObjectBase > &,Eigen::PlainObjectBase > &,Eigen::PlainObjectBase > &, Eigen::PlainObjectBase > &); +template int igl::copyleft::tetgen::tetrahedralize, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, std::basic_string, std::allocator >, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template int igl::copyleft::tetgen::tetrahedralize, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, std::basic_string, std::allocator >, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, unsigned long&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/copyleft/tetgen/tetrahedralize.h b/src/external/libigl-2.3.0/include/igl/copyleft/tetgen/tetrahedralize.h new file mode 100644 index 000000000..926ae84af --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/copyleft/tetgen/tetrahedralize.h @@ -0,0 +1,202 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_COPYLEFT_TETGEN_TETRAHEDRALIZE_H +#define IGL_COPYLEFT_TETGEN_TETRAHEDRALIZE_H +#include "../../igl_inline.h" + +#include +#include +#include +#ifndef TETLIBRARY +#define TETLIBRARY +#endif +#include // Defined REAL + +namespace igl +{ + namespace copyleft + { + namespace tetgen + { + // Mesh the interior of a surface mesh (V,F) using tetgen + // + // Inputs: + // V #V by 3 vertex position list + // F #F list of polygon face indices into V (0-indexed) + // switches string of tetgen options (See tetgen documentation) e.g. + // "pq1.414a0.01" tries to mesh the interior of a given surface with + // quality and area constraints + // "" will mesh the convex hull constrained to pass through V (ignores F) + // Outputs: + // TV #V by 3 vertex position list + // TT #T by 4 list of tet face indices + // TF #F by 3 list of triangle face indices + // Returns status: + // 0 success + // 1 tetgen threw exception + // 2 tetgen did not crash but could not create any tets (probably there are + // holes, duplicate faces etc.) + // -1 other error + IGL_INLINE int tetrahedralize( + const std::vector > & V, + const std::vector > & F, + const std::string switches, + std::vector > & TV, + std::vector > & TT, + std::vector > & TF); + + // Wrapper with Eigen types + // Templates: + // DerivedV real-value: i.e. from MatrixXd + // DerivedF integer-value: i.e. from MatrixXi + template < + typename DerivedV, + typename DerivedF, + typename DerivedTV, + typename DerivedTT, + typename DerivedTF> + IGL_INLINE int tetrahedralize( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + const std::string switches, + Eigen::PlainObjectBase& TV, + Eigen::PlainObjectBase& TT, + Eigen::PlainObjectBase& TF); + + // Mesh the interior of a surface mesh (V,F) using tetgen + // + // Inputs: + // V #V by 3 vertex position list + // F #F list of polygon face indices into V (0-indexed) + // M #V list of markers for vertices + // switches string of tetgen options (See tetgen documentation) e.g. + // "pq1.414a0.01" tries to mesh the interior of a given surface with + // quality and area constraints + // "" will mesh the convex hull constrained to pass through V (ignores F) + // Outputs: + // TV #V by 3 vertex position list + // TT #T by 4 list of tet face indices + // TF #F by 3 list of triangle face indices + // TM #V list of markers for vertices + // Returns status: + // 0 success + // 1 tetgen threw exception + // 2 tetgen did not crash but could not create any tets (probably there are + // holes, duplicate faces etc.) + // -1 other error + IGL_INLINE int tetrahedralize( + const std::vector > & V, + const std::vector > & F, + const std::vector & VM, + const std::vector & FM, + const std::string switches, + std::vector > & TV, + std::vector > & TT, + std::vector > & TF, + std::vector & TM); + // Wrapper with Eigen types + // Templates: + // DerivedV real-value: i.e. from MatrixXd + // DerivedF integer-value: i.e. from MatrixXi + template < + typename DerivedV, + typename DerivedF, + typename DerivedVM, + typename DerivedFM, + typename DerivedTV, + typename DerivedTT, + typename DerivedTF, + typename DerivedTM> + IGL_INLINE int tetrahedralize( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + const Eigen::MatrixBase& VM, + const Eigen::MatrixBase& FM, + const std::string switches, + Eigen::PlainObjectBase& TV, + Eigen::PlainObjectBase& TT, + Eigen::PlainObjectBase& TF, + Eigen::PlainObjectBase& TM); + // Mesh the interior of a surface mesh (V,F) using tetgen + // + // Inputs: + // V #V by 3 vertex position list + // F #F list of polygon face indices into V (0-indexed) + // H #H by 3 list of seed points inside holes + // R #R by 5 list of region attributes + // switches string of tetgen options (See tetgen documentation) e.g. + // "pq1.414a0.01" tries to mesh the interior of a given surface with + // quality and area constraints + // "" will mesh the convex hull constrained to pass through V (ignores F) + // Outputs: + // TV #V by 3 vertex position list + // TT #T by 4 list of tet face indices + // TF #F by 3 list of triangle face indices + // TR #T list of region ID for each tetrahedron + // TN #T by 4 list of indices neighbors for each tetrahedron + // PT #V list of incident tetrahedron for a vertex + // FT #F by 2 list of tetrahedrons sharing a triface + // numRegions Number of regions in output mesh + // Returns status: + // 0 success + // 1 tetgen threw exception + // 2 tetgen did not crash but could not create any tets (probably there are + // holes, duplicate faces etc.) + // -1 other error + IGL_INLINE int tetrahedralize( + const std::vector > &V, + const std::vector > &F, + const std::vector > &H, + const std::vector > &R, + const std::string switches, + std::vector > & TV, + std::vector > & TT, + std::vector > & TF, + std::vector > &TR, + std::vector > &TN, + std::vector > &PT, + std::vector > &FT, + size_t & numRegions); + // Wrapper with Eigen types + // Templates: + // DerivedV real-value: i.e. from MatrixXd + // DerivedF integer-value: i.e. from MatrixXi + template < + typename DerivedV, + typename DerivedF, + typename DerivedH, + typename DerivedR, + typename DerivedTV, + typename DerivedTT, + typename DerivedTF, + typename DerivedTR> + IGL_INLINE int tetrahedralize( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + const Eigen::MatrixBase& H, + const Eigen::MatrixBase& R, + const std::string switches, + Eigen::PlainObjectBase& TV, + Eigen::PlainObjectBase& TT, + Eigen::PlainObjectBase& TF, + Eigen::PlainObjectBase& TR, + Eigen::PlainObjectBase& TN, + Eigen::PlainObjectBase& PT, + Eigen::PlainObjectBase& FT, + size_t & numRegions); + } + } +} + + +#ifndef IGL_STATIC_LIBRARY +# include "tetrahedralize.cpp" +#endif + +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/cotmatrix.cpp b/src/external/libigl-2.3.0/include/igl/cotmatrix.cpp new file mode 100644 index 000000000..fe168cc8a --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/cotmatrix.cpp @@ -0,0 +1,232 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "cotmatrix.h" +#include + +// For error printing +#include +#include "cotmatrix_entries.h" + +// Bug in unsupported/Eigen/SparseExtra needs iostream first +#include + +template +IGL_INLINE void igl::cotmatrix( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + Eigen::SparseMatrix& L) +{ + using namespace Eigen; + using namespace std; + + L.resize(V.rows(),V.rows()); + Matrix edges; + int simplex_size = F.cols(); + // 3 for triangles, 4 for tets + assert(simplex_size == 3 || simplex_size == 4); + if(simplex_size == 3) + { + // This is important! it could decrease the comptuation time by a factor of 2 + // Laplacian for a closed 2d manifold mesh will have on average 7 entries per + // row + L.reserve(10*V.rows()); + edges.resize(3,2); + edges << + 1,2, + 2,0, + 0,1; + }else if(simplex_size == 4) + { + L.reserve(17*V.rows()); + edges.resize(6,2); + edges << + 1,2, + 2,0, + 0,1, + 3,0, + 3,1, + 3,2; + }else + { + return; + } + // Gather cotangents + Matrix C; + cotmatrix_entries(V,F,C); + + vector > IJV; + IJV.reserve(F.rows()*edges.rows()*4); + // Loop over triangles + for(int i = 0; i < F.rows(); i++) + { + // loop over edges of element + for(int e = 0;e(source,dest,C(i,e))); + IJV.push_back(Triplet(dest,source,C(i,e))); + IJV.push_back(Triplet(source,source,-C(i,e))); + IJV.push_back(Triplet(dest,dest,-C(i,e))); + } + } + L.setFromTriplets(IJV.begin(),IJV.end()); +} + +#include "massmatrix.h" +#include "pinv.h" +#include "cotmatrix_entries.h" +#include "diag.h" +#include "massmatrix.h" +#include +#include + +template < + typename DerivedV, + typename DerivedI, + typename DerivedC, + typename Scalar> +IGL_INLINE void igl::cotmatrix( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & I, + const Eigen::MatrixBase & C, + Eigen::SparseMatrix& L, + Eigen::SparseMatrix& M, + Eigen::SparseMatrix& P) +{ + typedef Eigen::Matrix RowVector3S; + typedef Eigen::Matrix MatrixXS; + typedef Eigen::Matrix VectorXS; + typedef Eigen::Index Index; + // number of vertices + const Index n = V.rows(); + // number of polyfaces + const Index m = C.size()-1; + assert(V.cols() == 2 || V.cols() == 3); + std::vector > Lfijv; + std::vector > Mfijv; + std::vector > Pijv; + // loop over vertices; set identity for original vertices + for(Index i = 0;i X = decltype(X)::Zero(np+1,3); + for(Index i = 0;i(A).solve(b); + X.row(np) = w.transpose()*X.topRows(np); + // scatter w into new row of P + for(Index i = 0;i M; + igl::massmatrix(X,F,igl::MASSMATRIX_TYPE_DEFAULT,M); + Mp = M.diagonal(); + } + // Scatter into fine Laplacian and mass matrices + const auto J = [&n,&np,&p,&I,&C](Index i)->Index{return i==np?n+p:I(C(p)+i);}; + // Should just build Mf as a vector... + for(Index i = 0;i Lf(n+m,n+m); + Lf.setFromTriplets(Lfijv.begin(),Lfijv.end()); + Eigen::SparseMatrix Mf(n+m,n+m); + Mf.setFromTriplets(Mfijv.begin(),Mfijv.end()); + L = P.transpose() * Lf * P; + // "unlumped" M + const Eigen::SparseMatrix PTMP = P.transpose() * Mf * P; + // Lump M + const VectorXS Mdiag = PTMP * VectorXS::Ones(n,1); + igl::diag(Mdiag,M); + + MatrixXS Vf = P*V; + Eigen::MatrixXi Ff(I.size(),3); + { + Index f = 0; + for(Index p = 0;p, Eigen::Matrix, Eigen::Matrix, double>(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::SparseMatrix&, Eigen::SparseMatrix&, Eigen::SparseMatrix&); +// generated by autoexplicit.sh +template void igl::cotmatrix, Eigen::Matrix, double>(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::SparseMatrix&); +template void igl::cotmatrix, Eigen::Matrix, double>(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::SparseMatrix&); +template void igl::cotmatrix, Eigen::Matrix, double>(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::SparseMatrix&); +template void igl::cotmatrix, Eigen::Matrix, double>(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::SparseMatrix&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/cotmatrix.h b/src/external/libigl-2.3.0/include/igl/cotmatrix.h new file mode 100644 index 000000000..c1483ebcb --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/cotmatrix.h @@ -0,0 +1,82 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_COTMATRIX_H +#define IGL_COTMATRIX_H +#include "igl_inline.h" + +#include +#include + +// History: +// Used const references rather than copying the entire mesh +// Alec 9 October 2011 +// removed cotan (uniform weights) optional parameter it was building a buggy +// half of the uniform laplacian, please see adjacency_matrix instead +// Alec 9 October 2011 + +namespace igl +{ + // Constructs the cotangent stiffness matrix (discrete laplacian) for a given + // mesh (V,F). + // + // Templates: + // DerivedV derived type of eigen matrix for V (e.g. derived from + // MatrixXd) + // DerivedF derived type of eigen matrix for F (e.g. derived from + // MatrixXi) + // Scalar scalar type for eigen sparse matrix (e.g. double) + // Inputs: + // V #V by dim list of mesh vertex positions + // F #F by simplex_size list of mesh elements (triangles or tetrahedra) + // Outputs: + // L #V by #V cotangent matrix, each row i corresponding to V(i,:) + // + // See also: adjacency_matrix + // + // Note: This Laplacian uses the convention that diagonal entries are + // **minus** the sum of off-diagonal entries. The diagonal entries are + // therefore in general negative and the matrix is **negative** semi-definite + // (immediately, -L is **positive** semi-definite) + // + template + IGL_INLINE void cotmatrix( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + Eigen::SparseMatrix& L); + // Cotangent Laplacian (and mass matrix) for polygon meshes according to + // "Polygon Laplacian Made Simple" [Bunge et al. 2020] + // + // Inputs: + // V #V by 3 list of mesh vertex positions + // I #I vectorized list of polygon corner indices into rows of some matrix V + // C #polygons+1 list of cumulative polygon sizes so that C(i+1)-C(i) = size of + // the ith polygon, and so I(C(i)) through I(C(i+1)-1) are the indices of + // the ith polygon + // Outputs: + // L #V by #V polygon Laplacian made simple matrix + // M #V by #V mass matrix + // P #V+#polygons by #V prolongation operator + template < + typename DerivedV, + typename DerivedI, + typename DerivedC, + typename Scalar> + IGL_INLINE void cotmatrix( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & I, + const Eigen::MatrixBase & C, + Eigen::SparseMatrix& L, + Eigen::SparseMatrix& M, + Eigen::SparseMatrix& P); +} + +#ifndef IGL_STATIC_LIBRARY +# include "cotmatrix.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/cotmatrix_entries.cpp b/src/external/libigl-2.3.0/include/igl/cotmatrix_entries.cpp new file mode 100644 index 000000000..af750a939 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/cotmatrix_entries.cpp @@ -0,0 +1,149 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// Copyright (C) 2018 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "cotmatrix_entries.h" +#include "doublearea.h" +#include "squared_edge_lengths.h" +#include "edge_lengths.h" +#include "face_areas.h" +#include "volume.h" +#include "dihedral_angles.h" + +#include "verbose.h" + + +template +IGL_INLINE void igl::cotmatrix_entries( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + Eigen::PlainObjectBase& C) +{ + using namespace std; + using namespace Eigen; + // simplex size (3: triangles, 4: tetrahedra) + int simplex_size = F.cols(); + // Number of elements + int m = F.rows(); + + // Law of cosines + law of sines + switch(simplex_size) + { + case 3: + { + // Triangles + //Compute Squared Edge lengths + Matrix l2; + igl::squared_edge_lengths(V,F,l2); + //Compute Edge lengths + Matrix l; + l = l2.array().sqrt(); + + // double area + Matrix dblA; + doublearea(l,0.,dblA); + // cotangents and diagonal entries for element matrices + // correctly divided by 4 (alec 2010) + C.resize(m,3); + for(int i = 0;i l; + edge_lengths(V,F,l); + Matrix s; + face_areas(l,s); + Matrix cos_theta,theta; + dihedral_angles_intrinsic(l,s,theta,cos_theta); + + // volume + Matrix vol; + volume(l,vol); + + + // Law of sines + // http://mathworld.wolfram.com/Tetrahedron.html + Matrix sin_theta(m,6); + sin_theta.col(0) = vol.array() / ((2./(3.*l.col(0).array())).array() * s.col(1).array() * s.col(2).array()); + sin_theta.col(1) = vol.array() / ((2./(3.*l.col(1).array())).array() * s.col(2).array() * s.col(0).array()); + sin_theta.col(2) = vol.array() / ((2./(3.*l.col(2).array())).array() * s.col(0).array() * s.col(1).array()); + sin_theta.col(3) = vol.array() / ((2./(3.*l.col(3).array())).array() * s.col(3).array() * s.col(0).array()); + sin_theta.col(4) = vol.array() / ((2./(3.*l.col(4).array())).array() * s.col(3).array() * s.col(1).array()); + sin_theta.col(5) = vol.array() / ((2./(3.*l.col(5).array())).array() * s.col(3).array() * s.col(2).array()); + + + // http://arxiv.org/pdf/1208.0354.pdf Page 18 + C = (1./6.) * l.array() * cos_theta.array() / sin_theta.array(); + + break; + } + default: + { + fprintf(stderr, + "cotmatrix_entries.h: Error: Simplex size (%d) not supported\n", simplex_size); + assert(false); + } + } +} + +template +IGL_INLINE void igl::cotmatrix_entries( + const Eigen::MatrixBase& l, + Eigen::PlainObjectBase& C) +{ + using namespace Eigen; + const int m = l.rows(); + assert(l.cols() == 3 && "Only triangles accepted"); + //Compute squared Edge lengths + Matrix l2; + l2 = l.array().square(); + // Alec: It's a little annoying that there's duplicate code here. The + // "extrinic" version above is first computing squared edge lengths, taking + // the square root and calling this. We can't have a cotmatrix_entries(l,l2,C) + // overload because it will confuse Eigen with the cotmatrix_entries(V,F,C) + // overload. In the end, I'd like to be convinced that using l2 directly above + // is actually better numerically (or significantly faster) than just calling + // edge_lengths and this cotmatrix_entries(l,C); + // + // double area + Matrix dblA; + doublearea(l,0.,dblA); + // cotangents and diagonal entries for element matrices + // correctly divided by 4 (alec 2010) + C.resize(m,3); + for(int i = 0;i, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::cotmatrix_entries, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::cotmatrix_entries, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::cotmatrix_entries, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::cotmatrix_entries, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::cotmatrix_entries, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::cotmatrix_entries, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::cotmatrix_entries, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/cotmatrix_entries.h b/src/external/libigl-2.3.0/include/igl/cotmatrix_entries.h new file mode 100644 index 000000000..5847fd517 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/cotmatrix_entries.h @@ -0,0 +1,49 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Alec Jacobson +// Copyright (C) 2018 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_COTMATRIX_ENTRIES_H +#define IGL_COTMATRIX_ENTRIES_H +#include "igl_inline.h" +#include +namespace igl +{ + // COTMATRIX_ENTRIES compute the cotangents of each angle in mesh (V,F) + // + // Inputs: + // V #V by dim list of rest domain positions + // F #F by {3|4} list of {triangle|tetrahedra} indices into V + // Outputs: + // C #F by 3 list of 1/2*cotangents corresponding angles + // for triangles, columns correspond to edges [1,2],[2,0],[0,1] + // OR + // C #F by 6 list of 1/6*cotangents of dihedral angles*edge lengths + // for tets, columns along edges [1,2],[2,0],[0,1],[3,0],[3,1],[3,2] + // + template + IGL_INLINE void cotmatrix_entries( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + Eigen::PlainObjectBase& C); + // Intrinsic version. + // + // Inputs: + // l #F by 3 list of triangle edge lengths (see edge_lengths) + // Outputs: + // C #F by 3 list of 1/2*cotangents corresponding angles + // for triangles, columns correspond to edges [1,2],[2,0],[0,1] + template + IGL_INLINE void cotmatrix_entries( + const Eigen::MatrixBase& l, + Eigen::PlainObjectBase& C); +} + +#ifndef IGL_STATIC_LIBRARY +# include "cotmatrix_entries.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/cotmatrix_intrinsic.cpp b/src/external/libigl-2.3.0/include/igl/cotmatrix_intrinsic.cpp new file mode 100644 index 000000000..1504db5a4 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/cotmatrix_intrinsic.cpp @@ -0,0 +1,67 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2018 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "cotmatrix_intrinsic.h" +#include "cotmatrix_entries.h" +#include + +template +IGL_INLINE void igl::cotmatrix_intrinsic( + const Eigen::MatrixBase & l, + const Eigen::MatrixBase & F, + Eigen::SparseMatrix& L) +{ + using namespace Eigen; + using namespace std; + // Cribbed from cotmatrix + + const int nverts = F.maxCoeff()+1; + L.resize(nverts,nverts); + Matrix edges; + int simplex_size = F.cols(); + // 3 for triangles, 4 for tets + assert(simplex_size == 3); + // This is important! it could decrease the comptuation time by a factor of 2 + // Laplacian for a closed 2d manifold mesh will have on average 7 entries per + // row + L.reserve(10*nverts); + edges.resize(3,2); + edges << + 1,2, + 2,0, + 0,1; + // Gather cotangents + Matrix C; + cotmatrix_entries(l,C); + + vector > IJV; + IJV.reserve(F.rows()*edges.rows()*4); + // Loop over triangles + for(int i = 0; i < F.rows(); i++) + { + // loop over edges of element + for(int e = 0;e(source,dest,C(i,e))); + IJV.push_back(Triplet(dest,source,C(i,e))); + IJV.push_back(Triplet(source,source,-C(i,e))); + IJV.push_back(Triplet(dest,dest,-C(i,e))); + } + } + L.setFromTriplets(IJV.begin(),IJV.end()); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +template void igl::cotmatrix_intrinsic, Eigen::Matrix, double>(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::SparseMatrix&); +template void igl::cotmatrix_intrinsic, Eigen::Matrix, double>(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::SparseMatrix&); +template void igl::cotmatrix_intrinsic, Eigen::Matrix, double>(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::SparseMatrix&); +template void igl::cotmatrix_intrinsic, Eigen::Matrix, double>(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::SparseMatrix&); +template void igl::cotmatrix_intrinsic, Eigen::Matrix, double>(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::SparseMatrix&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/cotmatrix_intrinsic.h b/src/external/libigl-2.3.0/include/igl/cotmatrix_intrinsic.h new file mode 100644 index 000000000..2a4f58be6 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/cotmatrix_intrinsic.h @@ -0,0 +1,40 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2018 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_COTMATRIX_INTRINSIC_H +#define IGL_COTMATRIX_INTRINSIC_H +#include "igl_inline.h" + +#include +#include + +namespace igl +{ + // Constructs the cotangent stiffness matrix (discrete laplacian) for a given + // mesh with faces F and edge lengths l. + // + // Inputs: + // l #F by 3 list of (half-)edge lengths + // F #F by 3 list of face indices into some (not necessarily + // determined/embedable) list of vertex positions V. It is assumed #V == + // F.maxCoeff()+1 + // Outputs: + // L #V by #V sparse Laplacian matrix + // + // See also: cotmatrix, intrinsic_delaunay_cotmatrix + template + IGL_INLINE void cotmatrix_intrinsic( + const Eigen::MatrixBase & l, + const Eigen::MatrixBase & F, + Eigen::SparseMatrix& L); +} + +#ifndef IGL_STATIC_LIBRARY +# include "cotmatrix_intrinsic.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/count.cpp b/src/external/libigl-2.3.0/include/igl/count.cpp new file mode 100644 index 000000000..bdde79ca7 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/count.cpp @@ -0,0 +1,65 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "count.h" +#include "redux.h" + +template +IGL_INLINE void igl::count( + const Eigen::SparseMatrix& X, + const int dim, + Eigen::SparseVector& S) +{ + // dim must be 2 or 1 + assert(dim == 1 || dim == 2); + // Get size of input + int m = X.rows(); + int n = X.cols(); + // resize output + if(dim==1) + { + S = Eigen::SparseVector(n); + }else + { + S = Eigen::SparseVector(m); + } + + // Iterate over outside + for(int k=0; k::InnerIterator it (X,k); it; ++it) + { + if(dim == 1) + { + S.coeffRef(it.col()) += (it.value() == 0? 0: 1); + }else + { + S.coeffRef(it.row()) += (it.value() == 0? 0: 1); + } + } + } + +} + +template +IGL_INLINE void igl::count( + const Eigen::SparseMatrix& A, + const int dim, + Eigen::PlainObjectBase& B) +{ + typedef typename DerivedB::Scalar Scalar; + igl::redux(A,dim,[](Scalar a, Scalar b){ return a+(b==0?0:1);},B); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::count >(Eigen::SparseMatrix const&, int, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::count >(Eigen::SparseMatrix const&, int, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/count.h b/src/external/libigl-2.3.0/include/igl/count.h new file mode 100644 index 000000000..61aeb94e8 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/count.h @@ -0,0 +1,46 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_COUNT_H +#define IGL_COUNT_H +#include "igl_inline.h" +#include + +namespace igl +{ + // Note: If your looking for dense matrix matlab like sum for eigen matrics + // just use: + // M.colwise().count() or M.rowwise().count() + // + + // Count the number of non-zeros in the columns or rows of a sparse matrix + // + // Inputs: + // X m by n sparse matrix + // dim dimension along which to sum (1 or 2) + // Output: + // S n-long sparse vector (if dim == 1) + // or + // S m-long sparse vector (if dim == 2) + template + IGL_INLINE void count( + const Eigen::SparseMatrix& X, + const int dim, + Eigen::SparseVector& S); + template + IGL_INLINE void count( + const Eigen::SparseMatrix& X, + const int dim, + Eigen::PlainObjectBase& S); +} + +#ifndef IGL_STATIC_LIBRARY +# include "count.cpp" +#endif + +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/covariance_scatter_matrix.cpp b/src/external/libigl-2.3.0/include/igl/covariance_scatter_matrix.cpp new file mode 100644 index 000000000..24fe9f760 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/covariance_scatter_matrix.cpp @@ -0,0 +1,76 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "covariance_scatter_matrix.h" +#include "arap_linear_block.h" +#include "cotmatrix.h" +#include "diag.h" +#include "sum.h" +#include "edges.h" +#include "verbose.h" +#include "cat.h" +#include "PI.h" + +IGL_INLINE void igl::covariance_scatter_matrix( + const Eigen::MatrixXd & V, + const Eigen::MatrixXi & F, + const ARAPEnergyType energy, + Eigen::SparseMatrix& CSM) +{ + using namespace Eigen; + // number of mesh vertices + int n = V.rows(); + assert(n > F.maxCoeff()); + // dimension of mesh + int dim = V.cols(); + // Number of mesh elements + int m = F.rows(); + + // number of rotations + int nr; + switch(energy) + { + case ARAP_ENERGY_TYPE_SPOKES: + nr = n; + break; + case ARAP_ENERGY_TYPE_SPOKES_AND_RIMS: + nr = n; + break; + case ARAP_ENERGY_TYPE_ELEMENTS: + nr = m; + break; + default: + fprintf( + stderr, + "covariance_scatter_matrix.h: Error: Unsupported arap energy %d\n", + energy); + return; + } + + SparseMatrix KX,KY,KZ; + arap_linear_block(V,F,0,energy,KX); + arap_linear_block(V,F,1,energy,KY); + SparseMatrix Z(n,nr); + if(dim == 2) + { + CSM = cat(1,cat(2,KX,Z),cat(2,Z,KY)).transpose(); + }else if(dim == 3) + { + arap_linear_block(V,F,2,energy,KZ); + SparseMatrixZZ(n,nr*2); + CSM = + cat(1,cat(1,cat(2,KX,ZZ),cat(2,cat(2,Z,KY),Z)),cat(2,ZZ,KZ)).transpose(); + }else + { + fprintf( + stderr, + "covariance_scatter_matrix.h: Error: Unsupported dimension %d\n", + dim); + return; + } + +} diff --git a/src/external/libigl-2.3.0/include/igl/covariance_scatter_matrix.h b/src/external/libigl-2.3.0/include/igl/covariance_scatter_matrix.h new file mode 100644 index 000000000..e70c77ab1 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/covariance_scatter_matrix.h @@ -0,0 +1,38 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_COVARIANCE_SCATTER_MATRIX_H +#define IGL_COVARIANCE_SCATTER_MATRIX_H + +#include "igl_inline.h" +#include "ARAPEnergyType.h" +#include +#include + +namespace igl +{ + // Construct the covariance scatter matrix for a given arap energy + // Inputs: + // V #V by Vdim list of initial domain positions + // F #F by 3 list of triangle indices into V + // energy ARAPEnergyType enum value defining which energy is being used. + // See ARAPEnergyType.h for valid options and explanations. + // Outputs: + // CSM dim*#V/#F by dim*#V sparse matrix containing special laplacians along + // the diagonal so that when multiplied by V gives covariance matrix + // elements, can be used to speed up covariance matrix computation + IGL_INLINE void covariance_scatter_matrix( + const Eigen::MatrixXd & V, + const Eigen::MatrixXi & F, + const ARAPEnergyType energy, + Eigen::SparseMatrix& CSM); +} + +#ifndef IGL_STATIC_LIBRARY +#include "covariance_scatter_matrix.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/cr_vector_curvature_correction.cpp b/src/external/libigl-2.3.0/include/igl/cr_vector_curvature_correction.cpp new file mode 100644 index 000000000..bd7f5103b --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/cr_vector_curvature_correction.cpp @@ -0,0 +1,189 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2020 Oded Stein +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +#include "cr_vector_curvature_correction.h" + +#include "orient_halfedges.h" +#include "gaussian_curvature.h" + +#include "squared_edge_lengths.h" +#include "doublearea.h" +#include "boundary_loop.h" +#include "internal_angles.h" + +#include "PI.h" + + +template +IGL_INLINE void +igl::cr_vector_curvature_correction( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + const Eigen::MatrixBase& E, + const Eigen::MatrixBase& oE, + Eigen::SparseMatrix& K) +{ + Eigen::Matrix + l_sq; + squared_edge_lengths(V, F, l_sq); + cr_vector_curvature_correction_intrinsic(F, l_sq, E, oE, K); +} + + +template +IGL_INLINE void +igl::cr_vector_curvature_correction( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + Eigen::PlainObjectBase& E, + Eigen::PlainObjectBase& oE, + Eigen::SparseMatrix& K) +{ + if(E.rows()!=F.rows() || E.cols()!=F.cols() || oE.rows()!=F.rows() || + oE.cols()!=F.cols()) { + orient_halfedges(F, E, oE); + } + + const Eigen::PlainObjectBase& cE = E; + const Eigen::PlainObjectBase& coE = oE; + cr_vector_curvature_correction(V, F, cE, coE, K); +} + + +template +IGL_INLINE void +igl::cr_vector_curvature_correction_intrinsic( + const Eigen::MatrixBase& F, + const Eigen::MatrixBase& l_sq, + const Eigen::MatrixBase& E, + const Eigen::MatrixBase& oE, + Eigen::SparseMatrix& K) +{ + Eigen::Matrix + theta; + internal_angles_using_squared_edge_lengths(l_sq, theta); + + cr_vector_curvature_correction_intrinsic(F, l_sq, theta, E, oE, K); +} + + +template +IGL_INLINE void +igl::cr_vector_curvature_correction_intrinsic( + const Eigen::MatrixBase& F, + const Eigen::MatrixBase& l_sq, + const Eigen::MatrixBase& theta, + const Eigen::MatrixBase& E, + const Eigen::MatrixBase& oE, + Eigen::SparseMatrix& K) +{ + // Compute the angle defect kappa, set it to 0 at the boundary + const typename DerivedF::Scalar n = F.maxCoeff() + 1; + Eigen::Matrix kappa(n); + kappa.setZero(); + for(Eigen::Index i=0; i > b; + boundary_loop(F, b); + for(const auto& loop : b) { + for(auto v : loop) { + kappa(v) = 0; + } + } + + cr_vector_curvature_correction_intrinsic(F, l_sq, theta, kappa, E, oE, K); +} + + +template +IGL_INLINE void +igl::cr_vector_curvature_correction_intrinsic( + const Eigen::MatrixBase& F, + const Eigen::MatrixBase& l_sq, + const Eigen::MatrixBase& theta, + const Eigen::MatrixBase& kappa, + const Eigen::MatrixBase& E, + const Eigen::MatrixBase& oE, + Eigen::SparseMatrix& K) +{ + assert(F.cols()==3 && "Faces have three vertices"); + assert(E.rows()==F.rows() && E.cols()==F.cols() && oE.rows()==F.rows() && + theta.rows()==F.rows() && theta.cols()==F.cols() && + oE.cols()==F.cols() && "Wrong dimension in edge vectors"); + assert(kappa.rows()==F.maxCoeff()+1 && + "Wrong dimension in theta or kappa"); + + const Eigen::Index m = F.rows(); + const typename DerivedE::Scalar nE = E.maxCoeff() + 1; + + //Divide kappa by the actual angle sum to weigh consistently. + Derivedtheta angleSum = Derivedtheta::Zero(kappa.rows(), 1); + for(Eigen::Index i=0; i + scaledKappa = kappa.array() / angleSum.array(); + + std::vector > tripletList; + tripletList.reserve(10*3*m); + for(Eigen::Index f=0; f, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, double>(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::SparseMatrix&); +template void igl::cr_vector_curvature_correction, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, double>(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::SparseMatrix&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/cr_vector_curvature_correction.h b/src/external/libigl-2.3.0/include/igl/cr_vector_curvature_correction.h new file mode 100644 index 000000000..8e00004c8 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/cr_vector_curvature_correction.h @@ -0,0 +1,115 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2020 Oded Stein +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_CR_VECTOR_CURVATURE_CORRECTION_H +#define IGL_CR_VECTOR_CURVATURE_CORRECTION_H + +#include "igl_inline.h" + +#include +#include + + +namespace igl +{ + // Computes the vector Crouzeix-Raviart curvature correction + // term of Oded Stein, Alec Jacobson, Max Wardetzky, Eitan + // Grinspun, 2020. "A Smoothness Energy without Boundary Distortion for + // Curved Surfaces", but using the basis functions by Oded Stein, + // Max Wardetzky, Alec Jacobson, Eitan Grinspun, 2020. + // "A Simple Discretization of the Vector Dirichlet Energy" + // + // Inputs: + // V, F: input mesh + // E: a mapping from each halfedge to each edge, as computed with + // orient_halfedges. + // will be computed if not provided. + // oE: the orientation of each halfedge compared to the orientation of the + // actual edge, as computed with orient_halfedges. + // will be computed if not provided. + // + // Outputs: + // K: computed curvature correction matrix + // E, oE: these are computed if they are not present, as described above + + template + IGL_INLINE void + cr_vector_curvature_correction( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + const Eigen::MatrixBase& E, + const Eigen::MatrixBase& oE, + Eigen::SparseMatrix& K); + + template + IGL_INLINE void + cr_vector_curvature_correction( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + Eigen::PlainObjectBase& E, + Eigen::PlainObjectBase& oE, + Eigen::SparseMatrix& K); + + + // Version that uses intrinsic quantities as input + // + // Inputs: + // F: input mesh connectivity + // l_sq: squared edge lengths of each halfedge + // theta: the tip angles at each halfedge + // kappa: the Gaussian curvature at each vertex + // E: a mapping from each halfedge to each edge. + // oE: the orientation of each halfedge compared to the orientation of the + // actual edge. + // + // Outputs: + // K: computed curvature correction matrix + + template + IGL_INLINE void + cr_vector_curvature_correction_intrinsic( + const Eigen::MatrixBase& F, + const Eigen::MatrixBase& l_sq, + const Eigen::MatrixBase& E, + const Eigen::MatrixBase& oE, + Eigen::SparseMatrix& K); + + template + IGL_INLINE void + cr_vector_curvature_correction_intrinsic( + const Eigen::MatrixBase& F, + const Eigen::MatrixBase& l_sq, + const Eigen::MatrixBase& theta, + const Eigen::MatrixBase& E, + const Eigen::MatrixBase& oE, + Eigen::SparseMatrix& K); + + template + IGL_INLINE void + cr_vector_curvature_correction_intrinsic( + const Eigen::MatrixBase& F, + const Eigen::MatrixBase& l_sq, + const Eigen::MatrixBase& theta, + const Eigen::MatrixBase& kappa, + const Eigen::MatrixBase& E, + const Eigen::MatrixBase& oE, + Eigen::SparseMatrix& K); +} + + +#ifndef IGL_STATIC_LIBRARY +# include "cr_vector_curvature_correction.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/cr_vector_laplacian.cpp b/src/external/libigl-2.3.0/include/igl/cr_vector_laplacian.cpp new file mode 100644 index 000000000..5bf539e66 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/cr_vector_laplacian.cpp @@ -0,0 +1,128 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2020 Oded Stein +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "cr_vector_laplacian.h" + +#include + +#include "orient_halfedges.h" + +#include "doublearea.h" +#include "squared_edge_lengths.h" + + +template +IGL_INLINE void +igl::cr_vector_laplacian( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + const Eigen::MatrixBase& E, + const Eigen::MatrixBase& oE, + Eigen::SparseMatrix& L) +{ + Eigen::Matrix + l_sq; + squared_edge_lengths(V, F, l_sq); + cr_vector_laplacian_intrinsic(F, l_sq, E, oE, L); +} + + +template +IGL_INLINE void +igl::cr_vector_laplacian( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + Eigen::PlainObjectBase& E, + Eigen::PlainObjectBase& oE, + Eigen::SparseMatrix& L) +{ + if(E.rows()!=F.rows() || E.cols()!=F.cols() || oE.rows()!=F.rows() || + oE.cols()!=F.cols()) { + orient_halfedges(F, E, oE); + } + + const Eigen::PlainObjectBase& cE = E; + const Eigen::PlainObjectBase& coE = oE; + cr_vector_laplacian(V, F, cE, coE, L); +} + + +template +IGL_INLINE void +igl::cr_vector_laplacian_intrinsic( + const Eigen::MatrixBase& F, + const Eigen::MatrixBase& l_sq, + const Eigen::MatrixBase& E, + const Eigen::MatrixBase& oE, + Eigen::SparseMatrix& L) +{ + Eigen::Matrix + dA; + DerivedL_sq l_sqrt = l_sq.array().sqrt().matrix(); + doublearea(l_sqrt, dA); + cr_vector_laplacian_intrinsic(F, l_sq, dA, E, oE, L); +} + + +template +IGL_INLINE void +igl::cr_vector_laplacian_intrinsic( + const Eigen::MatrixBase& F, + const Eigen::MatrixBase& l_sq, + const Eigen::MatrixBase& dA, + const Eigen::MatrixBase& E, + const Eigen::MatrixBase& oE, + Eigen::SparseMatrix& L) +{ + assert(F.cols()==3 && "Faces have three vertices"); + assert(E.rows()==F.rows() && E.cols()==F.cols() && oE.rows()==F.rows() && + oE.cols()==F.cols() && "Wrong dimension in edge vectors"); + assert(l_sq.rows()==F.rows() && l_sq.cols()==3 && "l_sq dimensions wrong"); + assert(dA.size()==F.rows() && "dA dimensions wrong"); + + const Eigen::Index m = F.rows(); + const typename DerivedE::Scalar nE = E.maxCoeff() + 1; + + std::vector > tripletList; + tripletList.reserve(10*3*m); + for(Eigen::Index f=0; f, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, double>(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::SparseMatrix&); +template void igl::cr_vector_laplacian_intrinsic, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, double>(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::SparseMatrix&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/cr_vector_laplacian.h b/src/external/libigl-2.3.0/include/igl/cr_vector_laplacian.h new file mode 100644 index 000000000..87f042782 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/cr_vector_laplacian.h @@ -0,0 +1,99 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2020 Oded Stein +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_CR_VECTOR_LAPLACIAN_H +#define IGL_CR_VECTOR_LAPLACIAN_H + +#include "igl_inline.h" + +#include +#include + + +namespace igl +{ + // Computes the CR vector Laplacian matrix. + // See Oded Stein, Max Wardetzky, Alec Jacobson, Eitan Grinspun, 2020. + // "A Simple Discretization of the Vector Dirichlet Energy" + // + // Inputs: + // V, F: input mesh + // E: a mapping from each halfedge to each edge, as computed with + // orient_halfedges. + // will be computed if not provided. + // oE: the orientation of each halfedge compared to the orientation of the + // actual edge, as computed with orient_halfedges. + // will be computed if not provided. + // + // Outputs: + // L: computed Laplacian matrix + // E, oE: these are computed if they are not present, as described above + + template + IGL_INLINE void + cr_vector_laplacian( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + const Eigen::MatrixBase& E, + const Eigen::MatrixBase& oE, + Eigen::SparseMatrix& L); + + template + IGL_INLINE void + cr_vector_laplacian( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + Eigen::PlainObjectBase& E, + Eigen::PlainObjectBase& oE, + Eigen::SparseMatrix& L); + + + // Version that uses intrinsic quantities as input + // + // Inputs: + // F: input mesh connectivity + // l_sq: squared edge lengths of each halfedge + // dA: double area of each face + // E: a mapping from each halfedge to each edge. + // oE: the orientation of each halfedge compared to the orientation of the + // actual edge. + // + // Outputs: + // L: computed Laplacian matrix + + template + IGL_INLINE void + cr_vector_laplacian_intrinsic( + const Eigen::MatrixBase& F, + const Eigen::MatrixBase& l_sq, + const Eigen::MatrixBase& E, + const Eigen::MatrixBase& oE, + Eigen::SparseMatrix& L); + + template + IGL_INLINE void + cr_vector_laplacian_intrinsic( + const Eigen::MatrixBase& F, + const Eigen::MatrixBase& l_sq, + const Eigen::MatrixBase& dA, + const Eigen::MatrixBase& E, + const Eigen::MatrixBase& oE, + Eigen::SparseMatrix& L); + + +} + + +#ifndef IGL_STATIC_LIBRARY +# include "cr_vector_laplacian.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/cr_vector_mass.cpp b/src/external/libigl-2.3.0/include/igl/cr_vector_mass.cpp new file mode 100644 index 000000000..1a5e45c8d --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/cr_vector_mass.cpp @@ -0,0 +1,112 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2020 Oded Stein +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "cr_vector_mass.h" + +#include + +#include "orient_halfedges.h" + +#include "doublearea.h" +#include "squared_edge_lengths.h" + + +template +IGL_INLINE void +igl::cr_vector_mass( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + const Eigen::MatrixBase& E, + const Eigen::MatrixBase& oE, + Eigen::SparseMatrix& M) +{ + Eigen::Matrix + l_sq; + squared_edge_lengths(V, F, l_sq); + cr_vector_mass_intrinsic(F, l_sq, E, oE, M); +} + + +template +IGL_INLINE void +igl::cr_vector_mass( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + Eigen::PlainObjectBase& E, + Eigen::PlainObjectBase& oE, + Eigen::SparseMatrix& M) +{ + if(E.rows()!=F.rows() || E.cols()!=F.cols() || oE.rows()!=F.rows() || + oE.cols()!=F.cols()) { + orient_halfedges(F, E, oE); + } + + const Eigen::PlainObjectBase& cE = E; + const Eigen::PlainObjectBase& coE = oE; + cr_vector_mass(V, F, cE, coE, M); +} + + +template +IGL_INLINE void +igl::cr_vector_mass_intrinsic( + const Eigen::MatrixBase& F, + const Eigen::MatrixBase& l_sq, + const Eigen::MatrixBase& E, + const Eigen::MatrixBase& oE, + Eigen::SparseMatrix& M) +{ + Eigen::Matrix + dA; + DerivedL_sq l_sqrt = l_sq.array().sqrt().matrix(); + doublearea(l_sqrt, dA); + cr_vector_mass_intrinsic(F, l_sq, dA, E, oE, M); +} + + +template +IGL_INLINE void +igl::cr_vector_mass_intrinsic( + const Eigen::MatrixBase& F, + const Eigen::MatrixBase& l_sq, + const Eigen::MatrixBase& dA, + const Eigen::MatrixBase& E, + const Eigen::MatrixBase& oE, + Eigen::SparseMatrix& M) +{ + assert(F.cols()==3 && "Faces have three vertices"); + assert(E.rows()==F.rows() && E.cols()==F.cols() && oE.rows()==F.rows() && + oE.cols()==F.cols() && "Wrong dimension in edge vectors"); + + const Eigen::Index m = F.rows(); + const typename DerivedE::Scalar nE = E.maxCoeff() + 1; + + std::vector > tripletList; + tripletList.reserve(2*3*m); + for(Eigen::Index f=0; f, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, double>(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::SparseMatrix&); +template void igl::cr_vector_mass_intrinsic, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, double>(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::SparseMatrix&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/cr_vector_mass.h b/src/external/libigl-2.3.0/include/igl/cr_vector_mass.h new file mode 100644 index 000000000..53b294c0a --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/cr_vector_mass.h @@ -0,0 +1,100 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2020 Oded Stein +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_CR_VECTOR_MASS +#define IGL_CR_VECTOR_MASS + +#include "igl_inline.h" + +#include +#include + + +namespace igl +{ + // Computes the CR vector mass matrix, using an arrangement of all parallel + // degrees of freedom first, and all perpendicular degrees of freedom next. + // See Oded Stein, Max Wardetzky, Alec Jacobson, Eitan Grinspun, 2020. + // "A Simple Discretization of the Vector Dirichlet Energy" + // + // Inputs: + // V, F: input mesh + // E: a mapping from each halfedge to each edge, as computed with + // orient_halfedges. + // will be computed if not provided. + // oE: the orientation of each halfedge compared to the orientation of the + // actual edge, as computed with orient_halfedges. + // will be computed if not provided. + // + // Outputs: + // M: computed mass matrix + // E, oE: these are computed if they are not present, as described above + + template + IGL_INLINE void + cr_vector_mass( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + const Eigen::MatrixBase& E, + const Eigen::MatrixBase& oE, + Eigen::SparseMatrix& M); + + template + IGL_INLINE void + cr_vector_mass( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + Eigen::PlainObjectBase& E, + Eigen::PlainObjectBase& oE, + Eigen::SparseMatrix& M); + + + // Version that uses intrinsic quantities as input + // + // Inputs: + // F: input mesh connectivity + // l_sq: squared edge lengths of each halfedge + // dA: double area of each face + // E: a mapping from each halfedge to each edge. + // oE: the orientation of each halfedge compared to the orientation of the + // actual edge. + // + // Outputs: + // M: computed mass matrix + + template + IGL_INLINE void + cr_vector_mass_intrinsic( + const Eigen::MatrixBase& F, + const Eigen::MatrixBase& l_sq, + const Eigen::MatrixBase& E, + const Eigen::MatrixBase& oE, + Eigen::SparseMatrix& M); + + template + IGL_INLINE void + cr_vector_mass_intrinsic( + const Eigen::MatrixBase& F, + const Eigen::MatrixBase& l_sq, + const Eigen::MatrixBase& dA, + const Eigen::MatrixBase& E, + const Eigen::MatrixBase& oE, + Eigen::SparseMatrix& M); + + +} + + +#ifndef IGL_STATIC_LIBRARY +# include "cr_vector_mass.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/cross.cpp b/src/external/libigl-2.3.0/include/igl/cross.cpp new file mode 100644 index 000000000..7b049c9bc --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/cross.cpp @@ -0,0 +1,47 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "cross.h" + +// http://www.antisphere.com/Wiki/tools:anttweakbar +IGL_INLINE void igl::cross( + const double *a, + const double *b, + double *out) +{ + out[0] = a[1] * b[2] - a[2] * b[1]; + out[1] = a[2] * b[0] - a[0] * b[2]; + out[2] = a[0] * b[1] - a[1] * b[0]; +} + +template < + typename DerivedA, + typename DerivedB, + typename DerivedC> +IGL_INLINE void igl::cross( + const Eigen::PlainObjectBase &A, + const Eigen::PlainObjectBase &B, + Eigen::PlainObjectBase &C) +{ + assert(A.cols() == 3 && "#cols should be 3"); + assert(B.cols() == 3 && "#cols should be 3"); + assert(A.rows() == B.rows() && "#rows in A and B should be equal"); + C.resize(A.rows(), 3); + for (int d = 0; d < 3; d++) + { + C.col(d) = + A.col((d + 1) % 3).array() * B.col((d + 2) % 3).array() - + A.col((d + 2) % 3).array() * B.col((d + 1) % 3).array(); + } +} + +#ifdef IGL_STATIC_LIBRARY +template void igl::cross, Eigen::Matrix, Eigen::Matrix>(Eigen::PlainObjectBase> const &, Eigen::PlainObjectBase> const &, Eigen::PlainObjectBase> &); +template void igl::cross, Eigen::Matrix, Eigen::Matrix>(Eigen::PlainObjectBase> const &, Eigen::PlainObjectBase> const &, Eigen::PlainObjectBase> &); +template void igl::cross, Eigen::Matrix, Eigen::Matrix>(Eigen::PlainObjectBase> const &, Eigen::PlainObjectBase> const &, Eigen::PlainObjectBase> &); +template void igl::cross, Eigen::Matrix, Eigen::Matrix>(Eigen::PlainObjectBase> const &, Eigen::PlainObjectBase> const &, Eigen::PlainObjectBase> &); +#endif \ No newline at end of file diff --git a/src/external/libigl-2.3.0/include/igl/cross.h b/src/external/libigl-2.3.0/include/igl/cross.h new file mode 100644 index 000000000..cfbe563ed --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/cross.h @@ -0,0 +1,42 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_CROSS_H +#define IGL_CROSS_H +#include "igl_inline.h" +#include +namespace igl +{ + // Computes out = cross(a,b) + // Inputs: + // a left 3d vector + // b right 3d vector + // Outputs: + // out result 3d vector + IGL_INLINE void cross( const double *a, const double *b, double *out); + // Computes C = cross(A,B,2); + // + // Inputs: + // A #A by 3 list of row-vectors + // B #A by 3 list of row-vectors + // Outputs: + // C #A by 3 list of row-vectors + template < + typename DerivedA, + typename DerivedB, + typename DerivedC> + IGL_INLINE void cross( + const Eigen::PlainObjectBase & A, + const Eigen::PlainObjectBase & B, + Eigen::PlainObjectBase & C); +} + +#ifndef IGL_STATIC_LIBRARY +# include "cross.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/cross_field_mismatch.cpp b/src/external/libigl-2.3.0/include/igl/cross_field_mismatch.cpp new file mode 100644 index 000000000..fa4df32af --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/cross_field_mismatch.cpp @@ -0,0 +1,132 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Daniele Panozzo , Olga Diamanti +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +#include "cross_field_mismatch.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace igl { + template + class MismatchCalculator + { + public: + + const Eigen::MatrixBase &V; + const Eigen::MatrixBase &F; + const Eigen::MatrixBase &PD1; + const Eigen::MatrixBase &PD2; + + DerivedV N; + + private: + // internal + std::vector V_border; // bool + std::vector > VF; + std::vector > VFi; + + DerivedF TT; + DerivedF TTi; + + + private: + ///compute the mismatch between 2 faces + inline int mismatchByCross(const int f0, + const int f1) + { + Eigen::Matrix dir0 = PD1.row(f0); + Eigen::Matrix dir1 = PD1.row(f1); + Eigen::Matrix n0 = N.row(f0); + Eigen::Matrix n1 = N.row(f1); + + Eigen::Matrix dir1Rot = igl::rotation_matrix_from_directions(n1,n0)*dir1; + dir1Rot.normalize(); + + double angle_diff = atan2(dir1Rot.dot(PD2.row(f0)),dir1Rot.dot(PD1.row(f0))); + + double step=igl::PI/2.0; + int i=(int)std::floor((angle_diff/step)+0.5); + int k=0; + if (i>=0) + k=i%4; + else + k=(-(3*i))%4; + return k; + } + + +public: + inline MismatchCalculator(const Eigen::MatrixBase &_V, + const Eigen::MatrixBase &_F, + const Eigen::MatrixBase &_PD1, + const Eigen::MatrixBase &_PD2): + V(_V), + F(_F), + PD1(_PD1), + PD2(_PD2) + { + igl::per_face_normals(V,F,N); + V_border = igl::is_border_vertex(F); + igl::vertex_triangle_adjacency(V,F,VF,VFi); + igl::triangle_triangle_adjacency(F,TT,TTi); + } + + inline void calculateMismatch(Eigen::PlainObjectBase &Handle_MMatch) + { + Handle_MMatch.setConstant(F.rows(),3,-1); + for (size_t i=0;i +IGL_INLINE void igl::cross_field_mismatch(const Eigen::MatrixBase &V, + const Eigen::MatrixBase &F, + const Eigen::MatrixBase &PD1, + const Eigen::MatrixBase &PD2, + const bool isCombed, + Eigen::PlainObjectBase &mismatch) +{ + DerivedV PD1_combed; + DerivedV PD2_combed; + + if (!isCombed) + igl::comb_cross_field(V,F,PD1,PD2,PD1_combed,PD2_combed); + else + { + PD1_combed = PD1; + PD2_combed = PD2; + } + igl::MismatchCalculator sf(V, F, PD1_combed, PD2_combed); + sf.calculateMismatch(mismatch); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +template void igl::cross_field_mismatch, Eigen::Matrix >(Eigen::MatrixBase > const &, Eigen::MatrixBase > const &, Eigen::MatrixBase > const &, Eigen::MatrixBase > const &, const bool, Eigen::PlainObjectBase > &); +template void igl::cross_field_mismatch, Eigen::Matrix >( Eigen::MatrixBase > const &, Eigen::MatrixBase > const &, Eigen::MatrixBase > const &, Eigen::MatrixBase > const &, const bool, Eigen::PlainObjectBase > &); +template void igl::cross_field_mismatch, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const &, Eigen::MatrixBase > const &, Eigen::MatrixBase > const &, Eigen::MatrixBase > const &, const bool, Eigen::PlainObjectBase > &); + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/cross_field_mismatch.h b/src/external/libigl-2.3.0/include/igl/cross_field_mismatch.h new file mode 100644 index 000000000..5f15e9641 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/cross_field_mismatch.h @@ -0,0 +1,43 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Daniele Panozzo , Olga Diamanti +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef IGL_CROSS_FIELD_MISMATCH_H +#define IGL_CROSS_FIELD_MISMATCH_H +#include "igl_inline.h" +#include +namespace igl +{ + // Calculates the mismatch (integer), at each face edge, of a cross field defined on the mesh faces. + // The integer mismatch is a multiple of pi/2 that transforms the cross on one side of the edge to + // the cross on the other side. It represents the deviation from a Lie connection across the edge. + + // Inputs: + // V #V by 3 eigen Matrix of mesh vertex 3D positions + // F #F by 3 eigen Matrix of face (quad) indices + // PD1 #F by 3 eigen Matrix of the first per face cross field vector + // PD2 #F by 3 eigen Matrix of the second per face cross field vector + // isCombed boolean, specifying whether the field is combed (i.e. matching has been precomputed. + // If not, the field is combed first. + // Output: + // mismatch #F by 3 eigen Matrix containing the integer mismatch of the cross field + // across all face edges + // + + template + IGL_INLINE void cross_field_mismatch(const Eigen::MatrixBase &V, + const Eigen::MatrixBase &F, + const Eigen::MatrixBase &PD1, + const Eigen::MatrixBase &PD2, + const bool isCombed, + Eigen::PlainObjectBase &mismatch); +} +#ifndef IGL_STATIC_LIBRARY +#include "cross_field_mismatch.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/crouzeix_raviart_cotmatrix.cpp b/src/external/libigl-2.3.0/include/igl/crouzeix_raviart_cotmatrix.cpp new file mode 100644 index 000000000..b89bd5586 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/crouzeix_raviart_cotmatrix.cpp @@ -0,0 +1,101 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2017 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "crouzeix_raviart_cotmatrix.h" +#include "unique_simplices.h" +#include "oriented_facets.h" +#include "is_edge_manifold.h" +#include "cotmatrix_entries.h" + +template +void igl::crouzeix_raviart_cotmatrix( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + Eigen::SparseMatrix & L, + Eigen::PlainObjectBase & E, + Eigen::PlainObjectBase & EMAP) +{ + // All occurrences of directed "facets" + Eigen::Matrix allE; + oriented_facets(F,allE); + Eigen::VectorXi _1; + unique_simplices(allE,E,_1,EMAP); + return crouzeix_raviart_cotmatrix(V,F,E,EMAP,L); +} + +template +void igl::crouzeix_raviart_cotmatrix( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const Eigen::MatrixBase & E, + const Eigen::MatrixBase & EMAP, + Eigen::SparseMatrix & L) +{ + // number of rows + const int m = F.rows(); + // Element simplex size + const int ss = F.cols(); + // Mesh should be edge-manifold + assert(F.cols() != 3 || is_edge_manifold(F)); + typedef Eigen::Matrix MatrixXS; + MatrixXS C; + cotmatrix_entries(V,F,C); + Eigen::MatrixXi F2E(m,ss); + { + int k =0; + for(int c = 0;c > LIJV;LIJV.reserve(k*m); + Eigen::VectorXi LI(k),LJ(k),LV(k); + // Compensation factor to match scales in matlab version + double factor = 2.0; + + switch(ss) + { + default: assert(false && "unsupported simplex size"); + case 3: + factor = 4.0; + LI<<0,1,2,1,2,0,0,1,2,1,2,0; + LJ<<1,2,0,0,1,2,0,1,2,1,2,0; + LV<<2,0,1,2,0,1,2,0,1,2,0,1; + break; + case 4: + factor *= -1.0; + LI<<0,3,3,3,1,2,1,0,1,2,2,0,0,3,3,3,1,2,1,0,1,2,2,0; + LJ<<1,0,1,2,2,0,0,3,3,3,1,2,0,3,3,3,1,2,1,0,1,2,2,0; + LV<<2,3,4,5,0,1,2,3,4,5,0,1,2,3,4,5,0,1,2,3,4,5,0,1; + break; + } + + for(int f=0;f, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, double>(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::SparseMatrix&); +template void igl::crouzeix_raviart_cotmatrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, double>(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::SparseMatrix&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/crouzeix_raviart_cotmatrix.h b/src/external/libigl-2.3.0/include/igl/crouzeix_raviart_cotmatrix.h new file mode 100644 index 000000000..1504ddad0 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/crouzeix_raviart_cotmatrix.h @@ -0,0 +1,49 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2017 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_CROUZEIX_RAVIART_COTMATRIX +#define IGL_CROUZEIX_RAVIART_COTMATRIX +#include "igl_inline.h" +#include +#include +namespace igl +{ + // CROUZEIX_RAVIART_COTMATRIX Compute the Crouzeix-Raviart cotangent + // stiffness matrix. + // + // See for example "Discrete Quadratic Curvature Energies" [Wardetzky, Bergou, + // Harmon, Zorin, Grinspun 2007] + // + // Inputs: + // V #V by dim list of vertex positions + // F #F by 3/4 list of triangle/tetrahedron indices + // Outputs: + // L #E by #E edge/face-based diagonal cotangent matrix + // E #E by 2/3 list of edges/faces + // EMAP #F*3/4 list of indices mapping allE to E + // + // See also: crouzeix_raviart_massmatrix + template + void crouzeix_raviart_cotmatrix( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + Eigen::SparseMatrix & L, + Eigen::PlainObjectBase & E, + Eigen::PlainObjectBase & EMAP); + // wrapper if E and EMAP are already computed (better match!) + template + void crouzeix_raviart_cotmatrix( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const Eigen::MatrixBase & E, + const Eigen::MatrixBase & EMAP, + Eigen::SparseMatrix & L); +} +#ifndef IGL_STATIC_LIBRARY +# include "crouzeix_raviart_cotmatrix.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/crouzeix_raviart_massmatrix.cpp b/src/external/libigl-2.3.0/include/igl/crouzeix_raviart_massmatrix.cpp new file mode 100644 index 000000000..b73d943b0 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/crouzeix_raviart_massmatrix.cpp @@ -0,0 +1,86 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "crouzeix_raviart_massmatrix.h" +#include "unique_simplices.h" +#include "oriented_facets.h" + +#include "is_edge_manifold.h" +#include "doublearea.h" +#include "volume.h" + +#include +#include + +template +void igl::crouzeix_raviart_massmatrix( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + Eigen::SparseMatrix & M, + Eigen::PlainObjectBase & E, + Eigen::PlainObjectBase & EMAP) +{ + // All occurrences of directed "facets" + Eigen::Matrix allE; + oriented_facets(F,allE); + Eigen::Matrix _1; + unique_simplices(allE,E,_1,EMAP); + return crouzeix_raviart_massmatrix(V,F,E,EMAP,M); +} + +template +void igl::crouzeix_raviart_massmatrix( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const Eigen::MatrixBase & E, + const Eigen::MatrixBase & EMAP, + Eigen::SparseMatrix & M) +{ + using namespace Eigen; + using namespace std; + // Mesh should be edge-manifold (TODO: replace `is_edge_manifold` with + // `is_facet_manifold`) + assert(F.cols() != 3 || is_edge_manifold(F)); + // number of elements (triangles) + const int m = F.rows(); + // Get triangle areas/volumes + VectorXd TA; + // Element simplex size + const int ss = F.cols(); + switch(ss) + { + default: + assert(false && "Unsupported simplex size"); + case 3: + doublearea(V,F,TA); + TA *= 0.5; + break; + case 4: + volume(V,F,TA); + break; + } + vector > MIJV(ss*m); + assert(EMAP.size() == m*ss); + for(int f = 0;f(EMAP(f+m*c, 0),EMAP(f+m*c, 0),TA(f)/(double)(ss)); + } + } + M.resize(E.rows(),E.rows()); + M.setFromTriplets(MIJV.begin(),MIJV.end()); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::crouzeix_raviart_massmatrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::SparseMatrix&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::crouzeix_raviart_massmatrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::SparseMatrix&); +template void igl::crouzeix_raviart_massmatrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::SparseMatrix&); +template void igl::crouzeix_raviart_massmatrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::SparseMatrix&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/crouzeix_raviart_massmatrix.h b/src/external/libigl-2.3.0/include/igl/crouzeix_raviart_massmatrix.h new file mode 100644 index 000000000..256aa2067 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/crouzeix_raviart_massmatrix.h @@ -0,0 +1,51 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef CROUZEIX_RAVIART_MASSMATRIX_H +#define CROUZEIX_RAVIART_MASSMATRIX_H +#include +#include + +namespace igl +{ + // CROUZEIX_RAVIART_MASSMATRIX Compute the Crouzeix-Raviart mass matrix where + // M(e,e) is just the sum of the areas of the triangles on either side of an + // edge e. + // + // See for example "Discrete Quadratic Curvature Energies" [Wardetzky, Bergou, + // Harmon, Zorin, Grinspun 2007] + // + // Inputs: + // V #V by dim list of vertex positions + // F #F by 3/4 list of triangle/tetrahedron indices + // Outputs: + // M #E by #E edge/face-based diagonal mass matrix + // E #E by 2/3 list of edges/faces + // EMAP #F*3/4 list of indices mapping allE to E + // + // See also: crouzeix_raviart_cotmatrix + template + void crouzeix_raviart_massmatrix( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + Eigen::SparseMatrix & M, + Eigen::PlainObjectBase & E, + Eigen::PlainObjectBase & EMAP); + // wrapper if E and EMAP are already computed (better match!) + template + void crouzeix_raviart_massmatrix( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const Eigen::MatrixBase & E, + const Eigen::MatrixBase & EMAP, + Eigen::SparseMatrix & M); +} +#ifndef IGL_STATIC_LIBRARY +# include "crouzeix_raviart_massmatrix.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/cumprod.cpp b/src/external/libigl-2.3.0/include/igl/cumprod.cpp new file mode 100644 index 000000000..f758fba40 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/cumprod.cpp @@ -0,0 +1,76 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2018 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "cumprod.h" +#include +#include + +template +IGL_INLINE void igl::cumprod( + const Eigen::MatrixBase & X, + const int dim, + Eigen::PlainObjectBase & Y) +{ + using namespace Eigen; + using namespace std; + Y.resizeLike(X); + // get number of columns (or rows) + int num_outer = (dim == 1 ? X.cols() : X.rows() ); + // get number of rows (or columns) + int num_inner = (dim == 1 ? X.rows() : X.cols() ); + // This has been optimized so that dim = 1 or 2 is roughly the same cost. + // (Optimizations assume ColMajor order) + if(dim == 1) + { +#pragma omp parallel for + for(int o = 0;o, Eigen::Matrix >(Eigen::MatrixBase > const&, int, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::cumprod, Eigen::Matrix >(Eigen::MatrixBase > const&, int, Eigen::PlainObjectBase >&); +template void igl::cumprod, Eigen::Matrix >(Eigen::MatrixBase > const&, int, Eigen::PlainObjectBase >&); +template void igl::cumprod, Eigen::Matrix >(Eigen::MatrixBase > const&, int, Eigen::PlainObjectBase >&); +template void igl::cumprod, Eigen::Matrix >(Eigen::MatrixBase > const&, int, Eigen::PlainObjectBase >&); +template void igl::cumprod, Eigen::Matrix >(Eigen::MatrixBase > const&, int, Eigen::PlainObjectBase >&); +template void igl::cumprod, Eigen::Matrix >(Eigen::MatrixBase > const&, int, Eigen::PlainObjectBase >&); +template void igl::cumprod, Eigen::Matrix >(Eigen::MatrixBase > const&, int, Eigen::PlainObjectBase >&); +#ifdef WIN32 +template void igl::cumprod, class Eigen::Matrix>(class Eigen::MatrixBase> const &, int, class Eigen::PlainObjectBase> &); +template void igl::cumprod, class Eigen::Matrix>(class Eigen::MatrixBase> const &, int, class Eigen::PlainObjectBase> &); +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/cumprod.h b/src/external/libigl-2.3.0/include/igl/cumprod.h new file mode 100644 index 000000000..d8fa73b48 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/cumprod.h @@ -0,0 +1,44 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2018 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_CUMPROD_H +#define IGL_CUMPROD_H + +#include "igl_inline.h" +#include + +namespace igl +{ + // Computes a cumulative product of the columns of X, like matlab's `cumprod`. + // + // Templates: + // DerivedX Type of matrix X + // DerivedY Type of matrix Y + // Inputs: + // X m by n Matrix to be cumulatively multiplied. + // dim dimension to take cumulative product (1 or 2) + // Output: + // Y m by n Matrix containing cumulative product. + // + template + IGL_INLINE void cumprod( + const Eigen::MatrixBase & X, + const int dim, + Eigen::PlainObjectBase & Y); + //template + //IGL_INLINE void cumprod( + // const Eigen::MatrixBase & X, + // Eigen::PlainObjectBase & Y); +} + +#ifndef IGL_STATIC_LIBRARY +# include "cumprod.cpp" +#endif + +#endif + + diff --git a/src/external/libigl-2.3.0/include/igl/cumsum.cpp b/src/external/libigl-2.3.0/include/igl/cumsum.cpp new file mode 100644 index 000000000..cd4e4fa87 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/cumsum.cpp @@ -0,0 +1,98 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "cumsum.h" +#include +#include + +template +IGL_INLINE void igl::cumsum( + const Eigen::MatrixBase & X, + const int dim, + Eigen::PlainObjectBase & Y) +{ + return cumsum(X,dim,false,Y); +} + +template +IGL_INLINE void igl::cumsum( + const Eigen::MatrixBase & X, + const int dim, + const bool zero_prefix, + Eigen::PlainObjectBase & Y) +{ + using namespace Eigen; + using namespace std; + Y.resize( + X.rows()+(zero_prefix&&dim==1?1:0), + X.cols()+(zero_prefix&&dim==2?1:0)); + // get number of columns (or rows) + Eigen::Index num_outer = (dim == 1 ? X.cols() : X.rows() ); + // get number of rows (or columns) + Eigen::Index num_inner = (dim == 1 ? X.rows() : X.cols() ); + // This has been optimized so that dim = 1 or 2 is roughly the same cost. + // (Optimizations assume ColMajor order) + if(dim == 1) + { + if(zero_prefix) + { + Y.row(0).setConstant(0); + } +#pragma omp parallel for + for(Eigen::Index o = 0;o, Eigen::Matrix >(Eigen::MatrixBase > const&, int, Eigen::PlainObjectBase >&); +template void igl::cumsum, Eigen::Matrix >(Eigen::MatrixBase > const&, int, Eigen::PlainObjectBase >&); +template void igl::cumsum, Eigen::Matrix >(Eigen::MatrixBase > const&, int, Eigen::PlainObjectBase >&); +template void igl::cumsum, Eigen::Matrix >(Eigen::MatrixBase > const&, int, Eigen::PlainObjectBase >&); +template void igl::cumsum, Eigen::Matrix >(Eigen::MatrixBase > const&, int, Eigen::PlainObjectBase >&); +template void igl::cumsum, Eigen::Matrix >(Eigen::MatrixBase > const&, int, Eigen::PlainObjectBase >&); +template void igl::cumsum, Eigen::Matrix >(Eigen::MatrixBase > const&, int, Eigen::PlainObjectBase >&); +template void igl::cumsum, Eigen::Matrix >(Eigen::MatrixBase > const&, int, Eigen::PlainObjectBase >&); +template void igl::cumsum, Eigen::Matrix >(Eigen::MatrixBase > const&, int, Eigen::PlainObjectBase >&); +template void igl::cumsum, Eigen::Matrix >(Eigen::MatrixBase > const&, int, bool, Eigen::PlainObjectBase >&); +#ifdef WIN32 +template void igl::cumsum, class Eigen::Matrix>(class Eigen::MatrixBase> const &, int, class Eigen::PlainObjectBase> &); +template void igl::cumsum, class Eigen::Matrix>(class Eigen::MatrixBase> const &, int, class Eigen::PlainObjectBase> &); +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/cumsum.h b/src/external/libigl-2.3.0/include/igl/cumsum.h new file mode 100644 index 000000000..d9a674851 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/cumsum.h @@ -0,0 +1,62 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_CUMSUM_H +#define IGL_CUMSUM_H + +#include "igl_inline.h" +#include + +namespace igl +{ + // Computes a cumulative sum of the columns of X, like matlab's `cumsum`. + // + // Templates: + // DerivedX Type of matrix X + // DerivedY Type of matrix Y + // Inputs: + // X m by n Matrix to be cumulatively summed. + // dim dimension to take cumulative sum (1 or 2) + // Output: + // Y m by n Matrix containing cumulative sum. + // + template + IGL_INLINE void cumsum( + const Eigen::MatrixBase & X, + const int dim, + Eigen::PlainObjectBase & Y); + // Computes a cumulative sum of the columns of [0;X] + // + // Inputs: + // X m by n Matrix to be cumulatively summed. + // dim dimension to take cumulative sum (1 or 2) + // zero_prefix whe + // Output: + // if zero_prefix == false + // Y m by n Matrix containing cumulative sum + // else + // Y m+1 by n Matrix containing cumulative sum if dim=1 + // or + // Y m by n+1 Matrix containing cumulative sum if dim=2 + template + IGL_INLINE void cumsum( + const Eigen::MatrixBase & X, + const int dim, + const bool zero_prefix, + Eigen::PlainObjectBase & Y); + //template + //IGL_INLINE void cumsum( + // const Eigen::MatrixBase & X, + // Eigen::PlainObjectBase & Y); +} + +#ifndef IGL_STATIC_LIBRARY +# include "cumsum.cpp" +#endif + +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/curved_hessian_energy.cpp b/src/external/libigl-2.3.0/include/igl/curved_hessian_energy.cpp new file mode 100644 index 000000000..8c57407d3 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/curved_hessian_energy.cpp @@ -0,0 +1,127 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2020 Oded Stein +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "curved_hessian_energy.h" + +#include "orient_halfedges.h" +#include "doublearea.h" +#include "squared_edge_lengths.h" +#include "cr_vector_laplacian.h" +#include "cr_vector_mass.h" +#include "cr_vector_curvature_correction.h" +#include "scalar_to_cr_vector_gradient.h" + + +template +IGL_INLINE void +igl::curved_hessian_energy( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + Eigen::SparseMatrix& Q) +{ + Eigen::MatrixXi E, oE; + curved_hessian_energy(V, F, E, oE, Q); +} + + +template +IGL_INLINE void +igl::curved_hessian_energy( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + const Eigen::MatrixBase& E, + const Eigen::MatrixBase& oE, + Eigen::SparseMatrix& Q) +{ + Eigen::Matrix + l_sq; + squared_edge_lengths(V, F, l_sq); + curved_hessian_energy_intrinsic(F, l_sq, E, oE, Q); +} + + +template +IGL_INLINE void +igl::curved_hessian_energy( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + Eigen::PlainObjectBase& E, + Eigen::PlainObjectBase& oE, + Eigen::SparseMatrix& Q) +{ + if(E.rows()!=F.rows() || E.cols()!=F.cols() || oE.rows()!=F.rows() || + oE.cols()!=F.cols()) { + orient_halfedges(F, E, oE); + } + + const Eigen::PlainObjectBase& cE = E; + const Eigen::PlainObjectBase& coE = oE; + curved_hessian_energy(V, F, cE, coE, Q); +} + + +template +IGL_INLINE void +igl::curved_hessian_energy_intrinsic( + const Eigen::MatrixBase& F, + const Eigen::MatrixBase& l_sq, + const Eigen::MatrixBase& E, + const Eigen::MatrixBase& oE, + Eigen::SparseMatrix& Q) +{ + Eigen::Matrix + dA; + Eigen::Matrix + l_sqrt = l_sq.array().sqrt().matrix(); + doublearea(l_sqrt, dA); + curved_hessian_energy_intrinsic(F, l_sq, dA, E, oE, Q); +} + + +template +IGL_INLINE void +igl::curved_hessian_energy_intrinsic( + const Eigen::MatrixBase& F, + const Eigen::MatrixBase& l_sq, + const Eigen::MatrixBase& dA, + const Eigen::MatrixBase& E, + const Eigen::MatrixBase& oE, + Eigen::SparseMatrix& Q) +{ + //Matrices that need to be combined + Eigen::SparseMatrix M, D, L, K; + cr_vector_mass_intrinsic(F, l_sq, dA, E, oE, M); + scalar_to_cr_vector_gradient_intrinsic(F, l_sq, dA, E, oE, D); + cr_vector_laplacian_intrinsic(F, l_sq, dA, E, oE, L); + cr_vector_curvature_correction_intrinsic(F, l_sq, E, oE, K); + + //Invert M + std::vector > tripletListMi; + for(Eigen::Index k=0; k::InnerIterator it(M,k); + it; ++it) { + if(it.value() > 0) { + tripletListMi.emplace_back(it.row(), it.col(), 1./it.value()); + } + } + } + Eigen::SparseMatrix Mi(M.rows(), M.cols()); + Mi.setFromTriplets(tripletListMi.begin(), tripletListMi.end()); + + //Hessian energy matrix + Q = D.transpose()*Mi*(L + K)*Mi*D; +} + + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +template void igl::curved_hessian_energy, Eigen::Matrix, double>(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::SparseMatrix&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/curved_hessian_energy.h b/src/external/libigl-2.3.0/include/igl/curved_hessian_energy.h new file mode 100644 index 000000000..4aeee5e6f --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/curved_hessian_energy.h @@ -0,0 +1,114 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2020 Oded Stein +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_CURVED_HESSIAN_ENERGY_H +#define IGL_CURVED_HESSIAN_ENERGY_H + +#include "igl_inline.h" + +#include +#include + + +namespace igl +{ + // Computes the curved Hessian energy using the Crouzeix-Raviart + // discretization. + // See Oded Stein, Alec Jacobson, Max Wardetzky, Eitan Grinspun, 2020. + // "A Smoothness Energy without Boundary Distortion for Curved Surfaces" + // + // Inputs: + // V, F: input mesh + // + // Outputs: + // Q: computed Hessian energy matrix + + template + IGL_INLINE void + curved_hessian_energy( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + Eigen::SparseMatrix& Q); + + // Version that exposes the edge orientation used. + // + // Inputs: + // V, F: input mesh + // E: a mapping from each halfedge to each edge, as computed with + // orient_halfedges. + // will be computed if not provided. + // oE: the orientation of each halfedge compared to the orientation of the + // actual edge, as computed with orient_halfedges. + // will be computed if not provided. + // + // Outputs: + // Q: computed Hessian energy matrix + // E, oE: these are computed if they are not present, as described above + template + IGL_INLINE void + curved_hessian_energy( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + const Eigen::MatrixBase& E, + const Eigen::MatrixBase& oE, + Eigen::SparseMatrix& Q); + + template + IGL_INLINE void + curved_hessian_energy( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + Eigen::PlainObjectBase& E, + Eigen::PlainObjectBase& oE, + Eigen::SparseMatrix& Q); + + + // Version that uses intrinsic quantities as input + // + // Inputs: + // F: input mesh connectivity + // l_sq: squared edge lengths of each halfedge + // dA: double area of each face + // E: a mapping from each halfedge to each edge. + // oE: the orientation of each halfedge compared to the orientation of the + // actual edge. + // + // Outputs: + // Q: computed Hessian energy matrix + + template + IGL_INLINE void + curved_hessian_energy_intrinsic( + const Eigen::MatrixBase& F, + const Eigen::MatrixBase& l_sq, + const Eigen::MatrixBase& E, + const Eigen::MatrixBase& oE, + Eigen::SparseMatrix& Q); + + template + IGL_INLINE void + curved_hessian_energy_intrinsic( + const Eigen::MatrixBase& F, + const Eigen::MatrixBase& l_sq, + const Eigen::MatrixBase& dA, + const Eigen::MatrixBase& E, + const Eigen::MatrixBase& oE, + Eigen::SparseMatrix& Q); + + +} + + +#ifndef IGL_STATIC_LIBRARY +# include "curved_hessian_energy.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/cut_mesh.cpp b/src/external/libigl-2.3.0/include/igl/cut_mesh.cpp new file mode 100644 index 000000000..fa35c3c24 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/cut_mesh.cpp @@ -0,0 +1,149 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2019 Hanxiao Shen +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include +#include +#include +#include + +// wrapper for input/output style +template +IGL_INLINE void igl::cut_mesh( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + const Eigen::MatrixBase& C, + Eigen::PlainObjectBase& Vn, + Eigen::PlainObjectBase& Fn +){ + Vn = V; + Fn = F; + typedef typename DerivedF::Scalar Index; + Eigen::Matrix _I; + cut_mesh(Vn,Fn,C,_I); +} + +template +IGL_INLINE void igl::cut_mesh( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + const Eigen::MatrixBase& C, + Eigen::PlainObjectBase& Vn, + Eigen::PlainObjectBase& Fn, + Eigen::PlainObjectBase& I +){ + Vn = V; + Fn = F; + cut_mesh(Vn,Fn,C,I); +} + +template +IGL_INLINE void igl::cut_mesh( + Eigen::PlainObjectBase& V, + Eigen::PlainObjectBase& F, + const Eigen::MatrixBase& C, + Eigen::PlainObjectBase& I +){ + typedef typename DerivedF::Scalar Index; + DerivedF FF, FFi; + igl::triangle_triangle_adjacency(F,FF,FFi); + igl::cut_mesh(V,F,FF,FFi,C,I); +} + +template +IGL_INLINE void igl::cut_mesh( + Eigen::PlainObjectBase& V, + Eigen::PlainObjectBase& F, + Eigen::MatrixBase& FF, + Eigen::MatrixBase& FFi, + const Eigen::MatrixBase& C, + Eigen::PlainObjectBase& I +){ + + typedef typename DerivedF::Scalar Index; + + // store current number of occurance of each vertex as the alg proceed + Eigen::Matrix occurence(V.rows()); + occurence.setConstant(1); + + // set eventual number of occurance of each vertex expected + Eigen::Matrix eventual(V.rows()); + eventual.setZero(); + for(Index i=0;i 0) ? eventual(i)-1 : 0); + V.conservativeResize(n_v+n_new,Eigen::NoChange); + I = DerivedI::LinSpaced(V.rows(),0,V.rows()); + + // pointing to the current bottom of V + Index pos = n_v; + for(Index f=0;f= n_v) continue; // ignore new vertices + if(C(f,k) == 1 && occurence(v0) != eventual(v0)){ + igl::HalfEdgeIterator he(F,FF,FFi,f,k); + + // rotate clock-wise around v0 until hit another cut + std::vector fan; + Index fi = he.Fi(); + Index ei = he.Ei(); + do{ + fan.push_back(fi); + he.flipE(); + he.flipF(); + fi = he.Fi(); + ei = he.Ei(); + }while(C(fi,ei) == 0 && !he.isBorder()); + + // make a copy + V.row(pos) << V.row(v0); + I(pos) = v0; + // add one occurance to v0 + occurence(v0) += 1; + + // replace old v0 + for(Index f0: fan) + for(Index j=0;j<3;j++) + if(F(f0,j) == v0) + F(f0,j) = pos; + + // mark cuts as boundary + FF(f,k) = -1; + FF(fi,ei) = -1; + + pos++; + } + } + } + +} + + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +template void igl::cut_mesh, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::cut_mesh, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::cut_mesh, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::cut_mesh, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/cut_mesh.h b/src/external/libigl-2.3.0/include/igl/cut_mesh.h new file mode 100644 index 000000000..1b175c8ae --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/cut_mesh.h @@ -0,0 +1,84 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2019 Hanxiao Shen +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_CUT_MESH_H +#define IGL_CUT_MESH_H +#include "igl_inline.h" + +#include + +namespace igl +{ + // Given a mesh and a list of edges that are to be cut, the function + // generates a new disk-topology mesh that has the cuts at its boundary. + // + // + // Known issues: Assumes mesh is edge-manifold. + // + // Inputs: + // V #V by 3 list of the vertex positions + // F #F by 3 list of the faces + // cuts #F by 3 list of boolean flags, indicating the edges that need to + // be cut (has 1 at the face edges that are to be cut, 0 otherwise) + // Outputs: + // Vn #V by 3 list of the vertex positions of the cut mesh. This matrix + // will be similar to the original vertices except some rows will be + // duplicated. + // Fn #F by 3 list of the faces of the cut mesh(must be triangles). This + // matrix will be similar to the original face matrix except some indices + // will be redirected to point to the newly duplicated vertices. + // I #V by 1 list of the map between Vn to original V index. + + // In place mesh cut + template + IGL_INLINE void cut_mesh( + Eigen::PlainObjectBase& V, + Eigen::PlainObjectBase& F, + const Eigen::MatrixBase& cuts, + Eigen::PlainObjectBase& I + ); + + template + IGL_INLINE void cut_mesh( + Eigen::PlainObjectBase& V, + Eigen::PlainObjectBase& F, + Eigen::MatrixBase& FF, + Eigen::MatrixBase& FFi, + const Eigen::MatrixBase& C, + Eigen::PlainObjectBase& I + ); + + template + IGL_INLINE void cut_mesh( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + const Eigen::MatrixBase& cuts, + Eigen::PlainObjectBase& Vn, + Eigen::PlainObjectBase& Fn + ); + + template + IGL_INLINE void cut_mesh( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + const Eigen::MatrixBase& cuts, + Eigen::PlainObjectBase& Vn, + Eigen::PlainObjectBase& Fn, + Eigen::PlainObjectBase& I + ); + + + +} + + +#ifndef IGL_STATIC_LIBRARY +#include "cut_mesh.cpp" +#endif + + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/cut_mesh_from_singularities.cpp b/src/external/libigl-2.3.0/include/igl/cut_mesh_from_singularities.cpp new file mode 100644 index 000000000..5f6150da5 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/cut_mesh_from_singularities.cpp @@ -0,0 +1,205 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Daniele Panozzo , Olga Diamanti +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +#include "cut_mesh_from_singularities.h" + +#include +#include + +#include +#include + + +namespace igl { + template < + typename DerivedV, + typename DerivedF, + typename DerivedM, + typename DerivedO + > + class MeshCutter + { + protected: + const Eigen::MatrixBase &V; + const Eigen::MatrixBase &F; + const Eigen::MatrixBase &Handle_MMatch; + + Eigen::VectorXi F_visited; + DerivedF TT; + DerivedF TTi; + + Eigen::MatrixXi E, F2E, E2F; + protected: + + inline bool IsRotSeam(const int f0,const int edge) + { + unsigned char MM = Handle_MMatch(f0,edge); + return (MM!=0); + } + + inline void FloodFill(const int start, Eigen::PlainObjectBase &Handle_Seams) + { + std::deque d; + ///clean the visited flag + F_visited(start) = true; + d.push_back(start); + + while (!d.empty()) + { + int f = d.at(0); d.pop_front(); + for (int s = 0; s<3; s++) + { + int g = TT(f,s); // f->FFp(s); + int j = TTi(f,s); // f->FFi(s); + + if (j == -1) + { + g = f; + j = s; + } + + if ((!(IsRotSeam(f,s))) && (!(IsRotSeam(g,j))) && (!F_visited(g)) ) + { + Handle_Seams(f,s)=false; + Handle_Seams(g,j)=false; + F_visited(g) = true; + d.push_back(g); + } + } + } + } + + inline void Retract(Eigen::PlainObjectBase &Handle_Seams) + { + std::vector e(V.rows(),0); // number of edges per vert + // for (unsigned f=0; fIsD()) + { + for (int s = 0; s<3; s++) + { + if (Handle_Seams(f,s)) + if (!(IsRotSeam(f,s))) // never retract rot seams + { + if (e[ F(f,s) ] == 1) { + // dissolve seam + Handle_Seams(f,s)=false; + if (TT(f,s) != -1) + Handle_Seams(TT(f,s),TTi(f,s))=false; + + e[ F(f,s)] --; + e[ F(f,(s+1)%3) ] --; + over = false; + } + } + } + } + + if (guard++>10000) + over = true; + + } while (!over); + } + + public: + + inline MeshCutter(const Eigen::MatrixBase &V_, + const Eigen::MatrixBase &F_, + const Eigen::MatrixBase &Handle_MMatch_): + V(V_), + F(F_), + Handle_MMatch(Handle_MMatch_) + { + triangle_triangle_adjacency(F,TT,TTi); + edge_topology(V,F,E,F2E,E2F); + }; + + inline void cut(Eigen::PlainObjectBase &Handle_Seams) + { + F_visited.setConstant(F.rows(),0); + Handle_Seams.setConstant(F.rows(),3,1); + + int index=0; + for (unsigned f = 0; f +IGL_INLINE void igl::cut_mesh_from_singularities(const Eigen::MatrixBase &V, + const Eigen::MatrixBase &F, + const Eigen::MatrixBase &Handle_MMatch, + Eigen::PlainObjectBase &Handle_Seams) +{ + igl::MeshCutter< DerivedV, DerivedF, DerivedM, DerivedO> mc(V, F, Handle_MMatch); + mc.cut(Handle_Seams); + +} +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +template void igl::cut_mesh_from_singularities, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::cut_mesh_from_singularities, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::cut_mesh_from_singularities, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::cut_mesh_from_singularities, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::cut_mesh_from_singularities, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::cut_mesh_from_singularities, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::cut_mesh_from_singularities, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/cut_mesh_from_singularities.h b/src/external/libigl-2.3.0/include/igl/cut_mesh_from_singularities.h new file mode 100644 index 000000000..c95adaade --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/cut_mesh_from_singularities.h @@ -0,0 +1,42 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Daniele Panozzo , Olga Diamanti +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef IGL_CUT_MESH_FROM_SINGULARITIES_H +#define IGL_CUT_MESH_FROM_SINGULARITIES_H +#include "igl_inline.h" +#include +namespace igl +{ + // Given a mesh (V,F) and the integer mismatch of a cross field per edge + // (mismatch), finds the cut_graph connecting the singularities (seams) and the + // degree of the singularities singularity_index + // + // Input: + // V #V by 3 list of mesh vertex positions + // F #F by 3 list of faces + // mismatch #F by 3 list of per corner integer mismatch + // Outputs: + // seams #F by 3 list of per corner booleans that denotes if an edge is a + // seam or not + // + template < + typename DerivedV, + typename DerivedF, + typename DerivedM, + typename DerivedO> + IGL_INLINE void cut_mesh_from_singularities( + const Eigen::MatrixBase &V, + const Eigen::MatrixBase &F, + const Eigen::MatrixBase &MMatch, + Eigen::PlainObjectBase &seams); +} +#ifndef IGL_STATIC_LIBRARY +#include "cut_mesh_from_singularities.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/cut_to_disk.cpp b/src/external/libigl-2.3.0/include/igl/cut_to_disk.cpp new file mode 100644 index 000000000..39c3c3789 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/cut_to_disk.cpp @@ -0,0 +1,342 @@ +#include "cut_to_disk.h" + +#include +#include +#include +#include + +namespace igl { + template + void cut_to_disk( + const Eigen::MatrixBase &F, + std::vector > &cuts) + { + cuts.clear(); + + Index nfaces = F.rows(); + + if (nfaces == 0) + return; + + std::map, std::vector > edges; + // build edges + + for (Index i = 0; i < nfaces; i++) + { + for (int j = 0; j < 3; j++) + { + Index v0 = F(i, j); + Index v1 = F(i, (j + 1) % 3); + std::pair e; + e.first = std::min(v0, v1); + e.second = std::max(v0, v1); + edges[e].push_back(i); + } + } + + int nedges = edges.size(); + Eigen::Matrix edgeVerts(nedges,2); + Eigen::Matrix edgeFaces(nedges,2); + Eigen::Matrix faceEdges(nfaces, 3); + std::set boundaryEdges; + std::map, Index> edgeidx; + Index idx = 0; + for (auto it : edges) + { + edgeidx[it.first] = idx; + edgeVerts(idx, 0) = it.first.first; + edgeVerts(idx, 1) = it.first.second; + edgeFaces(idx, 0) = it.second[0]; + if (it.second.size() > 1) + { + edgeFaces(idx, 1) = it.second[1]; + } + else + { + edgeFaces(idx, 1) = -1; + boundaryEdges.insert(idx); + } + idx++; + } + for (Index i = 0; i < nfaces; i++) + { + for (int j = 0; j < 3; j++) + { + Index v0 = F(i, j); + Index v1 = F(i, (j + 1) % 3); + std::pair e; + e.first = std::min(v0, v1); + e.second = std::max(v0, v1); + faceEdges(i, j) = edgeidx[e]; + } + } + + bool *deleted = new bool[nfaces]; + for (Index i = 0; i < nfaces; i++) + deleted[i] = false; + + std::set deletededges; + + // loop over faces + for (Index face = 0; face < nfaces; face++) + { + // stop at first undeleted face + if (deleted[face]) + continue; + deleted[face] = true; + std::deque processEdges; + for (int i = 0; i < 3; i++) + { + Index e = faceEdges(face, i); + if (boundaryEdges.count(e)) + continue; + int ndeleted = 0; + if (deleted[edgeFaces(e, 0)]) + ndeleted++; + if (deleted[edgeFaces(e, 1)]) + ndeleted++; + if (ndeleted == 1) + processEdges.push_back(e); + } + // delete all faces adjacent to edges with exactly one adjacent face + while (!processEdges.empty()) + { + Index nexte = processEdges.front(); + processEdges.pop_front(); + Index todelete = nfaces; + if (!deleted[edgeFaces(nexte, 0)]) + todelete = edgeFaces(nexte, 0); + if (!deleted[edgeFaces(nexte, 1)]) + todelete = edgeFaces(nexte, 1); + if (todelete != nfaces) + { + deletededges.insert(nexte); + deleted[todelete] = true; + for (int i = 0; i < 3; i++) + { + Index e = faceEdges(todelete, i); + if (boundaryEdges.count(e)) + continue; + int ndeleted = 0; + if (deleted[edgeFaces(e, 0)]) + ndeleted++; + if (deleted[edgeFaces(e, 1)]) + ndeleted++; + if (ndeleted == 1) + processEdges.push_back(e); + } + } + } + } + delete[] deleted; + + // accumulated non-deleted edges + std::vector leftedges; + for (Index i = 0; i < nedges; i++) + { + if (!deletededges.count(i)) + leftedges.push_back(i); + } + + deletededges.clear(); + // prune spines + std::map > spinevertedges; + for (Index i : leftedges) + { + spinevertedges[edgeVerts(i, 0)].push_back(i); + spinevertedges[edgeVerts(i, 1)].push_back(i); + } + + std::deque vertsProcess; + std::map spinevertnbs; + for (auto it : spinevertedges) + { + spinevertnbs[it.first] = it.second.size(); + if (it.second.size() == 1) + vertsProcess.push_back(it.first); + } + while (!vertsProcess.empty()) + { + Index vert = vertsProcess.front(); + vertsProcess.pop_front(); + for (Index e : spinevertedges[vert]) + { + if (!deletededges.count(e)) + { + deletededges.insert(e); + for (int j = 0; j < 2; j++) + { + spinevertnbs[edgeVerts(e, j)]--; + if (spinevertnbs[edgeVerts(e, j)] == 1) + { + vertsProcess.push_back(edgeVerts(e, j)); + } + } + } + } + } + std::vector loopedges; + for (Index i : leftedges) + if (!deletededges.count(i)) + loopedges.push_back(i); + + Index nloopedges = loopedges.size(); + if (nloopedges == 0) + return; + + std::map > loopvertedges; + for (Index e : loopedges) + { + loopvertedges[edgeVerts(e, 0)].push_back(e); + loopvertedges[edgeVerts(e, 1)].push_back(e); + } + + std::set usededges; + for (Index e : loopedges) + { + // make a cycle or chain starting from this edge + while (!usededges.count(e)) + { + std::vector cycleverts; + std::vector cycleedges; + cycleverts.push_back(edgeVerts(e, 0)); + cycleverts.push_back(edgeVerts(e, 1)); + cycleedges.push_back(e); + + std::map cycleidx; + cycleidx[cycleverts[0]] = 0; + cycleidx[cycleverts[1]] = 1; + + Index curvert = edgeVerts(e, 1); + Index cure = e; + bool foundcycle = false; + while (curvert != -1 && !foundcycle) + { + Index nextvert = -1; + Index nexte = -1; + for (Index cande : loopvertedges[curvert]) + { + if (!usededges.count(cande) && cande != cure) + { + int vidx = 0; + if (curvert == edgeVerts(cande, vidx)) + vidx = 1; + nextvert = edgeVerts(cande, vidx); + nexte = cande; + break; + } + } + if (nextvert != -1) + { + auto it = cycleidx.find(nextvert); + if (it != cycleidx.end()) + { + // we've hit outselves + std::vector cut; + for (Index i = it->second; i < cycleverts.size(); i++) + { + cut.push_back(cycleverts[i]); + } + cut.push_back(nextvert); + cuts.push_back(cut); + for (Index i = it->second; i < cycleedges.size(); i++) + { + usededges.insert(cycleedges[i]); + } + usededges.insert(nexte); + foundcycle = true; + } + else + { + cycleidx[nextvert] = cycleverts.size(); + cycleverts.push_back(nextvert); + cycleedges.push_back(nexte); + } + } + curvert = nextvert; + cure = nexte; + } + if (!foundcycle) + { + // we've hit a dead end. reverse and try the other direction + std::reverse(cycleverts.begin(), cycleverts.end()); + std::reverse(cycleedges.begin(), cycleedges.end()); + cycleidx.clear(); + for (Index i = 0; i < cycleverts.size(); i++) + { + cycleidx[cycleverts[i]] = i; + } + + curvert = cycleverts.back(); + cure = cycleedges.back(); + while (curvert != -1 && !foundcycle) + { + Index nextvert = -1; + Index nexte = -1; + for (Index cande : loopvertedges[curvert]) + { + if (!usededges.count(cande) && cande != cure) + { + int vidx = 0; + if (curvert == edgeVerts(cande, vidx)) + vidx = 1; + nextvert = edgeVerts(cande, vidx); + nexte = cande; + break; + } + } + if (nextvert != -1) + { + auto it = cycleidx.find(nextvert); + if (it != cycleidx.end()) + { + // we've hit outselves + std::vector cut; + for (Index i = it->second; i < cycleverts.size(); i++) + { + cut.push_back(cycleverts[i]); + } + cut.push_back(nextvert); + cuts.push_back(cut); + for (Index i = it->second; i < cycleedges.size(); i++) + { + usededges.insert(cycleedges[i]); + } + usededges.insert(nexte); + foundcycle = true; + } + else + { + cycleidx[nextvert] = cycleverts.size(); + cycleverts.push_back(nextvert); + cycleedges.push_back(nexte); + } + } + curvert = nextvert; + cure = nexte; + } + if (!foundcycle) + { + // we've found a chain + std::vector cut; + for (Index i = 0; i < cycleverts.size(); i++) + { + cut.push_back(cycleverts[i]); + } + cuts.push_back(cut); + for (Index i = 0; i < cycleedges.size(); i++) + { + usededges.insert(cycleedges[i]); + } + } + } + } + } + } +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +template void igl::cut_to_disk, int>(Eigen::MatrixBase > const&, std::vector >, std::allocator > > >&); + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/cut_to_disk.h b/src/external/libigl-2.3.0/include/igl/cut_to_disk.h new file mode 100644 index 000000000..cc6ae3266 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/cut_to_disk.h @@ -0,0 +1,52 @@ +#ifndef IGL_CUT_TO_DISK_H +#define IGL_CUT_TO_DISK_H +#include "igl_inline.h" + +#include + +#include + +namespace igl +{ + // Given a triangle mesh, computes a set of edge cuts sufficient to carve the + // mesh into a topological disk, without disconnecting any connected components. + // Nothing else about the cuts (including number, total length, or smoothness) + // is guaranteed to be optimal. + // + // Simply-connected components without boundary (topological spheres) are left + // untouched (delete any edge if you really want a disk). + // All other connected components are cut into disks. Meshes with boundary are + // supported; boundary edges will be included as cuts. + // + // The cut mesh itself can be materialized using cut_mesh(). + // + // Implements the triangle-deletion approach described by Gu et al's + // "Geometry Images." + // + // Template Parameters: + // Index Integrable type large enough to represent the total number of faces + // and edges in the surface represented by F, and all entries of F. + // + // Inputs: + // F #F by 3 list of the faces (must be triangles) + // + // Outputs: + // cuts List of cuts. Each cut is a sequence of vertex indices (where + // pairs of consecutive vertices share a face), is simple, and is either + // a closed loop (in which the first and last indices are identical) or + // an open curve. Cuts are edge-disjoint. + // + + template < + typename DerivedF, + typename Index> + IGL_INLINE void cut_to_disk( + const Eigen::MatrixBase &F, + std::vector > &cuts); +}; + +#ifndef IGL_STATIC_LIBRARY +#include "cut_to_disk.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/cylinder.cpp b/src/external/libigl-2.3.0/include/igl/cylinder.cpp new file mode 100644 index 000000000..ab0fd4d3d --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/cylinder.cpp @@ -0,0 +1,52 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "cylinder.h" +#include "PI.h" +#include +#include + +template +IGL_INLINE void igl::cylinder( + const int axis_devisions, + const int height_devisions, + Eigen::PlainObjectBase & V, + Eigen::PlainObjectBase & F) +{ + V.resize(axis_devisions*height_devisions,3); + F.resize(2*(axis_devisions*(height_devisions-1)),3); + int f = 0; + typedef typename DerivedV::Scalar Scalar; + for(int th = 0;th 0) + { + F(f,0) = ((th+0)%axis_devisions)+(h-1)*axis_devisions; + F(f,1) = ((th+1)%axis_devisions)+(h-1)*axis_devisions; + F(f,2) = ((th+0)%axis_devisions)+(h+0)*axis_devisions; + f++; + F(f,0) = ((th+1)%axis_devisions)+(h-1)*axis_devisions; + F(f,1) = ((th+1)%axis_devisions)+(h+0)*axis_devisions; + F(f,2) = ((th+0)%axis_devisions)+(h+0)*axis_devisions; + f++; + } + } + } + assert(f == F.rows()); +} + +#ifdef IGL_STATIC_LIBRARY +template void igl::cylinder, Eigen::Matrix >(int, int, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/cylinder.h b/src/external/libigl-2.3.0/include/igl/cylinder.h new file mode 100644 index 000000000..4c5ab7e22 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/cylinder.h @@ -0,0 +1,33 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_CYLINDER_H +#define IGL_CYLINDER_H +#include "igl_inline.h" +#include +namespace igl +{ + // Construct a triangle mesh of a cylinder (without caps) + // + // Inputs: + // axis_devisions number of vertices _around the cylinder_ + // height_devisions number of vertices _up the cylinder_ + // Outputs: + // V #V by 3 list of mesh vertex positions + // F #F by 3 list of triangle indices into V + // + template + IGL_INLINE void cylinder( + const int axis_devisions, + const int height_devisions, + Eigen::PlainObjectBase & V, + Eigen::PlainObjectBase & F); +} +#ifndef IGL_STATIC_LIBRARY +# include "cylinder.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/dated_copy.cpp b/src/external/libigl-2.3.0/include/igl/dated_copy.cpp new file mode 100644 index 000000000..735de6fc4 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/dated_copy.cpp @@ -0,0 +1,91 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "dated_copy.h" +#include "dirname.h" +#include "basename.h" + +#include +#include +#include +#include +#include + +#if !defined(_WIN32) +#include + +IGL_INLINE bool igl::dated_copy(const std::string & src_path, const std::string & dir) +{ + using namespace std; + // Get time and date as string + char buffer[80]; + time_t rawtime; + struct tm * timeinfo; + time (&rawtime); + timeinfo = localtime (&rawtime); + // ISO 8601 format with hyphens instead of colons and no timezone offset + strftime (buffer,80,"%Y-%m-%dT%H-%M-%S",timeinfo); + string src_basename = basename(src_path); + string dst_basename = src_basename+"-"+buffer; + string dst_path = dir+"/"+dst_basename; + cerr<<"Saving binary to "< +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +// Known issues: This function does not work under windows + +#ifndef IGL_DATED_COPY_H +#define IGL_DATED_COPY_H +#include "igl_inline.h" +#include +namespace igl +{ + // Copy the given file to a new file with the same basename in `dir` + // directory with the current date and time as a suffix. + // + // Inputs: + // src_path path to source file + // dir directory of destination file + // Example: + // dated_copy("/path/to/foo","/bar/"); + // // copies /path/to/foo to /bar/foo-2013-12-12T18-10-56 + IGL_INLINE bool dated_copy(const std::string & src_path, const std::string & dir); + // Wrapper using directory of source file + IGL_INLINE bool dated_copy(const std::string & src_path); +} +#ifndef IGL_STATIC_LIBRARY +# include "dated_copy.cpp" +#endif +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/decimate.cpp b/src/external/libigl-2.3.0/include/igl/decimate.cpp new file mode 100644 index 000000000..c5c6cf7f6 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/decimate.cpp @@ -0,0 +1,251 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "decimate.h" +#include "collapse_edge.h" +#include "edge_flaps.h" +#include "decimate_trivial_callbacks.h" +#include "is_edge_manifold.h" +#include "remove_unreferenced.h" +#include "slice_mask.h" +#include "slice.h" +#include "connect_boundary_to_infinity.h" +#include "parallel_for.h" +#include "max_faces_stopping_condition.h" +#include "shortest_edge_and_midpoint.h" + +IGL_INLINE bool igl::decimate( + const Eigen::MatrixXd & V, + const Eigen::MatrixXi & F, + const size_t max_m, + Eigen::MatrixXd & U, + Eigen::MatrixXi & G, + Eigen::VectorXi & J, + Eigen::VectorXi & I) +{ + // Original number of faces + const int orig_m = F.rows(); + // Tracking number of faces + int m = F.rows(); + typedef Eigen::MatrixXd DerivedV; + typedef Eigen::MatrixXi DerivedF; + DerivedV VO; + DerivedF FO; + igl::connect_boundary_to_infinity(V,F,VO,FO); + Eigen::VectorXi EMAP; + Eigen::MatrixXi E,EF,EI; + edge_flaps(FO,E,EMAP,EF,EI); + // decimate will not work correctly on non-edge-manifold meshes. By extension + // this includes meshes with non-manifold vertices on the boundary since these + // will create a non-manifold edge when connected to infinity. + { + Eigen::Array BF; + Eigen::Array BE; + if(!is_edge_manifold(FO,E.rows(),EMAP,BF,BE)) + { + return false; + } + } + decimate_pre_collapse_callback always_try; + decimate_post_collapse_callback never_care; + decimate_trivial_callbacks(always_try,never_care); + bool ret = decimate( + VO, + FO, + shortest_edge_and_midpoint, + max_faces_stopping_condition(m,orig_m,max_m), + always_try, + never_care, + E, + EMAP, + EF, + EI, + U, + G, + J, + I); + const Eigen::Array keep = (J.array() BF; + Eigen::Array BE; + if(!is_edge_manifold(F,E.rows(),EMAP,BF,BE)) + { + return false; + } + } + + igl::min_heap > Q; + // Could reserve with https://stackoverflow.com/a/29236236/148668 + Eigen::VectorXi EQ = Eigen::VectorXi::Zero(E.rows()); + // If an edge were collapsed, we'd collapse it to these points: + MatrixXd C(E.rows(),V.cols()); + // Pushing into a vector then using constructor was slower. Maybe using + // std::move + make_heap would squeeze out something? + + // Separating the cost/placement evaluation from the Q filling is a + // performance hit for serial but faster if we can parallelize the + // cost/placement. + { + Eigen::VectorXd costs(E.rows()); + igl::parallel_for(E.rows(),[&](const int e) + { + double cost = e; + RowVectorXd p(1,3); + cost_and_placement(e,V,F,E,EMAP,EF,EI,cost,p); + C.row(e) = p; + costs(e) = cost; + }, + 10000 + ); + for(int e = 0;e +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_DECIMATE_H +#define IGL_DECIMATE_H +#include "igl_inline.h" +#include "decimate_callback_types.h" +#include +namespace igl +{ + // Assumes (V,F) is a manifold mesh (possibly with boundary) Collapses edges + // until desired number of faces is achieved. This uses default edge cost and + // merged vertex placement functions {edge length, edge midpoint}. + // + // Inputs: + // V #V by dim list of vertex positions + // F #F by 3 list of face indices into V. + // max_m desired number of output faces + // Outputs: + // U #U by dim list of output vertex posistions (can be same ref as V) + // G #G by 3 list of output face indices into U (can be same ref as G) + // J #G list of indices into F of birth face + // I #U list of indices into V of birth vertices + // Returns true if m was reached (otherwise #G > m) + IGL_INLINE bool decimate( + const Eigen::MatrixXd & V, + const Eigen::MatrixXi & F, + const size_t max_m, + Eigen::MatrixXd & U, + Eigen::MatrixXi & G, + Eigen::VectorXi & J, + Eigen::VectorXi & I); + // Inputs: + // V #V by dim list of vertex positions + // F #F by 3 list of face indices into V. + // max_m desired number of output faces + // Outputs: + // U #U by dim list of output vertex posistions (can be same ref as V) + // G #G by 3 list of output face indices into U (can be same ref as G) + // J #G list of indices into F of birth face + // Returns true if m was reached (otherwise #G > m) + IGL_INLINE bool decimate( + const Eigen::MatrixXd & V, + const Eigen::MatrixXi & F, + const size_t max_m, + Eigen::MatrixXd & U, + Eigen::MatrixXi & G, + Eigen::VectorXi & J); + // Assumes a **closed** manifold mesh. See igl::connect_boundary_to_infinity + // and igl::decimate in decimate.cpp + // is handling meshes with boundary by connecting all boundary edges with + // dummy facets to infinity **and** modifying the stopping criteria. + // + // Inputs: + // cost_and_placement function computing cost of collapsing an edge and 3d + // position where it should be placed: + // cost_and_placement(V,F,E,EMAP,EF,EI,cost,placement); + // stopping_condition function returning whether to stop collapsing edges + // based on current state. Guaranteed to be called after _successfully_ + // collapsing edge e removing edges (e,e1,e2) and faces (f1,f2): + // bool should_stop = + // stopping_condition(V,F,E,EMAP,EF,EI,Q,Qit,C,e,e1,e2,f1,f2); + IGL_INLINE bool decimate( + const Eigen::MatrixXd & V, + const Eigen::MatrixXi & F, + const decimate_cost_and_placement_callback & cost_and_placement, + const decimate_stopping_condition_callback & stopping_condition, + Eigen::MatrixXd & U, + Eigen::MatrixXi & G, + Eigen::VectorXi & J, + Eigen::VectorXi & I); + // Inputs: + // pre_collapse callback called with index of edge whose collapse is about + // to be attempted (see collapse_edge) + // post_collapse callback called with index of edge whose collapse was + // just attempted and a flag revealing whether this was successful (see + // collapse_edge) + IGL_INLINE bool decimate( + const Eigen::MatrixXd & V, + const Eigen::MatrixXi & F, + const decimate_cost_and_placement_callback & cost_and_placement, + const decimate_stopping_condition_callback & stopping_condition, + const decimate_pre_collapse_callback & pre_collapse, + const decimate_post_collapse_callback & post_collapse, + Eigen::MatrixXd & U, + Eigen::MatrixXi & G, + Eigen::VectorXi & J, + Eigen::VectorXi & I); + // Inputs: + // EMAP #F*3 list of indices into E, mapping each directed edge to unique + // unique edge in E + // EF #E by 2 list of edge flaps, EF(e,0)=f means e=(i-->j) is the edge of + // F(f,:) opposite the vth corner, where EI(e,0)=v. Similarly EF(e,1) " + // e=(j->i) + // EI #E by 2 list of edge flap corners (see above). + IGL_INLINE bool decimate( + const Eigen::MatrixXd & V, + const Eigen::MatrixXi & F, + const decimate_cost_and_placement_callback & cost_and_placement, + const decimate_stopping_condition_callback & stopping_condition, + const decimate_pre_collapse_callback & pre_collapse, + const decimate_post_collapse_callback & post_collapse, + const Eigen::MatrixXi & E, + const Eigen::VectorXi & EMAP, + const Eigen::MatrixXi & EF, + const Eigen::MatrixXi & EI, + Eigen::MatrixXd & U, + Eigen::MatrixXi & G, + Eigen::VectorXi & J, + Eigen::VectorXi & I); + +} + +#ifndef IGL_STATIC_LIBRARY +# include "decimate.cpp" +#endif +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/decimate_callback_types.h b/src/external/libigl-2.3.0/include/igl/decimate_callback_types.h new file mode 100644 index 000000000..c622342a5 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/decimate_callback_types.h @@ -0,0 +1,76 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2020 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_DECIMATE_CALLBACK_TYPES_H +#define IGL_DECIMATE_CALLBACK_TYPES_H +#include +#include "min_heap.h" +namespace igl +{ + // Function handles used to customize the `igl::decimate` command. + using decimate_cost_and_placement_callback = + std::function; + using decimate_stopping_condition_callback = + std::function > & ,/*Q*/ + const Eigen::VectorXi & ,/*EQ*/ + const Eigen::MatrixXd & ,/*C*/ + const int ,/*e*/ + const int ,/*e1*/ + const int ,/*e2*/ + const int ,/*f1*/ + const int /*f2*/ + )>; + using decimate_pre_collapse_callback = + std::function > & ,/*Q*/ + const Eigen::VectorXi & ,/*EQ*/ + const Eigen::MatrixXd & ,/*C*/ + const int /*e*/ + )>; + using decimate_post_collapse_callback = + std::function > & ,/*Q*/ + const Eigen::VectorXi & ,/*EQ*/ + const Eigen::MatrixXd & ,/*C*/ + const int ,/*e*/ + const int ,/*e1*/ + const int ,/*e2*/ + const int ,/*f1*/ + const int ,/*f2*/ + const bool /*collapsed*/ + )>; +} +#endif diff --git a/src/external/libigl-2.3.0/include/igl/decimate_trivial_callbacks.cpp b/src/external/libigl-2.3.0/include/igl/decimate_trivial_callbacks.cpp new file mode 100644 index 000000000..e20bc25bd --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/decimate_trivial_callbacks.cpp @@ -0,0 +1,43 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2020 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "decimate_trivial_callbacks.h" + +IGL_INLINE void igl::decimate_trivial_callbacks( + decimate_pre_collapse_callback & always_try, + decimate_post_collapse_callback & never_care) +{ + always_try = []( + const Eigen::MatrixXd & ,/*V*/ + const Eigen::MatrixXi & ,/*F*/ + const Eigen::MatrixXi & ,/*E*/ + const Eigen::VectorXi & ,/*EMAP*/ + const Eigen::MatrixXi & ,/*EF*/ + const Eigen::MatrixXi & ,/*EI*/ + const igl::min_heap< std::tuple > & ,/*Q*/ + const Eigen::VectorXi & ,/*EQ*/ + const Eigen::MatrixXd & ,/*C*/ + const int /*e*/ + ) -> bool { return true;}; + never_care = []( + const Eigen::MatrixXd & ,/*V*/ + const Eigen::MatrixXi & ,/*F*/ + const Eigen::MatrixXi & ,/*E*/ + const Eigen::VectorXi & ,/*EMAP*/ + const Eigen::MatrixXi & ,/*EF*/ + const Eigen::MatrixXi & ,/*EI*/ + const igl::min_heap< std::tuple > & ,/*Q*/ + const Eigen::VectorXi & ,/*EQ*/ + const Eigen::MatrixXd & ,/*C*/ + const int ,/*e*/ + const int ,/*e1*/ + const int ,/*e2*/ + const int ,/*f1*/ + const int ,/*f2*/ + const bool /*collapsed*/ + )-> void { }; +} diff --git a/src/external/libigl-2.3.0/include/igl/decimate_trivial_callbacks.h b/src/external/libigl-2.3.0/include/igl/decimate_trivial_callbacks.h new file mode 100644 index 000000000..ea16dd555 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/decimate_trivial_callbacks.h @@ -0,0 +1,31 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2020 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_DECIMATE_TRIVIAL_CALLBACKS_H +#define IGL_DECIMATE_TRIVIAL_CALLBACKS_H +#include "igl_inline.h" +#include "decimate_callback_types.h" +namespace igl +{ + // Function to build trivial pre and post collapse actions. + // + // Outputs: + // always_try function that always returns true (always attempt the next + // edge collapse) + // never_care fuction that is always a no-op (never have a post collapse + // response) + IGL_INLINE void decimate_trivial_callbacks( + decimate_pre_collapse_callback & always_try, + decimate_post_collapse_callback & never_care); +}; + +#ifndef IGL_STATIC_LIBRARY +# include "decimate_trivial_callbacks.cpp" +#endif + +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/default_num_threads.cpp b/src/external/libigl-2.3.0/include/igl/default_num_threads.cpp new file mode 100644 index 000000000..8203d98be --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/default_num_threads.cpp @@ -0,0 +1,54 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2021 Jérémie Dumas +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +#include "default_num_threads.h" + +#include +#include + +IGL_INLINE unsigned int igl::default_num_threads(unsigned int user_num_threads) { + // Thread-safe initialization using Meyers' singleton + class MySingleton { + public: + static MySingleton &instance(unsigned int force_num_threads) { + static MySingleton instance(force_num_threads); + return instance; + } + + unsigned int get_num_threads() const { return m_num_threads; } + + private: + MySingleton(unsigned int force_num_threads) { + // User-defined default + if (force_num_threads) { + m_num_threads = force_num_threads; + return; + } + // Set from env var + if (char *env_str = getenv("IGL_NUM_THREADS")) { + const int env_num_thread = atoi(env_str); + if (env_num_thread > 0) { + m_num_threads = static_cast(env_num_thread); + return; + } + } + // Guess from hardware + const unsigned int hw_num_threads = std::thread::hardware_concurrency(); + if (hw_num_threads) { + m_num_threads = hw_num_threads; + return; + } + // Fallback when std::thread::hardware_concurrency doesn't work + m_num_threads = 8u; + } + + unsigned int m_num_threads = 0; + }; + + return MySingleton::instance(user_num_threads).get_num_threads(); +} diff --git a/src/external/libigl-2.3.0/include/igl/default_num_threads.h b/src/external/libigl-2.3.0/include/igl/default_num_threads.h new file mode 100644 index 000000000..5658fa7b2 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/default_num_threads.h @@ -0,0 +1,38 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2021 Jérémie Dumas +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_DEFAULT_NUM_THREADS_H +#define IGL_DEFAULT_NUM_THREADS_H +#include "igl_inline.h" + +namespace igl +{ + +/// +/// Returns the default number of threads used in libigl. The value returned by the first call to +/// this function is cached. The following strategy is used to determine the default number of +/// threads: +/// 1. User-provided argument force_num_threads if != 0. +/// 2. Environment variable IGL_NUM_THREADS if > 0. +/// 3. Hardware concurrency if != 0. +/// 4. A fallback value of 8 is used otherwise. +/// +/// @note It is safe to call this method from multiple threads. +/// +/// @param[in] force_num_threads User-provided default value. +/// +/// @return Default number of threads. +/// +IGL_INLINE unsigned int default_num_threads(unsigned int force_num_threads = 0); + +} // namespace igl + +#ifndef IGL_STATIC_LIBRARY +#include "default_num_threads.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/deform_skeleton.cpp b/src/external/libigl-2.3.0/include/igl/deform_skeleton.cpp new file mode 100644 index 000000000..b9d120edd --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/deform_skeleton.cpp @@ -0,0 +1,58 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "deform_skeleton.h" +void igl::deform_skeleton( + const Eigen::MatrixXd & C, + const Eigen::MatrixXi & BE, + const std::vector< + Eigen::Affine3d,Eigen::aligned_allocator > & vA, + Eigen::MatrixXd & CT, + Eigen::MatrixXi & BET) +{ + using namespace Eigen; + assert(BE.rows() == (int)vA.size()); + CT.resize(2*BE.rows(),C.cols()); + BET.resize(BE.rows(),2); + for(int e = 0;e +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_DEFORM_SKELETON_H +#define IGL_DEFORM_SKELETON_H +#include "igl_inline.h" +#include +#include +#include +#include +namespace igl +{ + // Deform a skeleton. + // + // Inputs: + // C #C by 3 list of joint positions + // BE #BE by 2 list of bone edge indices + // vA #BE list of bone transformations + // Outputs + // CT #BE*2 by 3 list of deformed joint positions + // BET #BE by 2 list of bone edge indices (maintains order) + // + IGL_INLINE void deform_skeleton( + const Eigen::MatrixXd & C, + const Eigen::MatrixXi & BE, + const std::vector< + Eigen::Affine3d,Eigen::aligned_allocator > & vA, + Eigen::MatrixXd & CT, + Eigen::MatrixXi & BET); + // Inputs: + // T #BE*4 by 3 list of stacked transformation matrix + IGL_INLINE void deform_skeleton( + const Eigen::MatrixXd & C, + const Eigen::MatrixXi & BE, + const Eigen::MatrixXd & T, + Eigen::MatrixXd & CT, + Eigen::MatrixXi & BET); +} + +#ifndef IGL_STATIC_LIBRARY +# include "deform_skeleton.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/delaunay_triangulation.cpp b/src/external/libigl-2.3.0/include/igl/delaunay_triangulation.cpp new file mode 100644 index 000000000..0d09cc642 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/delaunay_triangulation.cpp @@ -0,0 +1,63 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Qingnan Zhou +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +#include "delaunay_triangulation.h" +#include "flip_edge.h" +#include "lexicographic_triangulation.h" +#include "unique_edge_map.h" +#include "is_delaunay.h" + +#include +#include + +template< + typename DerivedV, + typename Orient2D, + typename InCircle, + typename DerivedF> +IGL_INLINE void igl::delaunay_triangulation( + const Eigen::MatrixBase& V, + Orient2D orient2D, + InCircle incircle, + Eigen::PlainObjectBase& F) +{ + assert(V.cols() == 2); + typedef typename DerivedF::Scalar Index; + typedef typename DerivedV::Scalar Scalar; + igl::lexicographic_triangulation(V, orient2D, F); + const size_t num_faces = F.rows(); + if (num_faces == 0) { + // Input points are degenerate. No faces will be generated. + return; + } + assert(F.cols() == 3); + + typedef Eigen::Matrix MatrixX2I; + MatrixX2I E,uE; + Eigen::VectorXi EMAP; + std::vector > uE2E; + igl::unique_edge_map(F, E, uE, EMAP, uE2E); + + bool all_delaunay = false; + while(!all_delaunay) { + all_delaunay = true; + for (size_t i=0; i, short (*)(double const*, double const*, double const*), short (*)(double const*, double const*, double const*, double const*), Eigen::Matrix >(Eigen::MatrixBase > const&, short (*)(double const*, double const*, double const*), short (*)(double const*, double const*, double const*, double const*), Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/delaunay_triangulation.h b/src/external/libigl-2.3.0/include/igl/delaunay_triangulation.h new file mode 100644 index 000000000..ed3938a6e --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/delaunay_triangulation.h @@ -0,0 +1,49 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Qingan Zhou +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef IGL_DELAUNAY_TRIANGULATION_H +#define IGL_DELAUNAY_TRIANGULATION_H + +#include "igl_inline.h" +#include + +namespace igl +{ + // Given a set of points in 2D, return a Delaunay triangulation of these + // points. + // + // Inputs: + // V #V by 2 list of vertex positions + // orient2D A functor such that orient2D(pa, pb, pc) returns + // 1 if pa,pb,pc forms a conterclockwise triangle. + // -1 if pa,pb,pc forms a clockwise triangle. + // 0 if pa,pb,pc are collinear. + // where the argument pa,pb,pc are of type Scalar[2]. + // incircle A functor such that incircle(pa, pb, pc, pd) returns + // 1 if pd is on the positive size of circumcirle of (pa,pb,pc) + // -1 if pd is on the positive size of circumcirle of (pa,pb,pc) + // 0 if pd is cocircular with pa, pb, pc. + // Outputs: + // F #F by 3 of faces in Delaunay triangulation. + template< + typename DerivedV, + typename Orient2D, + typename InCircle, + typename DerivedF + > + IGL_INLINE void delaunay_triangulation( + const Eigen::MatrixBase& V, + Orient2D orient2D, + InCircle incircle, + Eigen::PlainObjectBase& F); +} + +#ifndef IGL_STATIC_LIBRARY +# include "delaunay_triangulation.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/deprecated.h b/src/external/libigl-2.3.0/include/igl/deprecated.h new file mode 100644 index 000000000..6820dd320 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/deprecated.h @@ -0,0 +1,51 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_DEPRECATED_H +#define IGL_DEPRECATED_H +// Macro for marking a function as deprecated. +// Use C++14 feature [[deprecated]] if available. +// See also https://stackoverflow.com/questions/295120/c-mark-as-deprecated/21265197#21265197 + +#ifdef __has_cpp_attribute +# define IGL_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x) +#else +# define IGL_HAS_CPP_ATTRIBUTE(x) 0 +#endif + +#ifdef _MSC_VER +# define IGL_MSC_VER _MSC_VER +#else +# define IGL_MSC_VER 0 +#endif + +#ifndef IGL_DEPRECATED +# if (IGL_HAS_CPP_ATTRIBUTE(deprecated) && __cplusplus >= 201402L) || \ + IGL_MSC_VER >= 1900 +# define IGL_DEPRECATED [[deprecated]] +# else +# if defined(__GNUC__) || defined(__clang__) +# define IGL_DEPRECATED __attribute__((deprecated)) +# elif IGL_MSC_VER +# define IGL_DEPRECATED __declspec(deprecated) +# else +# pragma message("WARNING: You need to implement IGL_DEPRECATED for this compiler") +# define IGL_DEPRECATED /* deprecated */ +# endif +# endif +#endif + +// Usage: +// +// template +// IGL_INLINE void my_func(Arg1 a); +// +// becomes +// +// template +// IGL_DEPRECATED IGL_INLINE void my_func(Arg1 a); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/dfs.cpp b/src/external/libigl-2.3.0/include/igl/dfs.cpp new file mode 100644 index 000000000..627fbc26d --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/dfs.cpp @@ -0,0 +1,60 @@ +#include "dfs.h" +#include "list_to_matrix.h" +#include + +template < + typename AType, + typename DerivedD, + typename DerivedP, + typename DerivedC> +IGL_INLINE void igl::dfs( + const std::vector > & A, + const size_t s, + Eigen::PlainObjectBase & D, + Eigen::PlainObjectBase & P, + Eigen::PlainObjectBase & C) +{ + std::vector vD; + std::vector vP; + std::vector vC; + dfs(A,s,vD,vP,vC); + list_to_matrix(vD,D); + list_to_matrix(vP,P); + list_to_matrix(vC,C); +} + +template < + typename AType, + typename DType, + typename PType, + typename CType> +IGL_INLINE void igl::dfs( + const std::vector > & A, + const size_t s, + std::vector & D, + std::vector & P, + std::vector & C) +{ + // number of nodes + int N = s+1; + for(const auto & Ai : A) for(const auto & a : Ai) N = std::max(N,a+1); + std::vector seen(N,false); + P.resize(N,-1); + std::function dfs_helper; + dfs_helper = [&D,&P,&C,&dfs_helper,&seen,&A](const size_t s, const size_t p) + { + if(seen[s]) return; + seen[s] = true; + D.push_back(s); + P[s] = p; + for(const auto n : A[s]) dfs_helper(n,s); + C.push_back(s); + }; + dfs_helper(s,-1); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::dfs, Eigen::Matrix, Eigen::Matrix >(std::vector >, std::allocator > > > const&, const size_t, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/dfs.h b/src/external/libigl-2.3.0/include/igl/dfs.h new file mode 100644 index 000000000..5f3bf2ce6 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/dfs.h @@ -0,0 +1,49 @@ +#ifndef IGL_DFS_H +#define IGL_DFS_H +#include "igl_inline.h" +#include +#include +namespace igl +{ + // Traverse a **directed** graph represented by an adjacency list using + // depth first search + // + // Inputs: + // A #V list of adjacency lists + // s starting node (index into A) + // Outputs: + // D #V list of indices into rows of A in the order in which graph nodes + // are discovered. + // P #V list of indices into rows of A of predecessor in resulting + // spanning tree {-1 indicates root/not discovered), order corresponds to + // V **not** D. + // C #V list of indices into rows of A in order that nodes are "closed" + // (all descendants have been discovered) + template < + typename AType, + typename DerivedD, + typename DerivedP, + typename DerivedC> + IGL_INLINE void dfs( + const std::vector > & A, + const size_t s, + Eigen::PlainObjectBase & D, + Eigen::PlainObjectBase & P, + Eigen::PlainObjectBase & C); + template < + typename AType, + typename DType, + typename PType, + typename CType> + IGL_INLINE void dfs( + const std::vector > & A, + const size_t s, + std::vector & D, + std::vector & P, + std::vector & C); + +} +#ifndef IGL_STATIC_LIBRARY +# include "dfs.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/diag.cpp b/src/external/libigl-2.3.0/include/igl/diag.cpp new file mode 100644 index 000000000..d29382695 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/diag.cpp @@ -0,0 +1,108 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "diag.h" + +#include "verbose.h" + +// Bug in unsupported/Eigen/SparseExtra needs iostream first +#include +#include + +template +IGL_INLINE void igl::diag( + const Eigen::SparseMatrix& X, + Eigen::SparseVector& V) +{ + assert(false && "Just call X.diagonal().sparseView() directly"); + V = X.diagonal().sparseView(); + //// Get size of input + //int m = X.rows(); + //int n = X.cols(); + //V = Eigen::SparseVector((m>n?n:m)); + //V.reserve(V.size()); + + //// Iterate over outside + //for(int k=0; k::InnerIterator it (X,k); it; ++it) + // { + // if(it.col() == it.row()) + // { + // V.coeffRef(it.col()) += it.value(); + // } + // } + //} +} + +template +IGL_INLINE void igl::diag( + const Eigen::SparseMatrix& X, + Eigen::MatrixBase & V) +{ + assert(false && "Just call X.diagonal() directly"); + V = X.diagonal(); + //// Get size of input + //int m = X.rows(); + //int n = X.cols(); + //V.derived().resize((m>n?n:m),1); + + //// Iterate over outside + //for(int k=0; k::InnerIterator it (X,k); it; ++it) + // { + // if(it.col() == it.row()) + // { + // V(it.col()) = it.value(); + // } + // } + //} +} + +template +IGL_INLINE void igl::diag( + const Eigen::SparseVector& V, + Eigen::SparseMatrix& X) +{ + // clear and resize output + Eigen::DynamicSparseMatrix dyn_X(V.size(),V.size()); + dyn_X.reserve(V.size()); + // loop over non-zeros + for(typename Eigen::SparseVector::InnerIterator it(V); it; ++it) + { + dyn_X.coeffRef(it.index(),it.index()) += it.value(); + } + X = Eigen::SparseMatrix(dyn_X); +} + +template +IGL_INLINE void igl::diag( + const Eigen::MatrixBase & V, + Eigen::SparseMatrix& X) +{ + assert(V.rows() == 1 || V.cols() == 1); + // clear and resize output + Eigen::DynamicSparseMatrix dyn_X(V.size(),V.size()); + dyn_X.reserve(V.size()); + // loop over non-zeros + for(int i = 0;i(dyn_X); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +template void igl::diag >(Eigen::SparseMatrix const&, Eigen::MatrixBase >&); +template void igl::diag(Eigen::SparseMatrix const&, Eigen::SparseVector&); +template void igl::diag >(Eigen::MatrixBase > const&, Eigen::SparseMatrix&); +template void igl::diag(Eigen::SparseVector const&, Eigen::SparseMatrix&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/diag.h b/src/external/libigl-2.3.0/include/igl/diag.h new file mode 100644 index 000000000..8001f01b6 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/diag.h @@ -0,0 +1,62 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_DIAG_H +#define IGL_DIAG_H +#include "igl_inline.h" +#define EIGEN_YES_I_KNOW_SPARSE_MODULE_IS_NOT_STABLE_YET +#include + +namespace igl +{ + // http://forum.kde.org/viewtopic.php?f=74&t=117476&p=292388#p292388 + // + // This is superceded by + // VectorXd V = X.diagonal() and + // SparseVector V = X.diagonal().sparseView() + // SparseMatrix X = V.asDiagonal().sparseView() + // + // + // Either extracts the main diagonal of a matrix as a vector OR converts a + // vector into a matrix with vector along the main diagonal. Like matlab's + // diag function + + // Templates: + // T should be a eigen sparse matrix primitive type like int or double + // Inputs: + // X an m by n sparse matrix + // Outputs: + // V a min(m,n) sparse vector + template + IGL_INLINE void diag( + const Eigen::SparseMatrix& X, + Eigen::SparseVector& V); + template + IGL_INLINE void diag( + const Eigen::SparseMatrix& X, + Eigen::MatrixBase& V); + // Templates: + // T should be a eigen sparse matrix primitive type like int or double + // Inputs: + // V a m sparse vector + // Outputs: + // X a m by m sparse matrix + template + IGL_INLINE void diag( + const Eigen::SparseVector& V, + Eigen::SparseMatrix& X); + template + IGL_INLINE void diag( + const Eigen::MatrixBase& V, + Eigen::SparseMatrix& X); +} + +#ifndef IGL_STATIC_LIBRARY +# include "diag.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/dihedral_angles.cpp b/src/external/libigl-2.3.0/include/igl/dihedral_angles.cpp new file mode 100644 index 000000000..68427fdc0 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/dihedral_angles.cpp @@ -0,0 +1,98 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "dihedral_angles.h" +#include "edge_lengths.h" +#include "face_areas.h" + +#include + +template < + typename DerivedV, + typename DerivedT, + typename Derivedtheta, + typename Derivedcos_theta> +IGL_INLINE void igl::dihedral_angles( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& T, + Eigen::PlainObjectBase& theta, + Eigen::PlainObjectBase& cos_theta) +{ + using namespace Eigen; + assert(T.cols() == 4); + Matrix l; + edge_lengths(V,T,l); + Matrix s; + face_areas(l,s); + return dihedral_angles_intrinsic(l,s,theta,cos_theta); +} + +template < + typename DerivedL, + typename DerivedA, + typename Derivedtheta, + typename Derivedcos_theta> +IGL_INLINE void igl::dihedral_angles_intrinsic( + const Eigen::MatrixBase& L, + const Eigen::MatrixBase& A, + Eigen::PlainObjectBase& theta, + Eigen::PlainObjectBase& cos_theta) +{ + using namespace Eigen; + const int m = L.rows(); + assert(m == A.rows()); + // Law of cosines + // http://math.stackexchange.com/a/49340/35376 + Matrix H_sqr(m,6); + H_sqr.col(0) = (1./16.) * (4. * L.col(3).array().square() * L.col(0).array().square() - + ((L.col(1).array().square() + L.col(4).array().square()) - + (L.col(2).array().square() + L.col(5).array().square())).square()); + H_sqr.col(1) = (1./16.) * (4. * L.col(4).array().square() * L.col(1).array().square() - + ((L.col(2).array().square() + L.col(5).array().square()) - + (L.col(3).array().square() + L.col(0).array().square())).square()); + H_sqr.col(2) = (1./16.) * (4. * L.col(5).array().square() * L.col(2).array().square() - + ((L.col(3).array().square() + L.col(0).array().square()) - + (L.col(4).array().square() + L.col(1).array().square())).square()); + H_sqr.col(3) = (1./16.) * (4. * L.col(0).array().square() * L.col(3).array().square() - + ((L.col(4).array().square() + L.col(1).array().square()) - + (L.col(5).array().square() + L.col(2).array().square())).square()); + H_sqr.col(4) = (1./16.) * (4. * L.col(1).array().square() * L.col(4).array().square() - + ((L.col(5).array().square() + L.col(2).array().square()) - + (L.col(0).array().square() + L.col(3).array().square())).square()); + H_sqr.col(5) = (1./16.) * (4. * L.col(2).array().square() * L.col(5).array().square() - + ((L.col(0).array().square() + L.col(3).array().square()) - + (L.col(1).array().square() + L.col(4).array().square())).square()); + cos_theta.resize(m,6); + cos_theta.col(0) = (H_sqr.col(0).array() - + A.col(1).array().square() - A.col(2).array().square()).array() / + (-2.*A.col(1).array() * A.col(2).array()); + cos_theta.col(1) = (H_sqr.col(1).array() - + A.col(2).array().square() - A.col(0).array().square()).array() / + (-2.*A.col(2).array() * A.col(0).array()); + cos_theta.col(2) = (H_sqr.col(2).array() - + A.col(0).array().square() - A.col(1).array().square()).array() / + (-2.*A.col(0).array() * A.col(1).array()); + cos_theta.col(3) = (H_sqr.col(3).array() - + A.col(3).array().square() - A.col(0).array().square()).array() / + (-2.*A.col(3).array() * A.col(0).array()); + cos_theta.col(4) = (H_sqr.col(4).array() - + A.col(3).array().square() - A.col(1).array().square()).array() / + (-2.*A.col(3).array() * A.col(1).array()); + cos_theta.col(5) = (H_sqr.col(5).array() - + A.col(3).array().square() - A.col(2).array().square()).array() / + (-2.*A.col(3).array() * A.col(2).array()); + + theta = cos_theta.array().acos(); + + cos_theta.resize(m,6); + +} +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +template void igl::dihedral_angles_intrinsic< Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(const Eigen::MatrixBase >&, const Eigen::MatrixBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::dihedral_angles, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/dihedral_angles.h b/src/external/libigl-2.3.0/include/igl/dihedral_angles.h new file mode 100644 index 000000000..c4fc3bc19 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/dihedral_angles.h @@ -0,0 +1,55 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_DIHEDRAL_ANGLES_H +#define IGL_DIHEDRAL_ANGLES_H +#include "igl_inline.h" +#include +namespace igl +{ + // DIHEDRAL_ANGLES Compute dihedral angles for all tets of a given tet mesh + // (V,T) + // + // theta = dihedral_angles(V,T) + // theta = dihedral_angles(V,T,'ParameterName',parameter_value,...) + // + // Inputs: + // V #V by dim list of vertex positions + // T #V by 4 list of tet indices + // Outputs: + // theta #T by 6 list of dihedral angles (in radians) + // cos_theta #T by 6 list of cosine of dihedral angles (in radians) + // + template < + typename DerivedV, + typename DerivedT, + typename Derivedtheta, + typename Derivedcos_theta> + IGL_INLINE void dihedral_angles( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& T, + Eigen::PlainObjectBase& theta, + Eigen::PlainObjectBase& cos_theta); + template < + typename DerivedL, + typename DerivedA, + typename Derivedtheta, + typename Derivedcos_theta> + IGL_INLINE void dihedral_angles_intrinsic( + const Eigen::MatrixBase& L, + const Eigen::MatrixBase& A, + Eigen::PlainObjectBase& theta, + Eigen::PlainObjectBase& cos_theta); + +} + +#ifndef IGL_STATIC_LIBRARY +# include "dihedral_angles.cpp" +#endif + +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/dijkstra.cpp b/src/external/libigl-2.3.0/include/igl/dijkstra.cpp new file mode 100644 index 000000000..8ef4e2f63 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/dijkstra.cpp @@ -0,0 +1,138 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "dijkstra.h" + +template +IGL_INLINE int igl::dijkstra( + const IndexType &source, + const std::set &targets, + const std::vector >& VV, + const std::vector& weights, + Eigen::PlainObjectBase &min_distance, + Eigen::PlainObjectBase &previous) +{ + int numV = VV.size(); + min_distance.setConstant(numV, 1, std::numeric_limits::max()); + min_distance[source] = 0; + previous.setConstant(numV, 1, -1); + std::set > vertex_queue; + vertex_queue.insert(std::make_pair(min_distance[source], source)); + + while (!vertex_queue.empty()) + { + typename DerivedD::Scalar dist = vertex_queue.begin()->first; + IndexType u = vertex_queue.begin()->second; + vertex_queue.erase(vertex_queue.begin()); + + if (targets.find(u)!= targets.end()) + return u; + + // Visit each edge exiting u + const std::vector &neighbors = VV[u]; + for (std::vector::const_iterator neighbor_iter = neighbors.begin(); + neighbor_iter != neighbors.end(); + neighbor_iter++) + { + IndexType v = *neighbor_iter; + typename DerivedD::Scalar distance_through_u = dist + weights[u]; + if (distance_through_u < min_distance[v]) { + vertex_queue.erase(std::make_pair(min_distance[v], v)); + + min_distance[v] = distance_through_u; + previous[v] = u; + vertex_queue.insert(std::make_pair(min_distance[v], v)); + + } + + } + } + //we should never get here + return -1; +} + +template +IGL_INLINE int igl::dijkstra( + const IndexType &source, + const std::set &targets, + const std::vector >& VV, + Eigen::PlainObjectBase &min_distance, + Eigen::PlainObjectBase &previous) +{ + std::vector weights(VV.size(), 1.0); + return dijkstra(source, targets, VV, weights, min_distance, previous); +} + +template +IGL_INLINE void igl::dijkstra( + const IndexType &vertex, + const Eigen::MatrixBase &previous, + std::vector &path) +{ + IndexType source = vertex; + path.clear(); + for ( ; source != -1; source = previous[source]) + path.push_back(source); +} + + +template +IGL_INLINE int igl::dijkstra( + const Eigen::MatrixBase &V, + const std::vector >& VV, + const IndexType &source, + const std::set &targets, + Eigen::PlainObjectBase &min_distance, + Eigen::PlainObjectBase &previous) +{ + int numV = VV.size(); + + min_distance.setConstant(numV, 1, std::numeric_limits::infinity()); + min_distance[source] = 0; + previous.setConstant(numV, 1, -1); + std::set > vertex_queue; + vertex_queue.insert(std::make_pair(min_distance[source], source)); + + while (!vertex_queue.empty()) + { + typename DerivedD::Scalar dist = vertex_queue.begin()->first; + IndexType u = vertex_queue.begin()->second; + vertex_queue.erase(vertex_queue.begin()); + + if (targets.find(u)!= targets.end()) + return u; + + // Visit each edge exiting u + const std::vector &neighbors = VV[u]; + for (std::vector::const_iterator neighbor_iter = neighbors.begin(); + neighbor_iter != neighbors.end(); + neighbor_iter++) + { + IndexType v = *neighbor_iter; + typename DerivedD::Scalar distance_through_u = dist + (V.row(u) - V.row(v)).norm(); + if (distance_through_u < min_distance[v]) { + vertex_queue.erase(std::make_pair(min_distance[v], v)); + + min_distance[v] = distance_through_u; + previous[v] = u; + vertex_queue.insert(std::make_pair(min_distance[v], v)); + + } + + } + } + return -1; +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +template int igl::dijkstra, Eigen::Matrix >(int const&, std::set, std::allocator > const&, std::vector >, std::allocator > > > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template int igl::dijkstra, Eigen::Matrix >(int const&, std::set, std::allocator > const&, std::vector >, std::allocator > > > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::dijkstra >(int const&, Eigen::MatrixBase > const&, std::vector >&); +template int igl::dijkstra, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, std::vector >, std::allocator > > > const&, int const&, std::set, std::allocator > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/dijkstra.h b/src/external/libigl-2.3.0/include/igl/dijkstra.h new file mode 100644 index 000000000..f2fd0c0e1 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/dijkstra.h @@ -0,0 +1,109 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Olga Diamanti +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef IGL_DIJKSTRA +#define IGL_DIJKSTRA +#include "igl_inline.h" + +#include +#include +#include + +namespace igl { + + // Dijkstra's algorithm for vertex-weighted shortest paths, with multiple targets. + // Adapted from http://rosettacode.org/wiki/Dijkstra%27s_algorithm . + // + // Inputs: + // source index of source vertex + // targets target vector set + // VV #V list of lists of incident vertices (adjacency list), e.g. + // as returned by igl::adjacency_list + // weights #V list of scalar vertex weights + // + // Output: + // min_distance #V by 1 list of the minimum distances from source to all vertices + // previous #V by 1 list of the previous visited vertices (for each vertex) - used for backtracking + // + template + IGL_INLINE int dijkstra( + const IndexType &source, + const std::set &targets, + const std::vector >& VV, + const std::vector& weights, + Eigen::PlainObjectBase &min_distance, + Eigen::PlainObjectBase &previous); + + // Dijkstra's algorithm for shortest paths, with multiple targets. + // Adapted from http://rosettacode.org/wiki/Dijkstra%27s_algorithm . + // + // Inputs: + // source index of source vertex + // targets target vector set + // VV #V list of lists of incident vertices (adjacency list), e.g. + // as returned by igl::adjacency_list + // + // Output: + // min_distance #V by 1 list of the minimum distances from source to all vertices + // previous #V by 1 list of the previous visited vertices (for each vertex) - used for backtracking + // + template + IGL_INLINE int dijkstra( + const IndexType &source, + const std::set &targets, + const std::vector >& VV, + Eigen::PlainObjectBase &min_distance, + Eigen::PlainObjectBase &previous); + + // Backtracking after Dijkstra's algorithm, to find shortest path. + // + // Inputs: + // vertex vertex to which we want the shortest path (from same source as above) + // previous #V by 1 list of the previous visited vertices (for each vertex) - result of Dijkstra's algorithm + // + // Output: + // path #P by 1 list of vertex indices in the shortest path from vertex to source + // + template + IGL_INLINE void dijkstra( + const IndexType &vertex, + const Eigen::MatrixBase &previous, + std::vector &path); + + + // Dijkstra's algorithm for shortest paths on a mesh, with multiple targets, using edge length + // + // Inputs: + // V #V by 3 list of vertex positions + // VV #V list of lists of incident vertices (adjacency list), e.g. + // as returned by igl::adjacency_list, will be generated if empty. + // source index of source vertex + // targets target vector set + // + // Output: + // min_distance #V by 1 list of the minimum distances from source to all vertices + // previous #V by 1 list of the previous visited vertices (for each vertex) - used for backtracking + // + template + IGL_INLINE int dijkstra( + const Eigen::MatrixBase &V, + const std::vector >& VV, + const IndexType &source, + const std::set &targets, + Eigen::PlainObjectBase &min_distance, + Eigen::PlainObjectBase &previous); + +} + +#ifndef IGL_STATIC_LIBRARY +#include "dijkstra.cpp" +#endif + + +#endif /* defined(IGL_DIJKSTRA) */ diff --git a/src/external/libigl-2.3.0/include/igl/direct_delta_mush.cpp b/src/external/libigl-2.3.0/include/igl/direct_delta_mush.cpp new file mode 100644 index 000000000..206927a03 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/direct_delta_mush.cpp @@ -0,0 +1,268 @@ +// This file is part of libigl, a simple C++ geometry processing library. +// +// Copyright (C) 2020 Xiangyu Kong +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "direct_delta_mush.h" +#include "cotmatrix.h" + +template < + typename DerivedV, + typename DerivedOmega, + typename DerivedU> +IGL_INLINE void igl::direct_delta_mush( + const Eigen::MatrixBase & V, + const std::vector > & T, + const Eigen::MatrixBase & Omega, + Eigen::PlainObjectBase & U) +{ + using namespace Eigen; + + // Shape checks + assert(V.cols() == 3 && "V should contain 3D positions."); + assert(Omega.rows() == V.rows() && "Omega contain the same number of rows as V."); + assert(Omega.cols() == T.size() * 10 && "Omega should have #T*10 columns."); + + typedef typename DerivedV::Scalar Scalar; + + int n = V.rows(); + int m = T.size(); + + // V_homogeneous: #V by 4, homogeneous version of V + // Note: + // In the paper, the rest pose vertices are represented in U \in R^{4 x #V} + // Thus the formulae involving U would differ from the paper by a transpose. + Matrix V_homogeneous(n, 4); + V_homogeneous << V, Matrix::Ones(n, 1); + U.resize(n, 3); + + for (int i = 0; i < n; ++i) + { + // Construct Q matrix using Omega and Transformations + Matrix Q_mat(4, 4); + Q_mat = Matrix::Zero(4, 4); + for (int j = 0; j < m; ++j) + { + Matrix Omega_curr(4, 4); + Matrix curr = Omega.block(i, j * 10, 1, 10).transpose(); + Omega_curr << curr(0), curr(1), curr(2), curr(3), + curr(1), curr(4), curr(5), curr(6), + curr(2), curr(5), curr(7), curr(8), + curr(3), curr(6), curr(8), curr(9); + + Affine3d M_curr = T[j]; + Q_mat += M_curr.matrix() * Omega_curr; + } + // Normalize so that the last element is 1 + Q_mat /= Q_mat(Q_mat.rows() - 1, Q_mat.cols() - 1); + + Matrix Q_i = Q_mat.block(0, 0, 3, 3); + Matrix q_i = Q_mat.block(0, 3, 3, 1); + Matrix p_i = Q_mat.block(3, 0, 1, 3).transpose(); + + // Get rotation and translation matrices using SVD + Matrix SVD_i = Q_i - q_i * p_i.transpose(); + JacobiSVD> svd; + svd.compute(SVD_i, ComputeFullU | ComputeFullV); + Matrix R_i = svd.matrixU() * svd.matrixV().transpose(); + Matrix t_i = q_i - R_i * p_i; + + // Gamma final transformation matrix + Matrix Gamma_i(3, 4); + Gamma_i.block(0, 0, 3, 3) = R_i; + Gamma_i.block(0, 3, 3, 1) = t_i; + + // Final deformed position + Matrix v_i = V_homogeneous.row(i); + U.row(i) = Gamma_i * v_i; + } +} + +template < + typename DerivedV, + typename DerivedF, + typename DerivedW, + typename DerivedOmega> +IGL_INLINE void igl::direct_delta_mush_precomputation( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const Eigen::MatrixBase & W, + const int p, + const typename DerivedV::Scalar lambda, + const typename DerivedV::Scalar kappa, + const typename DerivedV::Scalar alpha, + Eigen::PlainObjectBase & Omega) +{ + using namespace Eigen; + + // Shape checks + assert(V.cols() == 3 && "V should contain 3D positions."); + assert(F.cols() == 3 && "F should contain triangles."); + assert(W.rows() == V.rows() && "W.rows() should be equal to V.rows()."); + + // Parameter checks + assert(p > 0 && "Laplacian iteration p should be positive."); + assert(lambda > 0 && "lambda should be positive."); + assert(kappa > 0 && kappa < lambda && "kappa should be positive and less than lambda."); + assert(alpha >= 0 && alpha < 1 && "alpha should be non-negative and less than 1."); + + typedef typename DerivedV::Scalar Scalar; + + // lambda helper + // Given a square matrix, extract the upper triangle (including diagonal) to an array. + // E.g. 1 2 3 4 + // 5 6 7 8 -> [1, 2, 3, 4, 6, 7, 8, 11, 12, 16] + // 9 10 11 12 0 1 2 3 4 5 6 7 8 9 + // 13 14 15 16 + auto extract_upper_triangle = []( + const Matrix & full) -> Matrix + { + int dims = full.rows(); + Matrix upper_triangle((dims * (dims + 1)) / 2); + int vector_idx = 0; + for (int i = 0; i < dims; ++i) + { + for (int j = i; j < dims; ++j) + { + upper_triangle(vector_idx) = full(i, j); + vector_idx++; + } + } + return upper_triangle; + }; + + const int n = V.rows(); + const int m = W.cols(); + + // V_homogeneous: #V by 4, homogeneous version of V + // Note: + // in the paper, the rest pose vertices are represented in U \in R^{4 \times #V} + // Thus the formulae involving U would differ from the paper by a transpose. + Matrix V_homogeneous(n, 4); + V_homogeneous << V, Matrix::Ones(n); + + // Identity matrix of #V by #V + SparseMatrix I(n, n); + I.setIdentity(); + + // Laplacian matrix of #V by #V + // L_bar = L \times D_L^{-1} + SparseMatrix L; + igl::cotmatrix(V, F, L); + L = -L; + // Inverse of diagonal matrix = reciprocal elements in diagonal + Matrix D_L = L.diagonal(); + // D_L = D_L.array().pow(-1); // Not using this since not sure if diagonal contains 0 + for (int i = 0; i < D_L.size(); ++i) + { + if (D_L(i) != 0) + { + D_L(i) = 1 / D_L(i); + } + } + SparseMatrix D_L_inv = D_L.asDiagonal().toDenseMatrix().sparseView(); + SparseMatrix L_bar = L * D_L_inv; + + // Implicitly and iteratively solve for W' + // w'_{ij} = \sum_{k=1}^{n}{C_{ki} w_{kj}} where C = (I + kappa L_bar)^{-p}: + // W' = C^T \times W => c^T W_k = W_{k-1} where c = (I + kappa L_bar) + // C positive semi-definite => ldlt solver + SimplicialLDLT> ldlt_W_prime; + SparseMatrix c(I + kappa * L_bar); + // working copy + DerivedW W_prime(W); + ldlt_W_prime.compute(c.transpose()); + for (int iter = 0; iter < p; ++iter) + { + W_prime = ldlt_W_prime.solve(W_prime); + } + + // U_precomputed: #V by 10 + // Cache u_i^T \dot u_i \in R^{4 x 4} to reduce computation time. + Matrix U_precomputed(n, 10); + for (int k = 0; k < n; ++k) + { + Matrix u_full = V_homogeneous.row(k).transpose() * V_homogeneous.row(k); + U_precomputed.row(k) = extract_upper_triangle(u_full); + } + + // U_prime: #V by #T*10 of u_{jx} + // Each column of U_prime (u_{jx}) is the element-wise product of + // W_j and U_precomputed_x where j \in {1...m}, x \in {1...10} + Matrix U_prime(n, m * 10); + for (int j = 0; j < m; ++j) + { + Matrix w_j = W.col(j); + for (int x = 0; x < 10; ++x) + { + Matrix u_x = U_precomputed.col(x); + U_prime.col(10 * j + x) = w_j.array() * u_x.array(); + } + } + + // Implicitly and iteratively solve for Psi: #V by #T*10 of \Psi_{ij}s. + // Note: Using dense matrices to solve for Psi will cause the program to hang. + // The following won't work + // Matrix Psi(U_prime); + // Matrix b((I + lambda * L_bar).transpose()); + // for (int iter = 0; iter < p; ++iter) + // { + // Psi = b.ldlt().solve(Psi); // hangs here + // } + // Convert to sparse matrices and compute + Matrix Psi = U_prime.sparseView(); + SparseMatrix b = (I + lambda * L_bar).transpose(); + SimplicialLDLT> ldlt_Psi; + ldlt_Psi.compute(b); + for (int iter = 0; iter < p; ++iter) + { + Psi = ldlt_Psi.solve(Psi); + } + + // P: #V by 10 precomputed upper triangle of + // p_i p_i^T , p_i + // p_i^T , 1 + // where p_i = (\sum_{j=1}^{n} Psi_{ij})'s top right 3 by 1 column + Matrix P(n, 10); + for (int i = 0; i < n; ++i) + { + Matrix p_i = Matrix::Zero(3); + Scalar last = 0; + for (int j = 0; j < m; ++j) + { + Matrix p_i_curr(3); + p_i_curr << Psi(i, j * 10 + 3), Psi(i, j * 10 + 6), Psi(i, j * 10 + 8); + p_i += p_i_curr; + last += Psi(i, j * 10 + 9); + } + p_i /= last; // normalize + Matrix p_matrix(4, 4); + p_matrix.block(0, 0, 3, 3) = p_i * p_i.transpose(); + p_matrix.block(0, 3, 3, 1) = p_i; + p_matrix.block(3, 0, 1, 3) = p_i.transpose(); + p_matrix(3, 3) = 1; + P.row(i) = extract_upper_triangle(p_matrix); + } + + // Omega + Omega.resize(n, m * 10); + for (int i = 0; i < n; ++i) + { + Matrix p_vector = P.row(i); + for (int j = 0; j < m; ++j) + { + Matrix Omega_curr(10); + Matrix Psi_curr = Psi.block(i, j * 10, 1, 10).transpose(); + Omega_curr = (1. - alpha) * Psi_curr + alpha * W_prime(i, j) * p_vector; + Omega.block(i, j * 10, 1, 10) = Omega_curr.transpose(); + } + } +} + +#ifdef IGL_STATIC_LIBRARY + +// Explicit template instantiation +template void igl::direct_delta_mush, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, std::vector, Eigen::aligned_allocator > > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); template void igl::direct_delta_mush_precomputation, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, int, Eigen::Matrix::Scalar, Eigen::Matrix::Scalar, Eigen::Matrix::Scalar, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/direct_delta_mush.h b/src/external/libigl-2.3.0/include/igl/direct_delta_mush.h new file mode 100644 index 000000000..53cc35de6 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/direct_delta_mush.h @@ -0,0 +1,72 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2020 Xiangyu Kong +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_DIRECT_DELTA_MUSH_H +#define IGL_DIRECT_DELTA_MUSH_H + +#include "igl_inline.h" + +#include +#include +#include +#include + +namespace igl { + // Computes Direct Delta Mesh Skinning (Variant 0) from "Direct Delta Mush + // Skinning and Variants" + // + // Inputs: + // V #V by 3 list of rest pose vertex positions + // T #T list of bone pose transformations + // Omega #V by #T*10 list of precomputated matrix values + // Outputs: + // U #V by 3 list of output vertex positions + template < + typename DerivedV, + typename DerivedOmega, + typename DerivedU> + IGL_INLINE void direct_delta_mush( + const Eigen::MatrixBase & V, + const std::vector< + Eigen::Affine3d, Eigen::aligned_allocator + > & T, /* should eventually be templated more generally than double */ + const Eigen::MatrixBase & Omega, + Eigen::PlainObjectBase & U); + + // Precomputation + // + // Inputs: + // V #V by 3 list of rest pose vertex positions + // F #F by 3 list of triangle indices into rows of V + // W #V by #Edges list of weights + // p number of smoothing iterations + // lambda rotation smoothing step size + // kappa translation smoothness step size + // alpha translation smoothness blending weight + // Outputs: + // Omega #V by #T*10 list of precomputated matrix values + template < + typename DerivedV, + typename DerivedF, + typename DerivedW, + typename DerivedOmega> + IGL_INLINE void direct_delta_mush_precomputation( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const Eigen::MatrixBase & W, + const int p, + const typename DerivedV::Scalar lambda, + const typename DerivedV::Scalar kappa, + const typename DerivedV::Scalar alpha, + Eigen::PlainObjectBase & Omega); +} // namespace igl + +#ifndef IGL_STATIC_LIBRARY +# include "direct_delta_mush.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/directed_edge_orientations.cpp b/src/external/libigl-2.3.0/include/igl/directed_edge_orientations.cpp new file mode 100644 index 000000000..03b8a44a9 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/directed_edge_orientations.cpp @@ -0,0 +1,29 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "directed_edge_orientations.h" + +template +IGL_INLINE void igl::directed_edge_orientations( + const Eigen::MatrixBase & C, + const Eigen::MatrixBase & E, + std::vector< + Eigen::Quaterniond,Eigen::aligned_allocator > & Q) +{ + using namespace Eigen; + Q.resize(E.rows()); + for(int e = 0;e, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, std::vector, Eigen::aligned_allocator > >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/directed_edge_orientations.h b/src/external/libigl-2.3.0/include/igl/directed_edge_orientations.h new file mode 100644 index 000000000..9a8ce05bd --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/directed_edge_orientations.h @@ -0,0 +1,39 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_DIRECTED_EDGE_ORIENTATIONS_H +#define IGL_DIRECTED_EDGE_ORIENTATIONS_H +#include "igl_inline.h" + +#include +#include +#include +#include + +namespace igl +{ + // Determine rotations that take each edge from the x-axis to its given rest + // orientation. + // + // Inputs: + // C #C by 3 list of edge vertex positions + // E #E by 2 list of directed edges + // Outputs: + // Q #E list of quaternions + // + template + IGL_INLINE void directed_edge_orientations( + const Eigen::MatrixBase & C, + const Eigen::MatrixBase & E, + std::vector< + Eigen::Quaterniond,Eigen::aligned_allocator > & Q); +} + +#ifndef IGL_STATIC_LIBRARY +# include "directed_edge_orientations.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/directed_edge_parents.cpp b/src/external/libigl-2.3.0/include/igl/directed_edge_parents.cpp new file mode 100644 index 000000000..b8180023c --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/directed_edge_parents.cpp @@ -0,0 +1,36 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "directed_edge_parents.h" +#include "slice_into.h" +#include "slice.h" +#include "colon.h" +#include "setdiff.h" +#include + +template +IGL_INLINE void igl::directed_edge_parents( + const Eigen::MatrixBase & E, + Eigen::PlainObjectBase & P) +{ + using namespace Eigen; + using namespace std; + typedef Eigen::Matrix VectorT; + + VectorT I = VectorT::Constant(E.maxCoeff()+1,1,-1); + //I(E.col(1)) = 0:E.rows()-1 + slice_into(colon(0, E.rows()-1), E.col(1).eval(), I); + VectorT roots,_; + setdiff(E.col(0).eval(),E.col(1).eval(),roots,_); + std::for_each(roots.data(),roots.data()+roots.size(),[&](typename VectorT::Scalar r){I(r)=-1;}); + slice(I,E.col(0).eval(),P); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +template void igl::directed_edge_parents, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/directed_edge_parents.h b/src/external/libigl-2.3.0/include/igl/directed_edge_parents.h new file mode 100644 index 000000000..5edc9dc32 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/directed_edge_parents.h @@ -0,0 +1,32 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_DIRECTED_EDGE_PARENTS_H +#define IGL_DIRECTED_EDGE_PARENTS_H +#include "igl_inline.h" + +#include + +namespace igl +{ + // Recover "parents" (preceding edges) in a tree given just directed edges. + // + // Inputs: + // E #E by 2 list of directed edges + // Outputs: + // P #E list of parent indices into E (-1) means root + // + template + IGL_INLINE void directed_edge_parents( + const Eigen::MatrixBase & E, + Eigen::PlainObjectBase & P); +} + +#ifndef IGL_STATIC_LIBRARY +# include "directed_edge_parents.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/dirname.cpp b/src/external/libigl-2.3.0/include/igl/dirname.cpp new file mode 100644 index 000000000..dad96526a --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/dirname.cpp @@ -0,0 +1,40 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2018 Alec Jacobson +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "dirname.h" + +#include +#include "verbose.h" + +IGL_INLINE std::string igl::dirname(const std::string & path) +{ + if(path == "") + { + return std::string(""); + } + // https://stackoverflow.com/a/3071694/148668 + size_t found = path.find_last_of("/\\"); + if(found == std::string::npos) + { + // No slashes found + return std::string("."); + }else if(found == 0) + { + // Slash is first char + return std::string(path.begin(),path.begin()+1); + }else if(found == path.length()-1) + { + // Slash is last char + std::string redo = std::string(path.begin(),path.end()-1); + return igl::dirname(redo); + } + // Return everything up to but not including last slash + return std::string(path.begin(),path.begin()+found); +} + + diff --git a/src/external/libigl-2.3.0/include/igl/dirname.h b/src/external/libigl-2.3.0/include/igl/dirname.h new file mode 100644 index 000000000..800d492ab --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/dirname.h @@ -0,0 +1,34 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2018 Alec Jacobson +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_DIRNAME_H +#define IGL_DIRNAME_H +#include "igl_inline.h" + +#include + +namespace igl +{ + // Function like PHP's dirname: /etc/passwd --> /etc, + // Input: + // path string containing input path + // Returns string containing dirname (see php's dirname) + // + // See also: basename, pathinfo + // + // **Note:** This function will have undefined behavior if **file names** in + // the path contain \ and / characters. This function interprets \ and / as + // file path separators. + IGL_INLINE std::string dirname(const std::string & path); +} + +#ifndef IGL_STATIC_LIBRARY +# include "dirname.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/dot.cpp b/src/external/libigl-2.3.0/include/igl/dot.cpp new file mode 100644 index 000000000..38f191546 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/dot.cpp @@ -0,0 +1,16 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "dot.h" + +// http://www.antisphere.com/Wiki/tools:anttweakbar +IGL_INLINE double igl::dot( + const double *a, + const double *b) +{ + return a[0]*b[0] + a[1]*b[1] + a[2]*b[2]; +} diff --git a/src/external/libigl-2.3.0/include/igl/dot.h b/src/external/libigl-2.3.0/include/igl/dot.h new file mode 100644 index 000000000..9494eac7b --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/dot.h @@ -0,0 +1,27 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_DOT_H +#define IGL_DOT_H +#include "igl_inline.h" +namespace igl +{ + // Computes out = dot(a,b) + // Inputs: + // a left 3d vector + // b right 3d vector + // Returns scalar dot product + IGL_INLINE double dot( + const double *a, + const double *b); +} + +#ifndef IGL_STATIC_LIBRARY +# include "dot.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/dot_row.cpp b/src/external/libigl-2.3.0/include/igl/dot_row.cpp new file mode 100644 index 000000000..6f6d57e06 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/dot_row.cpp @@ -0,0 +1,26 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Daniele Panozzo +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "igl/dot_row.h" + +template +IGL_INLINE DerivedV igl::dot_row( + const Eigen::PlainObjectBase& A, + const Eigen::PlainObjectBase& B + ) +{ + assert(A.rows() == B.rows()); + assert(A.cols() == B.cols()); + + return (A.array() * B.array()).rowwise().sum(); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template Eigen::Matrix igl::dot_row >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/dot_row.h b/src/external/libigl-2.3.0/include/igl/dot_row.h new file mode 100644 index 000000000..83d91aada --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/dot_row.h @@ -0,0 +1,36 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Daniele Panozzo +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_DOT_ROW_H +#define IGL_DOT_ROW_H + +#include "igl/igl_inline.h" +#include + +namespace igl +{ + // Compute the dot product between each row of A and B + // Templates: + // DerivedV derived from vertex positions matrix type: i.e. MatrixXd + // Inputs: + // A eigen matrix r by c + // B eigen matrix r by c + // Returns: + // d a column vector with r entries that contains the dot product of each corresponding row of A and B + // + template + IGL_INLINE DerivedV dot_row( + const Eigen::PlainObjectBase& A, + const Eigen::PlainObjectBase& B); + +} + +#ifndef IGL_STATIC_LIBRARY +# include "dot_row.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/doublearea.cpp b/src/external/libigl-2.3.0/include/igl/doublearea.cpp new file mode 100644 index 000000000..9d59a4c8e --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/doublearea.cpp @@ -0,0 +1,264 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "doublearea.h" +#include "edge_lengths.h" +#include "parallel_for.h" +#include "sort.h" +#include +#include +#include + +template +IGL_INLINE void igl::doublearea( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + Eigen::PlainObjectBase & dblA) +{ + // quads are handled by a specialized function + if (F.cols() == 4) return doublearea_quad(V,F,dblA); + + const int dim = V.cols(); + // Only support triangles + assert(F.cols() == 3); + const size_t m = F.rows(); + // Compute edge lengths + Eigen::Matrix l; + + // Projected area helper + const auto & proj_doublearea = + [&V,&F](const int x, const int y, const int f) + ->typename DerivedV::Scalar + { + auto rx = V(F(f,0),x)-V(F(f,2),x); + auto sx = V(F(f,1),x)-V(F(f,2),x); + auto ry = V(F(f,0),y)-V(F(f,2),y); + auto sy = V(F(f,1),y)-V(F(f,2),y); + return rx*sy - ry*sx; + }; + + switch(dim) + { + case 3: + { + dblA = DeriveddblA::Zero(m,1); + for(size_t f = 0;f +IGL_INLINE void igl::doublearea( + const Eigen::MatrixBase & A, + const Eigen::MatrixBase & B, + const Eigen::MatrixBase & C, + Eigen::PlainObjectBase & D) +{ + assert((B.cols() == A.cols()) && "dimensions of A and B should match"); + assert((C.cols() == A.cols()) && "dimensions of A and C should match"); + assert(A.rows() == B.rows() && "corners should have same length"); + assert(A.rows() == C.rows() && "corners should have same length"); + switch(A.cols()) + { + case 2: + { + // For 2d compute signed area + const auto & R = A-C; + const auto & S = B-C; + D = (R.col(0).array()*S.col(1).array() - + R.col(1).array()*S.col(0).array()).template cast< + typename DerivedD::Scalar>(); + break; + } + default: + { + Eigen::Matrix + uL(A.rows(),3); + uL.col(0) = ((B-C).rowwise().norm()).template cast(); + uL.col(1) = ((C-A).rowwise().norm()).template cast(); + uL.col(2) = ((A-B).rowwise().norm()).template cast(); + doublearea(uL,D); + } + } +} + +template < + typename DerivedA, + typename DerivedB, + typename DerivedC> +IGL_INLINE typename DerivedA::Scalar igl::doublearea_single( + const Eigen::MatrixBase & A, + const Eigen::MatrixBase & B, + const Eigen::MatrixBase & C) +{ + assert(A.size() == 2 && "Vertices should be 2D"); + assert(B.size() == 2 && "Vertices should be 2D"); + assert(C.size() == 2 && "Vertices should be 2D"); + auto r = A-C; + auto s = B-C; + return r(0)*s(1) - r(1)*s(0); +} + +template +IGL_INLINE void igl::doublearea( + const Eigen::MatrixBase & ul, + Eigen::PlainObjectBase & dblA) +{ + // Default is to leave NaNs and fire asserts in debug mode + return doublearea( + ul,std::numeric_limits::quiet_NaN(),dblA); +} + +template +IGL_INLINE void igl::doublearea( + const Eigen::MatrixBase & ul, + const typename Derivedl::Scalar nan_replacement, + Eigen::PlainObjectBase & dblA) +{ + using namespace Eigen; + using namespace std; + typedef typename Derivedl::Index Index; + // Only support triangles + assert(ul.cols() == 3); + // Number of triangles + const Index m = ul.rows(); + Eigen::Matrix l; + MatrixXi _; + // + // "Miscalculating Area and Angles of a Needle-like Triangle" + // https://people.eecs.berkeley.edu/~wkahan/Triangle.pdf + igl::sort(ul,2,false,l,_); + // semiperimeters + //Matrix s = l.rowwise().sum()*0.5; + //assert((Index)s.rows() == m); + // resize output + dblA.resize(l.rows(),1); + parallel_for( + m, + [&l,&dblA,&nan_replacement](const int i) + { + // Kahan's Heron's formula + typedef typename Derivedl::Scalar Scalar; + const Scalar arg = + (l(i,0)+(l(i,1)+l(i,2)))* + (l(i,2)-(l(i,0)-l(i,1)))* + (l(i,2)+(l(i,0)-l(i,1)))* + (l(i,0)+(l(i,1)-l(i,2))); + dblA(i) = 2.0*0.25*sqrt(arg); + // Alec: If the input edge lengths were computed from floating point + // vertex positions then there's no guarantee that they fulfill the + // triangle inequality (in their floating point approximations). For + // nearly degenerate triangles the round-off error during side-length + // computation may be larger than (or rather smaller) than the height of + // the triangle. In "Lecture Notes on Geometric Robustness" Shewchuck 09, + // Section 3.1 http://www.cs.berkeley.edu/~jrs/meshpapers/robnotes.pdf, + // he recommends computing the triangle areas for 2D and 3D using 2D + // signed areas computed with determinants. + assert( + (nan_replacement == nan_replacement || + (l(i,2) - (l(i,0)-l(i,1)))>=0) + && "Side lengths do not obey the triangle inequality."); + if(dblA(i) != dblA(i)) + { + dblA(i) = nan_replacement; + } + assert(dblA(i) == dblA(i) && "DOUBLEAREA() PRODUCED NaN"); + }, + 1000l); +} + +template +IGL_INLINE void igl::doublearea_quad( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + Eigen::PlainObjectBase & dblA) +{ + assert(V.cols() == 3); // Only supports points in 3D + assert(F.cols() == 4); // Only support quads + const size_t m = F.rows(); + + // Split the quads into triangles + Eigen::MatrixXi Ft(F.rows()*2,3); + + for(size_t i=0; i, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::doublearea, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::Matrix::Scalar, Eigen::PlainObjectBase >&); +template void igl::doublearea, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::doublearea, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::Matrix::Scalar, Eigen::PlainObjectBase >&); +template void igl::doublearea, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::doublearea, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::doublearea, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::doublearea, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::doublearea, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::doublearea, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::doublearea, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::doublearea, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::doublearea, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::doublearea, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::doublearea, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::doublearea, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::doublearea, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::doublearea, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::doublearea, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::doublearea, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::doublearea, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::doublearea, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::doublearea, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::doublearea, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::doublearea, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::doublearea, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::doublearea, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template Eigen::Matrix::Scalar igl::doublearea_single, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&); +template Eigen::Matrix::Scalar igl::doublearea_single, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/doublearea.h b/src/external/libigl-2.3.0/include/igl/doublearea.h new file mode 100644 index 000000000..95c151508 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/doublearea.h @@ -0,0 +1,104 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_DOUBLEAREA_H +#define IGL_DOUBLEAREA_H +#include "igl_inline.h" +#include +namespace igl +{ + // DOUBLEAREA computes twice the area for each input triangle[quad] + // + // Templates: + // DerivedV derived type of eigen matrix for V (e.g. derived from + // MatrixXd) + // DerivedF derived type of eigen matrix for F (e.g. derived from + // MatrixXi) + // DeriveddblA derived type of eigen matrix for dblA (e.g. derived from + // MatrixXd) + // Inputs: + // V #V by dim list of mesh vertex positions + // F #F by simplex_size list of mesh faces (must be triangles or quads) + // Outputs: + // dblA #F list of triangle[quad] double areas (SIGNED only for 2D input) + // + // Known bug: For dim==3 complexity is O(#V + #F)!! Not just O(#F). This is a big deal + // if you have 1million unreferenced vertices and 1 face + template + IGL_INLINE void doublearea( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + Eigen::PlainObjectBase & dblA); + // Stream of triangles, computes signed area... + template < + typename DerivedA, + typename DerivedB, + typename DerivedC, + typename DerivedD> + IGL_INLINE void doublearea( + const Eigen::MatrixBase & A, + const Eigen::MatrixBase & B, + const Eigen::MatrixBase & C, + Eigen::PlainObjectBase & D); + // Single triangle in 2D! + // + // This should handle streams of corners not just single corners + template < + typename DerivedA, + typename DerivedB, + typename DerivedC> + IGL_INLINE typename DerivedA::Scalar doublearea_single( + const Eigen::MatrixBase & A, + const Eigen::MatrixBase & B, + const Eigen::MatrixBase & C); + // Same as above but use instrinsic edge lengths rather than (V,F) mesh. This + // + // Inputs: + // l #F by dim list of edge lengths using + // for triangles, columns correspond to edges 23,31,12 + // nan_replacement what value should be used for triangles whose given + // edge lengths do not obey the triangle inequality. These may be very + // wrong (e.g., [100 1 1]) or may be nearly degenerate triangles whose + // floating point side length computation leads to breach of the triangle + // inequality. One may wish to set this parameter to 0 if side lengths l + // are _known_ to come from a valid embedding (e.g., some mesh (V,F)). In + // that case, the only circumstance the triangle inequality is broken is + // when the triangle is nearly degenerate and floating point error + // dominates: hence replacing with zero is reasonable. + // Outputs: + // dblA #F list of triangle double areas + template + IGL_INLINE void doublearea( + const Eigen::MatrixBase & l, + const typename Derivedl::Scalar nan_replacement, + Eigen::PlainObjectBase & dblA); + // default behavior is to assert on NaNs and leave them in place + template + IGL_INLINE void doublearea( + const Eigen::MatrixBase & l, + Eigen::PlainObjectBase & dblA); + // DOUBLEAREA_QUAD computes twice the area for each input quadrilateral + // + // Inputs: + // V #V by dim list of mesh vertex positions + // F #F by simplex_size list of mesh faces (must be quadrilaterals) + // Outputs: + // dblA #F list of quadrilateral double areas + // + template + IGL_INLINE void doublearea_quad( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + Eigen::PlainObjectBase & dblA); + +} + +#ifndef IGL_STATIC_LIBRARY +# include "doublearea.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/dqs.cpp b/src/external/libigl-2.3.0/include/igl/dqs.cpp new file mode 100644 index 000000000..56090ef47 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/dqs.cpp @@ -0,0 +1,74 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "dqs.h" +#include +template < + typename DerivedV, + typename DerivedW, + typename Q, + typename QAlloc, + typename T, + typename DerivedU> +IGL_INLINE void igl::dqs( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & W, + const std::vector & vQ, + const std::vector & vT, + Eigen::PlainObjectBase & U) +{ + using namespace std; + assert(V.rows() <= W.rows()); + assert(W.cols() == (int)vQ.size()); + assert(W.cols() == (int)vT.size()); + // resize output + U.resizeLike(V); + + // Convert quats + trans into dual parts + vector vD(vQ.size()); + for(int c = 0;c10000) + for(int i = 0;i, Eigen::Matrix, Eigen::Quaternion, Eigen::aligned_allocator >, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, std::vector, Eigen::aligned_allocator > > const&, std::vector, std::allocator > > const&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/dqs.h b/src/external/libigl-2.3.0/include/igl/dqs.h new file mode 100644 index 000000000..288d308fd --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/dqs.h @@ -0,0 +1,42 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_DQS_H +#define IGL_DQS_H +#include "igl_inline.h" +#include +#include +namespace igl +{ + // Dual quaternion skinning + // + // Inputs: + // V #V by 3 list of rest positions + // W #W by #C list of weights + // vQ #C list of rotation quaternions + // vT #C list of translation vectors + // Outputs: + // U #V by 3 list of new positions + template < + typename DerivedV, + typename DerivedW, + typename Q, + typename QAlloc, + typename T, + typename DerivedU> + IGL_INLINE void dqs( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & W, + const std::vector & vQ, + const std::vector & vT, + Eigen::PlainObjectBase & U); +}; + +#ifndef IGL_STATIC_LIBRARY +# include "dqs.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/dual_contouring.cpp b/src/external/libigl-2.3.0/include/igl/dual_contouring.cpp new file mode 100644 index 000000000..6a08aa1bf --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/dual_contouring.cpp @@ -0,0 +1,566 @@ +#include "dual_contouring.h" +#include "quadprog.h" +#include "parallel_for.h" +#include +#include +#include +#include +#include + +namespace igl +{ + // These classes not intended to be used directly + class Hash + { + public: + // https://stackoverflow.com/a/26348708/148668 + uint64_t operator()(const std::tuple & key) const + { + // Check that conversion is safe. Could use int16_t directly everywhere + // below but it's an uncommon type to expose and grid indices should + // never be more than 2¹⁵-1 in the first place. + assert( std::get<0>(key) == (int)(int16_t)std::get<0>(key)); + assert( std::get<1>(key) == (int)(int16_t)std::get<1>(key)); + assert( std::get<2>(key) == (int)(int16_t)std::get<2>(key)); + uint64_t result = uint16_t(std::get<0>(key)); + result = (result << 16) + uint16_t(std::get<1>(key)); + result = (result << 16) + uint16_t(std::get<2>(key)); + return result; + }; + }; + template + class DualContouring + { + // Types + public: + using RowVector3S = Eigen::Matrix; + using RowVector4S = Eigen::Matrix; + using Matrix4S = Eigen::Matrix; + using Matrix3S = Eigen::Matrix; + using Vector3S = Eigen::Matrix; + using KeyTriplet = std::tuple; + public: + // Working variables + // see dual_contouring.h + // f(x) returns >0 outside, <0 inside, and =0 on the surface + std::function f; + // f_grad(x) returns (df/dx)/‖df/dx‖ (normalization only important when + // f(x) = 0). + std::function f_grad; + bool constrained; + bool triangles; + bool root_finding; + RowVector3S min_corner; + RowVector3S step; + Eigen::Matrix V; + // Internal variables + // Running number of vertices added during contouring + typename decltype(V)::Index n; + // map from cell subscript to index in V + std::unordered_map< KeyTriplet, typename decltype(V)::Index, Hash > C2V; + // running list of aggregate vertex positions (used for spring + // regularization term) + std::vector> vV; + // running list of subscripts corresponding to vertices + std::vector> vI; + // running list of quadric matrices corresponding to inserted vertices + std::vector> vH; + // running list of number of faces incident on this vertex (used to + // normalize spring regulatization term) + std::vector vcount; + // running list of output quad faces + Eigen::Matrix Q; + // running number of real quads in Q (used for dynamic array allocation) + typename decltype(Q)::Index m; + // mutexes used to insert into Q and (vV,vI,vH,vcount) + std::mutex Qmut; + std::mutex Vmut; + public: + DualContouring( + const std::function & _f, + const std::function & _f_grad, + const bool _constrained = false, + const bool _triangles = false, + const bool _root_finding = true): + f(_f), + f_grad(_f_grad), + constrained(_constrained), + triangles(_triangles), + root_finding(_root_finding), + n(0), + C2V(0), + vV(),vI(),vH(),vcount(), + m(0) + { } + // Side effects: new entry in vV,vI,vH,vcount, increment n + // Returns index of new vertex + typename decltype(V)::Index new_vertex() + { + const auto v = n; + n++; + vcount.resize(n); + vV.resize(n); + vI.resize(n); + vH.resize(n); + vcount[v] = 0; + vV[v].setZero(); + vH[v].setZero(); + return v; + }; + // Inputs: + // kc 3-long vector of {x,y,z} index of primal grid **cell** + // Returns index to corresponding dual vertex + // Side effects: if vertex for this cell does not yet exist, creates it + typename decltype(V)::Index sub2dual(const Eigen::RowVector3i & kc) + { + const KeyTriplet key = {kc(0),kc(1),kc(2)}; + const auto it = C2V.find(key); + typename decltype(V)::Index v = -1; + if(it == C2V.end()) + { + v = new_vertex(); + C2V[key] = v; + vI[v] = kc; + }else + { + v = it->second; + } + return v; + }; + RowVector3S primal(const Eigen::RowVector3i & ic) const + { + return min_corner + (ic.cast().array() * step.array()).matrix(); + } + Eigen::RowVector3i inverse_primal(const RowVector3S & x) const + { + // x = min_corner + (ic.cast().array() * step.array()).matrix(); + // x-min_corner = (ic.cast().array() * step.array()) + // (x-min_corner).array() / step.array() = ic.cast().array() + // ((x-min_corner).array() / step.array()).round() = ic + return + ((x-min_corner).array()/step.array()).round().template cast(); + } + // Inputs: + // x x-index of vertex on primal grid + // y y-index of vertex on primal grid + // z z-index of vertex on primal grid + // o which edge are we looking back on? o=0->x,o=1->y,o=2->z + // Side effects: may insert new vertices into vV,vI,vH,vcount, new faces + // into Q + bool single_edge(const int & x, const int & y, const int & z, const int & o) + { + const RowVector3S e0 = primal(Eigen::RowVector3i(x,y,z)); + const Scalar f0 = f(e0); + return single_edge(x,y,z,o,e0,f0); + } + bool single_edge( + const int & x, + const int & y, + const int & z, + const int & o, + const RowVector3S & e0, + const Scalar & f0) + { + //e1 computed here needs to precisely agree with e0 when called with + //correspond x,y,z. So, don't do this: + //Eigen::RowVector3d e1 = e0; + //e1(o) -= step(o); + Eigen::RowVector3i jc(x,y,z); + jc(o) -= 1; + const RowVector3S e1 = primal(jc); + const Scalar f1 = f(e1); + return single_edge(x,y,z,o,e0,f0,e1,f1); + } + bool single_edge( + const int & x, + const int & y, + const int & z, + const int & o, + const RowVector3S & e0, + const Scalar & f0, + const RowVector3S & e1, + const Scalar & f1) + { + const Scalar isovalue = 0; + if((f0>isovalue) == (f1>isovalue)) { return false; } + // Position of crossing point along edge + RowVector3S p; + Scalar t = -1; + if(root_finding) + { + Scalar tl = 0; + bool gl = f0>0; + Scalar tu = 1; + bool gu = f1>0; + assert(gu ^ gl); + int riter = 0; + const int max_riter = 7; + while(true) + { + t = 0.5*(tu + tl); + p = e0+t*(e1-e0); + riter++; + if(riter > max_riter) { break;} + const Scalar ft = f(p); + if( (ft>0) == gu) { tu = t; } + else if( (ft>0) == gl){ tl = t; } + else { break; } + } + }else + { + // inverse lerp + const Scalar delta = f1-f0; + if(delta == 0) { t = 0.5; } + t = (isovalue - f0)/delta; + p = e0+t*(e1-e0); + } + // insert vertex at this point to triangulate quad face + const typename decltype(V)::Index ev = triangles ? new_vertex() : -1; + if(triangles) + { + const std::lock_guard lock(Vmut); + vV[ev] = p; + vcount[ev] = 1; + vI[ev] = Eigen::RowVector3i(-1,-1,-1); + } + // edge normal from function handle (could use grid finite + // differences/interpolation gradients) + const RowVector3S dfdx = f_grad(p); + // homogenous plane equation + const RowVector4S P = (RowVector4S()< lock(Vmut); + const typename decltype(V)::Index v = sub2dual(kc); + vV[v] += p; + vcount[v]++; + vH[v] += H; + face(k++) = v; + } + } + { + const std::lock_guard lock(Qmut); + if(triangles) + { + if(m+4 >= Q.rows()){ Q.conservativeResize(2*m+4,Q.cols()); } + if(f0>f1) + { + Q.row(m+0)<< ev,face(3),face(1) ; + Q.row(m+1)<< ev,face(1),face(0); + Q.row(m+2)<< face(2), ev,face(0); + Q.row(m+3)<< face(2),face(3), ev; + }else + { + Q.row(m+0)<< ev,face(1),face(3) ; + Q.row(m+1)<< ev,face(3),face(2); + Q.row(m+2)<< face(0), ev,face(2); + Q.row(m+3)<< face(0),face(1), ev; + } + m+=4; + }else + { + if(m+1 >= Q.rows()){ Q.conservativeResize(2*m+1,Q.cols()); } + if(f0>f1) + { + Q.row(m)<< face(2),face(3),face(1),face(0); + }else + { + Q.row(m)<< face(0),face(1),face(3),face(2); + } + m++; + } + } + return true; + } + // Side effects: Q resized to fit m, V constructed to fit n and + // reconstruct data in vH,vI,vV,vcount + void dual_vertex_positions() + { + Q.conservativeResize(m,Q.cols()); + V.resize(n,3); + igl::parallel_for(n,[&](const Eigen::Index v) + { + RowVector3S mid = vV[v] / Scalar(vcount[v]); + if(triangles && vI[v](0)<0 ){ V.row(v) = mid; return; } + const Scalar w = 1e-2*(0.01+vcount[v]); + Matrix3S A = vH[v].block(0,0,3,3) + w*Matrix3S::Identity(); + RowVector3S b = -vH[v].block(3,0,1,3) + w*mid; + // Replace with solver + //RowVector3S p = b * A.inverse(); + // + // min_p ½ pᵀ A p - pᵀb + // + // let p = p₀ + x + // + // min ½ (p₀ + x )ᵀ A (p₀ + x ) - (p₀ + x )ᵀb + // step≥x≥0 + const RowVector3S p0 = + min_corner + ((vI[v].template cast().array()) * step.array()).matrix(); + const RowVector3S x = + constrained ? + igl::quadprog(A,(p0*A-b).transpose(),Vector3S(0,0,0),step.transpose()) : + Eigen::LLT(A).solve(-(p0*A-b).transpose()); + V.row(v) = p0+x; + },1000ul); + } + // Inputs: + // _min_corner minimum (bottomLeftBack) corner of primal grid + // max_corner maximum (topRightFront) corner of primal grid + // nx number of primal grid vertices along x-axis + // ny number of primal grid vertices along y-ayis + // nz number of primal grid vertices along z-azis + // Side effects: prepares vV,vI,vH,vcount, Q for vertex_positions() + void dense( + const RowVector3S & _min_corner, + const RowVector3S & max_corner, + const int nx, + const int ny, + const int nz) + { + min_corner = _min_corner; + step = + (max_corner-min_corner).array()/(RowVector3S(nx,ny,nz).array()-1); + // Should do some reasonable reserves for C2V,vV,vI,vH,vcount + Q.resize(std::pow(nx*ny*nz,2./3.),triangles?3:4); + // loop over grid + igl::parallel_for(nx,[&](const int x) + { + for(int y = 0;y + void dense( + const Eigen::MatrixBase & Gf, + const Eigen::MatrixBase & GV, + const int nx, + const int ny, + const int nz) + { + min_corner = GV.colwise().minCoeff(); + const RowVector3S max_corner = GV.colwise().maxCoeff(); + step = + (max_corner-min_corner).array()/(RowVector3S(nx,ny,nz).array()-1); + + // Should do some reasonable reserves for C2V,vV,vI,vH,vcount + Q.resize(std::pow(nx*ny*nz,2./3.),triangles?3:4); + + const auto xyz2i = [&nx,&ny,&nz] + (const int & x, const int & y, const int & z)->Eigen::Index + { + return x+nx*(y+ny*(z)); + }; + + // loop over grid + igl::parallel_for(nz,[&](const int z) + { + for(int y = 0;y & Gf, + const Eigen::Matrix & GV, + const Eigen::Matrix & GI) + { + step = _step; + Q.resize((triangles?4:1)*GI.rows(),triangles?3:4); + // in perfect world doesn't matter where min_corner is so long as it is + // _on_ the grid. For models very far from origin, centering grid near + // model avoids possible rounding error in hash()/inverse_primal() + // [still very unlikely, but let's be safe] + min_corner = GV.colwise().minCoeff(); + // igl::parallel_for here made things worse. Probably need to do proper + // map-reduce rather than locks on mutexes. + for(Eigen::Index i = 0;i=0 && "Edges should differ in just one coordinate"); + // i0 is the larger subscript location and ic1 is backward in the o + // direction. + for(int j = 0;j<3;j++){ assert(ic0(j) == ic1(j)+(o==j)); } + const int x = ic0(0); + const int y = ic0(1); + const int z = ic0(2); + single_edge(x,y,z,o,e0,f0,e1,f1); + } + dual_vertex_positions(); + } + }; +} + +template < + typename DerivedV, + typename DerivedQ> +IGL_INLINE void igl::dual_contouring( + const std::function< + typename DerivedV::Scalar(const Eigen::Matrix &)> & f, + const std::function< + Eigen::Matrix( + const Eigen::Matrix &)> & f_grad, + const Eigen::Matrix & min_corner, + const Eigen::Matrix & max_corner, + const int nx, + const int ny, + const int nz, + const bool constrained, + const bool triangles, + const bool root_finding, + Eigen::PlainObjectBase & V, + Eigen::PlainObjectBase & Q) +{ + typedef typename DerivedV::Scalar Scalar; + DualContouring DC(f,f_grad,constrained,triangles,root_finding); + DC.dense(min_corner,max_corner,nx,ny,nz); + V = DC.V; + Q = DC.Q.template cast(); +} + +template < + typename DerivedGf, + typename DerivedGV, + typename DerivedV, + typename DerivedQ> +IGL_INLINE void igl::dual_contouring( + const std::function< + typename DerivedV::Scalar(const Eigen::Matrix &)> & f, + const std::function< + Eigen::Matrix( + const Eigen::Matrix &)> & f_grad, + const Eigen::MatrixBase & Gf, + const Eigen::MatrixBase & GV, + const int nx, + const int ny, + const int nz, + const bool constrained, + const bool triangles, + const bool root_finding, + Eigen::PlainObjectBase & V, + Eigen::PlainObjectBase & Q) +{ + typedef typename DerivedV::Scalar Scalar; + DualContouring DC(f,f_grad,constrained,triangles,root_finding); + DC.dense(Gf,GV,nx,ny,nz); + V = DC.V; + Q = DC.Q.template cast(); +} + +template < + typename DerivedGf, + typename DerivedGV, + typename DerivedGI, + typename DerivedV, + typename DerivedQ> +IGL_INLINE void igl::dual_contouring( + const std::function &)> & f, + const std::function(const Eigen::Matrix &)> & f_grad, + const Eigen::Matrix & step, + const Eigen::MatrixBase & Gf, + const Eigen::MatrixBase & GV, + const Eigen::MatrixBase & GI, + const bool constrained, + const bool triangles, + const bool root_finding, + Eigen::PlainObjectBase & V, + Eigen::PlainObjectBase & Q) +{ + if(GI.rows() == 0){ return;} + assert(GI.cols() == 2); + typedef typename DerivedV::Scalar Scalar; + DualContouring DC(f,f_grad,constrained,triangles,root_finding); + DC.sparse(step,Gf,GV,GI); + V = DC.V; + Q = DC.Q.template cast(); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::dual_contouring, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(std::function::Scalar (Eigen::Matrix::Scalar, 1, 3, 1, 1, 3> const&)> const&, std::function::Scalar, 1, 3, 1, 1, 3> (Eigen::Matrix::Scalar, 1, 3, 1, 1, 3> const&)> const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, int, int, int, bool, bool, bool, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::dual_contouring, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(std::function::Scalar (Eigen::Matrix::Scalar, 1, 3, 1, 1, 3> const&)> const&, std::function::Scalar, 1, 3, 1, 1, 3> (Eigen::Matrix::Scalar, 1, 3, 1, 1, 3> const&)> const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, int, int, int, bool, bool, bool, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::dual_contouring, Eigen::Matrix >(std::function::Scalar (Eigen::Matrix::Scalar, 1, 3, 1, 1, 3> const&)> const&, std::function::Scalar, 1, 3, 1, 1, 3> (Eigen::Matrix::Scalar, 1, 3, 1, 1, 3> const&)> const&, Eigen::Matrix::Scalar, 1, 3, 1, 1, 3> const&, Eigen::Matrix::Scalar, 1, 3, 1, 1, 3> const&, int, int, int, bool, bool, bool, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::dual_contouring, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(std::function::Scalar (Eigen::Matrix::Scalar, 1, 3, 1, 1, 3> const&)> const&, std::function::Scalar, 1, 3, 1, 1, 3> (Eigen::Matrix::Scalar, 1, 3, 1, 1, 3> const&)> const&, Eigen::Matrix::Scalar, 1, 3, 1, 1, 3> const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, bool, bool, bool, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::dual_contouring, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(std::function::Scalar (Eigen::Matrix::Scalar, 1, 3, 1, 1, 3> const&)> const&, std::function::Scalar, 1, 3, 1, 1, 3> (Eigen::Matrix::Scalar, 1, 3, 1, 1, 3> const&)> const&, Eigen::Matrix::Scalar, 1, 3, 1, 1, 3> const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, bool, bool, bool, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/dual_contouring.h b/src/external/libigl-2.3.0/include/igl/dual_contouring.h new file mode 100644 index 000000000..24c645457 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/dual_contouring.h @@ -0,0 +1,103 @@ +#ifndef IGL_DUAL_CONTOURING_H +#define IGL_DUAL_CONTOURING_H +#include "igl_inline.h" +#include +#include +#include +namespace igl +{ + // Dual contouring to extract a pure quad mesh from differentiable implicit + // function using a dense grid. + // + // Inputs: + // f function returning >0 outside, <0 inside and =0 on the surface + // f_grad function returning ∇f/‖∇f‖ + // min_corner position of primal grid vertex at minimum corner + // max_corner position of primal grid vertex at maximum corner + // nx number of vertices on x side of primal grid + // ny number of vertices on y side of primal grid + // nz number of vertices on z side of primal grid + // constrained whether to force dual vertices to lie strictly inside + // corresponding primal cell (prevents self-intersections at cost of + // surface quality; marginally slower) + // triangles whether to output four triangles instead of one quad per + // crossing edge (quad mesh usually looks fine) + // root_finding whether to use root finding to identify crossing point on + // each edge (improves quality a lot at cost of performance). If false, + // use linear interpolation. + // Outputs: + // V #V by 3 list of outputs vertex positions + // Q #Q by 4 (or 3 if triangles=true) face indices into rows of V + template < + typename DerivedV, + typename DerivedQ> + IGL_INLINE void dual_contouring( + const std::function< + typename DerivedV::Scalar(const Eigen::Matrix &)> & f, + const std::function< + Eigen::Matrix( + const Eigen::Matrix &)> & f_grad, + const Eigen::Matrix & min_corner, + const Eigen::Matrix & max_corner, + const int nx, + const int ny, + const int nz, + const bool constrained, + const bool triangles, + const bool root_finding, + Eigen::PlainObjectBase & V, + Eigen::PlainObjectBase & Q); + // Inputs: + // Gf nx*ny*nz list of function values so that Gf(k) = f(GV.row(k)) (only + // needs to be accurate near f=0 and correct sign elsewhere) + // GV nx*ny*nz list of grid positions so that the x,y,z grid position is at + // GV.row(x+nx*(y+z*ny)) + template < + typename DerivedGf, + typename DerivedGV, + typename DerivedV, + typename DerivedQ> + IGL_INLINE void dual_contouring( + const std::function< + typename DerivedV::Scalar(const Eigen::Matrix &)> & f, + const std::function< + Eigen::Matrix( + const Eigen::Matrix &)> & f_grad, + const Eigen::MatrixBase & Gf, + const Eigen::MatrixBase & GV, + const int nx, + const int ny, + const int nz, + const bool constrained, + const bool triangles, + const bool root_finding, + Eigen::PlainObjectBase & V, + Eigen::PlainObjectBase & Q); + // Sparse voxel grid + // + // Gf #GV list of corresponding f values. If using root finding then only the + // sign needs to be correct. + template < + typename DerivedGf, + typename DerivedGV, + typename DerivedGI, + typename DerivedV, + typename DerivedQ> + IGL_INLINE void dual_contouring( + const std::function &)> & f, + const std::function(const Eigen::Matrix &)> & f_grad, + const Eigen::Matrix & step, + const Eigen::MatrixBase & Gf, + const Eigen::MatrixBase & GV, + const Eigen::MatrixBase & GI, + const bool constrained, + const bool triangles, + const bool root_finding, + Eigen::PlainObjectBase & V, + Eigen::PlainObjectBase & Q); +} + +#ifndef IGL_STATIC_LIBRARY +# include "dual_contouring.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/ears.cpp b/src/external/libigl-2.3.0/include/igl/ears.cpp new file mode 100644 index 000000000..428ba161b --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/ears.cpp @@ -0,0 +1,34 @@ +#include "ears.h" +#include "on_boundary.h" +#include "find.h" +#include "slice.h" +#include "mat_min.h" +#include + +template < + typename DerivedF, + typename Derivedear, + typename Derivedear_opp> +IGL_INLINE void igl::ears( + const Eigen::MatrixBase & F, + Eigen::PlainObjectBase & ear, + Eigen::PlainObjectBase & ear_opp) +{ + assert(F.cols() == 3 && "F should contain triangles"); + Eigen::Array B; + { + Eigen::Array I; + on_boundary(F,I,B); + } + find(B.rowwise().count() == 2, ear); + Eigen::Array Bear; + slice(B, ear, 1, Bear); + Eigen::Array M; + mat_min(Bear,2,M,ear_opp); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::ears, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/ears.h b/src/external/libigl-2.3.0/include/igl/ears.h new file mode 100644 index 000000000..b7c51ec66 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/ears.h @@ -0,0 +1,30 @@ +#ifndef IGL_EARS_H +#define IGL_EARS_H +#include "igl_inline.h" +#include +namespace igl +{ + // FIND_EARS Find all ears (faces with two boundary edges) in a given mesh + // + // [ears,ear_opp] = find_ears(F) + // + // Inputs: + // F #F by 3 list of triangle mesh indices + // Outputs: + // ears #ears list of indices into F of ears + // ear_opp #ears list of indices indicating which edge is non-boundary + // (connecting to flops) + // + template < + typename DerivedF, + typename Derivedear, + typename Derivedear_opp> + IGL_INLINE void ears( + const Eigen::MatrixBase & F, + Eigen::PlainObjectBase & ear, + Eigen::PlainObjectBase & ear_opp); +} +#ifndef IGL_STATIC_LIBRARY +# include "ears.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/edge_collapse_is_valid.cpp b/src/external/libigl-2.3.0/include/igl/edge_collapse_is_valid.cpp new file mode 100644 index 000000000..e631800e3 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/edge_collapse_is_valid.cpp @@ -0,0 +1,124 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "edge_collapse_is_valid.h" +#include "collapse_edge.h" +#include "circulation.h" +#include "intersect.h" +#include "unique.h" +#include "list_to_matrix.h" +#include + +IGL_INLINE bool igl::edge_collapse_is_valid( + const int e, + const Eigen::MatrixXi & F, + const Eigen::MatrixXi & E, + const Eigen::VectorXi & EMAP, + const Eigen::MatrixXi & EF, + const Eigen::MatrixXi & EI) +{ + using namespace Eigen; + using namespace std; + // For consistency with collapse_edge.cpp, let's determine edge flipness + // (though not needed to check validity) + const int eflip = E(e,0)>E(e,1); + // source and destination + const int s = eflip?E(e,1):E(e,0); + const int d = eflip?E(e,0):E(e,1); + + if(s == IGL_COLLAPSE_EDGE_NULL && d==IGL_COLLAPSE_EDGE_NULL) + { + return false; + } + // check if edge collapse is valid: intersection of vertex neighbors of s and + // d should be exactly 2+(s,d) = 4 + // http://stackoverflow.com/a/27049418/148668 + { + // all vertex neighbors around edge, including the two vertices of the edge + const auto neighbors = []( + const int e, + const bool ccw, + const Eigen::MatrixXi & F, + const Eigen::MatrixXi & E, + const Eigen::VectorXi & EMAP, + const Eigen::MatrixXi & EF, + const Eigen::MatrixXi & EI) + { + vector N,uN; + vector V2Fe = circulation(e, ccw,EMAP,EF,EI); + for(auto f : V2Fe) + { + N.push_back(F(f,0)); + N.push_back(F(f,1)); + N.push_back(F(f,2)); + } + vector _1,_2; + igl::unique(N,uN,_1,_2); + VectorXi uNm; + list_to_matrix(uN,uNm); + return uNm; + }; + VectorXi Ns = neighbors(e, eflip,F,E,EMAP,EF,EI); + VectorXi Nd = neighbors(e,!eflip,F,E,EMAP,EF,EI); + VectorXi Nint = igl::intersect(Ns,Nd); + if(Nint.size() != 4) + { + return false; + } + if(Ns.size() == 4 && Nd.size() == 4) + { + VectorXi NsNd(8); + NsNd< & Nsv, + std::vector & Ndv) +{ + // Do we really need to check if edge is IGL_COLLAPSE_EDGE_NULL ? + + if(Nsv.size()<2 || Ndv.size()<2) + { + // Bogus data + assert(false); + return false; + } + // determine if the first two vertices are the same before reordering. + // If they are and there are 3 each, then (I claim) this is an edge on a + // single tet. + const bool first_two_same = (Nsv[0] == Ndv[0]) && (Nsv[1] == Ndv[1]); + if(Nsv.size() == 3 && Ndv.size() == 3 && first_two_same) + { + // single tet + return false; + } + // https://stackoverflow.com/a/19483741/148668 + std::sort(Nsv.begin(), Nsv.end()); + std::sort(Ndv.begin(), Ndv.end()); + std::vector Nint; + std::set_intersection( + Nsv.begin(), Nsv.end(), Ndv.begin(), Ndv.end(), std::back_inserter(Nint)); + // check if edge collapse is valid: intersection of vertex neighbors of s and + // d should be exactly 2+(s,d) = 4 + // http://stackoverflow.com/a/27049418/148668 + if(Nint.size() != 2) + { + return false; + } + + return true; +} diff --git a/src/external/libigl-2.3.0/include/igl/edge_collapse_is_valid.h b/src/external/libigl-2.3.0/include/igl/edge_collapse_is_valid.h new file mode 100644 index 000000000..3b7375566 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/edge_collapse_is_valid.h @@ -0,0 +1,59 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_EDGE_COLLAPSE_IS_VALID_H +#define IGL_EDGE_COLLAPSE_IS_VALID_H +#include "igl_inline.h" +#include +#include +namespace igl +{ + // Assumes (V,F) is a closed manifold mesh (except for previouslly collapsed + // faces which should be set to: + // [IGL_COLLAPSE_EDGE_NULL IGL_COLLAPSE_EDGE_NULL IGL_COLLAPSE_EDGE_NULL]. + // Tests whether collapsing exactly two faces and exactly 3 edges from E (e + // and one side of each face gets collapsed to the other) will result in a + // mesh with the same topology. + // + // Inputs: + // e index into E of edge to try to collapse. E(e,:) = [s d] or [d s] so + // that sj) is the edge of + // F(f,:) opposite the vth corner, where EI(e,0)=v. Similarly EF(e,1) " + // e=(j->i) + // EI #E by 2 list of edge flap corners (see above). + // Returns true if edge collapse is valid + IGL_INLINE bool edge_collapse_is_valid( + const int e, + const Eigen::MatrixXi & F, + const Eigen::MatrixXi & E, + const Eigen::VectorXi & EMAP, + const Eigen::MatrixXi & EF, + const Eigen::MatrixXi & EI); + // Inputs: + // Nsv #Nsv list of "next" vertices circulating around starting vertex of + // edge + // Ndv #Ndv list of "next" vertices circulating around destination vertex of + // edge + // Outputs: + // Nsv (side-effect: sorted by value) + // Ndv (side-effect: sorted by value) + // Returns true iff edge collapse is valid + // + // See also: circulation + IGL_INLINE bool edge_collapse_is_valid( + /*const*/ std::vector & Nsv, + /*const*/ std::vector & Ndv); +} +#ifndef IGL_STATIC_LIBRARY +# include "edge_collapse_is_valid.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/edge_exists_near.cpp b/src/external/libigl-2.3.0/include/igl/edge_exists_near.cpp new file mode 100644 index 000000000..e57b7da5f --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/edge_exists_near.cpp @@ -0,0 +1,96 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2018 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "edge_exists_near.h" + +template < + typename DeriveduE, + typename DerivedEMAP, + typename uE2EType, + typename Index> +IGL_INLINE bool igl::edge_exists_near( + const Eigen::MatrixBase & uE, + const Eigen::MatrixBase & EMAP, + const std::vector > & uE2E, + const Index & a, + const Index & b, + const Index & uei) +{ + std::vector face_queue; + face_queue.reserve(32); + std::vector pushed; + // 32 is faster than 8 + pushed.reserve(32); + assert(a!=b); + // starting with the (2) faces incident on e, consider all faces + // incident on edges containing either a or b. + // + // face_queue Queue containing faces incident on exactly one of a/b + // Using a vector seems mildly faster + assert(EMAP.size()%3 == 0); + const Index num_faces = EMAP.size()/3; + const Index f1 = uE2E[uei][0]%num_faces; + const Index f2 = uE2E[uei][1]%num_faces; + // map is faster than unordered_map here, and vector + brute force + // is_member check is even faster + face_queue.push_back(f1); + pushed.push_back(f1); + face_queue.push_back(f2); + pushed.push_back(f2); + while(!face_queue.empty()) + { + const Index f = face_queue.back(); + face_queue.pop_back(); + // consider each edge of this face + for(int c = 0;c<3;c++) + { + // Unique edge id + const Index uec = EMAP(c*num_faces+f); + const Index s = uE(uec,0); + const Index d = uE(uec,1); + const bool ona = s == a || d == a; + const bool onb = s == b || d == b; + // Is this the edge we're looking for? + if(ona && onb) + { + return true; + } + // not incident on either? + if(!ona && !onb) + { + continue; + } + // loop over all incident half-edges + for(const auto & he : uE2E[uec]) + { + // face of this he + const Index fhe = he%num_faces; + bool already_pushed = false; + for(const auto & fp : pushed) + { + if(fp == fhe) + { + already_pushed = true; + break; + } + } + if(!already_pushed) + { + pushed.push_back(fhe); + face_queue.push_back(fhe); + } + } + } + } + return false; +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template bool igl::edge_exists_near, Eigen::Matrix, int, int>(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, std::vector >, std::allocator > > > const&, int const&, int const&, int const&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/edge_exists_near.h b/src/external/libigl-2.3.0/include/igl/edge_exists_near.h new file mode 100644 index 000000000..6acfb8f80 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/edge_exists_near.h @@ -0,0 +1,47 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2018 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_EDGE_EXISTS_NEAR_H +#define IGL_EDGE_EXISTS_NEAR_H +#include "igl_inline.h" +#include +#include +namespace igl +{ + // Does edge (a,b) exist in the edges of all faces incident on + // existing unique edge uei. + // + // Inputs: + // uE #uE by 2 list of unique undirected edges + // EMAP #F*3 list of indices into uE, mapping each directed edge to unique + // undirected edge + // uE2E #uE list of lists of indices into E of coexisting edges + // E #F*3 by 2 list of half-edges + // a 1st end-point of query edge + // b 2nd end-point of query edge + // uei index into uE/uE2E of unique edge + // Returns true if edge exists near uei. + // + // See also: unique_edge_map + template < + typename DeriveduE, + typename DerivedEMAP, + typename uE2EType, + typename Index> + IGL_INLINE bool edge_exists_near( + const Eigen::MatrixBase & uE, + const Eigen::MatrixBase & EMAP, + const std::vector > & uE2E, + const Index & a, + const Index & b, + const Index & uei); +} +#ifndef IGL_STATIC_LIBRARY +# include "edge_exists_near.cpp" +#endif +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/edge_flaps.cpp b/src/external/libigl-2.3.0/include/igl/edge_flaps.cpp new file mode 100644 index 000000000..f2beadd2e --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/edge_flaps.cpp @@ -0,0 +1,59 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "edge_flaps.h" +#include "unique_edge_map.h" +#include +#include + +IGL_INLINE void igl::edge_flaps( + const Eigen::MatrixXi & F, + const Eigen::MatrixXi & uE, + const Eigen::VectorXi & EMAP, + Eigen::MatrixXi & EF, + Eigen::MatrixXi & EI) +{ + // Initialize to boundary value + EF.setConstant(uE.rows(),2,-1); + EI.setConstant(uE.rows(),2,-1); + // loop over all faces + for(int f = 0;f +// Copyright (C) 2020 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_EDGE_FLAPS_H +#define IGL_EDGE_FLAPS_H +#include "igl_inline.h" +#include +namespace igl +{ + // Determine "edge flaps": two faces on either side of a unique edge (assumes + // edge-manifold mesh) + // + // Inputs: + // F #F by 3 list of face indices + // uE #uE by 2 list of edge indices into V. + // EMAP #F*3 list of indices into uE, mapping each directed edge to unique + // unique edge in uE + // Outputs: + // EF #E by 2 list of edge flaps, EF(e,0)=f means e=(i-->j) is the edge of + // F(f,:) opposite the vth corner, where EI(e,0)=v. Similarly EF(e,1) " + // e=(j->i) + // EI #E by 2 list of edge flap corners (see above). + // + // See also: unique_edge_map + // + // TODO: This seems to be a duplicate of edge_topology.h + // igl::edge_topology(V,F,etEV,etFE,etEF); + // igl::edge_flaps(F,efE,efEMAP,efEF,efEI); + // [~,I] = sort(efE,2) + // all( efE(sub2ind(size(efE),repmat(1:size(efE,1),2,1)',I)) == etEV ) + // all( efEF(sub2ind(size(efE),repmat(1:size(efE,1),2,1)',I)) == etEF ) + // all(efEMAP(sub2ind(size(F),repmat(1:size(F,1),3,1)',repmat([1 2 3],size(F,1),1))) == etFE(:,[2 3 1])) + IGL_INLINE void edge_flaps( + const Eigen::MatrixXi & F, + const Eigen::MatrixXi & uE, + const Eigen::VectorXi & EMAP, + Eigen::MatrixXi & EF, + Eigen::MatrixXi & EI); + // Only faces as input + IGL_INLINE void edge_flaps( + const Eigen::MatrixXi & F, + Eigen::MatrixXi & uE, + Eigen::VectorXi & EMAP, + Eigen::MatrixXi & EF, + Eigen::MatrixXi & EI); +} +#ifndef IGL_STATIC_LIBRARY +# include "edge_flaps.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/edge_lengths.cpp b/src/external/libigl-2.3.0/include/igl/edge_lengths.cpp new file mode 100644 index 000000000..cff91a10e --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/edge_lengths.cpp @@ -0,0 +1,63 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "edge_lengths.h" +#include "squared_edge_lengths.h" + +template +IGL_INLINE void igl::edge_lengths( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + Eigen::PlainObjectBase& L) + { + igl::squared_edge_lengths(V,F,L); + L=L.array().sqrt().eval(); + } + + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::edge_lengths, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::edge_lengths, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::edge_lengths, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::edge_lengths, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::edge_lengths, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::edge_lengths, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::edge_lengths, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::edge_lengths, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::edge_lengths, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::edge_lengths, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::edge_lengths, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::edge_lengths, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::edge_lengths, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::edge_lengths, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::edge_lengths, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::edge_lengths, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::edge_lengths, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::edge_lengths, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::edge_lengths, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::edge_lengths, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::edge_lengths, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::edge_lengths, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::edge_lengths, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::edge_lengths, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::edge_lengths, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::edge_lengths, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::edge_lengths, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::edge_lengths, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::edge_lengths, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::edge_lengths, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::edge_lengths, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/edge_lengths.h b/src/external/libigl-2.3.0/include/igl/edge_lengths.h new file mode 100644 index 000000000..30dc3474b --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/edge_lengths.h @@ -0,0 +1,49 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_EDGE_LENGTHS_H +#define IGL_EDGE_LENGTHS_H +#include "igl_inline.h" + +#include + +namespace igl +{ + // Constructs a list of lengths of edges opposite each index in a face + // (triangle/tet) list + // + // Templates: + // DerivedV derived from vertex positions matrix type: i.e. MatrixXd + // DerivedF derived from face indices matrix type: i.e. MatrixXi + // DerivedL derived from edge lengths matrix type: i.e. MatrixXd + // Inputs: + // V eigen matrix #V by 3 + // F #F by 2 list of mesh edges + // or + // F #F by 3 list of mesh faces (must be triangles) + // or + // T #T by 4 list of mesh elements (must be tets) + // Outputs: + // L #F by {1|3|6} list of edge lengths + // for edges, column of lengths + // for triangles, columns correspond to edges [1,2],[2,0],[0,1] + // for tets, columns correspond to edges + // [3 0],[3 1],[3 2],[1 2],[2 0],[0 1] + // + template + IGL_INLINE void edge_lengths( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + Eigen::PlainObjectBase& L); +} + +#ifndef IGL_STATIC_LIBRARY +# include "edge_lengths.cpp" +#endif + +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/edge_midpoints.cpp b/src/external/libigl-2.3.0/include/igl/edge_midpoints.cpp new file mode 100644 index 000000000..32d89421f --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/edge_midpoints.cpp @@ -0,0 +1,48 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2020 Oded Stein +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "edge_midpoints.h" + +template +IGL_INLINE void +igl::edge_midpoints( + const Eigen::MatrixBase &V, + const Eigen::MatrixBase &F, + const Eigen::MatrixBase &E, + const Eigen::MatrixBase &oE, + Eigen::PlainObjectBase &mps) +{ + assert(E.rows()==F.rows() && "E does not match dimensions of F."); + assert(oE.rows()==F.rows() && "oE does not match dimensions of F."); + assert(E.cols()==3 && F.cols()==3 && oE.cols()==3 && + "This method is for triangle meshes."); + assert(F.maxCoeff(), Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/edge_midpoints.h b/src/external/libigl-2.3.0/include/igl/edge_midpoints.h new file mode 100644 index 000000000..b17711a39 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/edge_midpoints.h @@ -0,0 +1,38 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2020 Oded Stein +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_EDGE_MIDPOINTS_H +#define IGL_EDGE_MIDPOINTS_H +#include "igl_inline.h" + +#include +namespace igl +{ + // Computes the midpoints of edges in a triangle mesh. + // + // Input: + // V, F: triangle mesh + // E, oE: mapping from halfedges to edges and orientation as generated by + // orient_halfedges + // + // Output: + // mps: edge midpoints, one per edge in E + template + IGL_INLINE void edge_midpoints( + const Eigen::MatrixBase &V, + const Eigen::MatrixBase &F, + const Eigen::MatrixBase &E, + const Eigen::MatrixBase &oE, + Eigen::PlainObjectBase &mps); +} + +#ifndef IGL_STATIC_LIBRARY +# include "edge_midpoints.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/edge_topology.cpp b/src/external/libigl-2.3.0/include/igl/edge_topology.cpp new file mode 100644 index 000000000..1f2f66639 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/edge_topology.cpp @@ -0,0 +1,110 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "edge_topology.h" +#include "is_edge_manifold.h" +#include + +template +IGL_INLINE void igl::edge_topology( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + Eigen::PlainObjectBase& EV, + Eigen::PlainObjectBase& FE, + Eigen::PlainObjectBase& EF) +{ + // Only needs to be edge-manifold + if (V.rows() ==0 || F.rows()==0) + { + EV = Eigen::PlainObjectBase::Constant(0,2,-1); + FE = Eigen::PlainObjectBase::Constant(0,3,-1); + EF = Eigen::PlainObjectBase::Constant(0,2,-1); + return; + } + assert(igl::is_edge_manifold(F)); + std::vector > ETT; + for(int f=0;f v2) std::swap(v1,v2); + std::vector r(4); + r[0] = v1; r[1] = v2; + r[2] = f; r[3] = i; + ETT.push_back(r); + } + std::sort(ETT.begin(),ETT.end()); + + // count the number of edges (assume manifoldness) + int En = 1; // the last is always counted + for(int i=0;i& r1 = ETT[i]; + EV(En,0) = r1[0]; + EV(En,1) = r1[1]; + EF(En,0) = r1[2]; + FE(r1[2],r1[3]) = En; + } + else + { + std::vector& r1 = ETT[i]; + std::vector& r2 = ETT[i+1]; + EV(En,0) = r1[0]; + EV(En,1) = r1[1]; + EF(En,0) = r1[2]; + EF(En,1) = r2[2]; + FE(r1[2],r1[3]) = En; + FE(r2[2],r2[3]) = En; + ++i; // skip the next one + } + ++En; + } + + // Sort the relation EF, accordingly to EV + // the first one is the face on the left of the edge + for(unsigned i=0; i, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase>&, Eigen::PlainObjectBase>&, Eigen::PlainObjectBase>&); +template void igl::edge_topology, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase>&, Eigen::PlainObjectBase>&, Eigen::PlainObjectBase>&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/edge_topology.h b/src/external/libigl-2.3.0/include/igl/edge_topology.h new file mode 100644 index 000000000..eab31aa8a --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/edge_topology.h @@ -0,0 +1,50 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_EDGE_TOPOLOGY_H +#define IGL_EDGE_TOPOLOGY_H + +#include "igl_inline.h" + +#include +#include + +namespace igl +{ + // Initialize Edges and their topological relations (assumes an edge-manifold + // mesh) + // + // Inputs: + // V #V by dim list of mesh vertex positions (unused) + // F #F by 3 list of triangle indices into V + // Outputs: + // EV #Ex2 matrix storing the edge description as pair of indices to + // vertices + // FE #Fx3 matrix storing the Triangle-Edge relation + // EF #Ex2 matrix storing the Edge-Triangle relation + // + // TODO: This seems to be a inferior duplicate of edge_flaps.h: + // - unused input parameter V + // - roughly 2x slower than edge_flaps + // - outputs less information: edge_flaps reveals corner opposite edge + // - FE uses non-standard and ambiguous order: FE(f,c) is merely an edge + // incident on corner c of face f. In contrast, edge_flaps's EMAP(f,c) + // reveals the edge _opposite_ corner c of face f +template + IGL_INLINE void edge_topology( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + Eigen::PlainObjectBase& EV, + Eigen::PlainObjectBase& FE, + Eigen::PlainObjectBase& EF); +} + +#ifndef IGL_STATIC_LIBRARY +# include "edge_topology.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/edge_vectors.cpp b/src/external/libigl-2.3.0/include/igl/edge_vectors.cpp new file mode 100644 index 000000000..3807e52ee --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/edge_vectors.cpp @@ -0,0 +1,94 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2020 Oded Stein +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +#include "edge_vectors.h" + +#include +#include "per_face_normals.h" + +#include "PI.h" + + +template +IGL_INLINE void +igl::edge_vectors( + const Eigen::MatrixBase &V, + const Eigen::MatrixBase &F, + const Eigen::MatrixBase &E, + const Eigen::MatrixBase &oE, + Eigen::PlainObjectBase &vec) +{ + Eigen::Matrix + dummy; + edge_vectors(V, F, E, oE, vec, dummy); +} + + +template +IGL_INLINE void +igl::edge_vectors( + const Eigen::MatrixBase &V, + const Eigen::MatrixBase &F, + const Eigen::MatrixBase &E, + const Eigen::MatrixBase &oE, + Eigen::PlainObjectBase &vecParallel, + Eigen::PlainObjectBase &vecPerpendicular) +{ + using Scalar = typename DerivedvecParallel::Scalar; + using MatX = Eigen::Matrix; + + assert(E.rows()==F.rows() && "E does not match dimensions of F."); + assert(oE.rows()==F.rows() && "oE does not match dimensions of F."); + assert(E.cols()==3 && F.cols()==3 && oE.cols()==3 && + "This method is for triangle meshes."); + assert(F.maxCoeff()(0.5*PI, edgeN.row(e)) * + vecParallel.row(e).transpose(); + } + } + } +} + + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +template void igl::edge_vectors, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/edge_vectors.h b/src/external/libigl-2.3.0/include/igl/edge_vectors.h new file mode 100644 index 000000000..7d0a2121d --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/edge_vectors.h @@ -0,0 +1,68 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2020 Oded Stein +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_EDGE_VECTORS_H +#define IGL_EDGE_VECTORS_H +#include "igl_inline.h" + +#include +namespace igl +{ +// Computes the normalized edge vectors for edges in a triangle mesh +// +// Input: +// V, F: triangle mesh +// E, oE: mapping from halfedges to edges and orientation as generated by +// orient_halfedges +// +// Output: +// vec: normalized edge vectors for each unique edge in E, according to order +// of E. +template +IGL_INLINE void edge_vectors( + const Eigen::MatrixBase &V, + const Eigen::MatrixBase &F, + const Eigen::MatrixBase &E, + const Eigen::MatrixBase &oE, + Eigen::PlainObjectBase &vec); + + +// Computes the normalized edge vectors for edges in a triangle mesh +// +// Input: +// V, F: triangle mesh +// E, oE: mapping from halfedges to edges and orientation as generated by +// orient_halfedges +// template parameter computePerpendicular: whether to compute +// vecPerpendicular or not. +// +// Output: +// vecParallel: normalized edge vectors for each unique edge in E, according +// to order of E. +// vecPerpendicular: tangent unit perpendicular vector to each edge, according +// to orientation in oE, corresponds to each vector in +// vecParallel rotated by pi/2 around an edge-based normal. +// +template +IGL_INLINE void edge_vectors( + const Eigen::MatrixBase &V, + const Eigen::MatrixBase &F, + const Eigen::MatrixBase &E, + const Eigen::MatrixBase &oE, + Eigen::PlainObjectBase &vecParallel, + Eigen::PlainObjectBase &vecPerpendicular); +} + +#ifndef IGL_STATIC_LIBRARY +# include "edge_vectors.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/edges.cpp b/src/external/libigl-2.3.0/include/igl/edges.cpp new file mode 100644 index 000000000..9d8ca5847 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/edges.cpp @@ -0,0 +1,71 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "edges.h" +#include "adjacency_matrix.h" +#include + +template +IGL_INLINE void igl::edges( + const Eigen::MatrixBase & F, + Eigen::PlainObjectBase & E) +{ + // build adjacency matrix + typedef typename DerivedF::Scalar Index; + Eigen::SparseMatrix A; + igl::adjacency_matrix(F,A); + igl::edges(A,E); +} + +template +IGL_INLINE void igl::edges( + const Eigen::MatrixBase & I, + const Eigen::MatrixBase & C, + Eigen::PlainObjectBase & E) +{ + typedef typename DerivedE::Scalar Index; + Eigen::SparseMatrix A; + igl::adjacency_matrix(I,C,A); + igl::edges(A,E); +} + +template +IGL_INLINE void igl::edges( + const Eigen::SparseMatrix & A, + Eigen::PlainObjectBase & E) +{ + // Number of non zeros should be twice number of edges + assert(A.nonZeros()%2 == 0); + // Resize to fit edges + E.resize(A.nonZeros()/2,2); + int i = 0; + // Iterate over outside + for(int k=0; k::InnerIterator it (A,k); it; ++it) + { + // only add edge in one direction + if(it.row(), Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::edges, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::edges, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::edges, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/edges.h b/src/external/libigl-2.3.0/include/igl/edges.h new file mode 100644 index 000000000..72ba75d2b --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/edges.h @@ -0,0 +1,59 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_EDGES_H +#define IGL_EDGES_H +#include "igl_inline.h" + +#include +#include + +namespace igl +{ + // Constructs a list of unique edges represented in a given mesh (V,F) + // + // Inputs: + // F #F by 3 list of mesh faces (must be triangles) + // or + // T #T x 4 matrix of indices of tet corners + // Outputs: + // E #E by 2 list of edges in no particular order + // + // See also: adjacency_matrix + template + IGL_INLINE void edges( + const Eigen::MatrixBase & F, + Eigen::PlainObjectBase & E); + // Constructs a list of unique edges represented in a given polygon mesh. + // + // Inputs: + // I #I vectorized list of polygon corner indices into rows of some matrix V + // C #polygons+1 list of cumulative polygon sizes so that C(i+1)-C(i) = + // size of the ith polygon, and so I(C(i)) through I(C(i+1)-1) are the + // indices of the ith polygon + // Outputs: + // E #E by 2 list of edges in no particular order + template + IGL_INLINE void edges( + const Eigen::MatrixBase & I, + const Eigen::MatrixBase & C, + Eigen::PlainObjectBase & E); + // Inputs: + // A #V by #V symmetric adjacency matrix + // Outputs: + // E #E by 2 list of edges in no particular order + template + IGL_INLINE void edges( + const Eigen::SparseMatrix & A, + Eigen::PlainObjectBase & E); +} + +#ifndef IGL_STATIC_LIBRARY +# include "edges.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/edges_to_path.cpp b/src/external/libigl-2.3.0/include/igl/edges_to_path.cpp new file mode 100644 index 000000000..14cd895bc --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/edges_to_path.cpp @@ -0,0 +1,103 @@ +#include "edges_to_path.h" +#include "dfs.h" +#include "sort.h" +#include "slice.h" +#include "ismember.h" +#include "unique.h" +#include "adjacency_list.h" + +template < + typename DerivedE, + typename DerivedI, + typename DerivedJ, + typename DerivedK> +IGL_INLINE void igl::edges_to_path( + const Eigen::MatrixBase & OE, + Eigen::PlainObjectBase & I, + Eigen::PlainObjectBase & J, + Eigen::PlainObjectBase & K) +{ + assert(OE.rows()>=1); + if(OE.rows() == 1) + { + I.resize(2); + I(0) = OE(0); + I(1) = OE(1); + J.resize(1); + J(0) = 0; + K.resize(1); + K(0) = 0; + } + + // Compute on reduced graph + DerivedI U; + Eigen::VectorXi vE; + { + Eigen::VectorXi IA; + unique(OE,U,IA,vE); + } + + Eigen::VectorXi V = Eigen::VectorXi::Zero(vE.maxCoeff()+1); + for(int e = 0;e(vE.data(),OE.rows(),OE.cols()).eval(); + { + std::vector > A; + igl::adjacency_list(E,A); + Eigen::VectorXi P,C; + dfs(A,s,I,P,C); + } + if(c == 2) + { + I.conservativeResize(I.size()+1); + I(I.size()-1) = I(0); + } + + DerivedE sE; + Eigen::Matrix sEI; + { + Eigen::MatrixXi _; + sort(E,2,true,sE,_); + Eigen::Matrix EI(I.size()-1,2); + EI.col(0) = I.head(I.size()-1); + EI.col(1) = I.tail(I.size()-1); + sort(EI,2,true,sEI,_); + } + { + Eigen::Array F; + ismember_rows(sEI,sE,F,J); + } + K.resize(I.size()-1); + for(int k = 0;k, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/edges_to_path.h b/src/external/libigl-2.3.0/include/igl/edges_to_path.h new file mode 100644 index 000000000..403e7029a --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/edges_to_path.h @@ -0,0 +1,36 @@ +#ifndef IGL_EDGES_TO_PATH_H +#define IGL_EDGES_TO_PATH_H +#include "igl_inline.h" +#include +namespace igl +{ + // EDGES_TO_PATH Given a set of undirected, unique edges such that all form a + // single connected compoent with exactly 0 or 2 nodes with valence =1, + // determine the/a path visiting all nodes. + // + // Inputs: + // E #E by 2 list of undirected edges + // Outputs: + // I #E+1 list of nodes in order tracing the chain (loop), if the output + // is a loop then I(1) == I(end) + // J #I-1 list of indices into E of edges tracing I + // K #I-1 list of indices into columns of E {1,2} so that K(i) means that + // E(i,K(i)) comes before the other (i.e., E(i,3-K(i)) ). This means that + // I(i) == E(J(i),K(i)) for i<#I, or + // I == E(sub2ind(size(E),J([1:end end]),[K;3-K(end)])))) + // + template < + typename DerivedE, + typename DerivedI, + typename DerivedJ, + typename DerivedK> + IGL_INLINE void edges_to_path( + const Eigen::MatrixBase & E, + Eigen::PlainObjectBase & I, + Eigen::PlainObjectBase & J, + Eigen::PlainObjectBase & K); +} +#ifndef IGL_STATIC_LIBRARY +# include "edges_to_path.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/eigs.cpp b/src/external/libigl-2.3.0/include/igl/eigs.cpp new file mode 100644 index 000000000..766242694 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/eigs.cpp @@ -0,0 +1,173 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "eigs.h" + +#include "cotmatrix.h" +#include "sort.h" +#include "slice.h" +#include "massmatrix.h" +#include + +template < + typename Atype, + typename Btype, + typename DerivedU, + typename DerivedS> +IGL_INLINE bool igl::eigs( + const Eigen::SparseMatrix & A, + const Eigen::SparseMatrix & iB, + const size_t k, + const EigsType type, + Eigen::PlainObjectBase & sU, + Eigen::PlainObjectBase & sS) +{ + using namespace Eigen; + using namespace std; + const size_t n = A.rows(); + assert(A.cols() == n && "A should be square."); + assert(iB.rows() == n && "B should be match A's dims."); + assert(iB.cols() == n && "B should be square."); + assert(type == EIGS_TYPE_SM && "Only low frequencies are supported"); + DerivedU U(n,k); + DerivedS S(k,1); + typedef Atype Scalar; + typedef Eigen::Matrix VectorXS; + // Rescale B for better numerics + const Scalar rescale = std::abs(iB.diagonal().maxCoeff()); + const Eigen::SparseMatrix B = iB/rescale; + + Scalar tol = 1e-4; + Scalar conv = 1e-14; + int max_iter = 100; + int i = 0; + //std::cout<<"start"<0) + { + eff_sigma = 1e-8+std::abs(S(i-1)); + } + // whether to use rayleigh quotient method + bool ray = false; + Scalar err = std::numeric_limits::infinity(); + int iter; + Scalar sigma = std::numeric_limits::infinity(); + VectorXS x; + for(iter = 0;iter0 && !ray) + { + // project-out existing modes + for(int j = 0;j0?1.:-1.; + + Scalar err_prev = err; + err = (A*x-sigma*B*x).array().abs().maxCoeff(); + if(err > solver; + const SparseMatrix C = A-eff_sigma*B+tikhonov*B; + //mw.save(C,"C"); + //mw.save(eff_sigma,"eff_sigma"); + //mw.save(tikhonov,"tikhonov"); + solver.compute(C); + switch(solver.info()) + { + case Eigen::Success: + break; + case Eigen::NumericalIssue: + cerr<<"Error: Numerical issue."<1e-14 || + ((U.leftCols(i).transpose()*B*x).array().abs()<=1e-7).all() + ) + { + //cout<<"Found "<, Eigen::Matrix >(Eigen::SparseMatrix const&, Eigen::SparseMatrix const&, const size_t, igl::EigsType, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/eigs.h b/src/external/libigl-2.3.0/include/igl/eigs.h new file mode 100644 index 000000000..3b376379c --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/eigs.h @@ -0,0 +1,61 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_EIGS_H +#define IGL_EIGS_H +#include "igl_inline.h" +#include +#include + +namespace igl +{ + // Act like MATLAB's eigs function. Compute the first/last k eigen pairs of + // the generalized eigen value problem: + // + // A u = s B u + // + // Solutions are approximate and sorted. + // + // Ideally one should use ARPACK and the Eigen unsupported ARPACK module. + // This implementation does simple, naive power iterations. + // + // Inputs: + // A #A by #A symmetric matrix + // B #A by #A symmetric positive-definite matrix + // k number of eigen pairs to compute + // type whether to extract from the high or low end + // Outputs: + // sU #A by k list of sorted eigen vectors (descending) + // sS k list of sorted eigen values (descending) + // + // Known issues: + // - only the 'sm' small magnitude eigen values are well supported + // + enum EigsType + { + EIGS_TYPE_SM = 0, + EIGS_TYPE_LM = 1, + NUM_EIGS_TYPES = 2 + }; + template < + typename Atype, + typename Btype, + typename DerivedU, + typename DerivedS> + IGL_INLINE bool eigs( + const Eigen::SparseMatrix & A, + const Eigen::SparseMatrix & B, + const size_t k, + const EigsType type, + Eigen::PlainObjectBase & sU, + Eigen::PlainObjectBase & sS); +} + +#ifndef IGL_STATIC_LIBRARY +#include "eigs.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/embree/EmbreeDevice.h b/src/external/libigl-2.3.0/include/igl/embree/EmbreeDevice.h new file mode 100644 index 000000000..7267626a8 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/embree/EmbreeDevice.h @@ -0,0 +1,86 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2020 Vladimir Fonov +// 2013 Alec Jacobson +// 2014 Christian Schüller +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +// + +#ifndef IGL_EMBREE_EMBREE_DEVICE_H +#define IGL_EMBREE_EMBREE_DEVICE_H +#include +#include + +namespace igl +{ + namespace embree + { + // keep track of embree device + struct EmbreeDevice + { + RTCDevice embree_device; + int embree_device_cntr; + + static EmbreeDevice & instance() + { + static EmbreeDevice s; + return s; + } // instance + + EmbreeDevice(const EmbreeDevice &) = delete; + EmbreeDevice & operator = (const EmbreeDevice &) = delete; + + static RTCDevice get_device(const char *config=nullptr) + { + return instance().get(config); + } + + static void release_device(void) + { + instance().release(); + } + + private: + + EmbreeDevice():embree_device(nullptr),embree_device_cntr(0) {} + + ~EmbreeDevice() + { + if(embree_device) + rtcReleaseDevice(embree_device); + } + + RTCDevice get(const char *config=nullptr) + { + if(!embree_device) + { + embree_device = rtcNewDevice (config); + if(rtcGetDeviceError (embree_device) != RTC_ERROR_NONE) + std::cerr << "Embree: An error occurred while initializing embree core!" << std::endl; + #ifdef IGL_VERBOSE + else + std::cerr << "Embree: core initialized." << std::endl; + #endif + } + ++embree_device_cntr; + return embree_device; + } + + void release() + { + if(!--embree_device_cntr) { + rtcReleaseDevice (embree_device); + embree_device = nullptr; + #ifdef IGL_VERBOSE + std::cerr << "Embree: core released." << std::endl; + #endif + } + } + }; + } +} + +#endif // IGL_EMBREE_EMBREE_DEVICE_H \ No newline at end of file diff --git a/src/external/libigl-2.3.0/include/igl/embree/EmbreeIntersector.cpp b/src/external/libigl-2.3.0/include/igl/embree/EmbreeIntersector.cpp new file mode 100644 index 000000000..0bf8c9492 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/embree/EmbreeIntersector.cpp @@ -0,0 +1,396 @@ + +#include "EmbreeIntersector.h" + +// Implementation +#include + +IGL_INLINE igl::embree::EmbreeIntersector::EmbreeIntersector() + : + //scene(NULL), + geomID(0), + vertices(NULL), + triangles(NULL), + initialized(false), + device(igl::embree::EmbreeDevice::get_device()) +{ +} + +IGL_INLINE igl::embree::EmbreeIntersector::EmbreeIntersector( + const EmbreeIntersector &) + :// To make -Weffc++ happy + //scene(NULL), + geomID(0), + vertices(NULL), + triangles(NULL), + initialized(false) +{ + assert(false && "Embree: Copying EmbreeIntersector is not allowed"); +} + +IGL_INLINE igl::embree::EmbreeIntersector & igl::embree::EmbreeIntersector::operator=( + const EmbreeIntersector &) +{ + assert(false && "Embree: Assigning an EmbreeIntersector is not allowed"); + return *this; +} + + +IGL_INLINE void igl::embree::EmbreeIntersector::init( + const PointMatrixType& V, + const FaceMatrixType& F, + bool isStatic) +{ + std::vector Vtemp; + std::vector Ftemp; + std::vector masks; + Vtemp.push_back(&V); + Ftemp.push_back(&F); + masks.push_back(0xFFFFFFFF); + init(Vtemp,Ftemp,masks,isStatic); +} + +IGL_INLINE void igl::embree::EmbreeIntersector::init( + const std::vector& V, + const std::vector& F, + const std::vector& masks, + bool isStatic) +{ + + if(initialized) + deinit(); + + using namespace std; + + if(V.size() == 0 || F.size() == 0) + { + std::cerr << "Embree: No geometry specified!"; + return; + } + + RTCBuildQuality buildQuality = isStatic ? RTC_BUILD_QUALITY_HIGH : RTC_BUILD_QUALITY_MEDIUM; + + // create a scene + scene = rtcNewScene(device); + rtcSetSceneFlags(scene, RTC_SCENE_FLAG_ROBUST); + rtcSetSceneBuildQuality(scene, buildQuality); + + for(int g=0;g<(int)V.size();g++) + { + // create triangle mesh geometry in that scene + RTCGeometry geom_0 = rtcNewGeometry (device, RTC_GEOMETRY_TYPE_TRIANGLE); + rtcSetGeometryBuildQuality(geom_0,buildQuality); + rtcSetGeometryTimeStepCount(geom_0,1); + geomID = rtcAttachGeometry(scene,geom_0); + rtcReleaseGeometry(geom_0); + + // fill vertex buffer + vertices = (Vertex*)rtcSetNewGeometryBuffer(geom_0,RTC_BUFFER_TYPE_VERTEX,0,RTC_FORMAT_FLOAT3,4*sizeof(float),V[g]->rows()); + for(int i=0;i<(int)V[g]->rows();i++) + { + vertices[i].x = (float)V[g]->coeff(i,0); + vertices[i].y = (float)V[g]->coeff(i,1); + vertices[i].z = (float)V[g]->coeff(i,2); + } + + + // fill triangle buffer + triangles = (Triangle*) rtcSetNewGeometryBuffer(geom_0,RTC_BUFFER_TYPE_INDEX,0,RTC_FORMAT_UINT3,3*sizeof(int),F[g]->rows()); + for(int i=0;i<(int)F[g]->rows();i++) + { + triangles[i].v0 = (int)F[g]->coeff(i,0); + triangles[i].v1 = (int)F[g]->coeff(i,1); + triangles[i].v2 = (int)F[g]->coeff(i,2); + } + + + rtcSetGeometryMask(geom_0,masks[g]); + rtcCommitGeometry(geom_0); + } + + rtcCommitScene(scene); + + if(rtcGetDeviceError (device) != RTC_ERROR_NONE) + std::cerr << "Embree: An error occurred while initializing the provided geometry!" << endl; +#ifdef IGL_VERBOSE + else + std::cerr << "Embree: geometry added." << endl; +#endif + + initialized = true; +} + +IGL_INLINE igl::embree::EmbreeIntersector +::~EmbreeIntersector() +{ + if(initialized) + deinit(); + igl::embree::EmbreeDevice::release_device(); +} + +IGL_INLINE void igl::embree::EmbreeIntersector::deinit() +{ + if(device && scene) + { + rtcReleaseScene(scene); + + if(rtcGetDeviceError (device) != RTC_ERROR_NONE) + { + std::cerr << "Embree: An error occurred while resetting!" << std::endl; + } +#ifdef IGL_VERBOSE + else + { + std::cerr << "Embree: geometry removed." << std::endl; + } +#endif + } +} + +IGL_INLINE bool igl::embree::EmbreeIntersector::intersectRay( + const Eigen::RowVector3f& origin, + const Eigen::RowVector3f& direction, + Hit& hit, + float tnear, + float tfar, + int mask) const +{ + RTCRayHit ray; // EMBREE_FIXME: use RTCRay for occlusion rays + ray.ray.flags = 0; + createRay(ray, origin,direction,tnear,tfar,mask); + + // shot ray + { + RTCIntersectContext context; + rtcInitIntersectContext(&context); + rtcIntersect1(scene,&context,&ray); + ray.hit.Ng_x = -ray.hit.Ng_x; // EMBREE_FIXME: only correct for triangles,quads, and subdivision surfaces + ray.hit.Ng_y = -ray.hit.Ng_y; + ray.hit.Ng_z = -ray.hit.Ng_z; + } +#ifdef IGL_VERBOSE + if(rtcGetDeviceError (device) != RTC_ERROR_NONE) + std::cerr << "Embree: An error occurred while resetting!" << std::endl; +#endif + + if((unsigned)ray.hit.geomID != RTC_INVALID_GEOMETRY_ID) + { + hit.id = ray.hit.primID; + hit.gid = ray.hit.geomID; + hit.u = ray.hit.u; + hit.v = ray.hit.v; + hit.t = ray.ray.tfar; + return true; + } + + return false; +} + +IGL_INLINE bool igl::embree::EmbreeIntersector::intersectBeam( + const Eigen::RowVector3f& origin, + const Eigen::RowVector3f& direction, + Hit& hit, + float tnear, + float tfar, + int mask, + int geoId, + bool closestHit, + unsigned int samples) const +{ + bool hasHit = false; + Hit bestHit; + + if(closestHit) + bestHit.t = std::numeric_limits::max(); + else + bestHit.t = 0; + + if((intersectRay(origin,direction,hit,tnear,tfar,mask) && (hit.gid == geoId || geoId == -1))) + { + bestHit = hit; + hasHit = true; + } + + // sample points around actual ray (conservative hitcheck) + const float eps= 1e-5; + + Eigen::RowVector3f up(0,1,0); + if (direction.cross(up).norm() < eps) up = Eigen::RowVector3f(1,0,0); + Eigen::RowVector3f offset = direction.cross(up).normalized(); + + Eigen::Matrix3f rot = Eigen::AngleAxis(2*3.14159265358979/samples,direction).toRotationMatrix(); + + for(int r=0;r<(int)samples;r++) + { + if(intersectRay(origin+offset*eps,direction,hit,tnear,tfar,mask) && + ((closestHit && (hit.t < bestHit.t)) || + (!closestHit && (hit.t > bestHit.t))) && + (hit.gid == geoId || geoId == -1)) + { + bestHit = hit; + hasHit = true; + } + offset = rot*offset.transpose(); + } + + hit = bestHit; + return hasHit; +} + +IGL_INLINE bool +igl::embree::EmbreeIntersector +::intersectRay( + const Eigen::RowVector3f& origin, + const Eigen::RowVector3f& direction, + std::vector &hits, + int& num_rays, + float tnear, + float tfar, + int mask) const +{ + using namespace std; + num_rays = 0; + hits.clear(); + int last_id0 = -1; + double self_hits = 0; + // This epsilon is directly correleated to the number of missed hits, smaller + // means more accurate and slower + //const double eps = DOUBLE_EPS; + const double eps = FLOAT_EPS; + double min_t = tnear; + bool large_hits_warned = false; + RTCRayHit ray; // EMBREE_FIXME: use RTCRay for occlusion rays + ray.ray.flags = 0; + createRay(ray,origin,direction,tnear,tfar,mask); + + while(true) + { + ray.ray.tnear = min_t; + ray.ray.tfar = tfar; + ray.hit.geomID = RTC_INVALID_GEOMETRY_ID; + ray.hit.primID = RTC_INVALID_GEOMETRY_ID; + ray.hit.instID[0] = RTC_INVALID_GEOMETRY_ID; + num_rays++; + { + RTCIntersectContext context; + rtcInitIntersectContext(&context); + rtcIntersect1(scene,&context,&ray); + ray.hit.Ng_x = -ray.hit.Ng_x; // EMBREE_FIXME: only correct for triangles,quads, and subdivision surfaces + ray.hit.Ng_y = -ray.hit.Ng_y; + ray.hit.Ng_z = -ray.hit.Ng_z; + } + if((unsigned)ray.hit.geomID != RTC_INVALID_GEOMETRY_ID) + { + // Hit self again, progressively advance + if(ray.hit.primID == last_id0 || ray.ray.tfar <= min_t) + { + // push min_t a bit more + //double t_push = pow(2.0,self_hits-4)*(hit.t1000 && !large_hits_warned) + { + std::cout<<"Warning: Large number of hits..."<::iterator hit = hits.begin(); hit != hits.end();hit++) + { + std::cout<<(hit->id+1)<<" "; + } + + std::cout.precision(std::numeric_limits< double >::digits10); + std::cout<<"[ "; + + for(vector::iterator hit = hits.begin(); hit != hits.end(); hit++) + { + std::cout<<(hit->t)< +// 2014 Christian Schüller +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +// igl function interface for Embree2.2 +// +// Necessary changes to switch from previous Embree versions: +// * Use igl:Hit instead of embree:Hit (where id0 -> id) +// * For Embree2.2 +// * Uncomment #define __USE_RAY_MASK__ in platform.h to enable masking + +#ifndef IGL_EMBREE_EMBREE_INTERSECTOR_H +#define IGL_EMBREE_EMBREE_INTERSECTOR_H + +#include "../Hit.h" +#include +#include + +#include +#include +#include +#include + +#include "EmbreeDevice.h" + +namespace igl +{ + namespace embree + { + class EmbreeIntersector + { + public: + typedef Eigen::Matrix PointMatrixType; + typedef Eigen::Matrix FaceMatrixType; + public: + EmbreeIntersector(); + private: + // Copying and assignment are not allowed. + EmbreeIntersector(const EmbreeIntersector & that); + EmbreeIntersector & operator=(const EmbreeIntersector &); + public: + virtual ~EmbreeIntersector(); + + // Initialize with a given mesh. + // + // Inputs: + // V #V by 3 list of vertex positions + // F #F by 3 list of Oriented triangles + // isStatic scene is optimized for static geometry + // Side effects: + // The first time this is ever called the embree engine is initialized. + void init( + const PointMatrixType& V, + const FaceMatrixType& F, + bool isStatic = false); + + // Initialize with a given mesh. + // + // Inputs: + // V vector of #V by 3 list of vertex positions for each geometry + // F vector of #F by 3 list of Oriented triangles for each geometry + // masks a 32 bit mask to identify active geometries. + // isStatic scene is optimized for static geometry + // Side effects: + // The first time this is ever called the embree engine is initialized. + void init( + const std::vector& V, + const std::vector& F, + const std::vector& masks, + bool isStatic = false); + + // Deinitialize embree datasctructures for current mesh. Also called on + // destruction: no need to call if you just want to init() once and + // destroy. + void deinit(); + + // Given a ray find the first hit + // + // Inputs: + // origin 3d origin point of ray + // direction 3d (not necessarily normalized) direction vector of ray + // tnear start of ray segment + // tfar end of ray segment + // masks a 32 bit mask to identify active geometries. + // Output: + // hit information about hit + // Returns true if and only if there was a hit + bool intersectRay( + const Eigen::RowVector3f& origin, + const Eigen::RowVector3f& direction, + Hit& hit, + float tnear = 0, + float tfar = std::numeric_limits::infinity(), + int mask = 0xFFFFFFFF) const; + + // Given a ray find the first hit + // This is a conservative hit test where multiple rays within a small radius + // will be tested and only the closesest hit is returned. + // + // Inputs: + // origin 3d origin point of ray + // direction 3d (not necessarily normalized) direction vector of ray + // tnear start of ray segment + // tfar end of ray segment + // masks a 32 bit mask to identify active geometries. + // geoId id of geometry mask (default std::numeric_limits::infinity() if no: no masking) + // closestHit true for gets closest hit, false for furthest hit + // Output: + // hit information about hit + // Returns true if and only if there was a hit + bool intersectBeam( + const Eigen::RowVector3f& origin, + const Eigen::RowVector3f& direction, + Hit& hit, + float tnear = 0, + float tfar = std::numeric_limits::infinity(), + int mask = 0xFFFFFFFF, + int geoId = -1, + bool closestHit = true, + unsigned int samples = 4) const; + + // Given a ray find all hits in order + // + // Inputs: + // origin 3d origin point of ray + // direction 3d (not necessarily normalized) direction vector of ray + // tnear start of ray segment + // tfar end of ray segment + // masks a 32 bit mask to identify active geometries. + // Output: + // hit information about hit + // num_rays number of rays shot (at least one) + // Returns true if and only if there was a hit + bool intersectRay( + const Eigen::RowVector3f& origin, + const Eigen::RowVector3f& direction, + std::vector &hits, + int& num_rays, + float tnear = 0, + float tfar = std::numeric_limits::infinity(), + int mask = 0xFFFFFFFF) const; + + // Given a ray find the first hit + // + // Inputs: + // a 3d first end point of segment + // ab 3d vector from a to other endpoint b + // Output: + // hit information about hit + // Returns true if and only if there was a hit + bool intersectSegment( + const Eigen::RowVector3f& a, + const Eigen::RowVector3f& ab, + Hit &hit, + int mask = 0xFFFFFFFF) const; + + private: + + struct Vertex {float x,y,z,a;}; + struct Triangle {int v0, v1, v2;}; + + RTCScene scene; + unsigned geomID; + Vertex* vertices; + Triangle* triangles; + bool initialized; + + RTCDevice device; + + void createRay( + RTCRayHit& ray, + const Eigen::RowVector3f& origin, + const Eigen::RowVector3f& direction, + float tnear, + float tfar, + int mask) const; + }; + } +} + +#ifndef IGL_STATIC_LIBRARY +# include "EmbreeIntersector.cpp" +#endif + +#endif //EMBREE_INTERSECTOR_H diff --git a/src/external/libigl-2.3.0/include/igl/embree/EmbreeRenderer.cpp b/src/external/libigl-2.3.0/include/igl/embree/EmbreeRenderer.cpp new file mode 100644 index 000000000..c96fd2454 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/embree/EmbreeRenderer.cpp @@ -0,0 +1,423 @@ +#include "EmbreeRenderer.h" +// Implementation + +//IGL viewing parts +#include "../unproject.h" +#include "../look_at.h" +#include "../frustum.h" +#include "../ortho.h" + +// color map +#include "../jet.h" + +#include "../PI.h" + + +IGL_INLINE void igl::embree::EmbreeRenderer::init_view() +{ + camera_base_zoom = 1.0f; + camera_zoom = 1.0f; + + camera_view_angle = 45.0; + camera_dnear = 1.0; + camera_dfar = 100.0; + camera_base_translation << 0, 0, 0; + camera_translation << 0, 0, 0; + camera_eye << 0, 0, 5; + camera_center << 0, 0, 0; + camera_up << 0, 1, 0; + + rot_matrix = Eigen::Matrix3f::Identity(); + + view = Eigen::Matrix4f::Identity(); + proj = Eigen::Matrix4f::Identity(); + norm = Eigen::Matrix4f::Identity(); + + orthographic = false; + + + uC << 1,0,0; +} + +IGL_INLINE igl::embree::EmbreeRenderer::EmbreeRenderer() + : + scene(NULL), + geomID(0), + initialized(false), + device(igl::embree::EmbreeDevice::get_device()) +{ + init_view(); +} + +IGL_INLINE igl::embree::EmbreeRenderer::EmbreeRenderer( + const EmbreeRenderer &) + :// To make -Weffc++ happy + scene(NULL), + geomID(0), + initialized(false) +{ + assert(false && "Embree: Copying EmbreeRenderer is not allowed"); +} + +IGL_INLINE igl::embree::EmbreeRenderer & igl::embree::EmbreeRenderer::operator=( + const EmbreeRenderer &) +{ + assert(false && "Embree: Assigning an EmbreeRenderer is not allowed"); + return *this; +} + + +IGL_INLINE void igl::embree::EmbreeRenderer::init( + const PointMatrixType& V, + const FaceMatrixType& F, + bool isStatic) +{ + std::vector Vtemp; + std::vector Ftemp; + std::vector masks; + Vtemp.push_back(&V); + Ftemp.push_back(&F); + masks.push_back(0xFFFFFFFF); + init(Vtemp,Ftemp,masks,isStatic); +} + +IGL_INLINE void igl::embree::EmbreeRenderer::init( + const std::vector& V, + const std::vector& F, + const std::vector& masks, + bool isStatic) +{ + if(initialized) + deinit(); + + using namespace std; + + if(V.size() == 0 || F.size() == 0) + { + std::cerr << "Embree: No geometry specified!"; + return; + } + RTCBuildQuality buildQuality = isStatic ? RTC_BUILD_QUALITY_HIGH : RTC_BUILD_QUALITY_MEDIUM; + + // create a scene + scene = rtcNewScene(device); + rtcSetSceneFlags(scene, RTC_SCENE_FLAG_ROBUST); + rtcSetSceneBuildQuality(scene, buildQuality); + + for(int g=0;g<(int)V.size();g++) + { + // create triangle mesh geometry in that scene + RTCGeometry geom_0 = rtcNewGeometry (device, RTC_GEOMETRY_TYPE_TRIANGLE); + rtcSetGeometryBuildQuality(geom_0, buildQuality); + rtcSetGeometryTimeStepCount(geom_0,1); + geomID = rtcAttachGeometry(scene,geom_0); + rtcReleaseGeometry(geom_0); + + // fill vertex buffer, have to be 16 byte wide( sizeof(float)*4 ) + Eigen::Map> vertices( + (float*)rtcSetNewGeometryBuffer(geom_0,RTC_BUFFER_TYPE_VERTEX,0,RTC_FORMAT_FLOAT3,4*sizeof(float),V[g]->rows()), + V[g]->rows(),4 + ); + vertices.block(0,0,V[g]->rows(),3) = V[g]->cast(); + + // fill triangle buffer + Eigen::Map> triangles( + (unsigned int*) rtcSetNewGeometryBuffer(geom_0,RTC_BUFFER_TYPE_INDEX,0,RTC_FORMAT_UINT3,3*sizeof(unsigned int), F[g]->rows()), + F[g]->rows(),3 + ); + triangles = F[g]->cast(); + //TODO: store vertices and triangles in array for whatever reason? + + rtcSetGeometryMask(geom_0, masks[g]); + rtcCommitGeometry(geom_0); + } + + rtcCommitScene(scene); + + if(rtcGetDeviceError (device) != RTC_ERROR_NONE) + std::cerr << "Embree: An error occurred while initializing the provided geometry!" << endl; +#ifdef IGL_VERBOSE + else + std::cerr << "Embree: geometry added." << endl; +#endif + + initialized = true; +} + +IGL_INLINE igl::embree::EmbreeRenderer::~EmbreeRenderer() +{ + if(initialized) + deinit(); + + igl::embree::EmbreeDevice::release_device(); +} + +IGL_INLINE void igl::embree::EmbreeRenderer::deinit() +{ + if(scene) + { + rtcReleaseScene(scene); + + if(rtcGetDeviceError (device) != RTC_ERROR_NONE) + { + std::cerr << "Embree: An error occurred while resetting!" << std::endl; + } +#ifdef IGL_VERBOSE + else + { + std::cerr << "Embree: geometry removed." << std::endl; + } +#endif + } +} + +IGL_INLINE bool igl::embree::EmbreeRenderer::intersect_ray( + const Eigen::RowVector3f& origin, + const Eigen::RowVector3f& direction, + Hit& hit, + float tnear, + float tfar, + int mask) const +{ + RTCRayHit ray; + ray.ray.flags = 0; + create_ray(ray, origin,direction,tnear,tfar,mask); + + // shot ray + { + RTCIntersectContext context; + rtcInitIntersectContext(&context); + rtcIntersect1(scene, &context, &ray); + ray.hit.Ng_x = -ray.hit.Ng_x; // EMBREE_FIXME: only correct for triangles,quads, and subdivision surfaces + ray.hit.Ng_y = -ray.hit.Ng_y; + ray.hit.Ng_z = -ray.hit.Ng_z; + } +#ifdef IGL_VERBOSE + if(rtcGetDeviceError (device) != RTC_ERROR_NONE) + std::cerr << "Embree: An error occurred while resetting!" << std::endl; +#endif + + if((unsigned)ray.hit.geomID != RTC_INVALID_GEOMETRY_ID) + { + hit.id = ray.hit.primID; + hit.gid = ray.hit.geomID; + hit.u = ray.hit.u; + hit.v = ray.hit.v; + hit.t = ray.ray.tfar; + hit.N = Vec3f(ray.hit.Ng_x, ray.hit.Ng_y, ray.hit.Ng_z); + return true; + } + + return false; +} + +IGL_INLINE void +igl::embree::EmbreeRenderer +::create_ray(RTCRayHit& ray, const Eigen::RowVector3f& origin, + const Eigen::RowVector3f& direction, float tnear, float tfar, int mask) const +{ + ray.ray.org_x = origin[0]; + ray.ray.org_y = origin[1]; + ray.ray.org_z = origin[2]; + ray.ray.dir_x = direction[0]; + ray.ray.dir_y = direction[1]; + ray.ray.dir_z = direction[2]; + ray.ray.tnear = tnear; + ray.ray.tfar = tfar; + ray.ray.id = RTC_INVALID_GEOMETRY_ID; + ray.ray.mask = mask; + ray.ray.time = 0.0f; + + ray.hit.geomID = RTC_INVALID_GEOMETRY_ID; + ray.hit.instID[0] = RTC_INVALID_GEOMETRY_ID; + ray.hit.primID = RTC_INVALID_GEOMETRY_ID; +} + + +IGL_INLINE void +igl::embree::EmbreeRenderer +::set_mesh(const Eigen::Matrix & MV, + const Eigen::Matrix & MF, + bool is_static) +{ + V = MV.cast(); + F = MF; + this->init(V,F,is_static); + + auto min_point = V.colwise().minCoeff(); + auto max_point = V.colwise().maxCoeff(); + auto centroid = (0.5*(min_point + max_point)).eval(); + + camera_base_translation.setConstant(0); + camera_base_translation.head(centroid.size()) = -centroid.cast(); + camera_base_zoom = 2.0 / (max_point-min_point).array().abs().maxCoeff(); +} + +IGL_INLINE void +igl::embree::EmbreeRenderer +::render_buffer(PixelMatrixType& R, PixelMatrixType&G, PixelMatrixType &B,PixelMatrixType &A) +{ + assert(R.rows()==G.rows());assert(R.rows()==B.rows());assert(R.rows()==A.rows()); + assert(R.cols()==G.cols());assert(R.cols()==B.cols());assert(R.cols()==A.cols()); + + Eigen::Vector4f viewport(0,0,R.rows(),R.cols()); + + float width = R.rows(); + float height = R.cols(); + + // update view matrix + igl::look_at( camera_eye, camera_center, camera_up, view); + + view = view + * (rot_matrix * Eigen::Scaling(camera_zoom * camera_base_zoom) + * Eigen::Translation3f(camera_translation + camera_base_translation)).matrix(); + + if (orthographic) + { + float length = (camera_eye - camera_center).norm(); + float h = tan(camera_view_angle/360.0 * igl::PI) * (length); + igl::ortho(-h*width/height, h*width/height, -h, h, camera_dnear, camera_dfar, proj); + } else { + float fH = tan(camera_view_angle / 360.0 * igl::PI) * camera_dnear; + float fW = fH * (double)width/(double)height; + igl::frustum(-fW, fW, -fH, fH, camera_dnear, camera_dfar, proj); + } + + // go over all pixels in the "view" + for(int x=0;x<(int)width;++x) + { + for(int y=0;y<(int)height;++y) + { + Vec3f s,d,dir; + igl::embree::EmbreeRenderer::Hit hit; + + // look into the screen + Vec3f win_s(x,y,0); + Vec3f win_d(x,y,1); + // Source, destination and direction in world + igl::unproject(win_s,this->view,this->proj,viewport,s); + igl::unproject(win_d,this->view,this->proj,viewport,d); + dir = d-s; + dir.normalize(); + + auto clamp=[](float x)->unsigned char {return (unsigned char)(x<0?0:x>1.0?255:x*255);}; + + if(this->intersect_ray(s,dir,hit)) + { + if ( dir.dot(hit.N) > 0.0f) + { + // TODO: interpolate normals ? + hit.N.normalize(); + // cos between ray and face normal + float face_proj=dir.dot(hit.N); + + Eigen::RowVector3f c; + + if(this->uniform_color) + { + // same color for the whole mesh + c=uC; + } else if(this->face_based) { + // flat color per face + c=this->C.row(hit.id); + } else { //use barycentric coordinates to interpolate colour + c=this->C.row(F(hit.id,1))*hit.u+ + this->C.row(F(hit.id,2))*hit.v+ + this->C.row(F(hit.id,0))*(1.0-hit.u-hit.v); + } + + R(x,y) = clamp(face_proj*c(0)); + G(x,y) = clamp(face_proj*c(1)); + B(x,y) = clamp(face_proj*c(2)); + } + // give the same alpha to all points with something behind + A(x,y)=255; + } else { + R(x,y)=0; + G(x,y)=0; + B(x,y)=0; + A(x,y)=0; + } + + } + } +} + + +IGL_INLINE void +igl::embree::EmbreeRenderer +::set_colors(const Eigen::MatrixXd & C) +{ + if(C.rows()==V.rows()) // per vertex color + { + face_based = false; + this->C = C.cast(); + this->uniform_color=false; + } else if (C.rows()==F.rows()) { + face_based = true; + this->C = C.cast(); + this->uniform_color=false; + } else if (C.rows()==1) { + face_based = true; + this->uC = C.cast(); + this->uniform_color=true; + }else { + // don't know what to do + this->uniform_color=true; + assert(false); //? + } +} + +IGL_INLINE void +igl::embree::EmbreeRenderer +::set_data(const Eigen::VectorXd & D, igl::ColorMapType cmap) +{ + const double caxis_min = D.minCoeff(); + const double caxis_max = D.maxCoeff(); + return set_data(D,caxis_min,caxis_max,cmap); +} + + +IGL_INLINE void igl::embree::EmbreeRenderer::set_data( + const Eigen::VectorXd & D, + double caxis_min, + double caxis_max, + igl::ColorMapType cmap) +{ + Eigen::MatrixXd C; + igl::colormap(cmap,D,caxis_min,caxis_max,C); + set_colors(C); +} + +IGL_INLINE void +igl::embree::EmbreeRenderer::set_rot(const Eigen::Matrix3d &r) +{ + this->rot_matrix = r.cast(); +} + +IGL_INLINE void +igl::embree::EmbreeRenderer::set_zoom(double zoom) +{ + this->camera_zoom=zoom; +} + +IGL_INLINE void +igl::embree::EmbreeRenderer::set_translation(const Eigen::Vector3d &tr) +{ + this->camera_translation=tr.cast(); +} + +IGL_INLINE void +igl::embree::EmbreeRenderer::set_face_based(bool _f) +{ + this->face_based=_f; +} + +IGL_INLINE void +igl::embree::EmbreeRenderer::set_orthographic(bool o) +{ + this->orthographic=o; +} + +#ifdef IGL_STATIC_LIBRARY +#endif //IGL_STATIC_LIBRARY diff --git a/src/external/libigl-2.3.0/include/igl/embree/EmbreeRenderer.h b/src/external/libigl-2.3.0/include/igl/embree/EmbreeRenderer.h new file mode 100644 index 000000000..838c8638e --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/embree/EmbreeRenderer.h @@ -0,0 +1,248 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// +// Copyright (C) 2020 Vladimir Fonov +// 2013 Alec Jacobson +// 2014 Christian Schüller +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +// + +#ifndef IGL_EMBREE_EMBREE_RENDERER_H +#define IGL_EMBREE_EMBREE_RENDERER_H + +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include "EmbreeDevice.h" + + +namespace igl +{ + namespace embree + { + // embree-based mesh renderer + class EmbreeRenderer + { + public: + typedef Eigen::RowVector3f Vec3f; + + struct Hit + { + int id; // primitive id + int gid; // geometry id + float u,v; // barycentric coordinates + float t; // distance = direction*t to intersection + Vec3f N; // element normal + }; + + public: + typedef Eigen::Matrix PointMatrixType; + typedef Eigen::Matrix ColorMatrixType; + typedef Eigen::Matrix FaceMatrixType; + + typedef Eigen::Matrix PixelMatrixType; + + public: + EmbreeRenderer(); + private: + // Copying and assignment are not allowed. + EmbreeRenderer(const EmbreeRenderer & that); + EmbreeRenderer & operator=(const EmbreeRenderer &); + public: + virtual ~EmbreeRenderer(); + + // Specify mesh, this call reinitializes embree structures + // Inputs: + // V #V x dim matrix of vertex coordinates + // F #F x simplex_size matrix of indices of simplex corners into V + // is_static - optimize for static thene (HQ rendering) + void set_mesh(const Eigen::Matrix & V, + const Eigen::Matrix & F, + bool is_static=true); + // Specify per-vertex or per-face color + // Inputs: + // C #V x 3 matrix of vertex colors + // or #F x 3 matrix of face colors + // or 1 x 3 matrix of uniform color + void set_colors(const Eigen::MatrixXd & C); + + + // Use min(D) and max(D) to set caxis. + void set_data(const Eigen::VectorXd & D, + igl::ColorMapType cmap = igl::COLOR_MAP_TYPE_VIRIDIS); + + // Specify per-vertex or per-face scalar field + // that will be converted to color using jet color map + // Inputs: + // caxis_min caxis minimum bound + // caxis_max caxis maximum bound + // D #V by 1 list of scalar values + // cmap colormap type + // num_steps number of intervals to discretize the colormap + void set_data( + const Eigen::VectorXd & D, + double caxis_min, + double caxis_max, + igl::ColorMapType cmap = igl::COLOR_MAP_TYPE_VIRIDIS); + + // Specify mesh rotation + // Inputs: + // r 3 x 3 rotaton matrix + void set_rot(const Eigen::Matrix3d &r); + + // Specify mesh magnification + // Inputs: + // z magnification ratio + void set_zoom(double z); + + // Specify mesh translation + // Inputs: + // tr translation vector + void set_translation(const Eigen::Vector3d &tr); + + // Specify that color is face based + // Inputs: + // f - face or vertex colours + void set_face_based(bool f); + + // Use orthographic projection + // Inputs: + // f - orthographic or perspective projection + void set_orthographic(bool f ); + + // render full buffer + // Outputs: + // all outputs should have the same size (size of the output picture) + // area outside of the visible object will have zero alpha component (transparant) + // R - red channel + // G - green channel + // B - blue channel + // A - alpha channel + void render_buffer(PixelMatrixType &R, + PixelMatrixType &G, + PixelMatrixType &B, + PixelMatrixType &A); + + // Given a ray find the first hit + // + // Inputs: + // origin 3d origin point of ray + // direction 3d (not necessarily normalized) direction vector of ray + // tnear start of ray segment + // tfar end of ray segment + // mask a 32 bit mask to identify active geometries. + // Output: + // hit information about hit + // Returns true if and only if there was a hit + bool intersect_ray( + const Eigen::RowVector3f& origin, + const Eigen::RowVector3f& direction, + Hit& hit, + float tnear = 0, + float tfar = std::numeric_limits::infinity(), + int mask = 0xFFFFFFFF) const; + + private: + + // Initialize with a given mesh. + // + // Inputs: + // V #V by 3 list of vertex positions + // F #F by 3 list of Oriented triangles + // isStatic scene is optimized for static geometry + // Side effects: + // The first time this is ever called the embree engine is initialized. + void init( + const PointMatrixType& V, + const FaceMatrixType& F, + bool isStatic = false); + + // Initialize embree with a given mesh. + // + // Inputs: + // V vector of #V by 3 list of vertex positions for each geometry + // F vector of #F by 3 list of Oriented triangles for each geometry + // masks a 32 bit mask to identify active geometries. + // isStatic scene is optimized for static geometry + // Side effects: + // The first time this is ever called the embree engine is initialized. + void init( + const std::vector& V, + const std::vector& F, + const std::vector& masks, + bool isStatic = false); + + + // Deinitialize embree datasctructures for current mesh. Also called on + // destruction: no need to call if you just want to init() once and + // destroy. + void deinit(); + // initialize view parameters + void init_view(); + + // scene data + PointMatrixType V; // vertices + FaceMatrixType F; // faces + ColorMatrixType C; // colours + + Eigen::RowVector3f uC; // uniform color + + bool face_based; + bool uniform_color; + + // Camera parameters + float camera_base_zoom; + float camera_zoom; + + Eigen::Vector3f camera_base_translation; + Eigen::Vector3f camera_translation; + Eigen::Vector3f camera_eye; + Eigen::Vector3f camera_up; + Eigen::Vector3f camera_center; + float camera_view_angle; + float camera_dnear; + float camera_dfar; + + // projection matrixes + Eigen::Matrix4f view; + Eigen::Matrix4f proj; + Eigen::Matrix4f norm; + + Eigen::Matrix3f rot_matrix; + + bool orthographic; + + // embree data + RTCScene scene; + unsigned geomID; + bool initialized; + + RTCDevice device; + + void create_ray( + RTCRayHit& ray, + const Eigen::RowVector3f& origin, + const Eigen::RowVector3f& direction, + float tnear, + float tfar, + int mask) const; + + }; + } +} + +#ifndef IGL_STATIC_LIBRARY +# include "EmbreeRenderer.cpp" +#endif +#endif //IGL_EMBREE_EMBREE_RENDERER_H diff --git a/src/external/libigl-2.3.0/include/igl/embree/ambient_occlusion.cpp b/src/external/libigl-2.3.0/include/igl/embree/ambient_occlusion.cpp new file mode 100644 index 000000000..d19aa9c46 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/embree/ambient_occlusion.cpp @@ -0,0 +1,62 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "ambient_occlusion.h" +#include "../ambient_occlusion.h" +#include "EmbreeIntersector.h" +#include "../Hit.h" + +template < + typename DerivedP, + typename DerivedN, + typename DerivedS > +IGL_INLINE void igl::embree::ambient_occlusion( + const igl::embree::EmbreeIntersector & ei, + const Eigen::PlainObjectBase & P, + const Eigen::PlainObjectBase & N, + const int num_samples, + Eigen::PlainObjectBase & S) +{ + const auto & shoot_ray = [&ei]( + const Eigen::Vector3f& s, + const Eigen::Vector3f& dir)->bool + { + igl::Hit hit; + const float tnear = 1e-4f; + return ei.intersectRay(s,dir,hit,tnear); + }; + return igl::ambient_occlusion(shoot_ray,P,N,num_samples,S); +} + +template < + typename DerivedV, + typename DerivedF, + typename DerivedP, + typename DerivedN, + typename DerivedS > +IGL_INLINE void igl::embree::ambient_occlusion( + const Eigen::PlainObjectBase & V, + const Eigen::PlainObjectBase & F, + const Eigen::PlainObjectBase & P, + const Eigen::PlainObjectBase & N, + const int num_samples, + Eigen::PlainObjectBase & S) +{ + using namespace Eigen; + EmbreeIntersector ei; + ei.init(V.template cast(),F.template cast()); + ambient_occlusion(ei,P,N,num_samples,S); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +template void igl::embree::ambient_occlusion, Eigen::Matrix, Eigen::Matrix >(igl::embree::EmbreeIntersector const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, int, Eigen::PlainObjectBase >&); +template void igl::embree::ambient_occlusion, Eigen::Matrix, Eigen::Matrix >(igl::embree::EmbreeIntersector const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, int, Eigen::PlainObjectBase >&); +template void igl::embree::ambient_occlusion, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, int, Eigen::PlainObjectBase >&); +template void igl::embree::ambient_occlusion, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, int, Eigen::PlainObjectBase >&); +template void igl::embree::ambient_occlusion, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, int, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/embree/ambient_occlusion.h b/src/external/libigl-2.3.0/include/igl/embree/ambient_occlusion.h new file mode 100644 index 000000000..6df3a53ee --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/embree/ambient_occlusion.h @@ -0,0 +1,59 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_EMBREE_AMBIENT_OCCLUSION_H +#define IGL_EMBREE_AMBIENT_OCCLUSION_H +#include "../igl_inline.h" +#include +namespace igl +{ + namespace embree + { + // Forward define + class EmbreeIntersector; + // Compute ambient occlusion per given point + // + // Inputs: + // ei EmbreeIntersector containing (V,F) + // P #P by 3 list of origin points + // N #P by 3 list of origin normals + // Outputs: + // S #P list of ambient occlusion values between 1 (fully occluded) and + // 0 (not occluded) + // + template < + typename DerivedP, + typename DerivedN, + typename DerivedS > + IGL_INLINE void ambient_occlusion( + const EmbreeIntersector & ei, + const Eigen::PlainObjectBase & P, + const Eigen::PlainObjectBase & N, + const int num_samples, + Eigen::PlainObjectBase & S); + // Wrapper which builds new EmbreeIntersector for (V,F). That's expensive so + // avoid this if repeatedly calling. + template < + typename DerivedV, + typename DerivedF, + typename DerivedP, + typename DerivedN, + typename DerivedS > + IGL_INLINE void ambient_occlusion( + const Eigen::PlainObjectBase & V, + const Eigen::PlainObjectBase & F, + const Eigen::PlainObjectBase & P, + const Eigen::PlainObjectBase & N, + const int num_samples, + Eigen::PlainObjectBase & S); + } +}; +#ifndef IGL_STATIC_LIBRARY +# include "ambient_occlusion.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/embree/bone_heat.cpp b/src/external/libigl-2.3.0/include/igl/embree/bone_heat.cpp new file mode 100644 index 000000000..8a85af98c --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/embree/bone_heat.cpp @@ -0,0 +1,116 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "bone_heat.h" +#include "EmbreeIntersector.h" +#include "bone_visible.h" +#include "../project_to_line_segment.h" +#include "../cotmatrix.h" +#include "../massmatrix.h" +#include "../mat_min.h" +#include + +bool igl::embree::bone_heat( + const Eigen::MatrixXd & V, + const Eigen::MatrixXi & F, + const Eigen::MatrixXd & C, + const Eigen::VectorXi & P, + const Eigen::MatrixXi & BE, + const Eigen::MatrixXi & CE, + Eigen::MatrixXd & W) +{ + using namespace std; + using namespace Eigen; + assert(CE.rows() == 0 && "Cage edges not supported."); + assert(C.cols() == V.cols() && "V and C should have same #cols"); + assert(BE.cols() == 2 && "BE should have #cols=2"); + assert(F.cols() == 3 && "F should contain triangles."); + assert(V.cols() == 3 && "V should contain 3D positions."); + + const int n = V.rows(); + const int np = P.rows(); + const int nb = BE.rows(); + const int m = np + nb; + + // "double sided lighting" + MatrixXi FF; + FF.resize(F.rows()*2,F.cols()); + FF << F, F.rowwise().reverse(); + // Initialize intersector + EmbreeIntersector ei; + ei.init(V.cast(),F.cast()); + + typedef Matrix VectorXb; + typedef Matrix MatrixXb; + MatrixXb vis_mask(n,m); + // Distances + MatrixXd D(n,m); + // loop over points + for(int j = 0;j 0) + { + cerr<<"Error: Cage edges are not supported. Ignored."<1e10?1e10:hii); + } + } + SparseMatrix Q,L,M; + cotmatrix(V,F,L); + massmatrix(V,F,MASSMATRIX_TYPE_DEFAULT,M); + const auto & H = Hdiag.asDiagonal(); + Q = (-L+M*H); + SimplicialLLT > llt; + llt.compute(Q); + switch(llt.info()) + { + case Eigen::Success: + break; + case Eigen::NumericalIssue: + cerr<<"Error: Numerical issue."< +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_EMBREE_BONE_HEAT_H +#define IGL_EMBREE_BONE_HEAT_H +#include "../igl_inline.h" +#include + +namespace igl +{ + namespace embree + { + // BONE_HEAT Compute skinning weights W given a surface mesh (V,F) and an + // internal skeleton (C,BE) according to "Automatic Rigging" [Baran and + // Popovic 2007]. + // + // Inputs: + // V #V by 3 list of mesh vertex positions + // F #F by 3 list of mesh corner indices into V + // C #C by 3 list of joint locations + // P #P list of point handle indices into C + // BE #BE by 2 list of bone edge indices into C + // CE #CE by 2 list of cage edge indices into **P** + // Outputs: + // W #V by #P+#BE matrix of weights. + // Returns true only on success. + // + IGL_INLINE bool bone_heat( + const Eigen::MatrixXd & V, + const Eigen::MatrixXi & F, + const Eigen::MatrixXd & C, + const Eigen::VectorXi & P, + const Eigen::MatrixXi & BE, + const Eigen::MatrixXi & CE, + Eigen::MatrixXd & W); + } +}; + +#ifndef IGL_STATIC_LIBRARY +# include "bone_heat.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/embree/bone_visible.cpp b/src/external/libigl-2.3.0/include/igl/embree/bone_visible.cpp new file mode 100644 index 000000000..4f2fe9126 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/embree/bone_visible.cpp @@ -0,0 +1,145 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "bone_visible.h" +#include "../project_to_line.h" +#include "../EPS.h" +#include "../Hit.h" +#include "../Timer.h" +#include + +template < + typename DerivedV, + typename DerivedF, + typename DerivedSD, + typename Derivedflag> +IGL_INLINE void igl::embree::bone_visible( + const Eigen::PlainObjectBase & V, + const Eigen::PlainObjectBase & F, + const Eigen::PlainObjectBase & s, + const Eigen::PlainObjectBase & d, + Eigen::PlainObjectBase & flag) +{ + // "double sided lighting" + Eigen::Matrix FF; + FF.resize(F.rows()*2,F.cols()); + FF << F, F.rowwise().reverse(); + // Initialize intersector + EmbreeIntersector ei; + ei.init(V.template cast(),FF.template cast()); + return bone_visible(V,F,ei,s,d,flag); +} + +template < + typename DerivedV, + typename DerivedF, + typename DerivedSD, + typename Derivedflag> +IGL_INLINE void igl::embree::bone_visible( + const Eigen::PlainObjectBase & V, + const Eigen::PlainObjectBase & F, + const EmbreeIntersector & ei, + const Eigen::PlainObjectBase & s, + const Eigen::PlainObjectBase & d, + Eigen::PlainObjectBase & flag) +{ + using namespace std; + using namespace Eigen; + flag.resize(V.rows()); + const double sd_norm = (s-d).norm(); + // Embree seems to be parallel when constructing but not when tracing rays +#pragma omp parallel for + // loop over mesh vertices + for(int v = 0;v1) + { + t = 1; + sqrd = (Vv-d).array().pow(2).sum(); + projv = d; + } + } + igl::Hit hit; + // perhaps 1.0 should be 1.0-epsilon, or actually since we checking the + // incident face, perhaps 1.0 should be 1.0+eps + const Vector3d dir = (Vv-projv)*1.0; + if(ei.intersectSegment( + projv.template cast(), + dir.template cast(), + hit)) + { + // mod for double sided lighting + const int fi = hit.id % F.rows(); + + //if(v == 1228-1) + //{ + // Vector3d bc,P; + // bc << 1 - hit.u - hit.v, hit.u, hit.v; // barycentric + // P = V.row(F(fi,0))*bc(0) + + // V.row(F(fi,1))*bc(1) + + // V.row(F(fi,2))*bc(2); + // cout<<(fi+1)<sqrd) + { + flag(v) = true; + } + }else + { + // no hit so vectex v is visible + flag(v) = true; + } + } +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +template void igl::embree::bone_visible, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&); +template void igl::embree::bone_visible, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/embree/bone_visible.h b/src/external/libigl-2.3.0/include/igl/embree/bone_visible.h new file mode 100644 index 000000000..1e490b51d --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/embree/bone_visible.h @@ -0,0 +1,68 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_EMBREE_BONE_VISIBLE_H +#define IGL_EMBREE_BONE_VISIBLE_H +#include +#include +#include "EmbreeIntersector.h" +namespace igl +{ + namespace embree + { + // + // BONE_VISIBLE test whether vertices of mesh are "visible" to a given bone, + // where "visible" is defined as in [Baran & Popovic 07]. Instead of checking + // whether each point can see *any* of the bone, we just check if each point + // can see its own projection onto the bone segment. In other words, we project + // each vertex v onto the bone, projv. Then we check if there are any + // intersections between the line segment (projv-->v) and the mesh. + // + // [flag] = bone_visible(V,F,s,d); + // + // Input: + // V #V by 3 list of vertex positions + // F #F by 3 list of triangle indices + // s row vector of position of start end point of bone + // d row vector of position of dest end point of bone + // Output: + // flag #V by 1 list of bools (true) visible, (false) obstructed + // + // Note: This checks for hits along the segment which are facing in *any* + // direction from the ray. + // + template < + typename DerivedV, + typename DerivedF, + typename DerivedSD, + typename Derivedflag> + IGL_INLINE void bone_visible( + const Eigen::PlainObjectBase & V, + const Eigen::PlainObjectBase & F, + const Eigen::PlainObjectBase & s, + const Eigen::PlainObjectBase & d, + Eigen::PlainObjectBase & flag); + // Inputs: + // ei EmbreeIntersector for mesh (V,F) should be double sided + template < + typename DerivedV, + typename DerivedF, + typename DerivedSD, + typename Derivedflag> + IGL_INLINE void bone_visible( + const Eigen::PlainObjectBase & V, + const Eigen::PlainObjectBase & F, + const EmbreeIntersector & ei, + const Eigen::PlainObjectBase & s, + const Eigen::PlainObjectBase & d, + Eigen::PlainObjectBase & flag); + } +} +#ifndef IGL_STATIC_LIBRARY +# include "bone_visible.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/embree/line_mesh_intersection.cpp b/src/external/libigl-2.3.0/include/igl/embree/line_mesh_intersection.cpp new file mode 100644 index 000000000..0f6e02b8c --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/embree/line_mesh_intersection.cpp @@ -0,0 +1,85 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Daniele Panozzo +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "line_mesh_intersection.h" +#include "../Hit.h" + +// For error printing +#include +#include + +#include +#include + +template +IGL_INLINE ScalarMatrix igl::embree::line_mesh_intersection +( + const ScalarMatrix & V_source, + const ScalarMatrix & N_source, + const ScalarMatrix & V_target, + const IndexMatrix & F_target +) +{ + + double tol = 0.00001; + + Eigen::MatrixXd ray_pos = V_source; + Eigen::MatrixXd ray_dir = N_source; + + // Allocate matrix for the result + ScalarMatrix R; + R.resize(V_source.rows(), 3); + + // Initialize embree + EmbreeIntersector embree; + embree.init(V_target.template cast(),F_target.template cast()); + + // Shoot rays from the source to the target + for (unsigned i=0; i(), A_dir.cast(),A); + + Eigen::RowVector3d B_pos = ray_pos.row(i) - tol * ray_dir.row(i); + Eigen::RowVector3d B_dir = ray_dir.row(i); + + bool B_hit = embree.intersectBeam(B_pos.cast(), B_dir.cast(),B); + + + int choice = -1; + + if (A_hit && ! B_hit) + choice = 0; + else if (!A_hit && B_hit) + choice = 1; + else if (A_hit && B_hit) + choice = A.t > B.t; + + Eigen::RowVector3d temp; + + if (choice == -1) + temp << -1, 0, 0; + else if (choice == 0) + temp << A.id, A.u, A.v; + else if (choice == 1) + temp << B.id, B.u, B.v; + + R.row(i) = temp; + + } + + return R; + +} + +#ifdef IGL_STATIC_LIBRARY +template Eigen::Matrix igl::embree::line_mesh_intersection, Eigen::Matrix >(Eigen::Matrix const&, Eigen::Matrix const&, Eigen::Matrix const&, Eigen::Matrix const&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/embree/line_mesh_intersection.h b/src/external/libigl-2.3.0/include/igl/embree/line_mesh_intersection.h new file mode 100644 index 000000000..b7b849c8a --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/embree/line_mesh_intersection.h @@ -0,0 +1,51 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Daniele Panozzo +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_EMBREE_LINE_MESH_INTERSECTION_H +#define IGL_EMBREE_LINE_MESH_INTERSECTION_H +#include + +#include +#include +#include + +namespace igl +{ + namespace embree + { + // Project the point cloud V_source onto the triangle mesh + // V_target,F_target. + // A ray is casted for every vertex in the direction specified by + // N_source and its opposite. + // + // Input: + // V_source: #Vx3 Vertices of the source mesh + // N_source: #Vx3 Normals of the point cloud + // V_target: #V2x3 Vertices of the target mesh + // F_target: #F2x3 Faces of the target mesh + // + // Output: + // #Vx3 matrix of baricentric coordinate. Each row corresponds to + // a vertex of the projected mesh and it has the following format: + // id b1 b2. id is the id of a face of the source mesh. b1 and b2 are + // the barycentric coordinates wrt the first two edges of the triangle + // To convert to standard global coordinates, see barycentric_to_global.h + template + IGL_INLINE ScalarMatrix line_mesh_intersection + ( + const ScalarMatrix & V_source, + const ScalarMatrix & N_source, + const ScalarMatrix & V_target, + const IndexMatrix & F_target + ); + } +} +#ifndef IGL_STATIC_LIBRARY +# include "line_mesh_intersection.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/embree/reorient_facets_raycast.cpp b/src/external/libigl-2.3.0/include/igl/embree/reorient_facets_raycast.cpp new file mode 100644 index 000000000..fabc021d9 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/embree/reorient_facets_raycast.cpp @@ -0,0 +1,259 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "reorient_facets_raycast.h" +#include "../per_face_normals.h" +#include "../doublearea.h" +#include "../random_dir.h" +#include "../bfs_orient.h" +#include "EmbreeIntersector.h" +#include +#include +#include +#include + +template < + typename DerivedV, + typename DerivedF, + typename DerivedI, + typename DerivedC> +IGL_INLINE void igl::embree::reorient_facets_raycast( + const Eigen::PlainObjectBase & V, + const Eigen::PlainObjectBase & F, + int rays_total, + int rays_minimum, + bool facet_wise, + bool use_parity, + bool is_verbose, + Eigen::PlainObjectBase & I, + Eigen::PlainObjectBase & C) +{ + using namespace Eigen; + using namespace std; + assert(F.cols() == 3); + assert(V.cols() == 3); + + // number of faces + const int m = F.rows(); + + MatrixXi FF = F; + if (facet_wise) { + C.resize(m); + for (int i = 0; i < m; ++i) C(i) = i; + + } else { + if (is_verbose) cout << "extracting patches... "; + bfs_orient(F,FF,C); + } + if (is_verbose) cout << (C.maxCoeff() + 1) << " components. "; + + // number of patches + const int num_cc = C.maxCoeff()+1; + + // Init Embree + EmbreeIntersector ei; + ei.init(V.template cast(),FF); + + // face normal + MatrixXd N; + per_face_normals(V,FF,N); + + // face area + Matrix A; + doublearea(V,FF,A); + double area_total = A.sum(); + + // determine number of rays per component according to its area + VectorXd area_per_component; + area_per_component.setZero(num_cc); + for (int f = 0; f < m; ++f) + { + area_per_component(C(f)) += A(f); + } + VectorXi num_rays_per_component(num_cc); + for (int c = 0; c < num_cc; ++c) + { + num_rays_per_component(c) = max(static_cast(rays_total * area_per_component(c) / area_total), rays_minimum); + } + rays_total = num_rays_per_component.sum(); + + // generate all the rays + if (is_verbose) cout << "generating rays... "; + uniform_real_distribution rdist; + mt19937 prng; + prng.seed(time(nullptr)); + vector ray_face; + vector ray_ori; + vector ray_dir; + ray_face.reserve(rays_total); + ray_ori .reserve(rays_total); + ray_dir .reserve(rays_total); + for (int c = 0; c < num_cc; ++c) + { + if (area_per_component[c] == 0) + { + continue; + } + vector CF; // set of faces per component + vector CF_area; + for (int f = 0; f < m; ++f) + { + if (C(f)==c) + { + CF.push_back(f); + CF_area.push_back(A(f)); + } + } + // discrete distribution for random selection of faces with probability proportional to their areas + discrete_distribution ddist(CF.size(), 0, CF.size(), [&](double i){ return CF_area[static_cast(i)]; }); // simple ctor of (Iter, Iter) not provided by the stupid VC11/12 + for (int i = 0; i < num_rays_per_component[c]; ++i) + { + int f = CF[ddist(prng)]; // select face with probability proportional to face area + float s = rdist(prng); // random barycentric coordinate (reference: Generating Random Points in Triangles [Turk, Graphics Gems I 1990]) + float t = rdist(prng); + float sqrt_t = sqrtf(t); + float a = 1 - sqrt_t; + float b = (1 - s) * sqrt_t; + float c = s * sqrt_t; + Vector3f p = a * V.row(FF(f,0)).template cast().eval() // be careful with the index!!! + + b * V.row(FF(f,1)).template cast().eval() + + c * V.row(FF(f,2)).template cast().eval(); + Vector3f n = N.row(f).cast(); + if (n.isZero()) continue; + // random direction in hemisphere around n (avoid too grazing angle) + Vector3f d; + while (true) { + d = random_dir().cast(); + float ndotd = n.dot(d); + if (fabsf(ndotd) < 0.1f) + { + continue; + } + if (ndotd < 0) + { + d *= -1.0f; + } + break; + } + ray_face.push_back(f); + ray_ori .push_back(p); + ray_dir .push_back(d); + + if (is_verbose && ray_face.size() % (rays_total / 10) == 0) cout << "."; + } + } + if (is_verbose) cout << ray_face.size() << " rays. "; + + // per component voting: first=front, second=back + vector> C_vote_distance(num_cc, make_pair(0, 0)); // sum of distance between ray origin and intersection + vector> C_vote_infinity(num_cc, make_pair(0, 0)); // number of rays reaching infinity + vector> C_vote_parity(num_cc, make_pair(0, 0)); // sum of parity count for each ray + + if (is_verbose) cout << "shooting rays... "; +#pragma omp parallel for + for (int i = 0; i < (int)ray_face.size(); ++i) + { + int f = ray_face[i]; + Vector3f o = ray_ori [i]; + Vector3f d = ray_dir [i]; + int c = C(f); + + // shoot ray toward front & back + vector hits_front; + vector hits_back; + int num_rays_front; + int num_rays_back; + ei.intersectRay(o, d, hits_front, num_rays_front); + ei.intersectRay(o, -d, hits_back , num_rays_back ); + if (!hits_front.empty() && hits_front[0].id == f) hits_front.erase(hits_front.begin()); + if (!hits_back .empty() && hits_back [0].id == f) hits_back .erase(hits_back .begin()); + + if (use_parity) { +#pragma omp atomic + C_vote_parity[c].first += hits_front.size() % 2; +#pragma omp atomic + C_vote_parity[c].second += hits_back .size() % 2; + + } else { + if (hits_front.empty()) + { +#pragma omp atomic + C_vote_infinity[c].first++; + } else { +#pragma omp atomic + C_vote_distance[c].first += hits_front[0].t; + } + + if (hits_back.empty()) + { +#pragma omp atomic + C_vote_infinity[c].second++; + } else { +#pragma omp atomic + C_vote_distance[c].second += hits_back[0].t; + } + } + } + + I.resize(m); + for(int f = 0; f < m; ++f) + { + int c = C(f); + if (use_parity) { + I(f) = C_vote_parity[c].first > C_vote_parity[c].second ? 1 : 0; // Ideally, parity for the front/back side should be 1/0 (i.e., parity sum for all rays should be smaller on the front side) + + } else { + I(f) = (C_vote_infinity[c].first == C_vote_infinity[c].second && C_vote_distance[c].first < C_vote_distance[c].second) || + C_vote_infinity[c].first < C_vote_infinity[c].second + ? 1 : 0; + } + // To account for the effect of bfs_orient + if (F.row(f) != FF.row(f)) + I(f) = 1 - I(f); + } + if (is_verbose) cout << "done!" << endl; +} + +template < + typename DerivedV, + typename DerivedF, + typename DerivedFF, + typename DerivedI> +IGL_INLINE void igl::embree::reorient_facets_raycast( + const Eigen::PlainObjectBase & V, + const Eigen::PlainObjectBase & F, + Eigen::PlainObjectBase & FF, + Eigen::PlainObjectBase & I) +{ + const int rays_total = F.rows()*100; + const int rays_minimum = 10; + const bool facet_wise = false; + const bool use_parity = false; + const bool is_verbose = false; + Eigen::VectorXi C; + reorient_facets_raycast( + V,F,rays_total,rays_minimum,facet_wise,use_parity,is_verbose,I,C); + // Conservative in case FF = F + FF.conservativeResize(F.rows(),F.cols()); + for(int i = 0;i, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::embree::reorient_facets_raycast, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, int, int, bool, bool, bool, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::embree::reorient_facets_raycast, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, int, int, bool, bool, bool, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/embree/reorient_facets_raycast.h b/src/external/libigl-2.3.0/include/igl/embree/reorient_facets_raycast.h new file mode 100644 index 000000000..a43efac94 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/embree/reorient_facets_raycast.h @@ -0,0 +1,73 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_EMBREE_REORIENT_FACETS_RAYCAST_H +#define IGL_EMBREE_REORIENT_FACETS_RAYCAST_H +#include "../igl_inline.h" +#include +namespace igl +{ + namespace embree + { + // Orient each component (identified by C) of a mesh (V,F) using ambient + // occlusion such that the front side is less occluded than back side, as + // described in "A Simple Method for Correcting Facet Orientations in + // Polygon Meshes Based on Ray Casting" [Takayama et al. 2014]. + // + // Inputs: + // V #V by 3 list of vertex positions + // F #F by 3 list of triangle indices + // rays_total Total number of rays that will be shot + // rays_minimum Minimum number of rays that each patch should receive + // facet_wise Decision made for each face independently, no use of patches + // (i.e., each face is treated as a patch) + // use_parity Use parity mode + // is_verbose Verbose output to cout + // Outputs: + // I #F list of whether face has been flipped + // C #F list of patch ID (output of bfs_orient > manifold patches) + template < + typename DerivedV, + typename DerivedF, + typename DerivedI, + typename DerivedC> + IGL_INLINE void reorient_facets_raycast( + const Eigen::PlainObjectBase & V, + const Eigen::PlainObjectBase & F, + int rays_total, + int rays_minimum, + bool facet_wise, + bool use_parity, + bool is_verbose, + Eigen::PlainObjectBase & I, + Eigen::PlainObjectBase & C); + // Outputs: + // FF #F by 3 list of reoriented faces + // Defaults: + // rays_total = F.rows()*100; + // rays_minimum = 10; + // facet_wise = false; + // use_parity = false; + // is_verbose = false; + template < + typename DerivedV, + typename DerivedF, + typename DerivedFF, + typename DerivedI> + IGL_INLINE void reorient_facets_raycast( + const Eigen::PlainObjectBase & V, + const Eigen::PlainObjectBase & F, + Eigen::PlainObjectBase & FF, + Eigen::PlainObjectBase & I); + } +}; + +#ifndef IGL_STATIC_LIBRARY +# include "reorient_facets_raycast.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/embree/shape_diameter_function.cpp b/src/external/libigl-2.3.0/include/igl/embree/shape_diameter_function.cpp new file mode 100644 index 000000000..3b0be489e --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/embree/shape_diameter_function.cpp @@ -0,0 +1,69 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "shape_diameter_function.h" +#include "../shape_diameter_function.h" +#include "EmbreeIntersector.h" +#include "../Hit.h" + +template < + typename DerivedP, + typename DerivedN, + typename DerivedS > +IGL_INLINE void igl::embree::shape_diameter_function( + const igl::embree::EmbreeIntersector & ei, + const Eigen::PlainObjectBase & P, + const Eigen::PlainObjectBase & N, + const int num_samples, + Eigen::PlainObjectBase & S) +{ + const auto & shoot_ray = [&ei]( + const Eigen::Vector3f& s, + const Eigen::Vector3f& dir)->double + { + igl::Hit hit; + const float tnear = 1e-4f; + if(ei.intersectRay(s,dir,hit,tnear)) + { + return hit.t; + }else + { + return std::numeric_limits::infinity(); + } + }; + return igl::shape_diameter_function(shoot_ray,P,N,num_samples,S); +} + +template < + typename DerivedV, + typename DerivedF, + typename DerivedP, + typename DerivedN, + typename DerivedS > +IGL_INLINE void igl::embree::shape_diameter_function( + const Eigen::PlainObjectBase & V, + const Eigen::PlainObjectBase & F, + const Eigen::PlainObjectBase & P, + const Eigen::PlainObjectBase & N, + const int num_samples, + Eigen::PlainObjectBase & S) +{ + using namespace Eigen; + EmbreeIntersector ei; + ei.init(V.template cast(),F.template cast()); + shape_diameter_function(ei,P,N,num_samples,S); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +template void igl::embree::shape_diameter_function, Eigen::Matrix, Eigen::Matrix >(igl::embree::EmbreeIntersector const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, int, Eigen::PlainObjectBase >&); +template void igl::embree::shape_diameter_function, Eigen::Matrix, Eigen::Matrix >(igl::embree::EmbreeIntersector const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, int, Eigen::PlainObjectBase >&); +template void igl::embree::shape_diameter_function, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, int, Eigen::PlainObjectBase >&); +template void igl::embree::shape_diameter_function, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, int, Eigen::PlainObjectBase >&); +template void igl::embree::shape_diameter_function, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, int, Eigen::PlainObjectBase >&); +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/embree/shape_diameter_function.h b/src/external/libigl-2.3.0/include/igl/embree/shape_diameter_function.h new file mode 100644 index 000000000..c18922d28 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/embree/shape_diameter_function.h @@ -0,0 +1,60 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_EMBREE_SHAPE_DIAMETER_FUNCTION_H +#define IGL_EMBREE_SHAPE_DIAMETER_FUNCTION_H +#include "../igl_inline.h" +#include +namespace igl +{ + namespace embree + { + // Forward define + class EmbreeIntersector; + // Compute shape diamter function per given point + // + // Inputs: + // ei EmbreeIntersector containing (V,F) + // P #P by 3 list of origin points + // N #P by 3 list of origin normals + // Outputs: + // S #P list of shape diamater function values between bounding box + // diagonal (perfect sphere) and 0 (perfect needle hook) + // + template < + typename DerivedP, + typename DerivedN, + typename DerivedS > + IGL_INLINE void shape_diameter_function( + const EmbreeIntersector & ei, + const Eigen::PlainObjectBase & P, + const Eigen::PlainObjectBase & N, + const int num_samples, + Eigen::PlainObjectBase & S); + // Wrapper which builds new EmbreeIntersector for (V,F). That's expensive so + // avoid this if repeatedly calling. + template < + typename DerivedV, + typename DerivedF, + typename DerivedP, + typename DerivedN, + typename DerivedS > + IGL_INLINE void shape_diameter_function( + const Eigen::PlainObjectBase & V, + const Eigen::PlainObjectBase & F, + const Eigen::PlainObjectBase & P, + const Eigen::PlainObjectBase & N, + const int num_samples, + Eigen::PlainObjectBase & S); + } +}; +#ifndef IGL_STATIC_LIBRARY +# include "shape_diameter_function.cpp" +#endif + +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/embree/unproject_in_mesh.cpp b/src/external/libigl-2.3.0/include/igl/embree/unproject_in_mesh.cpp new file mode 100644 index 000000000..79a24a0ab --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/embree/unproject_in_mesh.cpp @@ -0,0 +1,55 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "unproject_in_mesh.h" +#include "EmbreeIntersector.h" +#include "../unproject_ray.h" +#include "../unproject_in_mesh.h" +#include + +template +IGL_INLINE int igl::embree::unproject_in_mesh( + const Eigen::Vector2f& pos, + const Eigen::Matrix4f& model, + const Eigen::Matrix4f& proj, + const Eigen::Vector4f& viewport, + const EmbreeIntersector & ei, + Eigen::PlainObjectBase & obj, + std::vector & hits) +{ + using namespace std; + using namespace Eigen; + const auto & shoot_ray = [&ei]( + const Eigen::Vector3f& s, + const Eigen::Vector3f& dir, + std::vector & hits) + { + int num_rays_shot; + ei.intersectRay(s,dir,hits,num_rays_shot); + }; + return igl::unproject_in_mesh(pos,model,proj,viewport,shoot_ray,obj,hits); +} + +template +IGL_INLINE int igl::embree::unproject_in_mesh( + const Eigen::Vector2f& pos, + const Eigen::Matrix4f& model, + const Eigen::Matrix4f& proj, + const Eigen::Vector4f& viewport, + const EmbreeIntersector & ei, + Eigen::PlainObjectBase & obj) +{ + std::vector hits; + return unproject_in_mesh(pos,model,proj,viewport,ei,obj,hits); +} + + +#ifdef IGL_STATIC_LIBRARY +template int igl::embree::unproject_in_mesh >(Eigen::Matrix const&, Eigen::Matrix const&, Eigen::Matrix const&, Eigen::Matrix const&, igl::embree::EmbreeIntersector const&, Eigen::PlainObjectBase >&, std::vector >&); +template int igl::embree::unproject_in_mesh >(Eigen::Matrix const&, Eigen::Matrix const&, Eigen::Matrix const&, Eigen::Matrix const&, igl::embree::EmbreeIntersector const&, Eigen::PlainObjectBase >&, std::vector >&); +template int igl::embree::unproject_in_mesh >(Eigen::Matrix const&, Eigen::Matrix const&, Eigen::Matrix const&, Eigen::Matrix const&, igl::embree::EmbreeIntersector const&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/embree/unproject_in_mesh.h b/src/external/libigl-2.3.0/include/igl/embree/unproject_in_mesh.h new file mode 100644 index 000000000..707c1e625 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/embree/unproject_in_mesh.h @@ -0,0 +1,72 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_EMBREE_UNPROJECT_IN_MESH +#define IGL_EMBREE_UNPROJECT_IN_MESH +#include +#include + +#include +#include "../Hit.h" + +namespace igl +{ + namespace embree + { + // Forward define + class EmbreeIntersector; + + // Unproject a screen location (using current opengl viewport, projection, and + // model view) to a 3D position _inside_ a given mesh. If the ray through the + // given screen location (x,y) _hits_ the mesh more than twice then the 3D + // midpoint between the first two hits is return. If it hits once, then that + // point is return. If it does not hit the mesh then obj is not set. + // + // + // Inputs: + // pos screen space coordinates + // model model matrix + // proj projection matrix + // viewport vieweport vector + // ei EmbreeIntersector containing (V,F) + // Outputs: + // obj 3d unprojected mouse point in mesh + // hits vector of embree hits + // Returns number of hits + // + // Note: Previous prototype did not require model, proj, and viewport. This + // has been removed. Instead replace with: + // + // Eigen::Matrix4f model,proj; + // Eigen::Vector4f viewport; + // igl::opengl2::model_proj_viewport(model,proj,viewport); + // igl::embree::unproject_in_mesh(Vector2f(x,y),model,proj,viewport,ei,obj,hits); + // + template < typename Derivedobj> + IGL_INLINE int unproject_in_mesh( + const Eigen::Vector2f& pos, + const Eigen::Matrix4f& model, + const Eigen::Matrix4f& proj, + const Eigen::Vector4f& viewport, + const EmbreeIntersector & ei, + Eigen::PlainObjectBase & obj, + std::vector & hits); + template < typename Derivedobj> + IGL_INLINE int unproject_in_mesh( + const Eigen::Vector2f& pos, + const Eigen::Matrix4f& model, + const Eigen::Matrix4f& proj, + const Eigen::Vector4f& viewport, + const EmbreeIntersector & ei, + Eigen::PlainObjectBase & obj); + + } +} +#ifndef IGL_STATIC_LIBRARY +# include "unproject_in_mesh.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/embree/unproject_onto_mesh.cpp b/src/external/libigl-2.3.0/include/igl/embree/unproject_onto_mesh.cpp new file mode 100644 index 000000000..a9d336690 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/embree/unproject_onto_mesh.cpp @@ -0,0 +1,59 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Daniele Panozzo +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "unproject_onto_mesh.h" +#include "EmbreeIntersector.h" +#include "../unproject_onto_mesh.h" +#include + +IGL_INLINE bool igl::embree::unproject_onto_mesh( + const Eigen::Vector2f& pos, + const Eigen::MatrixXi& F, + const Eigen::Matrix4f& model, + const Eigen::Matrix4f& proj, + const Eigen::Vector4f& viewport, + const EmbreeIntersector & ei, + int& fid, + Eigen::Vector3f& bc) +{ + using namespace std; + using namespace Eigen; + const auto & shoot_ray = [&ei]( + const Eigen::Vector3f& s, + const Eigen::Vector3f& dir, + igl::Hit & hit)->bool + { + return ei.intersectRay(s,dir,hit); + }; + return igl::unproject_onto_mesh(pos,model,proj,viewport,shoot_ray,fid,bc); +} + +IGL_INLINE bool igl::embree::unproject_onto_mesh( + const Eigen::Vector2f& pos, + const Eigen::MatrixXi& F, + const Eigen::Matrix4f& model, + const Eigen::Matrix4f& proj, + const Eigen::Vector4f& viewport, + const EmbreeIntersector & ei, + int& fid, + int& vid) +{ + Eigen::Vector3f bc; + if(!igl::embree::unproject_onto_mesh(pos,F,model,proj,viewport,ei,fid,bc)) + { + return false; + } + int i; + bc.maxCoeff(&i); + vid = F(fid,i); + return true; +} + + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +#endif diff --git a/src/external/libigl-2.3.0/include/igl/embree/unproject_onto_mesh.h b/src/external/libigl-2.3.0/include/igl/embree/unproject_onto_mesh.h new file mode 100644 index 000000000..db0a2e0cb --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/embree/unproject_onto_mesh.h @@ -0,0 +1,73 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Daniele Panozzo +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_EMBREE_UNPROJECT_ONTO_MESH_H +#define IGL_EMBREE_UNPROJECT_ONTO_MESH_H +#include +#include + +#include + +namespace igl +{ + namespace embree + { + // Forward define + class EmbreeIntersector; + // Unproject a screen location (using the given model, proj and viewport) to find + // the first hit on a mesh. + // + // Inputs: + // pos screen space coordinates + // F #F by 3 face matrix + // model model matrix + // proj projection matrix + // viewport vieweport vector + // ei EmbreeIntersector containing (V,F) + // Outputs: + // fid id of the first face hit + // bc barycentric coordinates of hit + // Returns true if there is a hit + IGL_INLINE bool unproject_onto_mesh( + const Eigen::Vector2f& pos, + const Eigen::MatrixXi& F, + const Eigen::Matrix4f& model, + const Eigen::Matrix4f& proj, + const Eigen::Vector4f& viewport, + const EmbreeIntersector & ei, + int& fid, + Eigen::Vector3f& bc); + + // Unproject a screen location (using the given model, proj and viewport) to find + // the first face on the mesh and the closest vertex + // + // Inputs: + // pos screen space coordinates + // F #F by 3 face matrix + // model model matrix + // proj projection matrix + // viewport vieweport vector + // ei EmbreeIntersector containing (V,F) + // Outputs: + // fid id of the first face hit + // vid vertex id of the closest vertex hit + // Returns true if there is a hit + IGL_INLINE bool unproject_onto_mesh( + const Eigen::Vector2f& pos, + const Eigen::MatrixXi& F, + const Eigen::Matrix4f& model, + const Eigen::Matrix4f& proj, + const Eigen::Vector4f& viewport, + const EmbreeIntersector & ei, + int& fid, + int& vid); + } +} +#ifndef IGL_STATIC_LIBRARY +# include "unproject_onto_mesh.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/euler_characteristic.cpp b/src/external/libigl-2.3.0/include/igl/euler_characteristic.cpp new file mode 100644 index 000000000..c3ca6303b --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/euler_characteristic.cpp @@ -0,0 +1,46 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Michael Rabinovich +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "euler_characteristic.h" + +#include "edge_topology.h" +#include "edges.h" + +template +IGL_INLINE int igl::euler_characteristic( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F) +{ + + int euler_v = V.rows(); + Eigen::MatrixXi EV, FE, EF; + igl::edge_topology(V, F, EV, FE, EF); + int euler_e = EV.rows(); + int euler_f = F.rows(); + + int euler_char = euler_v - euler_e + euler_f; + return euler_char; + +} + +template +IGL_INLINE int igl::euler_characteristic( + const Eigen::MatrixBase & F) +{ + const int nf = F.rows(); + const int nv = F.maxCoeff()+1; + Eigen::Matrix E; + edges(F,E); + const int ne = E.rows(); + return nv - ne + nf; +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +template int igl::euler_characteristic, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&); +template int igl::euler_characteristic >(Eigen::MatrixBase > const&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/euler_characteristic.h b/src/external/libigl-2.3.0/include/igl/euler_characteristic.h new file mode 100644 index 000000000..9a2f33edc --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/euler_characteristic.h @@ -0,0 +1,46 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Michael Rabinovich +// Copyright (C) 2017 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_EULER_CHARACTERISTIC_H +#define IGL_EULER_CHARACTERISTIC_H +#include "igl_inline.h" + +#include +#include +#include +namespace igl +{ + // Computes the Euler characteristic of a given mesh (V,F) + // + // Inputs: + // F #F by dim list of mesh faces (must be triangles) + // Returns An int containing the Euler characteristic + template + IGL_INLINE int euler_characteristic( + const Eigen::MatrixBase & F); + + // Computes the Euler characteristic of a given mesh (V,F) + // Templates: + // Scalar should be a floating point number type + // Index should be an integer type + // Inputs: + // V #V by dim list of mesh vertex positions + // F #F by dim list of mesh faces (must be triangles) + // Returns An int containing the Euler characteristic + template + IGL_INLINE int euler_characteristic( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F); + +} + +#ifndef IGL_STATIC_LIBRARY +# include "euler_characteristic.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/exact_geodesic.cpp b/src/external/libigl-2.3.0/include/igl/exact_geodesic.cpp new file mode 100644 index 000000000..b758714f5 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/exact_geodesic.cpp @@ -0,0 +1,3224 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2018 Zhongshi Jiang +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +#include "exact_geodesic.h" + +//Copyright (C) 2008 Danil Kirsanov, MIT License +//Code from https://code.google.com/archive/p/geodesic/ +// Compiled into a single file by Zhongshi Jiang + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +namespace igl{ +namespace geodesic{ + +//#include "geodesic_constants_and_simple_functions.h" + +//double const GEODESIC_INF = std::numeric_limits::max(); +double const GEODESIC_INF = 1e100; + +//in order to avoid numerical problems with "infinitely small" intervals, +//we drop all the intervals smaller than SMALLEST_INTERVAL_RATIO*edge_length +double const SMALLEST_INTERVAL_RATIO = 1e-6; +//double const SMALL_EPSILON = 1e-10; + + +inline double cos_from_edges(double const a, //compute the cosine of the angle given the lengths of the edges + double const b, + double const c) +{ + assert(a>1e-50); + assert(b>1e-50); + assert(c>1e-50); + + double result = (b*b + c*c - a*a)/(2.0*b*c); + result = std::max(result, -1.0); + return std::min(result, 1.0); +} + +inline double angle_from_edges(double const a, //compute the cosine of the angle given the lengths of the edges + double const b, + double const c) +{ + return acos(cos_from_edges(a,b,c)); +} + +template +inline bool read_mesh_from_file(char* filename, + Points& points, + Faces& faces) +{ + std::ifstream file(filename); + assert(file.is_open()); + if(!file.is_open()) return false; + + unsigned num_points; + file >> num_points; + assert(num_points>=3); + + unsigned num_faces; + file >> num_faces; + + points.resize(num_points*3); + for(typename Points::iterator i=points.begin(); i!=points.end(); ++i) + { + file >> *i; + } + + faces.resize(num_faces*3); + for(typename Faces::iterator i=faces.begin(); i!=faces.end(); ++i) + { + file >> *i; + } + file.close(); + + return true; +} + +// #include "geodesic_memory" +template //quickly allocates multiple elements of a given type; no deallocation +class SimlpeMemoryAllocator +{ +public: + typedef T* pointer; + + SimlpeMemoryAllocator(unsigned block_size = 0, + unsigned max_number_of_blocks = 0) + { + reset(block_size, + max_number_of_blocks); + }; + + ~SimlpeMemoryAllocator(){}; + + void reset(unsigned block_size, + unsigned max_number_of_blocks) + { + m_block_size = block_size; + m_max_number_of_blocks = max_number_of_blocks; + + + m_current_position = 0; + + m_storage.reserve(max_number_of_blocks); + m_storage.resize(1); + m_storage[0].resize(block_size); + }; + + pointer allocate(unsigned const n) //allocate n units + { + assert(n < m_block_size); + + if(m_current_position + n >= m_block_size) + { + m_storage.push_back( std::vector() ); + m_storage.back().resize(m_block_size); + m_current_position = 0; + } + pointer result = & m_storage.back()[m_current_position]; + m_current_position += n; + + return result; + }; +private: + std::vector > m_storage; + unsigned m_block_size; //size of a single block + unsigned m_max_number_of_blocks; //maximum allowed number of blocks + unsigned m_current_position; //first unused element inside the current block +}; + + +template //quickly allocates and deallocates single elements of a given type +class MemoryAllocator +{ +public: + typedef T* pointer; + + MemoryAllocator(unsigned block_size = 1024, + unsigned max_number_of_blocks = 1024) + { + reset(block_size, + max_number_of_blocks); + }; + + ~MemoryAllocator(){}; + + void clear() + { + reset(m_block_size, + m_max_number_of_blocks); + } + + void reset(unsigned block_size, + unsigned max_number_of_blocks) + { + m_block_size = block_size; + m_max_number_of_blocks = max_number_of_blocks; + + assert(m_block_size > 0); + assert(m_max_number_of_blocks > 0); + + m_current_position = 0; + + m_storage.reserve(max_number_of_blocks); + m_storage.resize(1); + m_storage[0].resize(block_size); + + m_deleted.clear(); + m_deleted.reserve(2*block_size); + }; + + pointer allocate() //allocates single unit of memory + { + pointer result; + if(m_deleted.empty()) + { + if(m_current_position + 1 >= m_block_size) + { + m_storage.push_back( std::vector() ); + m_storage.back().resize(m_block_size); + m_current_position = 0; + } + result = & m_storage.back()[m_current_position]; + ++m_current_position; + } + else + { + result = m_deleted.back(); + m_deleted.pop_back(); + } + + return result; + }; + + void deallocate(pointer p) //allocate n units + { + if(m_deleted.size() < m_deleted.capacity()) + { + m_deleted.push_back(p); + } + }; + +private: + std::vector > m_storage; + unsigned m_block_size; //size of a single block + unsigned m_max_number_of_blocks; //maximum allowed number of blocks + unsigned m_current_position; //first unused element inside the current block + + std::vector m_deleted; //pointers to deleted elemets +}; + + +class OutputBuffer +{ +public: + OutputBuffer(): + m_num_bytes(0) + {} + + void clear() + { + m_num_bytes = 0; + m_buffer = std::shared_ptr(); + } + + template + T* allocate(unsigned n) + { + double wanted = n*sizeof(T); + if(wanted > m_num_bytes) + { + unsigned new_size = (unsigned) ceil(wanted / (double)sizeof(double)); + m_buffer = std::shared_ptr(new double[new_size]); + m_num_bytes = new_size*sizeof(double); + } + + return (T*)m_buffer.get(); + } + + template + T* get() + { + return (T*)m_buffer.get(); + } + + template + unsigned capacity() + { + return (unsigned)floor((double)m_num_bytes/(double)sizeof(T)); + }; + +private: + + std::shared_ptr m_buffer; + unsigned m_num_bytes; +}; + + + + +class Vertex; +class Edge; +class Face; +class Mesh; +class MeshElementBase; + +typedef Vertex* vertex_pointer; +typedef Edge* edge_pointer; +typedef Face* face_pointer; +typedef Mesh* mesh_pointer; +typedef MeshElementBase* base_pointer; + +template //simple vector that stores info about mesh references +class SimpleVector //for efficiency, it uses an outside memory allocator +{ +public: + SimpleVector(): + m_size(0), + m_begin(NULL) + {}; + + typedef Data* iterator; + + unsigned size(){return m_size;}; + iterator begin(){return m_begin;}; + iterator end(){return m_begin + m_size;}; + + template + void set_allocation(DataPointer begin, unsigned size) + { + assert(begin != NULL || size == 0); + m_size = size; + m_begin = (iterator)begin; + } + + Data& operator[](unsigned i) + { + assert(i < m_size); + return *(m_begin + i); + } + + void clear() + { + m_size = 0; + m_begin = NULL; + } + +private: + unsigned m_size; + Data* m_begin; +}; + +enum PointType +{ + VERTEX, + EDGE, + FACE, + UNDEFINED_POINT +}; + +class MeshElementBase //prototype of vertices, edges and faces +{ +public: + typedef SimpleVector vertex_pointer_vector; + typedef SimpleVector edge_pointer_vector; + typedef SimpleVector face_pointer_vector; + + MeshElementBase(): + m_id(0), + m_type(UNDEFINED_POINT) + {}; + + vertex_pointer_vector& adjacent_vertices(){return m_adjacent_vertices;}; + edge_pointer_vector& adjacent_edges(){return m_adjacent_edges;}; + face_pointer_vector& adjacent_faces(){return m_adjacent_faces;}; + + unsigned& id(){return m_id;}; + PointType type(){return m_type;}; + +protected: + vertex_pointer_vector m_adjacent_vertices; //list of the adjacent vertices + edge_pointer_vector m_adjacent_edges; //list of the adjacent edges + face_pointer_vector m_adjacent_faces; //list of the adjacent faces + + unsigned m_id; //unique id + PointType m_type; //vertex, edge or face +}; + +class Point3D //point in 3D and corresponding operations +{ +public: + Point3D(){}; + Point3D(Point3D* p) + { + x() = p->x(); + y() = p->y(); + z() = p->z(); + }; + + double* xyz(){return m_coordinates;}; + double& x(){return *m_coordinates;}; + double& y(){return *(m_coordinates+1);}; + double& z(){return *(m_coordinates+2);}; + + void set(double new_x, double new_y, double new_z) + { + x() = new_x; + y() = new_y; + z() = new_z; + } + + void set(double* data) + { + x() = *data; + y() = *(data+1); + z() = *(data+2); + } + + double distance(double* v) + { + double dx = m_coordinates[0] - v[0]; + double dy = m_coordinates[1] - v[1]; + double dz = m_coordinates[2] - v[2]; + + return sqrt(dx*dx + dy*dy + dz*dz); + }; + + double distance(Point3D* v) + { + return distance(v->xyz()); + }; + + void add(Point3D* v) + { + x() += v->x(); + y() += v->y(); + z() += v->z(); + }; + + void multiply(double v) + { + x() *= v; + y() *= v; + z() *= v; + }; + +private: + double m_coordinates[3]; //xyz +}; + +class Vertex: public MeshElementBase, public Point3D +{ +public: + Vertex() + { + m_type = VERTEX; + }; + + ~Vertex(){}; + + bool& saddle_or_boundary(){return m_saddle_or_boundary;}; +private: + //this flag speeds up exact geodesic algorithm + bool m_saddle_or_boundary; //it is true if total adjacent angle is larger than 2*PI or this vertex belongs to the mesh boundary +}; + + +class Face: public MeshElementBase +{ +public: + Face() + { + m_type = FACE; + }; + + ~Face(){}; + + edge_pointer opposite_edge(vertex_pointer v); + vertex_pointer opposite_vertex(edge_pointer e); + edge_pointer next_edge(edge_pointer e, vertex_pointer v); + + double vertex_angle(vertex_pointer v) + { + for(unsigned i=0; i<3; ++i) + { + if(adjacent_vertices()[i]->id() == v->id()) + { + return m_corner_angles[i]; + } + } + assert(0); + return 0; + } + + double* corner_angles(){return m_corner_angles;}; + +private: + double m_corner_angles[3]; //triangle angles in radians; angles correspond to vertices in m_adjacent_vertices +}; + +class Edge: public MeshElementBase +{ +public: + Edge() + { + m_type = EDGE; + }; + + ~Edge(){}; + + double& length(){return m_length;}; + + face_pointer opposite_face(face_pointer f) + { + if(adjacent_faces().size() == 1) + { + assert(adjacent_faces()[0]->id() == f->id()); + return NULL; + } + + assert(adjacent_faces()[0]->id() == f->id() || + adjacent_faces()[1]->id() == f->id()); + + return adjacent_faces()[0]->id() == f->id() ? + adjacent_faces()[1] : adjacent_faces()[0]; + }; + + vertex_pointer opposite_vertex(vertex_pointer v) + { + assert(belongs(v)); + + return adjacent_vertices()[0]->id() == v->id() ? + adjacent_vertices()[1] : adjacent_vertices()[0]; + }; + + bool belongs(vertex_pointer v) + { + return adjacent_vertices()[0]->id() == v->id() || + adjacent_vertices()[1]->id() == v->id(); + } + + bool is_boundary(){return adjacent_faces().size() == 1;}; + + vertex_pointer v0(){return adjacent_vertices()[0];}; + vertex_pointer v1(){return adjacent_vertices()[1];}; + + void local_coordinates(Point3D* point, + double& x, + double& y) + { + double d0 = point->distance(v0()); + if(d0 < 1e-50) + { + x = 0.0; + y = 0.0; + return; + } + + double d1 = point->distance(v1()); + if(d1 < 1e-50) + { + x = m_length; + y = 0.0; + return; + } + + x = m_length/2.0 + (d0*d0 - d1*d1)/(2.0*m_length); + y = sqrt(std::max(0.0, d0*d0 - x*x)); + return; + } + +private: + double m_length; //length of the edge +}; + +class SurfacePoint:public Point3D //point on the surface of the mesh +{ +public: + SurfacePoint(): + m_p(NULL) + {}; + + SurfacePoint(vertex_pointer v): //set the surface point in the vertex + SurfacePoint::Point3D(v), + m_p(v) + {}; + + SurfacePoint(face_pointer f): //set the surface point in the center of the face + m_p(f) + { + set(0,0,0); + add(f->adjacent_vertices()[0]); + add(f->adjacent_vertices()[1]); + add(f->adjacent_vertices()[2]); + multiply(1./3.); + }; + + SurfacePoint(edge_pointer e, //set the surface point in the middle of the edge + double a = 0.5): + m_p(e) + { + double b = 1 - a; + + vertex_pointer v0 = e->adjacent_vertices()[0]; + vertex_pointer v1 = e->adjacent_vertices()[1]; + + x() = b*v0->x() + a*v1->x(); + y() = b*v0->y() + a*v1->y(); + z() = b*v0->z() + a*v1->z(); + }; + + SurfacePoint(base_pointer g, + double x, + double y, + double z, + PointType t = UNDEFINED_POINT): + m_p(g) + { + set(x,y,z); + }; + + void initialize(SurfacePoint const& p) + { + *this = p; + } + + ~SurfacePoint(){}; + + PointType type(){return m_p ? m_p->type() : UNDEFINED_POINT;}; + base_pointer& base_element(){return m_p;}; +protected: + base_pointer m_p; //could be face, vertex or edge pointer +}; + +inline edge_pointer Face::opposite_edge(vertex_pointer v) +{ + for(unsigned i=0; i<3; ++i) + { + edge_pointer e = adjacent_edges()[i]; + if(!e->belongs(v)) + { + return e; + } + } + assert(0); + return NULL; +} + +inline vertex_pointer Face::opposite_vertex(edge_pointer e) +{ + for(unsigned i=0; i<3; ++i) + { + vertex_pointer v = adjacent_vertices()[i]; + if(!e->belongs(v)) + { + return v; + } + } + assert(0); + return NULL; +} + +inline edge_pointer Face::next_edge(edge_pointer e, vertex_pointer v) +{ + assert(e->belongs(v)); + + for(unsigned i=0; i<3; ++i) + { + edge_pointer next = adjacent_edges()[i]; + if(e->id() != next->id() && next->belongs(v)) + { + return next; + } + } + assert(0); + return NULL; +} + +struct HalfEdge //prototype of the edge; used for mesh construction +{ + unsigned face_id; + unsigned vertex_0; //adjacent vertices sorted by id value + unsigned vertex_1; //they are sorted, vertex_0 < vertex_1 +}; + +inline bool operator < (const HalfEdge &x, const HalfEdge &y) +{ + if(x.vertex_0 == y.vertex_0) + { + return x.vertex_1 < y.vertex_1; + } + else + { + return x.vertex_0 < y.vertex_0; + } +} + +inline bool operator != (const HalfEdge &x, const HalfEdge &y) +{ + return x.vertex_0 != y.vertex_0 || x.vertex_1 != y.vertex_1; +} + +inline bool operator == (const HalfEdge &x, const HalfEdge &y) +{ + return x.vertex_0 == y.vertex_0 && x.vertex_1 == y.vertex_1; +} + +struct edge_visible_from_source +{ + unsigned source; + edge_pointer edge; +}; + +class Mesh +{ +public: + Mesh() + {}; + + ~Mesh(){}; + + template + void initialize_mesh_data(unsigned num_vertices, + Points& p, + unsigned num_faces, + Faces& tri); //build mesh from regular point-triangle representation + + template + void initialize_mesh_data(Points& p, Faces& tri); //build mesh from regular point-triangle representation + + std::vector& vertices(){return m_vertices;}; + std::vector& edges(){return m_edges;}; + std::vector& faces(){return m_faces;}; + + unsigned closest_vertices(SurfacePoint* p, + std::vector* storage = NULL); //list vertices closest to the point + +private: + + void build_adjacencies(); //build internal structure of the mesh + bool verify(); //verifies connectivity of the mesh and prints some debug info + + typedef void* void_pointer; + void_pointer allocate_pointers(unsigned n) + { + return m_pointer_allocator.allocate(n); + } + + std::vector m_vertices; + std::vector m_edges; + std::vector m_faces; + + SimlpeMemoryAllocator m_pointer_allocator; //fast memory allocating for Face/Vertex/Edge cross-references +}; + +inline unsigned Mesh::closest_vertices(SurfacePoint* p, + std::vector* storage) +{ + assert(p->type() != UNDEFINED_POINT); + + if(p->type() == VERTEX) + { + if(storage) + { + storage->push_back(static_cast(p->base_element())); + } + return 1; + } + else if(p->type() == FACE) + { + if(storage) + { + vertex_pointer* vp= p->base_element()->adjacent_vertices().begin(); + storage->push_back(*vp); + storage->push_back(*(vp+1)); + storage->push_back(*(vp+2)); + } + return 2; + } + else if(p->type() == EDGE) //for edge include all 4 adjacent vertices + { + edge_pointer edge = static_cast(p->base_element()); + + if(storage) + { + storage->push_back(edge->adjacent_vertices()[0]); + storage->push_back(edge->adjacent_vertices()[1]); + + for(unsigned i = 0; i < edge->adjacent_faces().size(); ++i) + { + face_pointer face = edge->adjacent_faces()[i]; + storage->push_back(face->opposite_vertex(edge)); + } + } + return 2 + edge->adjacent_faces().size(); + } + + assert(0); + return 0; +} + +template +void Mesh::initialize_mesh_data(Points& p, Faces& tri) //build mesh from regular point-triangle representation +{ + assert(p.size() % 3 == 0); + unsigned const num_vertices = p.size() / 3; + assert(tri.size() % 3 == 0); + unsigned const num_faces = tri.size() / 3; + + initialize_mesh_data(num_vertices, p, num_faces, tri); +} + +template +void Mesh::initialize_mesh_data(unsigned num_vertices, + Points& p, + unsigned num_faces, + Faces& tri) +{ + unsigned const approximate_number_of_internal_pointers = (num_vertices + num_faces)*4; + unsigned const max_number_of_pointer_blocks = 100; + m_pointer_allocator.reset(approximate_number_of_internal_pointers, + max_number_of_pointer_blocks); + + m_vertices.resize(num_vertices); + for(unsigned i=0; iadjacent Faces + std::vector count(m_vertices.size()); //count adjacent vertices + for(unsigned i=0; iid(); + assert(vertex_id < m_vertices.size()); + count[vertex_id]++; + } + } + + for(unsigned i=0; iadjacent_faces()[count[v->id()]++] = &f; + } + } + + //find all edges + //i.e. find all half-edges, sort and combine them into edges + std::vector half_edges(m_faces.size()*3); + unsigned k = 0; + for(unsigned i=0; iid(); + unsigned vertex_id_2 = f.adjacent_vertices()[(j+1) % 3]->id(); + half_edges[k].vertex_0 = std::min(vertex_id_1, vertex_id_2); + half_edges[k].vertex_1 = std::max(vertex_id_1, vertex_id_2); + + k++; + } + } + std::sort(half_edges.begin(), half_edges.end()); + + unsigned number_of_edges = 1; + for(unsigned i=1; iadjacent Vertices and Faces + m_edges.resize(number_of_edges); + unsigned edge_id = 0; + for(unsigned i=0; idistance(e.adjacent_vertices()[1]); + assert(e.length() > 1e-100); //algorithm works well with non-degenerate meshes only + + if(i != half_edges.size()-1 && half_edges[i] == half_edges[i+1]) //double edge + { + e.adjacent_faces().set_allocation(allocate_pointers(2),2); + e.adjacent_faces()[0] = &m_faces[half_edges[i].face_id]; + e.adjacent_faces()[1] = &m_faces[half_edges[i+1].face_id]; + i += 2; + } + else //single edge + { + e.adjacent_faces().set_allocation(allocate_pointers(1),1); //one adjucent faces + e.adjacent_faces()[0] = &m_faces[half_edges[i].face_id]; + i += 1; + } + } + + // Vertices->adjacent Edges + std::fill(count.begin(), count.end(), 0); + for(unsigned i=0; iid()]++; + count[e.adjacent_vertices()[1]->id()]++; + } + for(unsigned i=0; iadjacent_edges()[count[v->id()]++] = &e; + } + } + + // Faces->adjacent Edges + for(unsigned i=0; iid()]<3); + f->adjacent_edges()[count[f->id()]++] = &e; + } + } + + //compute angles for the faces + for(unsigned i=0; ilength(); + } + + double angle = angle_from_edges(abc[0], abc[1], abc[2]); + assert(angle>1e-5); //algorithm works well with non-degenerate meshes only + + f.corner_angles()[j] = angle; + sum += angle; + } + assert(std::abs(sum - igl::PI) < 1e-5); //algorithm works well with non-degenerate meshes only + } + + //define m_turn_around_flag for vertices + std::vector total_vertex_angle(m_vertices.size()); + for(unsigned i=0; iid()] += f.corner_angles()[j]; + } + } + + for(unsigned i=0; i 2.0*igl::PI - 1e-5); + } + + for(unsigned i=0; isaddle_or_boundary() = true; + e.adjacent_vertices()[1]->saddle_or_boundary() = true; + } + } + + assert(verify()); +} + +inline bool Mesh::verify() //verifies connectivity of the mesh and prints some debug info +{ + // make sure that all vertices are mentioned at least once. + // though the loose vertex is not a bug, it most likely indicates that something is wrong with the mesh + std::vector map(m_vertices.size(), false); + for(unsigned i=0; iadjacent_vertices()[0]->id()] = true; + map[e->adjacent_vertices()[1]->id()] = true; + } + assert(std::find(map.begin(), map.end(), false) == map.end()); + + //make sure that the mesh is connected trough its edges + //if mesh has more than one connected component, it is most likely a bug + std::vector stack(1,&m_faces[0]); + stack.reserve(m_faces.size()); + + map.resize(m_faces.size()); + std::fill(map.begin(), map.end(), false); + map[0] = true; + + while(!stack.empty()) + { + face_pointer f = stack.back(); + stack.pop_back(); + + for(unsigned i=0; i<3; ++i) + { + edge_pointer e = f->adjacent_edges()[i]; + face_pointer f_adjacent = e->opposite_face(f); + if(f_adjacent && !map[f_adjacent->id()]) + { + map[f_adjacent->id()] = true; + stack.push_back(f_adjacent); + } + } + } + assert(std::find(map.begin(), map.end(), false) == map.end()); + + //print some mesh statistics that can be useful in debugging + // std::cout << "mesh has " << m_vertices.size() + // << " vertices, " << m_faces.size() + // << " faces, " << m_edges.size() + // << " edges\n"; + + unsigned total_boundary_edges = 0; + double longest_edge = 0; + double shortest_edge = 1e100; + for(unsigned i=0; iset(data); + unsigned type = (unsigned) data[3]; + unsigned id = (unsigned) data[4]; + + + if(type == 0) //vertex + { + point->base_element() = &mesh->vertices()[id]; + } + else if(type == 1) //edge + { + point->base_element() = &mesh->edges()[id]; + } + else //face + { + point->base_element() = &mesh->faces()[id]; + } +} + +inline void fill_surface_point_double(geodesic::SurfacePoint* point, + double* data, + long mesh_id) +{ + data[0] = point->x(); + data[1] = point->y(); + data[2] = point->z(); + data[4] = point->base_element()->id(); + + if(point->type() == VERTEX) //vertex + { + data[3] = 0; + } + else if(point->type() == EDGE) //edge + { + data[3] = 1; + } + else //face + { + data[3] = 2; + } +} + +class Interval; +class IntervalList; +typedef Interval* interval_pointer; +typedef IntervalList* list_pointer; + +class Interval //interval of the edge +{ +public: + + Interval(){}; + ~Interval(){}; + + enum DirectionType + { + FROM_FACE_0, + FROM_FACE_1, + FROM_SOURCE, + UNDEFINED_DIRECTION + }; + + double signal(double x) //geodesic distance function at point x + { + assert(x>=0.0 && x <= m_edge->length()); + + if(m_d == GEODESIC_INF) + { + return GEODESIC_INF; + } + else + { + double dx = x - m_pseudo_x; + if(m_pseudo_y == 0.0) + { + return m_d + std::abs(dx); + } + else + { + return m_d + sqrt(dx*dx + m_pseudo_y*m_pseudo_y); + } + } + } + + double max_distance(double end) + { + if(m_d == GEODESIC_INF) + { + return GEODESIC_INF; + } + else + { + double a = std::abs(m_start - m_pseudo_x); + double b = std::abs(end - m_pseudo_x); + + return a > b ? m_d + sqrt(a*a + m_pseudo_y*m_pseudo_y): + m_d + sqrt(b*b + m_pseudo_y*m_pseudo_y); + } + } + + void compute_min_distance(double stop) //compute min, given c,d theta, start, end. + { + assert(stop > m_start); + + if(m_d == GEODESIC_INF) + { + m_min = GEODESIC_INF; + } + else if(m_start > m_pseudo_x) + { + m_min = signal(m_start); + } + else if(stop < m_pseudo_x) + { + m_min = signal(stop); + } + else + { + assert(m_pseudo_y<=0); + m_min = m_d - m_pseudo_y; + } + } + //compare two intervals in the queue + bool operator()(interval_pointer const x, interval_pointer const y) const + { + if(x->min() != y->min()) + { + return x->min() < y->min(); + } + else if(x->start() != y->start()) + { + return x->start() < y->start(); + } + else + { + return x->edge()->id() < y->edge()->id(); + } + } + + double stop() //return the endpoint of the interval + { + return m_next ? m_next->start() : m_edge->length(); + } + + double hypotenuse(double a, double b) + { + return sqrt(a*a + b*b); + } + + void find_closest_point(double const x, + double const y, + double& offset, + double& distance); //find the point on the interval that is closest to the point (alpha, s) + + double& start(){return m_start;}; + double& d(){return m_d;}; + double& pseudo_x(){return m_pseudo_x;}; + double& pseudo_y(){return m_pseudo_y;}; + double& min(){return m_min;}; + interval_pointer& next(){return m_next;}; + edge_pointer& edge(){return m_edge;}; + DirectionType& direction(){return m_direction;}; + bool visible_from_source(){return m_direction == FROM_SOURCE;}; + unsigned& source_index(){return m_source_index;}; + + void initialize(edge_pointer edge, + SurfacePoint* point = NULL, + unsigned source_index = 0); + +protected: + double m_start; //initial point of the interval on the edge + double m_d; //distance from the source to the pseudo-source + double m_pseudo_x; //coordinates of the pseudo-source in the local coordinate system + double m_pseudo_y; //y-coordinate should be always negative + double m_min; //minimum distance on the interval + + interval_pointer m_next; //pointer to the next interval in the list + edge_pointer m_edge; //edge that the interval belongs to + unsigned m_source_index; //the source it belongs to + DirectionType m_direction; //where the interval is coming from +}; + +struct IntervalWithStop : public Interval +{ +public: + double& stop(){return m_stop;}; +protected: + double m_stop; +}; + +class IntervalList //list of the of intervals of the given edge +{ +public: + IntervalList(){m_first = NULL;}; + ~IntervalList(){}; + + void clear() + { + m_first = NULL; + }; + + void initialize(edge_pointer e) + { + m_edge = e; + m_first = NULL; + }; + + interval_pointer covering_interval(double offset) //returns the interval that covers the offset + { + assert(offset >= 0.0 && offset <= m_edge->length()); + + interval_pointer p = m_first; + while(p && p->stop() < offset) + { + p = p->next(); + } + + return p;// && p->start() <= offset ? p : NULL; + }; + + void find_closest_point(SurfacePoint* point, + double& offset, + double& distance, + interval_pointer& interval) + { + interval_pointer p = m_first; + distance = GEODESIC_INF; + interval = NULL; + + double x,y; + m_edge->local_coordinates(point, x, y); + + while(p) + { + if(p->min()find_closest_point(x, y, o, d); + if(d < distance) + { + distance = d; + offset = o; + interval = p; + } + } + p = p->next(); + } + }; + + unsigned number_of_intervals() + { + interval_pointer p = m_first; + unsigned count = 0; + while(p) + { + ++count; + p = p->next(); + } + return count; + } + + interval_pointer last() + { + interval_pointer p = m_first; + if(p) + { + while(p->next()) + { + p = p->next(); + } + } + return p; + } + + double signal(double x) + { + interval_pointer interval = covering_interval(x); + + return interval ? interval->signal(x) : GEODESIC_INF; + } + + interval_pointer& first(){return m_first;}; + edge_pointer& edge(){return m_edge;}; +private: + interval_pointer m_first; //pointer to the first member of the list + edge_pointer m_edge; //edge that owns this list +}; + +class SurfacePointWithIndex : public SurfacePoint +{ +public: + unsigned index(){return m_index;}; + + void initialize(SurfacePoint& p, unsigned index) + { + SurfacePoint::initialize(p); + m_index = index; + } + + bool operator()(SurfacePointWithIndex* x, SurfacePointWithIndex* y) const //used for sorting + { + assert(x->type() != UNDEFINED_POINT && y->type() !=UNDEFINED_POINT); + + if(x->type() != y->type()) + { + return x->type() < y->type(); + } + else + { + return x->base_element()->id() < y->base_element()->id(); + } + } + +private: + unsigned m_index; +}; + +class SortedSources : public std::vector +{ +private: + typedef std::vector sorted_vector_type; +public: + typedef sorted_vector_type::iterator sorted_iterator; + typedef std::pair sorted_iterator_pair; + + sorted_iterator_pair sources(base_pointer mesh_element) + { + m_search_dummy.base_element() = mesh_element; + + return equal_range(m_sorted.begin(), + m_sorted.end(), + &m_search_dummy, + m_compare_less); + } + + void initialize(std::vector& sources) //we initialize the sources by copie + { + resize(sources.size()); + m_sorted.resize(sources.size()); + for(unsigned i=0; ilength(); + if(std::abs(hs+hc) < local_epsilon) + { + if(rs<=m_start) + { + r = m_start; + d_out = signal(m_start) + std::abs(rs - m_start); + } + else if(rs>=end) + { + r = end; + d_out = signal(end) + fabs(end - rs); + } + else + { + r = rs; + d_out = signal(rs); + } + } + else + { + double ri = (rs*hc + hs*rc)/(hs+hc); + + if(riend) + { + r = end; + d_out = signal(end) + hypotenuse(end - rs, hs); + } + else + { + r = ri; + d_out = m_d + hypotenuse(rc - rs, hc + hs); + } + } + } + + +inline void Interval::initialize(edge_pointer edge, + SurfacePoint* source, + unsigned source_index) +{ + m_next = NULL; + //m_geodesic_previous = NULL; + m_direction = UNDEFINED_DIRECTION; + m_edge = edge; + m_source_index = source_index; + + m_start = 0.0; + //m_stop = edge->length(); + if(!source) + { + m_d = GEODESIC_INF; + m_min = GEODESIC_INF; + return; + } + m_d = 0; + + if(source->base_element()->type() == VERTEX) + { + if(source->base_element()->id() == edge->v0()->id()) + { + m_pseudo_x = 0.0; + m_pseudo_y = 0.0; + m_min = 0.0; + return; + } + else if(source->base_element()->id() == edge->v1()->id()) + { + m_pseudo_x = stop(); + m_pseudo_y = 0.0; + m_min = 0.0; + return; + } + } + + edge->local_coordinates(source, m_pseudo_x, m_pseudo_y); + m_pseudo_y = -m_pseudo_y; + + compute_min_distance(stop()); +} + + + +// #include "geodesic_algorithm_base.h" +class GeodesicAlgorithmBase +{ +public: + enum AlgorithmType + { + EXACT, + DIJKSTRA, + SUBDIVISION, + UNDEFINED_ALGORITHM + }; + + GeodesicAlgorithmBase(geodesic::Mesh* mesh): + m_type(UNDEFINED_ALGORITHM), + m_max_propagation_distance(1e100), + m_mesh(mesh) + {}; + + virtual ~GeodesicAlgorithmBase(){}; + + virtual void propagate(std::vector& sources, + double max_propagation_distance = GEODESIC_INF, //propagation algorithm stops after reaching the certain distance from the source + std::vector* stop_points = NULL) = 0; //or after ensuring that all the stop_points are covered + + virtual void trace_back(SurfacePoint& destination, //trace back piecewise-linear path + std::vector& path) = 0; + + void geodesic(SurfacePoint& source, + SurfacePoint& destination, + std::vector& path); //lazy people can find geodesic path with one function call + + void geodesic(std::vector& sources, + std::vector& destinations, + std::vector >& paths); //lazy people can find geodesic paths with one function call + + virtual unsigned best_source(SurfacePoint& point, //after propagation step is done, quickly find what source this point belongs to and what is the distance to this source + double& best_source_distance) = 0; + + virtual void print_statistics() //print info about timing and memory usage in the propagation step of the algorithm + { + std::cout << "propagation step took " << m_time_consumed << " seconds " << std::endl; + }; + + AlgorithmType type(){return m_type;}; + + virtual std::string name(); + + geodesic::Mesh* mesh(){return m_mesh;}; +protected: + + void set_stop_conditions(std::vector* stop_points, + double stop_distance); + double stop_distance() + { + return m_max_propagation_distance; + } + + AlgorithmType m_type; // type of the algorithm + + typedef std::pair stop_vertex_with_distace_type; + std::vector m_stop_vertices; // algorithm stops propagation after covering certain vertices + double m_max_propagation_distance; // or reaching the certain distance + + geodesic::Mesh* m_mesh; + + double m_time_consumed; //how much time does the propagation step takes + double m_propagation_distance_stopped; //at what distance (if any) the propagation algorithm stopped +}; + +inline double length(std::vector& path) +{ + double length = 0; + if(!path.empty()) + { + for(unsigned i=0; i& path) +{ + std::cout << "number of the points in the path = " << path.size() + << ", length of the path = " << length(path) + << std::endl; +} + +inline std::string GeodesicAlgorithmBase::name() +{ + switch(m_type) + { + case EXACT: + return "exact"; + case DIJKSTRA: + return "dijkstra"; + case SUBDIVISION: + return "subdivision"; + default: + case UNDEFINED_ALGORITHM: + return "undefined"; + } +} + +inline void GeodesicAlgorithmBase::geodesic(SurfacePoint& source, + SurfacePoint& destination, + std::vector& path) //lazy people can find geodesic path with one function call +{ + std::vector sources(1, source); + std::vector stop_points(1, destination); + double const max_propagation_distance = GEODESIC_INF; + + propagate(sources, + max_propagation_distance, + &stop_points); + + trace_back(destination, path); +} + +inline void GeodesicAlgorithmBase::geodesic(std::vector& sources, + std::vector& destinations, + std::vector >& paths) //lazy people can find geodesic paths with one function call +{ + double const max_propagation_distance = GEODESIC_INF; + + propagate(sources, + max_propagation_distance, + &destinations); //we use desinations as stop points + + paths.resize(destinations.size()); + + for(unsigned i=0; i* stop_points, + double stop_distance) +{ + m_max_propagation_distance = stop_distance; + + if(!stop_points) + { + m_stop_vertices.clear(); + return; + } + + m_stop_vertices.resize(stop_points->size()); + + std::vector possible_vertices; + for(unsigned i = 0; i < stop_points->size(); ++i) + { + SurfacePoint* point = &(*stop_points)[i]; + + possible_vertices.clear(); + m_mesh->closest_vertices(point, &possible_vertices); + + vertex_pointer closest_vertex = NULL; + double min_distance = 1e100; + for(unsigned j = 0; j < possible_vertices.size(); ++j) + { + double distance = point->distance(possible_vertices[j]); + if(distance < min_distance) + { + min_distance = distance; + closest_vertex = possible_vertices[j]; + } + } + assert(closest_vertex); + + m_stop_vertices[i].first = closest_vertex; + m_stop_vertices[i].second = min_distance; + } +} + + + +class GeodesicAlgorithmExact : public GeodesicAlgorithmBase +{ +public: + GeodesicAlgorithmExact(geodesic::Mesh* mesh): + GeodesicAlgorithmBase(mesh), + m_memory_allocator(mesh->edges().size(), mesh->edges().size()), + m_edge_interval_lists(mesh->edges().size()) + { + m_type = EXACT; + + for(unsigned i=0; iedges()[i]); + } + }; + + ~GeodesicAlgorithmExact(){}; + + void propagate(std::vector& sources, + double max_propagation_distance = GEODESIC_INF, //propagation algorithm stops after reaching the certain distance from the source + std::vector* stop_points = NULL); //or after ensuring that all the stop_points are covered + + void trace_back(SurfacePoint& destination, //trace back piecewise-linear path + std::vector& path); + + unsigned best_source(SurfacePoint& point, //quickly find what source this point belongs to and what is the distance to this source + double& best_source_distance); + + void print_statistics(); + +private: + typedef std::set IntervalQueue; + + void update_list_and_queue(list_pointer list, + IntervalWithStop* candidates, //up to two candidates + unsigned num_candidates); + + unsigned compute_propagated_parameters(double pseudo_x, + double pseudo_y, + double d, //parameters of the interval + double start, + double end, //start/end of the interval + double alpha, //corner angle + double L, //length of the new edge + bool first_interval, //if it is the first interval on the edge + bool last_interval, + bool turn_left, + bool turn_right, + IntervalWithStop* candidates); //if it is the last interval on the edge + + void construct_propagated_intervals(bool invert, + edge_pointer edge, + face_pointer face, //constructs iNew from the rest of the data + IntervalWithStop* candidates, + unsigned& num_candidates, + interval_pointer source_interval); + + double compute_positive_intersection(double start, + double pseudo_x, + double pseudo_y, + double sin_alpha, + double cos_alpha); //used in construct_propagated_intervals + + unsigned intersect_intervals(interval_pointer zero, + IntervalWithStop* one); //intersecting two intervals with up to three intervals in the end + + interval_pointer best_first_interval(SurfacePoint& point, + double& best_total_distance, + double& best_interval_position, + unsigned& best_source_index); + + bool check_stop_conditions(unsigned& index); + + void clear() + { + m_memory_allocator.clear(); + m_queue.clear(); + for(unsigned i=0; iid()]; + }; + + void set_sources(std::vector& sources) + { + m_sources.initialize(sources); + } + + void initialize_propagation_data(); + + void list_edges_visible_from_source(MeshElementBase* p, + std::vector& storage); //used in initialization + + long visible_from_source(SurfacePoint& point); //used in backtracing + + void best_point_on_the_edge_set(SurfacePoint& point, + std::vector const& storage, + interval_pointer& best_interval, + double& best_total_distance, + double& best_interval_position); + + void possible_traceback_edges(SurfacePoint& point, + std::vector& storage); + + bool erase_from_queue(interval_pointer p); + + IntervalQueue m_queue; //interval queue + + MemoryAllocator m_memory_allocator; //quickly allocate and deallocate intervals + std::vector m_edge_interval_lists; //every edge has its interval data + + enum MapType {OLD, NEW}; //used for interval intersection + MapType map[5]; + double start[6]; + interval_pointer i_new[5]; + + unsigned m_queue_max_size; //used for statistics + unsigned m_iterations; //used for statistics + + SortedSources m_sources; +}; + +inline void GeodesicAlgorithmExact::best_point_on_the_edge_set(SurfacePoint& point, + std::vector const& storage, + interval_pointer& best_interval, + double& best_total_distance, + double& best_interval_position) +{ + best_total_distance = 1e100; + for(unsigned i=0; ifind_closest_point(&point, + offset, + distance, + interval); + + if(distance < best_total_distance) + { + best_interval = interval; + best_total_distance = distance; + best_interval_position = offset; + } + } +} + +inline void GeodesicAlgorithmExact::possible_traceback_edges(SurfacePoint& point, + std::vector& storage) +{ + storage.clear(); + + if(point.type() == VERTEX) + { + vertex_pointer v = static_cast(point.base_element()); + for(unsigned i=0; iadjacent_faces().size(); ++i) + { + face_pointer f = v->adjacent_faces()[i]; + storage.push_back(f->opposite_edge(v)); + } + } + else if(point.type() == EDGE) + { + edge_pointer e = static_cast(point.base_element()); + for(unsigned i=0; iadjacent_faces().size(); ++i) + { + face_pointer f = e->adjacent_faces()[i]; + + storage.push_back(f->next_edge(e,e->v0())); + storage.push_back(f->next_edge(e,e->v1())); + } + } + else + { + face_pointer f = static_cast(point.base_element()); + storage.push_back(f->adjacent_edges()[0]); + storage.push_back(f->adjacent_edges()[1]); + storage.push_back(f->adjacent_edges()[2]); + } +} + + +inline long GeodesicAlgorithmExact::visible_from_source(SurfacePoint& point) //negative if not visible +{ + assert(point.type() != UNDEFINED_POINT); + + if(point.type() == EDGE) + { + edge_pointer e = static_cast(point.base_element()); + list_pointer list = interval_list(e); + double position = std::min(point.distance(e->v0()), e->length()); + interval_pointer interval = list->covering_interval(position); + //assert(interval); + if(interval && interval->visible_from_source()) + { + return (long)interval->source_index(); + } + else + { + return -1; + } + } + else if(point.type() == FACE) + { + return -1; + } + else if(point.type() == VERTEX) + { + vertex_pointer v = static_cast(point.base_element()); + for(unsigned i=0; iadjacent_edges().size(); ++i) + { + edge_pointer e = v->adjacent_edges()[i]; + list_pointer list = interval_list(e); + + double position = e->v0()->id() == v->id() ? 0.0 : e->length(); + interval_pointer interval = list->covering_interval(position); + if(interval && interval->visible_from_source()) + { + return (long)interval->source_index(); + } + } + + return -1; + } + + assert(0); + return 0; +} + +inline double GeodesicAlgorithmExact::compute_positive_intersection(double start, + double pseudo_x, + double pseudo_y, + double sin_alpha, + double cos_alpha) +{ + assert(pseudo_y < 0); + + double denominator = sin_alpha*(pseudo_x - start) - cos_alpha*pseudo_y; + if(denominator<0.0) + { + return -1.0; + } + + double numerator = -pseudo_y*start; + + if(numerator < 1e-30) + { + return 0.0; + } + + if(denominator < 1e-30) + { + return -1.0; + } + + return numerator/denominator; +} + +inline void GeodesicAlgorithmExact::list_edges_visible_from_source(MeshElementBase* p, + std::vector& storage) +{ + assert(p->type() != UNDEFINED_POINT); + + if(p->type() == FACE) + { + face_pointer f = static_cast(p); + for(unsigned i=0; i<3; ++i) + { + storage.push_back(f->adjacent_edges()[i]); + } + } + else if(p->type() == EDGE) + { + edge_pointer e = static_cast(p); + storage.push_back(e); + } + else //VERTEX + { + vertex_pointer v = static_cast(p); + for(unsigned i=0; iadjacent_edges().size(); ++i) + { + storage.push_back(v->adjacent_edges()[i]); + } + + } +} + +inline bool GeodesicAlgorithmExact::erase_from_queue(interval_pointer p) +{ + if(p->min() < GEODESIC_INF/10.0)// && p->min >= queue->begin()->first) + { + assert(m_queue.count(p)<=1); //the set is unique + + IntervalQueue::iterator it = m_queue.find(p); + + if(it != m_queue.end()) + { + m_queue.erase(it); + return true; + } + } + + return false; +} + +inline unsigned GeodesicAlgorithmExact::intersect_intervals(interval_pointer zero, + IntervalWithStop* one) //intersecting two intervals with up to three intervals in the end +{ + assert(zero->edge()->id() == one->edge()->id()); + assert(zero->stop() > one->start() && zero->start() < one->stop()); + assert(one->min() < GEODESIC_INF/10.0); + + double const local_epsilon = SMALLEST_INTERVAL_RATIO*one->edge()->length(); + + unsigned N=0; + if(zero->min() > GEODESIC_INF/10.0) + { + start[0] = zero->start(); + if(zero->start() < one->start() - local_epsilon) + { + map[0] = OLD; + start[1] = one->start(); + map[1] = NEW; + N = 2; + } + else + { + map[0] = NEW; + N = 1; + } + + if(zero->stop() > one->stop() + local_epsilon) + { + map[N] = OLD; //"zero" interval + start[N++] = one->stop(); + } + + start[N+1] = zero->stop(); + return N; + } + + double const local_small_epsilon = 1e-8*one->edge()->length(); + + double D = zero->d() - one->d(); + double x0 = zero->pseudo_x(); + double x1 = one->pseudo_x(); + double R0 = x0*x0 + zero->pseudo_y()*zero->pseudo_y(); + double R1 = x1*x1 + one->pseudo_y()*one->pseudo_y(); + + double inter[2]; //points of intersection + char Ninter=0; //number of the points of the intersection + + if(std::abs(D)local_small_epsilon) + { + inter[0] = (R1 - R0)/(2.*denom); //one solution + Ninter = 1; + } + } + else + { + double D2 = D*D; + double Q = 0.5*(R1-R0-D2); + double X = x0 - x1; + + double A = X*X - D2; + double B = Q*X + D2*x0; + double C = Q*Q - D2*R0; + + if (std::abs(A)local_small_epsilon) + { + inter[0] = -C/B; //one solution + Ninter = 1; + } + } + else + { + double det = B*B-A*C; + if(det>local_small_epsilon*local_small_epsilon) //two roots + { + det = sqrt(det); + if(A>0.0) //make sure that the roots are ordered + { + inter[0] = (-B - det)/A; + inter[1] = (-B + det)/A; + } + else + { + inter[0] = (-B + det)/A; + inter[1] = (-B - det)/A; + } + + if(inter[1] - inter[0] > local_small_epsilon) + { + Ninter = 2; + } + else + { + Ninter = 1; + } + } + else if(det>=0.0) //single root + { + inter[0] = -B/A; + Ninter = 1; + } + } + } + //---------------------------find possible intervals--------------------------------------- + double left = std::max(zero->start(), one->start()); //define left and right boundaries of the intersection of the intervals + double right = std::min(zero->stop(), one->stop()); + + double good_start[4]; //points of intersection within the (left, right) limits +"left" + "right" + good_start[0] = left; + char Ngood_start=1; //number of the points of the intersection + + for(char i=0; i left + local_epsilon && x < right - local_epsilon) + { + good_start[Ngood_start++] = x; + } + } + good_start[Ngood_start++] = right; + + MapType mid_map[3]; + for(char i=0; isignal(mid) <= one->signal(mid) ? OLD : NEW; + } + + //-----------------------------------output---------------------------------- + N = 0; + if(zero->start() < left - local_epsilon) //additional "zero" interval + { + if(mid_map[0] == OLD) //first interval in the map is already the old one + { + good_start[0] = zero->start(); + } + else + { + map[N] = OLD; //"zero" interval + start[N++] = zero->start(); + } + } + + for(long i=0;istop() > one->stop() + local_epsilon) + { + if(N==0 || map[N-1] == NEW) + { + map[N] = OLD; //"zero" interval + start[N++] = one->stop(); + } + } + + start[0] = zero->start(); // just to make sure that epsilons do not damage anything + //start[N] = zero->stop(); + + return N; +} + +inline void GeodesicAlgorithmExact::initialize_propagation_data() +{ + clear(); + + IntervalWithStop candidate; + std::vector edges_visible_from_source; + for(unsigned i=0; ibase_element(), + edges_visible_from_source); + + for(unsigned j=0; jlength(); + candidate.compute_min_distance(candidate.stop()); + candidate.direction() = Interval::FROM_SOURCE; + + update_list_and_queue(interval_list(e), &candidate, 1); + } + } +} + +inline void GeodesicAlgorithmExact::propagate(std::vector& sources, + double max_propagation_distance, //propagation algorithm stops after reaching the certain distance from the source + std::vector* stop_points) +{ + set_stop_conditions(stop_points, max_propagation_distance); + set_sources(sources); + initialize_propagation_data(); + + clock_t start = clock(); + + unsigned satisfied_index = 0; + + m_iterations = 0; //for statistics + m_queue_max_size = 0; + + IntervalWithStop candidates[2]; + + while(!m_queue.empty()) + { + m_queue_max_size = std::max(static_cast(m_queue.size()), m_queue_max_size); + + unsigned const check_period = 10; + if(++m_iterations % check_period == 0) //check if we covered all required vertices + { + if (check_stop_conditions(satisfied_index)) + { + break; + } + } + + interval_pointer min_interval = *m_queue.begin(); + m_queue.erase(m_queue.begin()); + edge_pointer edge = min_interval->edge(); + list_pointer list = interval_list(edge); + + assert(min_interval->d() < GEODESIC_INF); + + bool const first_interval = min_interval->start() == 0.0; + //bool const last_interval = min_interval->stop() == edge->length(); + bool const last_interval = min_interval->next() == NULL; + + bool const turn_left = edge->v0()->saddle_or_boundary(); + bool const turn_right = edge->v1()->saddle_or_boundary(); + + for(unsigned i=0; iadjacent_faces().size(); ++i) //two possible faces to propagate + { + if(!edge->is_boundary()) //just in case, always propagate boundary edges + { + if((i == 0 && min_interval->direction() == Interval::FROM_FACE_0) || + (i == 1 && min_interval->direction() == Interval::FROM_FACE_1)) + { + continue; + } + } + + face_pointer face = edge->adjacent_faces()[i]; //if we come from 1, go to 2 + edge_pointer next_edge = face->next_edge(edge,edge->v0()); + + unsigned num_propagated = compute_propagated_parameters(min_interval->pseudo_x(), + min_interval->pseudo_y(), + min_interval->d(), //parameters of the interval + min_interval->start(), + min_interval->stop(), //start/end of the interval + face->vertex_angle(edge->v0()), //corner angle + next_edge->length(), //length of the new edge + first_interval, //if it is the first interval on the edge + last_interval, + turn_left, + turn_right, + candidates); //if it is the last interval on the edge + bool propagate_to_right = true; + + if(num_propagated) + { + if(candidates[num_propagated-1].stop() != next_edge->length()) + { + propagate_to_right = false; + } + + bool const invert = next_edge->v0()->id() != edge->v0()->id(); //if the origins coinside, do not invert intervals + + construct_propagated_intervals(invert, //do not inverse + next_edge, + face, + candidates, + num_propagated, + min_interval); + + update_list_and_queue(interval_list(next_edge), + candidates, + num_propagated); + } + + if(propagate_to_right) + { + //propogation to the right edge + double length = edge->length(); + next_edge = face->next_edge(edge,edge->v1()); + + num_propagated = compute_propagated_parameters(length - min_interval->pseudo_x(), + min_interval->pseudo_y(), + min_interval->d(), //parameters of the interval + length - min_interval->stop(), + length - min_interval->start(), //start/end of the interval + face->vertex_angle(edge->v1()), //corner angle + next_edge->length(), //length of the new edge + last_interval, //if it is the first interval on the edge + first_interval, + turn_right, + turn_left, + candidates); //if it is the last interval on the edge + + if(num_propagated) + { + bool const invert = next_edge->v0()->id() != edge->v1()->id(); //if the origins coinside, do not invert intervals + + construct_propagated_intervals(invert, //do not inverse + next_edge, + face, + candidates, + num_propagated, + min_interval); + + update_list_and_queue(interval_list(next_edge), + candidates, + num_propagated); + } + } + } + } + + m_propagation_distance_stopped = m_queue.empty() ? GEODESIC_INF : (*m_queue.begin())->min(); + clock_t stop = clock(); + m_time_consumed = (static_cast(stop)-static_cast(start))/CLOCKS_PER_SEC; + +/* for(unsigned i=0; ifirst(); + assert(p->start() == 0.0); + while(p->next()) + { + assert(p->stop() == p->next()->start()); + assert(p->d() < GEODESIC_INF); + p = p->next(); + } + }*/ +} + + +inline bool GeodesicAlgorithmExact::check_stop_conditions(unsigned& index) +{ + double queue_distance = (*m_queue.begin())->min(); + if(queue_distance < stop_distance()) + { + return false; + } + + while(index < m_stop_vertices.size()) + { + vertex_pointer v = m_stop_vertices[index].first; + edge_pointer edge = v->adjacent_edges()[0]; //take any edge + + double distance = edge->v0()->id() == v->id() ? + interval_list(edge)->signal(0.0) : + interval_list(edge)->signal(edge->length()); + + if(queue_distance < distance + m_stop_vertices[index].second) + { + return false; + } + + ++index; + } + return true; +} + + +inline void GeodesicAlgorithmExact::update_list_and_queue(list_pointer list, + IntervalWithStop* candidates, //up to two candidates + unsigned num_candidates) +{ + assert(num_candidates <= 2); + //assert(list->first() != NULL); + edge_pointer edge = list->edge(); + double const local_epsilon = SMALLEST_INTERVAL_RATIO * edge->length(); + + if(list->first() == NULL) + { + interval_pointer* p = &list->first(); + IntervalWithStop* first; + IntervalWithStop* second; + + if(num_candidates == 1) + { + first = candidates; + second = candidates; + first->compute_min_distance(first->stop()); + } + else + { + if(candidates->start() <= (candidates+1)->start()) + { + first = candidates; + second = candidates+1; + } + else + { + first = candidates+1; + second = candidates; + } + assert(first->stop() == second->start()); + + first->compute_min_distance(first->stop()); + second->compute_min_distance(second->stop()); + } + + if(first->start() > 0.0) + { + *p = m_memory_allocator.allocate(); + (*p)->initialize(edge); + p = &(*p)->next(); + } + + *p = m_memory_allocator.allocate(); + memcpy(*p,first,sizeof(Interval)); + m_queue.insert(*p); + + if(num_candidates == 2) + { + p = &(*p)->next(); + *p = m_memory_allocator.allocate(); + memcpy(*p,second,sizeof(Interval)); + m_queue.insert(*p); + } + + if(second->stop() < edge->length()) + { + p = &(*p)->next(); + *p = m_memory_allocator.allocate(); + (*p)->initialize(edge); + (*p)->start() = second->stop(); + } + else + { + (*p)->next() = NULL; + } + return; + } + + bool propagate_flag; + + for(unsigned i=0; ifirst(); + assert(p->start() == 0.0); + + while(p != NULL && p->stop() - local_epsilon < q->start()) + { + p = p->next(); + } + + while(p != NULL && p->start() < q->stop() - local_epsilon) //go through all old intervals + { + unsigned const N = intersect_intervals(p, q); //interset two intervals + + if(N == 1) + { + if(map[0]==OLD) //if "p" is always better, we do not need to update anything) + { + if(previous) //close previous interval and put in into the queue + { + previous->next() = p; + previous->compute_min_distance(p->start()); + m_queue.insert(previous); + previous = NULL; + } + + p = p->next(); + + } + else if(previous) //extend previous interval to cover everything; remove p + { + previous->next() = p->next(); + erase_from_queue(p); + m_memory_allocator.deallocate(p); + + p = previous->next(); + } + else //p becomes "previous" + { + previous = p; + interval_pointer next = p->next(); + erase_from_queue(p); + + memcpy(previous,q,sizeof(Interval)); + + previous->start() = start[0]; + previous->next() = next; + + p = next; + } + continue; + } + + //update_flag = true; + + Interval swap(*p); //used for swapping information + propagate_flag = erase_from_queue(p); + + for(unsigned j=1; jnext() = p; + previous->compute_min_distance(previous->stop()); + m_queue.insert(previous); + previous = NULL; + } + i_new[0] = p; + p->next() = i_new[1]; + p->start() = start[0]; + } + else if(previous) //extend previous interval to cover everything; remove p + { + i_new[0] = previous; + previous->next() = i_new[1]; + m_memory_allocator.deallocate(p); + previous = NULL; + } + else //p becomes "previous" + { + i_new[0] = p; + memcpy(p,q,sizeof(Interval)); + + p->next() = i_new[1]; + p->start() = start[0]; + } + + assert(!previous); + + for(unsigned j=1; jnext() = swap.next(); + } + else + { + current_interval->next() = i_new[j+1]; + } + + current_interval->start() = start[j]; + } + + for(unsigned j=0; jcompute_min_distance(current_interval->stop()); //compute minimal distance + + if(map[j]==NEW || (map[j]==OLD && propagate_flag)) + { + m_queue.insert(current_interval); + } + } + } + + p = swap.next(); + } + + if(previous) //close previous interval and put in into the queue + { + previous->compute_min_distance(previous->stop()); + m_queue.insert(previous); + previous = NULL; + } + } +} + +inline unsigned GeodesicAlgorithmExact::compute_propagated_parameters(double pseudo_x, + double pseudo_y, + double d, //parameters of the interval + double begin, + double end, //start/end of the interval + double alpha, //corner angle + double L, //length of the new edge + bool first_interval, //if it is the first interval on the edge + bool last_interval, + bool turn_left, + bool turn_right, + IntervalWithStop* candidates) //if it is the last interval on the edge +{ + assert(pseudo_y<=0.0); + assert(dstart() = 0.0; + p->stop() = L; + p->d() = d - pseudo_x; + p->pseudo_x() = 0.0; + p->pseudo_y() = 0.0; + return 1; + } + else if(last_interval && pseudo_x >= end) + { + p->start() = 0.0; + p->stop() = L; + p->d() = d + pseudo_x-end; + p->pseudo_x() = end*cos(alpha); + p->pseudo_y() = -end*sin(alpha); + return 1; + } + else if(pseudo_x >= begin && pseudo_x <= end) + { + p->start() = 0.0; + p->stop() = L; + p->d() = d; + p->pseudo_x() = pseudo_x*cos(alpha); + p->pseudo_y() = -pseudo_x*sin(alpha); + return 1; + } + else + { + return 0; + } + } + + double sin_alpha = sin(alpha); + double cos_alpha = cos(alpha); + + //important: for the first_interval, this function returns zero only if the new edge is "visible" from the source + //if the new edge can be covered only after turn_over, the value is negative (-1.0) + double L1 = compute_positive_intersection(begin, + pseudo_x, + pseudo_y, + sin_alpha, + cos_alpha); + + if(L1 < 0 || L1 >= L) + { + if(first_interval && turn_left) + { + p->start() = 0.0; + p->stop() = L; + p->d() = d + sqrt(pseudo_x*pseudo_x + pseudo_y*pseudo_y); + p->pseudo_y() = 0.0; + p->pseudo_x() = 0.0; + return 1; + } + else + { + return 0; + } + } + + double L2 = compute_positive_intersection(end, + pseudo_x, + pseudo_y, + sin_alpha, + cos_alpha); + + if(L2 < 0 || L2 >= L) + { + p->start() = L1; + p->stop() = L; + p->d() = d; + p->pseudo_x() = cos_alpha*pseudo_x + sin_alpha*pseudo_y; + p->pseudo_y() = -sin_alpha*pseudo_x + cos_alpha*pseudo_y; + + return 1; + } + + p->start() = L1; + p->stop() = L2; + p->d() = d; + p->pseudo_x() = cos_alpha*pseudo_x + sin_alpha*pseudo_y; + p->pseudo_y() = -sin_alpha*pseudo_x + cos_alpha*pseudo_y; + assert(p->pseudo_y() <= 0.0); + + if(!(last_interval && turn_right)) + { + return 1; + } + else + { + p = candidates + 1; + + p->start() = L2; + p->stop() = L; + double dx = pseudo_x - end; + p->d() = d + sqrt(dx*dx + pseudo_y*pseudo_y); + p->pseudo_x() = end*cos_alpha; + p->pseudo_y() = -end*sin_alpha; + + return 2; + } +} + +inline void GeodesicAlgorithmExact::construct_propagated_intervals(bool invert, + edge_pointer edge, + face_pointer face, //constructs iNew from the rest of the data + IntervalWithStop* candidates, + unsigned& num_candidates, + interval_pointer source_interval) //up to two candidates +{ + double edge_length = edge->length(); + double local_epsilon = SMALLEST_INTERVAL_RATIO * edge_length; + + //kill very small intervals in order to avoid precision problems + if(num_candidates == 2) + { + double start = std::min(candidates->start(), (candidates+1)->start()); + double stop = std::max(candidates->stop(), (candidates+1)->stop()); + if(candidates->stop()-candidates->start() < local_epsilon) // kill interval 0 + { + *candidates = *(candidates+1); + num_candidates = 1; + candidates->start() = start; + candidates->stop() = stop; + } + else if ((candidates+1)->stop() - (candidates+1)->start() < local_epsilon) + { + num_candidates = 1; + candidates->start() = start; + candidates->stop() = stop; + } + } + + IntervalWithStop* first; + IntervalWithStop* second; + if(num_candidates == 1) + { + first = candidates; + second = candidates; + } + else + { + if(candidates->start() <= (candidates+1)->start()) + { + first = candidates; + second = candidates+1; + } + else + { + first = candidates+1; + second = candidates; + } + assert(first->stop() == second->start()); + } + + if(first->start() < local_epsilon) + { + first->start() = 0.0; + } + if(edge_length - second->stop() < local_epsilon) + { + second->stop() = edge_length; + } + + //invert intervals if necessary; fill missing data and set pointers correctly + Interval::DirectionType direction = edge->adjacent_faces()[0]->id() == face->id() ? + Interval::FROM_FACE_0 : + Interval::FROM_FACE_1; + + if(!invert) //in this case everything is straighforward, we do not have to invert the intervals + { + for(unsigned i=0; inext() = (i == num_candidates - 1) ? NULL : candidates + i + 1; + p->edge() = edge; + p->direction() = direction; + p->source_index() = source_interval->source_index(); + + p->min() = 0.0; //it will be changed later on + + assert(p->start() < p->stop()); + } + } + else //now we have to invert the intervals + { + for(unsigned i=0; inext() = (i == 0) ? NULL : candidates + i - 1; + p->edge() = edge; + p->direction() = direction; + p->source_index() = source_interval->source_index(); + + double length = edge_length; + p->pseudo_x() = length - p->pseudo_x(); + + double start = length - p->stop(); + p->stop() = length - p->start(); + p->start() = start; + + p->min() = 0; + + assert(p->start() < p->stop()); + assert(p->start() >= 0.0); + assert(p->stop() <= edge->length()); + } + } +} + + +inline unsigned GeodesicAlgorithmExact::best_source(SurfacePoint& point, //quickly find what source this point belongs to and what is the distance to this source + double& best_source_distance) +{ + double best_interval_position; + unsigned best_source_index; + + best_first_interval(point, + best_source_distance, + best_interval_position, + best_source_index); + + return best_source_index; +} + +inline interval_pointer GeodesicAlgorithmExact::best_first_interval(SurfacePoint& point, + double& best_total_distance, + double& best_interval_position, + unsigned& best_source_index) +{ + assert(point.type() != UNDEFINED_POINT); + + interval_pointer best_interval = NULL; + best_total_distance = GEODESIC_INF; + + if(point.type() == EDGE) + { + edge_pointer e = static_cast(point.base_element()); + list_pointer list = interval_list(e); + + best_interval_position = point.distance(e->v0()); + best_interval = list->covering_interval(best_interval_position); + if(best_interval) + { + //assert(best_interval && best_interval->d() < GEODESIC_INF); + best_total_distance = best_interval->signal(best_interval_position); + best_source_index = best_interval->source_index(); + } + } + else if(point.type() == FACE) + { + face_pointer f = static_cast(point.base_element()); + for(unsigned i=0; i<3; ++i) + { + edge_pointer e = f->adjacent_edges()[i]; + list_pointer list = interval_list(e); + + double offset; + double distance; + interval_pointer interval; + + list->find_closest_point(&point, + offset, + distance, + interval); + + if(interval && distance < best_total_distance) + { + best_interval = interval; + best_total_distance = distance; + best_interval_position = offset; + best_source_index = interval->source_index(); + } + } + + //check for all sources that might be located inside this face + SortedSources::sorted_iterator_pair local_sources = m_sources.sources(f); + for(SortedSources::sorted_iterator it=local_sources.first; it != local_sources.second; ++it) + { + SurfacePointWithIndex* source = *it; + double distance = point.distance(source); + if(distance < best_total_distance) + { + best_interval = NULL; + best_total_distance = distance; + best_interval_position = 0.0; + best_source_index = source->index(); + } + } + } + else if(point.type() == VERTEX) + { + vertex_pointer v = static_cast(point.base_element()); + for(unsigned i=0; iadjacent_edges().size(); ++i) + { + edge_pointer e = v->adjacent_edges()[i]; + list_pointer list = interval_list(e); + + double position = e->v0()->id() == v->id() ? 0.0 : e->length(); + interval_pointer interval = list->covering_interval(position); + if(interval) + { + double distance = interval->signal(position); + + if(distance < best_total_distance) + { + best_interval = interval; + best_total_distance = distance; + best_interval_position = position; + best_source_index = interval->source_index(); + } + } + } + } + + if(best_total_distance > m_propagation_distance_stopped) //result is unreliable + { + best_total_distance = GEODESIC_INF; + return NULL; + } + else + { + return best_interval; + } +} + +inline void GeodesicAlgorithmExact::trace_back(SurfacePoint& destination, //trace back piecewise-linear path + std::vector& path) +{ + path.clear(); + double best_total_distance; + double best_interval_position; + unsigned source_index = std::numeric_limits::max(); + interval_pointer best_interval = best_first_interval(destination, + best_total_distance, + best_interval_position, + source_index); + + if(best_total_distance >= GEODESIC_INF/2.0) //unable to find the right path + { + return; + } + + path.push_back(destination); + + if(best_interval) //if we did not hit the face source immediately + { + std::vector possible_edges; + possible_edges.reserve(10); + + while(visible_from_source(path.back()) < 0) //while this point is not in the direct visibility of some source (if we are inside the FACE, we obviously hit the source) + { + SurfacePoint& q = path.back(); + + possible_traceback_edges(q, possible_edges); + + interval_pointer interval; + double total_distance; + double position; + + best_point_on_the_edge_set(q, + possible_edges, + interval, + total_distance, + position); + + //std::cout << total_distance + length(path) << std::endl; + assert(total_distancesource_index(); + + edge_pointer e = interval->edge(); + double local_epsilon = SMALLEST_INTERVAL_RATIO*e->length(); + if(position < local_epsilon) + { + path.push_back(SurfacePoint(e->v0())); + } + else if(position > e->length()-local_epsilon) + { + path.push_back(SurfacePoint(e->v1())); + } + else + { + double normalized_position = position/e->length(); + path.push_back(SurfacePoint(e, normalized_position)); + } + } + } + + SurfacePoint& source = static_cast(m_sources[source_index]); + if(path.back().distance(&source) > 0) + { + path.push_back(source); + } +} + +inline void GeodesicAlgorithmExact::print_statistics() +{ + GeodesicAlgorithmBase::print_statistics(); + + unsigned interval_counter = 0; + for(unsigned i=0; i +IGL_INLINE void igl::exact_geodesic( + const Eigen::MatrixBase &V, + const Eigen::MatrixBase &F, + const Eigen::MatrixBase &VS, + const Eigen::MatrixBase &FS, + const Eigen::MatrixBase &VT, + const Eigen::MatrixBase &FT, + Eigen::PlainObjectBase &D) +{ + assert(V.cols() == 3 && F.cols() == 3 && "Only support 3D triangle mesh"); + assert(VS.cols() <=1 && FS.cols() <= 1 && VT.cols() <= 1 && FT.cols() <=1 && "Only support one dimensional inputs"); + std::vector points(V.rows() * V.cols()); + std::vector faces(F.rows() * F.cols()); + for (int i = 0; i < points.size(); i++) + { + points[i] = V(i / 3, i % 3); + } + for (int i = 0; i < faces.size(); i++) + { + faces[i] = F(i / 3, i % 3); + } + + igl::geodesic::Mesh mesh; + mesh.initialize_mesh_data(points, faces); + igl::geodesic::GeodesicAlgorithmExact exact_algorithm(&mesh); + + std::vector source(VS.rows() + FS.rows()); + std::vector target(VT.rows() + FT.rows()); + for (int i = 0; i < VS.rows(); i++) + { + source[i] = (igl::geodesic::SurfacePoint(&mesh.vertices()[VS(i, 0)])); + } + for (int i = 0; i < FS.rows(); i++) + { + source[i] = (igl::geodesic::SurfacePoint(&mesh.faces()[FS(i, 0)])); + } + + for (int i = 0; i < VT.rows(); i++) + { + target[i] = (igl::geodesic::SurfacePoint(&mesh.vertices()[VT(i, 0)])); + } + for (int i = 0; i < FT.rows(); i++) + { + target[i] = (igl::geodesic::SurfacePoint(&mesh.faces()[FT(i, 0)])); + } + + exact_algorithm.propagate(source); + std::vector path; + D.resize(target.size(), 1); + for (int i = 0; i < target.size(); i++) + { + exact_algorithm.trace_back(target[i], path); + D(i) = igl::geodesic::length(path); + } +} + +#ifdef IGL_STATIC_LIBRARY +template void igl::exact_geodesic, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix>(Eigen::MatrixBase> const &, Eigen::MatrixBase> const &, Eigen::MatrixBase> const &, Eigen::MatrixBase> const &, Eigen::MatrixBase> const &, Eigen::MatrixBase> const &, Eigen::PlainObjectBase> &); +template void igl::exact_geodesic, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/exact_geodesic.h b/src/external/libigl-2.3.0/include/igl/exact_geodesic.h new file mode 100644 index 000000000..cec59de69 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/exact_geodesic.h @@ -0,0 +1,55 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2017 Zhongshi Jiang +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef IGL_EXACT_GEODESIC_H +#define IGL_EXACT_GEODESIC_H + +#include "igl_inline.h" +#include + +namespace igl +{ + // Exact geodesic algorithm for triangular mesh with the implementation from https://code.google.com/archive/p/geodesic/, + // and the algorithm first described by Mitchell, Mount and Papadimitriou in 1987 + // + // Inputs: + // V #V by 3 list of 3D vertex positions + // F #F by 3 list of mesh faces + // VS #VS by 1 vector specifying indices of source vertices + // FS #FS by 1 vector specifying indices of source faces + // VT #VT by 1 vector specifying indices of target vertices + // FT #FT by 1 vector specifying indices of target faces + // Output: + // D #VT+#FT by 1 vector of geodesic distances of each target w.r.t. the nearest one in the source set + // + // Note: + // Specifying a face as target/source means its center. + // + template < + typename DerivedV, + typename DerivedF, + typename DerivedVS, + typename DerivedFS, + typename DerivedVT, + typename DerivedFT, + typename DerivedD> + IGL_INLINE void exact_geodesic( + const Eigen::MatrixBase &V, + const Eigen::MatrixBase &F, + const Eigen::MatrixBase &VS, + const Eigen::MatrixBase &FS, + const Eigen::MatrixBase &VT, + const Eigen::MatrixBase &FT, + Eigen::PlainObjectBase &D); +} + +#ifndef IGL_STATIC_LIBRARY +# include "exact_geodesic.cpp" +#endif + +#endif \ No newline at end of file diff --git a/src/external/libigl-2.3.0/include/igl/example_fun.cpp b/src/external/libigl-2.3.0/include/igl/example_fun.cpp new file mode 100644 index 000000000..9796c68e3 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/example_fun.cpp @@ -0,0 +1,23 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "example_fun.h" +#include + +template +IGL_INLINE bool igl::example_fun(const Printable & input) +{ + using namespace std; + cout<<"example_fun: "<(const double& input); +template bool igl::example_fun(const int& input); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/example_fun.h b/src/external/libigl-2.3.0/include/igl/example_fun.h new file mode 100644 index 000000000..16c9ec645 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/example_fun.h @@ -0,0 +1,31 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_EXAMPLE_FUN_H +#define IGL_EXAMPLE_FUN_H + +#include "igl_inline.h" + +namespace igl +{ + // This is an example of a function, it takes a templated parameter and + // shovels it into cout + // + // Templates: + // T type that supports + // Input: + // input some input of a Printable type + // Returns true for the sake of returning something + template + IGL_INLINE bool example_fun(const Printable & input); +} + +#ifndef IGL_STATIC_LIBRARY +# include "example_fun.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/exploded_view.cpp b/src/external/libigl-2.3.0/include/igl/exploded_view.cpp new file mode 100644 index 000000000..d23b6162c --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/exploded_view.cpp @@ -0,0 +1,70 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2020 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "exploded_view.h" +#include "barycenter.h" +#include "volume.h" + +template < + typename DerivedV, + typename DerivedT, + typename DerivedEV, + typename DerivedEF, + typename DerivedI, + typename DerivedJ> +IGL_INLINE void igl::exploded_view( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & T, + const typename DerivedV::Scalar s, + const typename DerivedV::Scalar t, + Eigen::PlainObjectBase & EV, + Eigen::PlainObjectBase & EF, + Eigen::PlainObjectBase & I, + Eigen::PlainObjectBase & J) +{ + assert(T.cols() == 4 && "T should be a tet mesh"); + EV.resize(4*T.rows(),3); + EF.resize(4*T.rows(),3); + I.resize(EV.rows()); + J.resize(EF.rows()); + Eigen::MatrixXd BC; + igl::barycenter(V,T,BC); + Eigen::VectorXd vol; + igl::volume(V,T,vol); + const Eigen::RowVectorXd c = vol.transpose()*BC/vol.array().sum(); + for(int i = 0;i, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::Matrix::Scalar, Eigen::Matrix::Scalar, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/exploded_view.h b/src/external/libigl-2.3.0/include/igl/exploded_view.h new file mode 100644 index 000000000..e925404bb --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/exploded_view.h @@ -0,0 +1,50 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2020 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_EXPLODED_VIEW_H +#define IGL_EXPLODED_VIEW_H +#include "igl_inline.h" +#include +namespace igl +{ + // Given a tet-mesh, create a trivial surface mesh (4 triangles per tet) with + // each tet scaled individually and translated outward from the mesh's + // centroid, creating an exploded-view visualization. + // + // Inputs: + // V #V by 3 list of tet mesh vertex positions + // T #T by 4 list of tet mesh indices into rows of V + // s amount to scale each tet indvidually, typically (0,1] + // t amount to scale away from mesh's centroid, typically >=1 + // Outputs: + // EV #T*4 by 3 list of output mesh vertex positions + // EF #T*4 by 3 list of output triangle indices into rows of EV + // I #EV list of indices into V revealing birth parent + // J #EF list of indices into F revealing birth parent + template < + typename DerivedV, + typename DerivedT, + typename DerivedEV, + typename DerivedEF, + typename DerivedI, + typename DerivedJ> + IGL_INLINE void exploded_view( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & T, + const typename DerivedV::Scalar s, + const typename DerivedV::Scalar t, + Eigen::PlainObjectBase & EV, + Eigen::PlainObjectBase & EF, + Eigen::PlainObjectBase & I, + Eigen::PlainObjectBase & J); +} + +#ifndef IGL_STATIC_LIBRARY +# include "exploded_view.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/extension.cpp b/src/external/libigl-2.3.0/include/igl/extension.cpp new file mode 100644 index 000000000..6bb6ee3e5 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/extension.cpp @@ -0,0 +1,9 @@ +#include "extension.h" +#include "pathinfo.h" + +IGL_INLINE std::string igl::extension( const std::string & path) +{ + std::string d,b,e,f; + pathinfo(path,d,b,e,f); + return e; +} diff --git a/src/external/libigl-2.3.0/include/igl/extension.h b/src/external/libigl-2.3.0/include/igl/extension.h new file mode 100644 index 000000000..977ac2ff9 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/extension.h @@ -0,0 +1,29 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2020 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_EXTENSION_H +#define IGL_EXTENSION_H +#include "igl_inline.h" + +#include + +namespace igl +{ + // Inputs: + // path path with an extension (path/to/foo.obj) + // Returns extension without dot (obj) + // + // See also: pathinfo, basename, dirname + IGL_INLINE std::string extension( const std::string & path); +} + +#ifndef IGL_STATIC_LIBRARY +# include "extension.cpp" +#endif + +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/exterior_edges.cpp b/src/external/libigl-2.3.0/include/igl/exterior_edges.cpp new file mode 100644 index 000000000..04c1e9b8a --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/exterior_edges.cpp @@ -0,0 +1,106 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "exterior_edges.h" +#include "oriented_facets.h" +#include "sort.h" +#include "unique_rows.h" + +#include +#include +#include +#include + +//template inline int sgn(T val) { +// return (T(0) < val) - (val < T(0)); +//} + +//static void mod2(std::pair, int>& p) +//{ +// using namespace std; +// // Be sure that sign of mod matches sign of argument +// p.second = p.second%2 ? sgn(p.second) : 0; +//} + +//// http://stackoverflow.com/a/5517869/148668 +//struct Compare +//{ +// int i; +// Compare(const int& i) : i(i) {} +//}; +//bool operator==(const std::pair,int>&p, const Compare& c) +//{ +// return c.i == p.second; +//} +//bool operator==(const Compare& c, const std::pair, int> &p) +//{ +// return c.i == p.second; +//} + +IGL_INLINE void igl::exterior_edges( + const Eigen::MatrixXi & F, + Eigen::MatrixXi & E) +{ + using namespace Eigen; + using namespace std; + assert(F.cols() == 3); + const size_t m = F.rows(); + MatrixXi all_E,sall_E,sort_order; + // Sort each edge by index + oriented_facets(F,all_E); + sort(all_E,2,true,sall_E,sort_order); + // Find unique edges + MatrixXi uE; + VectorXi IA,EMAP; + unique_rows(sall_E,uE,IA,EMAP); + VectorXi counts = VectorXi::Zero(uE.rows()); + for(size_t a = 0;a<3*m;a++) + { + counts(EMAP(a)) += (sort_order(a)==0?1:-1); + } + + E.resize(all_E.rows(),2); + { + int e = 0; + const size_t nue = uE.rows(); + // Append each unique edge with a non-zero amount of signed occurrences + for(size_t ue = 0; ue 0) + { + i = uE(ue,0); + j = uE(ue,1); + } + // Append edge for every repeated entry + const int abs_count = abs(count); + for(int k = 0;k +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_EXTERIOR_EDGES_H +#define IGL_EXTERIOR_EDGES_H +#include "igl_inline.h" +#include +namespace igl +{ + // EXTERIOR_EDGES Determines boundary "edges" and also edges with an + // odd number of occurrences where seeing edge (i,j) counts as +1 and seeing + // the opposite edge (j,i) counts as -1 + // + // Inputs: + // F #F by simplex_size list of "faces" + // Outputs: + // E #E by simplex_size-1 list of exterior edges + // + IGL_INLINE void exterior_edges( + const Eigen::MatrixXi & F, + Eigen::MatrixXi & E); + // Inline version + IGL_INLINE Eigen::MatrixXi exterior_edges( const Eigen::MatrixXi & F); +} +#ifndef IGL_STATIC_LIBRARY +# include "exterior_edges.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/extract_manifold_patches.cpp b/src/external/libigl-2.3.0/include/igl/extract_manifold_patches.cpp new file mode 100644 index 000000000..10763f8d5 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/extract_manifold_patches.cpp @@ -0,0 +1,103 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "extract_manifold_patches.h" +#include "unique_edge_map.h" +#include +#include +#include + +template< + typename DerivedF, + typename DerivedEMAP, + typename uE2EType, + typename DerivedP> +IGL_INLINE size_t igl::extract_manifold_patches( + const Eigen::MatrixBase& F, + const Eigen::MatrixBase& EMAP, + const std::vector >& uE2E, + Eigen::PlainObjectBase& P) +{ + assert(F.cols() == 3); + const size_t num_faces = F.rows(); + + auto edge_index_to_face_index = [&](size_t ei) { return ei % num_faces; }; + auto face_and_corner_index_to_edge_index = [&](size_t fi, size_t ci) { + return ci*num_faces + fi; + }; + auto is_manifold_edge = [&](size_t fi, size_t ci) -> bool { + const size_t ei = face_and_corner_index_to_edge_index(fi, ci); + return uE2E[EMAP(ei, 0)].size() == 2; + }; + auto get_adj_face_index = [&](size_t fi, size_t ci) -> size_t { + const size_t ei = face_and_corner_index_to_edge_index(fi, ci); + const auto& adj_faces = uE2E[EMAP(ei, 0)]; + assert(adj_faces.size() == 2); + if (adj_faces[0] == ei) { + return edge_index_to_face_index(adj_faces[1]); + } else { + assert(adj_faces[1] == ei); + return edge_index_to_face_index(adj_faces[0]); + } + }; + + typedef typename DerivedP::Scalar Scalar; + const Scalar INVALID = std::numeric_limits::max(); + P.resize(num_faces,1); + P.setConstant(INVALID); + size_t num_patches = 0; + for (size_t i=0; i Q; + Q.push(i); + P(i,0) = num_patches; + while (!Q.empty()) { + const size_t fid = Q.front(); + Q.pop(); + for (size_t j=0; j<3; j++) { + if (is_manifold_edge(fid, j)) { + const size_t adj_fid = get_adj_face_index(fid, j); + if (P(adj_fid,0) == INVALID) { + Q.push(adj_fid); + P(adj_fid,0) = num_patches; + } + } + } + } + num_patches++; + } + assert((P.array() != INVALID).all()); + + return num_patches; +} + +template < + typename DerivedF, + typename DerivedP> +IGL_INLINE size_t igl::extract_manifold_patches( + const Eigen::MatrixBase &F, + Eigen::PlainObjectBase &P) +{ + Eigen::MatrixXi E, uE; + Eigen::VectorXi EMAP; + std::vector > uE2E; + igl::unique_edge_map(F, E, uE, EMAP, uE2E); + return igl::extract_manifold_patches(F, EMAP, uE2E, P); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template size_t igl::extract_manifold_patches, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template size_t igl::extract_manifold_patches, Eigen::Matrix, unsigned long, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, std::vector >, std::allocator > > > const&, Eigen::PlainObjectBase >&); +template size_t igl::extract_manifold_patches, Eigen::Matrix, unsigned long, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, std::vector >, std::allocator > > > const&, Eigen::PlainObjectBase >&); +#ifdef WIN32 +template unsigned __int64 igl::extract_manifold_patches, class Eigen::Matrix, unsigned __int64, class Eigen::Matrix>(class Eigen::MatrixBase> const &, class Eigen::MatrixBase> const &, class std::vector>, class std::allocator>>> const &, class Eigen::PlainObjectBase> &); +template unsigned __int64 igl::extract_manifold_patches, class Eigen::Matrix, unsigned __int64, class Eigen::Matrix>(class Eigen::MatrixBase> const &, class Eigen::MatrixBase> const &, class std::vector>, class std::allocator>>> const &, class Eigen::PlainObjectBase> &); +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/extract_manifold_patches.h b/src/external/libigl-2.3.0/include/igl/extract_manifold_patches.h new file mode 100644 index 000000000..c9467014b --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/extract_manifold_patches.h @@ -0,0 +1,51 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_EXTRACT_MANIFOLD_PATCHES +#define IGL_EXTRACT_MANIFOLD_PATCHES + +#include "igl_inline.h" +#include +#include + +namespace igl { + // Extract a set of maximal patches from a given mesh. + // A maximal patch is a subset of the input faces that are connected via + // manifold edges; a patch is as large as possible. + // + // Inputs: + // F #F by 3 list representing triangles. + // EMAP #F*3 list of indices of unique undirected edges. + // uE2E #uE list of lists of indices into E of coexisting edges. + // + // Output: + // P #F list of patch incides. + // + // Returns: + // number of manifold patches. + template < + typename DerivedF, + typename DerivedEMAP, + typename uE2EType, + typename DerivedP> + IGL_INLINE size_t extract_manifold_patches( + const Eigen::MatrixBase& F, + const Eigen::MatrixBase& EMAP, + const std::vector >& uE2E, + Eigen::PlainObjectBase& P); + template < + typename DerivedF, + typename DerivedP> + IGL_INLINE size_t extract_manifold_patches( + const Eigen::MatrixBase &F, + Eigen::PlainObjectBase &P); +} +#ifndef IGL_STATIC_LIBRARY +# include "extract_manifold_patches.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/extract_non_manifold_edge_curves.cpp b/src/external/libigl-2.3.0/include/igl/extract_non_manifold_edge_curves.cpp new file mode 100644 index 000000000..4bcbed470 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/extract_non_manifold_edge_curves.cpp @@ -0,0 +1,123 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "extract_non_manifold_edge_curves.h" +#include +#include +#include +#include +#include + +template< +typename DerivedF, +typename DerivedEMAP, +typename uE2EType > +IGL_INLINE void igl::extract_non_manifold_edge_curves( + const Eigen::MatrixBase& F, + const Eigen::MatrixBase& /*EMAP*/, + const std::vector >& uE2E, + std::vector >& curves) { + const size_t num_faces = F.rows(); + assert(F.cols() == 3); + //typedef std::pair Edge; + auto edge_index_to_face_index = [&](size_t ei) { return ei % num_faces; }; + auto edge_index_to_corner_index = [&](size_t ei) { return ei / num_faces; }; + auto get_edge_end_points = [&](size_t ei, size_t& s, size_t& d) { + const size_t fi = edge_index_to_face_index(ei); + const size_t ci = edge_index_to_corner_index(ei); + s = F(fi, (ci+1)%3); + d = F(fi, (ci+2)%3); + }; + + curves.clear(); + const size_t num_unique_edges = uE2E.size(); + std::unordered_multimap vertex_edge_adjacency; + std::vector non_manifold_edges; + for (size_t i=0; i 0); + assert(vertex_edge_adjacency.count(d) > 0); + } + + auto expand_forward = [&](std::list& edge_curve, + size_t& front_vertex, size_t& end_vertex) { + while(vertex_edge_adjacency.count(front_vertex) == 2 && + front_vertex != end_vertex) { + auto adj_edges = vertex_edge_adjacency.equal_range(front_vertex); + for (auto itr = adj_edges.first; itr!=adj_edges.second; itr++) { + const size_t uei = itr->second; + assert(uE2E.at(uei).size() != 2); + const size_t ei = uE2E[uei][0]; + if (uei == edge_curve.back()) continue; + size_t s,d; + get_edge_end_points(ei, s, d); + edge_curve.push_back(uei); + if (s == front_vertex) { + front_vertex = d; + } else if (d == front_vertex) { + front_vertex = s; + } else { + throw "Invalid vertex/edge adjacency!"; + } + break; + } + } + }; + + auto expand_backward = [&](std::list& edge_curve, + size_t& front_vertex, size_t& end_vertex) { + while(vertex_edge_adjacency.count(front_vertex) == 2 && + front_vertex != end_vertex) { + auto adj_edges = vertex_edge_adjacency.equal_range(front_vertex); + for (auto itr = adj_edges.first; itr!=adj_edges.second; itr++) { + const size_t uei = itr->second; + assert(uE2E.at(uei).size() != 2); + const size_t ei = uE2E[uei][0]; + if (uei == edge_curve.front()) continue; + size_t s,d; + get_edge_end_points(ei, s, d); + edge_curve.push_front(uei); + if (s == front_vertex) { + front_vertex = d; + } else if (d == front_vertex) { + front_vertex = s; + } else { + throw "Invalid vertex/edge adjcency!"; + } + break; + } + } + }; + + std::vector visited(num_unique_edges, false); + for (const size_t i : non_manifold_edges) { + if (visited[i]) continue; + std::list edge_curve; + edge_curve.push_back(i); + + const auto& adj_edges = uE2E[i]; + assert(adj_edges.size() != 2); + const size_t ei = adj_edges[0]; + size_t s,d; + get_edge_end_points(ei, s, d); + + expand_forward(edge_curve, d, s); + expand_backward(edge_curve, s, d); + curves.emplace_back(edge_curve.begin(), edge_curve.end()); + for (auto itr = edge_curve.begin(); itr!=edge_curve.end(); itr++) { + visited[*itr] = true; + } + } + +} diff --git a/src/external/libigl-2.3.0/include/igl/extract_non_manifold_edge_curves.h b/src/external/libigl-2.3.0/include/igl/extract_non_manifold_edge_curves.h new file mode 100644 index 000000000..c8ddbec72 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/extract_non_manifold_edge_curves.h @@ -0,0 +1,47 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_NON_MANIFOLD_EDGE_CURVES +#define IGL_NON_MANIFOLD_EDGE_CURVES + +#include "igl_inline.h" +#include +#include + +namespace igl { + // Extract non-manifold curves from a given mesh. + // A non-manifold curves are a set of connected non-manifold edges that + // does not touch other non-manifold edges except at the end points. + // They are also maximal in the sense that they cannot be expanded by + // including more edges. + // + // Assumes the input mesh have all self-intersection resolved. See + // ``igl::cgal::remesh_self_intersection`` for more details. + // + // Inputs: + // F #F by 3 list representing triangles. + // EMAP #F*3 list of indices of unique undirected edges. + // uE2E #uE list of lists of indices into E of coexisting edges. + // + // Output: + // curves An array of arries of unique edge indices. + template< + typename DerivedF, + typename DerivedEMAP, + typename uE2EType> + IGL_INLINE void extract_non_manifold_edge_curves( + const Eigen::MatrixBase& F, + const Eigen::MatrixBase& EMAP, + const std::vector >& uE2E, + std::vector >& curves); +} + +#ifndef IGL_STATIC_LIBRARY +# include "extract_non_manifold_edge_curves.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/face_areas.cpp b/src/external/libigl-2.3.0/include/igl/face_areas.cpp new file mode 100644 index 000000000..74bf7fce0 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/face_areas.cpp @@ -0,0 +1,65 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "face_areas.h" +#include "edge_lengths.h" +#include "doublearea.h" + +template +IGL_INLINE void igl::face_areas( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& T, + Eigen::PlainObjectBase& A) +{ + assert(T.cols() == 4); + DerivedA L; + edge_lengths(V,T,L); + return face_areas(L,A); +} + +template +IGL_INLINE void igl::face_areas( + const Eigen::MatrixBase& L, + Eigen::PlainObjectBase& A) +{ + return face_areas( + L,std::numeric_limits::quiet_NaN(),A); +} + +template +IGL_INLINE void igl::face_areas( + const Eigen::MatrixBase& L, + const typename DerivedL::Scalar doublearea_nan_replacement, + Eigen::PlainObjectBase& A) +{ + using namespace Eigen; + assert(L.cols() == 6); + const int m = L.rows(); + // (unsigned) face Areas (opposite vertices: 1 2 3 4) + Matrix + A0(m,1), A1(m,1), A2(m,1), A3(m,1); + Matrix + L0(m,3), L1(m,3), L2(m,3), L3(m,3); + L0<, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/face_areas.h b/src/external/libigl-2.3.0/include/igl/face_areas.h new file mode 100644 index 000000000..9676deadc --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/face_areas.h @@ -0,0 +1,58 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_FACE_AREAS_H +#define IGL_FACE_AREAS_H +#include "igl_inline.h" + +#include + +namespace igl +{ + // Constructs a list of face areas of faces opposite each index in a tet list + // + // Inputs: + // V #V by 3 list of mesh vertex positions + // T #T by 3 list of tet mesh indices into V + // Outputs: + // A #T by 4 list of face areas corresponding to faces opposite vertices + // 0,1,2,3 + // + template + IGL_INLINE void face_areas( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& T, + Eigen::PlainObjectBase& A); + // Compute tet-mesh face areas from edge lengths. + // + // Inputs: + // L #T by 6 list of tet-mesh edge lengths corresponding to edges + // [3 0],[3 1],[3 2],[1 2],[2 0],[0 1] + // Outputs: + // A #T by 4 list of face areas corresponding to faces opposite vertices + // 0,1,2,3: i.e. made of edges [123],[024],[015],[345] + // + // + template + IGL_INLINE void face_areas( + const Eigen::MatrixBase& L, + Eigen::PlainObjectBase& A); + // doublearea_nan_replacement See doublearea.h + template + IGL_INLINE void face_areas( + const Eigen::MatrixBase& L, + const typename DerivedL::Scalar doublearea_nan_replacement, + Eigen::PlainObjectBase& A); +} + +#ifndef IGL_STATIC_LIBRARY +# include "face_areas.cpp" +#endif + +#endif + + diff --git a/src/external/libigl-2.3.0/include/igl/face_occurrences.cpp b/src/external/libigl-2.3.0/include/igl/face_occurrences.cpp new file mode 100644 index 000000000..1f5c4531e --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/face_occurrences.cpp @@ -0,0 +1,73 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "face_occurrences.h" +#include "list_to_matrix.h" +#include "matrix_to_list.h" + +#include +#include "sort.h" +#include + +template +IGL_INLINE void igl::face_occurrences( + const std::vector > & F, + std::vector & C) +{ + using namespace std; + + // Get a list of sorted faces + vector > sortedF = F; + for(int i = 0; i < (int)F.size();i++) + { + sort(sortedF[i].begin(),sortedF[i].end()); + } + // Count how many times each sorted face occurs + map,int> counts; + for(int i = 0; i < (int)sortedF.size();i++) + { + if(counts.find(sortedF[i]) == counts.end()) + { + // initialize to count of 1 + counts[sortedF[i]] = 1; + }else + { + // increment count + counts[sortedF[i]]++; + assert(counts[sortedF[i]] == 2 && "Input should be manifold"); + } + } + + // Resize output to fit number of ones + C.resize(F.size()); + for(int i = 0;i< (int)F.size();i++) + { + // sorted face should definitely be in counts map + assert(counts.find(sortedF[i]) != counts.end()); + C[i] = static_cast(counts[sortedF[i]]); + } +} + +template +IGL_INLINE void igl::face_occurrences( + const Eigen::MatrixBase & F, + Eigen::PlainObjectBase & C) +{ + // Should really just rewrite using Eigen+libigl ... + std::vector > vF; + matrix_to_list(F,vF); + std::vector vC; + igl::face_occurrences(vF,vC); + list_to_matrix(vC,C); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::face_occurrences(std::vector >, std::allocator > > > const&, std::vector >&); +template void igl::face_occurrences(std::vector >, std::allocator > > > const&, std::vector >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/face_occurrences.h b/src/external/libigl-2.3.0/include/igl/face_occurrences.h new file mode 100644 index 000000000..48f4b11e2 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/face_occurrences.h @@ -0,0 +1,39 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_FACE_OCCURRENCES +#define IGL_FACE_OCCURRENCES +#include "igl_inline.h" +#include + +#include +namespace igl +{ + // Count the occurances of each face (row) in a list of face indices + // (irrespecitive of order) + // Inputs: + // F #F by simplex-size + // Outputs + // C #F list of counts + // Known bug: triangles/tets only (where ignoring order still gives simplex) + template + IGL_INLINE void face_occurrences( + const std::vector > & F, + std::vector & C); + template + IGL_INLINE void face_occurrences( + const Eigen::MatrixBase & F, + Eigen::PlainObjectBase & C); +} + +#ifndef IGL_STATIC_LIBRARY +# include "face_occurrences.cpp" +#endif + +#endif + + diff --git a/src/external/libigl-2.3.0/include/igl/faces_first.cpp b/src/external/libigl-2.3.0/include/igl/faces_first.cpp new file mode 100644 index 000000000..9c0fa0d0b --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/faces_first.cpp @@ -0,0 +1,103 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "faces_first.h" + +#include +#include + +template +IGL_INLINE void igl::faces_first( + const MatV & V, + const MatF & F, + MatV & RV, + MatF & RF, + VecI & IM) +{ + assert(&V != &RV); + assert(&F != &RF); + using namespace std; + using namespace Eigen; + vector in_face(V.rows()); + for(int i = 0; i +IGL_INLINE void igl::faces_first( + MatV & V, + MatF & F, + VecI & IM) +{ + MatV RV; + // Copying F may not be needed, seems RF = F is safe (whereas RV = V is not) + MatF RF; + igl::faces_first(V,F,RV,RF,IM); + V = RV; + F = RF; +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +template void igl::faces_first, Eigen::Matrix, Eigen::Matrix >(Eigen::Matrix&, Eigen::Matrix&, Eigen::Matrix&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/faces_first.h b/src/external/libigl-2.3.0/include/igl/faces_first.h new file mode 100644 index 000000000..92d1d5565 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/faces_first.h @@ -0,0 +1,60 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_FACES_FIRST_H +#define IGL_FACES_FIRST_H +#include "igl_inline.h" +namespace igl +{ + // FACES_FIRST Reorder vertices so that vertices in face list come before + // vertices that don't appear in the face list. This is especially useful if + // the face list contains only surface faces and you want surface vertices + // listed before internal vertices + // + // [RV,RT,RF,IM] = faces_first(V,T,F); + // + // Templates: + // MatV matrix for vertex positions, e.g. MatrixXd + // MatF matrix for face indices, e.g. MatrixXi + // VecI vector for index map, e.g. VectorXi + // Input: + // V # vertices by 3 vertex positions + // F # faces by 3 list of face indices + // Output: + // RV # vertices by 3 vertex positions, order such that if the jth vertex is + // some face in F, and the kth vertex is not then j comes before k + // RF # faces by 3 list of face indices, reindexed to use RV + // IM #V by 1 list of indices such that: RF = IM(F) and RT = IM(T) + // and RV(IM,:) = V + // + // + // Example: + // // Tet mesh in (V,T,F) + // faces_first(V,F,IM); + // T = T.unaryExpr(bind1st(mem_fun( static_cast(&VectorXi::operator())), + // &IM)).eval(); + template + IGL_INLINE void faces_first( + const MatV & V, + const MatF & F, + MatV & RV, + MatF & RF, + VecI & IM); + // Virtual "in place" wrapper + template + IGL_INLINE void faces_first( + MatV & V, + MatF & F, + VecI & IM); +} + +#ifndef IGL_STATIC_LIBRARY +# include "faces_first.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/facet_adjacency_matrix.cpp b/src/external/libigl-2.3.0/include/igl/facet_adjacency_matrix.cpp new file mode 100644 index 000000000..669b4ef0c --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/facet_adjacency_matrix.cpp @@ -0,0 +1,58 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2020 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "facet_adjacency_matrix.h" +#include "unique_edge_map.h" + +template +IGL_INLINE void igl::facet_adjacency_matrix( + const Eigen::MatrixBase & F, Eigen::SparseMatrix & A) +{ + using namespace Eigen; + typedef typename DerivedF::Scalar Index; + const auto m = F.rows(); + Eigen::Matrix EMAP,uEE,uEC; + Eigen::Matrix E,uE; + igl::unique_edge_map(F,E,uE,EMAP,uEC,uEE); + std::vector > AIJV; + AIJV.reserve(2*uE.rows()); + const Eigen::Index nu = uE.rows(); + for(Eigen::Index ue = 0;ue0 + A.resize(m,m); + A.setFromTriplets(AIJV.begin(),AIJV.end()); + // Set all non-zerro values to 1 + for(Eigen::Index g = 0;g::InnerIterator it (A,g); it; ++it) + { + if(it.value()) it.valueRef() = 1; + } + } +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::facet_adjacency_matrix, int>(Eigen::MatrixBase > const&, Eigen::SparseMatrix&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/facet_adjacency_matrix.h b/src/external/libigl-2.3.0/include/igl/facet_adjacency_matrix.h new file mode 100644 index 000000000..4f258ccd5 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/facet_adjacency_matrix.h @@ -0,0 +1,33 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2020 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_FACET_ADJACENCY_MATRIX_H +#define IGL_FACET_ADJACENCY_MATRIX_H +#include +#include +#include "igl_inline.h" + +namespace igl +{ + // Construct a #F×#F adjacency matrix with A(i,j)>0 indicating that faces i and j + // share an edge. + // + // Inputs: + // F #F by 3 list of facets + // Outputs: + // A #F by #F adjacency matrix + template + IGL_INLINE void facet_adjacency_matrix( + const Eigen::MatrixBase & F, + Eigen::SparseMatrix & A); +}; + +#ifndef IGL_STATIC_LIBRARY +# include "facet_adjacency_matrix.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/facet_components.cpp b/src/external/libigl-2.3.0/include/igl/facet_components.cpp new file mode 100644 index 000000000..922a330f8 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/facet_components.cpp @@ -0,0 +1,98 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// Copyright (C) 2020 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "facet_components.h" +#include "triangle_triangle_adjacency.h" +#include "facet_adjacency_matrix.h" +#include "connected_components.h" +#include +#include + +template +IGL_INLINE int igl::facet_components( + const Eigen::MatrixBase & F, + Eigen::PlainObjectBase & C) +{ + typedef typename DerivedF::Scalar Index; + Eigen::SparseMatrix A; + igl::facet_adjacency_matrix(F,A); + Eigen::Matrix counts; + C = DerivedC::Zero(1,1); + return connected_components(A,C,counts); +} + +template < + typename TTIndex, + typename DerivedC, + typename Derivedcounts> +IGL_INLINE void igl::facet_components( + const std::vector > > & TT, + Eigen::PlainObjectBase & C, + Eigen::PlainObjectBase & counts) +{ + using namespace std; + typedef TTIndex Index; + const Index m = TT.size(); + C.resize(m,1); + vector seen(m,false); + Index id = 0; + vector vcounts; + for(Index g = 0;g Q; + Q.push(g); + while(!Q.empty()) + { + const Index f = Q.front(); + Q.pop(); + if(seen[f]) + { + continue; + } + seen[f] = true; + vcounts[id]++; + C(f,0) = id; + // Face f's neighbor lists opposite opposite each corner + for(const auto & c : TT[f]) + { + // Each neighbor + for(const auto & n : c) + { + if(!seen[n]) + { + Q.push(n); + } + } + } + } + id++; + } + assert((size_t) id == vcounts.size()); + const size_t ncc = vcounts.size(); + assert((size_t)C.maxCoeff()+1 == ncc); + counts.resize(ncc,1); + for(size_t i = 0;i, Eigen::Matrix >(std::vector >, std::allocator > > >, std::allocator >, std::allocator > > > > > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::facet_components, Eigen::Matrix >(std::vector >, std::allocator > > >, std::allocator >, std::allocator > > > > > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template int igl::facet_components, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +#ifdef WIN32 +template void igl::facet_components<__int64,class Eigen::Matrix<__int64,-1,1,0,-1,1>,class Eigen::Matrix<__int64,-1,1,0,-1,1> >(class std::vector >,class std::allocator > > >,class std::allocator >,class std::allocator > > > > > const &,class Eigen::PlainObjectBase > &,class Eigen::PlainObjectBase > &); +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/facet_components.h b/src/external/libigl-2.3.0/include/igl/facet_components.h new file mode 100644 index 000000000..d043b0fc9 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/facet_components.h @@ -0,0 +1,50 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef FACET_COMPONENTS_H +#define FACET_COMPONENTS_H +#include "igl_inline.h" +#include +#include +namespace igl +{ + // Compute connected components of facets based on edge-edge adjacency. + // + // For connected components on vertices see igl::vertex_components + // + // Inputs: + // F #F by 3 list of triangle indices + // Outputs: + // C #F list of connected component ids + template + IGL_INLINE int facet_components( + const Eigen::MatrixBase & F, + Eigen::PlainObjectBase & C); + + // Compute connected components of facets based on edge-edge adjacency. + // + // For connected components on vertices see igl::vertex_components + // + // Inputs: + // TT #TT by 3 list of list of adjacency triangles (see + // triangle_triangle_adjacency.h) + // Outputs: + // C #F list of connected component ids + // counts #C list of number of facets in each components + template < + typename TTIndex, + typename DerivedC, + typename Derivedcounts> + IGL_INLINE void facet_components( + const std::vector > > & TT, + Eigen::PlainObjectBase & C, + Eigen::PlainObjectBase & counts); +} +#ifndef IGL_STATIC_LIBRARY +# include "facet_components.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/false_barycentric_subdivision.cpp b/src/external/libigl-2.3.0/include/igl/false_barycentric_subdivision.cpp new file mode 100644 index 000000000..8ea807a50 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/false_barycentric_subdivision.cpp @@ -0,0 +1,59 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "false_barycentric_subdivision.h" + +#include "verbose.h" +#include +#include + +template +IGL_INLINE void igl::false_barycentric_subdivision( + const Eigen::PlainObjectBase & V, + const Eigen::PlainObjectBase & F, + Eigen::PlainObjectBase & VD, + Eigen::PlainObjectBase & FD) +{ + using namespace Eigen; + // Compute face barycenter + Eigen::MatrixXd BC; + igl::barycenter(V,F,BC); + + // Add the barycenters to the vertices + VD.resize(V.rows()+F.rows(),3); + VD.block(0,0,V.rows(),3) = V; + VD.block(V.rows(),0,F.rows(),3) = BC; + + // Each face is split four ways + FD.resize(F.rows()*3,3); + + for (unsigned i=0; i, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::false_barycentric_subdivision, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/false_barycentric_subdivision.h b/src/external/libigl-2.3.0/include/igl/false_barycentric_subdivision.h new file mode 100644 index 000000000..98426b572 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/false_barycentric_subdivision.h @@ -0,0 +1,39 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_ADD_BARYCENTER_H +#define IGL_ADD_BARYCENTER_H +#include "igl_inline.h" + +#include + +namespace igl +{ + // Refine the mesh by adding the barycenter of each face + // Inputs: + // V #V by 3 coordinates of the vertices + // F #F by 3 list of mesh faces (must be triangles) + // Outputs: + // VD #V + #F by 3 coordinate of the vertices of the dual mesh + // The added vertices are added at the end of VD (should not be + // same references as (V,F) + // FD #F*3 by 3 faces of the dual mesh + // + template + IGL_INLINE void false_barycentric_subdivision( + const Eigen::PlainObjectBase & V, + const Eigen::PlainObjectBase & F, + Eigen::PlainObjectBase & VD, + Eigen::PlainObjectBase & FD); + +} + +#ifndef IGL_STATIC_LIBRARY +# include "false_barycentric_subdivision.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/fast_winding_number.cpp b/src/external/libigl-2.3.0/include/igl/fast_winding_number.cpp new file mode 100644 index 000000000..4a5f7ea37 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/fast_winding_number.cpp @@ -0,0 +1,484 @@ +#include "fast_winding_number.h" +#include "octree.h" +#include "knn.h" +#include "parallel_for.h" +#include "PI.h" +#include +#include + +template < + typename DerivedP, + typename DerivedA, + typename DerivedN, + typename Index, + typename DerivedCH, + typename DerivedCM, + typename DerivedR, + typename DerivedEC> +IGL_INLINE void igl::fast_winding_number( + const Eigen::MatrixBase& P, + const Eigen::MatrixBase& N, + const Eigen::MatrixBase& A, + const std::vector > & point_indices, + const Eigen::MatrixBase& CH, + const int expansion_order, + Eigen::PlainObjectBase& CM, + Eigen::PlainObjectBase& R, + Eigen::PlainObjectBase& EC) +{ + typedef typename DerivedP::Scalar real_p; + typedef typename DerivedN::Scalar real_n; + typedef typename DerivedA::Scalar real_a; + typedef typename DerivedCM::Scalar real_cm; + typedef typename DerivedR::Scalar real_r; + typedef typename DerivedEC::Scalar real_ec; + + typedef Eigen::Matrix RowVec3p; + + int m = CH.size(); + int num_terms; + + assert(expansion_order < 3 && expansion_order >= 0 && "m must be less than n"); + if(expansion_order == 0){ + num_terms = 3; + } else if(expansion_order ==1){ + num_terms = 3 + 9; + } else if(expansion_order == 2){ + num_terms = 3 + 9 + 27; + } + + R.resize(m); + CM.resize(m,3); + EC.resize(m,num_terms); + EC.setZero(m,num_terms); + std::function< void(const int) > helper; + helper = [&helper, + &P,&N,&A,&expansion_order,&point_indices,&CH,&EC,&R,&CM] + (const int index)-> void + { + Eigen::Matrix masscenter; + masscenter << 0,0,0; + Eigen::Matrix zeroth_expansion; + zeroth_expansion << 0,0,0; + real_p areatotal = 0.0; + for(int j = 0; j < point_indices[index].size(); j++){ + int curr_point_index = point_indices[index][j]; + + areatotal += A(curr_point_index); + masscenter += A(curr_point_index)*P.row(curr_point_index); + zeroth_expansion += A(curr_point_index)*N.row(curr_point_index); + } + + masscenter = masscenter/areatotal; + CM.row(index) = masscenter; + EC.block(index,0,1,3) = zeroth_expansion; + + real_r max_norm = 0; + real_r curr_norm; + + for(int i = 0; i < point_indices[index].size(); i++){ + //Get max distance from center of mass: + int curr_point_index = point_indices[index][i]; + Eigen::Matrix point = + P.row(curr_point_index)-masscenter; + curr_norm = point.norm(); + if(curr_norm > max_norm){ + max_norm = curr_norm; + } + + //Calculate higher order terms if necessary + Eigen::Matrix TempCoeffs; + if(EC.cols() >= (3+9)){ + TempCoeffs = A(curr_point_index)*point.transpose()* + N.row(curr_point_index); + EC.block(index,3,1,9) += + Eigen::Map >(TempCoeffs.data(), + TempCoeffs.size()); + } + + if(EC.cols() == (3+9+27)){ + for(int k = 0; k < 3; k++){ + TempCoeffs = 0.5 * point(k) * (A(curr_point_index)* + point.transpose()*N.row(curr_point_index)); + EC.block(index,12+9*k,1,9) += Eigen::Map< + Eigen::Matrix >(TempCoeffs.data(), + TempCoeffs.size()); + } + } + } + + R(index) = max_norm; + if(CH(index,0) != -1) + { + for(int i = 0; i < 8; i++){ + int child = CH(index,i); + helper(child); + } + } + }; + helper(0); +} + +template < + typename DerivedP, + typename DerivedA, + typename DerivedN, + typename Index, + typename DerivedCH, + typename DerivedCM, + typename DerivedR, + typename DerivedEC, + typename DerivedQ, + typename BetaType, + typename DerivedWN> +IGL_INLINE void igl::fast_winding_number( + const Eigen::MatrixBase& P, + const Eigen::MatrixBase& N, + const Eigen::MatrixBase& A, + const std::vector > & point_indices, + const Eigen::MatrixBase& CH, + const Eigen::MatrixBase& CM, + const Eigen::MatrixBase& R, + const Eigen::MatrixBase& EC, + const Eigen::MatrixBase& Q, + const BetaType beta, + Eigen::PlainObjectBase& WN) +{ + + typedef typename DerivedP::Scalar real_p; + typedef typename DerivedN::Scalar real_n; + typedef typename DerivedA::Scalar real_a; + typedef typename DerivedCM::Scalar real_cm; + typedef typename DerivedR::Scalar real_r; + typedef typename DerivedEC::Scalar real_ec; + typedef typename DerivedQ::Scalar real_q; + typedef typename DerivedWN::Scalar real_wn; + const real_wn PI_4 = 4.0*igl::PI; + + typedef Eigen::Matrix< + typename DerivedEC::Scalar, + 1, + DerivedEC::ColsAtCompileTime> ECRow; + + typedef Eigen::Matrix RowVec; + typedef Eigen::Matrix EC_3by3; + + auto direct_eval = [&PI_4]( + const RowVec & loc, + const Eigen::Matrix & anorm)->real_wn + { + const typename RowVec::Scalar loc_norm = loc.norm(); + if(loc_norm == 0) + { + return 0.5; + }else + { + return (loc(0)*anorm(0)+loc(1)*anorm(1)+loc(2)*anorm(2)) + /(PI_4*(loc_norm*loc_norm*loc_norm)); + } + }; + + auto expansion_eval = + [&direct_eval,&EC,&PI_4]( + const RowVec & loc, + const int & child_index)->real_wn + { + real_wn wn; + wn = direct_eval(loc,EC.row(child_index).template head<3>()); + real_wn r = loc.norm(); + real_wn PI_4_r3; + real_wn PI_4_r5; + real_wn PI_4_r7; + if(EC.row(child_index).size()>3) + { + PI_4_r3 = PI_4*r*r*r; + PI_4_r5 = PI_4_r3*r*r; + const real_ec d = 1.0/(PI_4_r3); + Eigen::Matrix SecondDerivative = + loc.transpose()*loc*(-3.0/(PI_4_r5)); + SecondDerivative(0,0) += d; + SecondDerivative(1,1) += d; + SecondDerivative(2,2) += d; + wn += + Eigen::Map >( + SecondDerivative.data(), + SecondDerivative.size()).dot( + EC.row(child_index).template segment<9>(3)); + } + if(EC.row(child_index).size()>3+9) + { + PI_4_r7 = PI_4_r5*r*r; + const Eigen::Matrix locTloc = loc.transpose()*(loc/(PI_4_r7)); + for(int i = 0; i < 3; i++) + { + Eigen::Matrix RowCol_Diagonal = + Eigen::Matrix::Zero(3,3); + for(int u = 0;u<3;u++) + { + for(int v = 0;v<3;v++) + { + if(u==v) RowCol_Diagonal(u,v) += loc(i); + if(u==i) RowCol_Diagonal(u,v) += loc(v); + if(v==i) RowCol_Diagonal(u,v) += loc(u); + } + } + Eigen::Matrix ThirdDerivative = + 15.0*loc(i)*locTloc + (-3.0/(PI_4_r5))*(RowCol_Diagonal); + + wn += Eigen::Map >( + ThirdDerivative.data(), + ThirdDerivative.size()).dot( + EC.row(child_index).template segment<9>(12 + i*9)); + } + } + return wn; + }; + + int m = Q.rows(); + WN.resize(m,1); + + std::function< real_wn(const RowVec & , const std::vector &) > helper; + helper = [&helper, + &P,&N,&A, + &point_indices,&CH, + &CM,&R,&EC,&beta, + &direct_eval,&expansion_eval] + (const RowVec & query, const std::vector & near_indices)-> real_wn + { + real_wn wn = 0; + std::vector new_near_indices; + new_near_indices.reserve(8); + for(int i = 0; i < near_indices.size(); i++) + { + int index = near_indices[i]; + //Leaf Case, Brute force + if(CH(index,0) == -1) + { + for(int j = 0; j < point_indices[index].size(); j++) + { + int curr_row = point_indices[index][j]; + wn += direct_eval(P.row(curr_row)-query, + N.row(curr_row)*A(curr_row)); + } + } + //Non-Leaf Case + else + { + for(int child = 0; child < 8; child++) + { + int child_index = CH(index,child); + if(point_indices[child_index].size() > 0) + { + const RowVec CMciq = (CM.row(child_index)-query); + if(CMciq.norm() > beta*R(child_index)) + { + if(CH(child_index,0) == -1) + { + for(int j=0;j 0) + { + wn += helper(query,new_near_indices); + } + return wn; + }; + + if(beta > 0) + { + const std::vector near_indices_start = {0}; + igl::parallel_for(m,[&](int iter){ + WN(iter) = helper(Q.row(iter).eval(),near_indices_start); + },1000); + } else + { + igl::parallel_for(m,[&](int iter){ + double wn = 0; + for(int j = 0; j +IGL_INLINE void igl::fast_winding_number( + const Eigen::MatrixBase& P, + const Eigen::MatrixBase& N, + const Eigen::MatrixBase& A, + const Eigen::MatrixBase& Q, + const int expansion_order, + const BetaType beta, + Eigen::PlainObjectBase& WN) +{ + typedef typename DerivedWN::Scalar real; + + std::vector > point_indices; + Eigen::Matrix CH; + Eigen::Matrix CN; + Eigen::Matrix W; + + octree(P,point_indices,CH,CN,W); + + Eigen::Matrix EC; + Eigen::Matrix CM; + Eigen::Matrix R; + + fast_winding_number(P,N,A,point_indices,CH,expansion_order,CM,R,EC); + fast_winding_number(P,N,A,point_indices,CH,CM,R,EC,Q,beta,WN); +} + +template < + typename DerivedP, + typename DerivedA, + typename DerivedN, + typename DerivedQ, + typename DerivedWN> +IGL_INLINE void igl::fast_winding_number( + const Eigen::MatrixBase& P, + const Eigen::MatrixBase& N, + const Eigen::MatrixBase& A, + const Eigen::MatrixBase& Q, + Eigen::PlainObjectBase& WN) +{ + fast_winding_number(P,N,A,Q,2,2.0,WN); +} + +template < + typename DerivedV, + typename DerivedF, + typename DerivedQ, + typename DerivedW> +IGL_INLINE void igl::fast_winding_number( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const Eigen::MatrixBase & Q, + Eigen::PlainObjectBase & W) +{ + igl::FastWindingNumberBVH fwn_bvh; + int order = 2; + igl::fast_winding_number(V,F,order,fwn_bvh); + float accuracy_scale = 2; + igl::fast_winding_number(fwn_bvh,accuracy_scale,Q,W); +} + +template < + typename DerivedV, + typename DerivedF> +IGL_INLINE void igl::fast_winding_number( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const int order, + FastWindingNumberBVH & fwn_bvh) +{ + assert(V.cols() == 3 && "V should be 3D"); + assert(F.cols() == 3 && "F should contain triangles"); + // Extra copies. Usuually this won't be the bottleneck. + fwn_bvh.U.resize(V.rows()); + for(int i = 0;i +IGL_INLINE void igl::fast_winding_number( + const FastWindingNumberBVH & fwn_bvh, + const float accuracy_scale, + const Eigen::MatrixBase & Q, + Eigen::PlainObjectBase & W) +{ + assert(Q.cols() == 3 && "Q should be 3D"); + W.resize(Q.rows(),1); + igl::parallel_for(Q.rows(),[&](int p) + { + FastWindingNumber::HDK_Sample::UT_Vector3TQp; + Qp[0] = Q(p,0); + Qp[1] = Q(p,1); + Qp[2] = Q(p,2); + W(p) = fwn_bvh.ut_solid_angle.computeSolidAngle(Qp,accuracy_scale) / (4.0*igl::PI); + },1000); +} + +template +IGL_INLINE typename Derivedp::Scalar igl::fast_winding_number( + const FastWindingNumberBVH & fwn_bvh, + const float accuracy_scale, + const Eigen::MatrixBase & p) +{ + assert(p.cols() == 3 && "p should be 3D"); + + FastWindingNumber::HDK_Sample::UT_Vector3TQp; + Qp[0] = p(0,0); + Qp[1] = p(0,1); + Qp[2] = p(0,2); + + typename Derivedp::Scalar w = fwn_bvh.ut_solid_angle.computeSolidAngle(Qp,accuracy_scale) / (4.0*igl::PI); + + return w; +} + + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::fast_winding_number, Eigen::Matrix >(igl::FastWindingNumberBVH const&, float, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template Eigen::Matrix::Scalar igl::fast_winding_number >(igl::FastWindingNumberBVH const&, float, Eigen::MatrixBase > const&); +// generated by autoexplicit.sh +template void igl::fast_winding_number, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::fast_winding_number, Eigen::Matrix, Eigen::Matrix, int, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, int, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, std::vector >, std::allocator > > > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, int, Eigen::PlainObjectBase >&); +template void igl::fast_winding_number, Eigen::Matrix, Eigen::Matrix, int, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, std::vector >, std::allocator > > > const&, Eigen::MatrixBase > const&, int, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::fast_winding_number, Eigen::Matrix >(igl::FastWindingNumberBVH const&, float, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::fast_winding_number, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, int, igl::FastWindingNumberBVH&); +template void igl::fast_winding_number, Eigen::Matrix >(igl::FastWindingNumberBVH const&, float, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::fast_winding_number, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, int, igl::FastWindingNumberBVH&); + +// tom did this manually. Unsure how to generate otherwise... sorry. +template Eigen::Matrix::Scalar igl::fast_winding_number >(igl::FastWindingNumberBVH const&, float, Eigen::MatrixBase > const&); +template void igl::fast_winding_number, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, int, igl::FastWindingNumberBVH&); +template void igl::fast_winding_number, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, int, igl::FastWindingNumberBVH&); +template Eigen::CwiseUnaryOp, Eigen::Matrix const>::Scalar igl::fast_winding_number, Eigen::Matrix const> >(igl::FastWindingNumberBVH const&, float, Eigen::MatrixBase, Eigen::Matrix const> > const&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/fast_winding_number.h b/src/external/libigl-2.3.0/include/igl/fast_winding_number.h new file mode 100644 index 000000000..0b742d350 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/fast_winding_number.h @@ -0,0 +1,228 @@ +#ifndef IGL_FAST_WINDING_NUMBER +#define IGL_FAST_WINDING_NUMBER +#include "igl_inline.h" +#include "FastWindingNumberForSoups.h" +#include +#include +namespace igl +{ + // Generate the precomputation for the fast winding number for point data + // [Barill et. al 2018]. + // + // Given a set of 3D points P, with normals N, areas A, along with octree + // data, and an expansion order, we define a taylor series expansion at each + // octree cell. + // + // The octree data is designed to come from igl::octree, and the areas (if not + // obtained at scan time), may be calculated using + // igl::copyleft::cgal::point_areas. + // + // Inputs: + // P #P by 3 list of point locations + // N #P by 3 list of point normals + // A #P by 1 list of point areas + // point_indices a vector of vectors, where the ith entry is a vector of + // the indices into P that are the ith octree cell's points + // CH #OctreeCells by 8, where the ith row is the indices of + // the ith octree cell's children + // expansion_order the order of the taylor expansion. We support 0,1,2. + // Outputs: + // CM #OctreeCells by 3 list of each cell's center of mass + // R #OctreeCells by 1 list of each cell's maximum distance of any point + // to the center of mass + // EC #OctreeCells by #TaylorCoefficients list of expansion coefficients. + // (Note that #TaylorCoefficients = ∑_{i=1}^{expansion_order} 3^i) + // + // See also: igl::copyleft::cgal::point_areas, igl::knn + template < + typename DerivedP, + typename DerivedA, + typename DerivedN, + typename Index, + typename DerivedCH, + typename DerivedCM, + typename DerivedR, + typename DerivedEC> + IGL_INLINE void fast_winding_number( + const Eigen::MatrixBase& P, + const Eigen::MatrixBase& N, + const Eigen::MatrixBase& A, + const std::vector > & point_indices, + const Eigen::MatrixBase& CH, + const int expansion_order, + Eigen::PlainObjectBase& CM, + Eigen::PlainObjectBase& R, + Eigen::PlainObjectBase& EC); + // Evaluate the fast winding number for point data, having already done the + // the precomputation + // + // Inputs: + // P #P by 3 list of point locations + // N #P by 3 list of point normals + // A #P by 1 list of point areas + // point_indices a vector of vectors, where the ith entry is a vector of + // the indices into P that are the ith octree cell's points + // CH #OctreeCells by 8, where the ith row is the indices of + // the ith octree cell's children + // CM #OctreeCells by 3 list of each cell's center of mass + // R #OctreeCells by 1 list of each cell's maximum distance of any point + // to the center of mass + // EC #OctreeCells by #TaylorCoefficients list of expansion coefficients. + // (Note that #TaylorCoefficients = ∑_{i=1}^{expansion_order} 3^i) + // Q #Q by 3 list of query points for the winding number + // beta This is a Barnes-Hut style accuracy term that separates near feild + // from far field. The higher the beta, the more accurate and slower + // the evaluation. We reccommend using a beta value of 2. Note that + // for a beta value ≤ 0, we use the direct evaluation, rather than + // the fast approximation + // Outputs: + // WN #Q by 1 list of windinng number values at each query point + // + template < + typename DerivedP, + typename DerivedA, + typename DerivedN, + typename Index, + typename DerivedCH, + typename DerivedCM, + typename DerivedR, + typename DerivedEC, + typename DerivedQ, + typename BetaType, + typename DerivedWN> + IGL_INLINE void fast_winding_number( + const Eigen::MatrixBase& P, + const Eigen::MatrixBase& N, + const Eigen::MatrixBase& A, + const std::vector > & point_indices, + const Eigen::MatrixBase& CH, + const Eigen::MatrixBase& CM, + const Eigen::MatrixBase& R, + const Eigen::MatrixBase& EC, + const Eigen::MatrixBase& Q, + const BetaType beta, + Eigen::PlainObjectBase& WN); + template < + typename DerivedP, + typename DerivedA, + typename DerivedN, + typename DerivedQ, + typename BetaType, + typename DerivedWN> + IGL_INLINE void fast_winding_number( + const Eigen::MatrixBase& P, + const Eigen::MatrixBase& N, + const Eigen::MatrixBase& A, + const Eigen::MatrixBase& Q, + const int expansion_order, + const BetaType beta, + Eigen::PlainObjectBase& WN); + // Evaluate the fast winding number for point data, with default expansion + // order and beta (both are set to 2). + // + // This function performes the precomputation and evaluation all in one. + // If you need to acess the precomuptation for repeated evaluations, use the + // two functions designed for exposed precomputation (described above). + // + // Inputs: + // P #P by 3 list of point locations + // N #P by 3 list of point normals + // A #P by 1 list of point areas + // Q #Q by 3 list of query points for the winding number + // Outputs: + // WN #Q by 1 list of windinng number values at each query point + // + template < + typename DerivedP, + typename DerivedA, + typename DerivedN, + typename DerivedQ, + typename DerivedWN> + IGL_INLINE void fast_winding_number( + const Eigen::MatrixBase& P, + const Eigen::MatrixBase& N, + const Eigen::MatrixBase& A, + const Eigen::MatrixBase& Q, + Eigen::PlainObjectBase& WN); + // Class declaration + namespace FastWindingNumber { namespace HDK_Sample{ template class UT_SolidAngle;} } + struct FastWindingNumberBVH { + FastWindingNumber::HDK_Sample::UT_SolidAngle ut_solid_angle; + // Need copies of these so they stay alive between calls. + std::vector > U; + std::vector F; + }; + // Compute approximate winding number of a triangle soup mesh according to + // "Fast Winding Numbers for Soups and Clouds" [Barill et al. 2018]. + // + // Inputs: + // V #V by 3 list of mesh vertex positions + // F #F by 3 list of triangle mesh indices into rows of V + // Q #Q by 3 list of query positions + // Outputs: + // W #Q list of winding number values + template < + typename DerivedV, + typename DerivedF, + typename DerivedQ, + typename DerivedW> + IGL_INLINE void fast_winding_number( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const Eigen::MatrixBase & Q, + Eigen::PlainObjectBase & W); + // Precomputation for computing approximate winding numbers of a triangle + // soup. + // + // Inputs: + // V #V by 3 list of mesh vertex positions + // F #F by 3 list of triangle mesh indices into rows of V + // order Taylor series expansion order to use (e.g., 2) + // Outputs: + // fwn_bvh Precomputed bounding volume hierarchy + // + template < + typename DerivedV, + typename DerivedF> + IGL_INLINE void fast_winding_number( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const int order, + FastWindingNumberBVH & fwn_bvh); + // After precomputation, compute winding number at a each of many points in a + // list. + // + // Inputs: + // fwn_bvh Precomputed bounding volume hierarchy + // accuracy_scale parameter controlling accuracy (e.g., 2) + // Q #Q by 3 list of query positions + // Outputs: + // W #Q list of winding number values + template < + typename DerivedQ, + typename DerivedW> + IGL_INLINE void fast_winding_number( + const FastWindingNumberBVH & fwn_bvh, + const float accuracy_scale, + const Eigen::MatrixBase & Q, + Eigen::PlainObjectBase & W); + // After precomputation, compute winding number at a a single point + // + // Inputs: + // fwn_bvh Precomputed bounding volume hierarchy + // accuracy_scale parameter controlling accuracy (e.g., 2) + // p single position + // Outputs: + // w winding number of this point + template + IGL_INLINE typename Derivedp::Scalar fast_winding_number( + const FastWindingNumberBVH & fwn_bvh, + const float accuracy_scale, + const Eigen::MatrixBase & p); +} +#ifndef IGL_STATIC_LIBRARY +# include "fast_winding_number.cpp" +#endif + +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/file_contents_as_string.cpp b/src/external/libigl-2.3.0/include/igl/file_contents_as_string.cpp new file mode 100644 index 000000000..fd945dff2 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/file_contents_as_string.cpp @@ -0,0 +1,45 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "file_contents_as_string.h" + +#include +#include +#include + +IGL_INLINE bool igl::file_contents_as_string( + const std::string file_name, + std::string & content) +{ + std::ifstream ifs(file_name.c_str()); + // Check that opening the stream worked successfully + if(!ifs.good()) + { + fprintf( + stderr, + "IOError: file_contents_as_string() cannot open %s\n", + file_name.c_str()); + return false; + } + // Stream file contents into string + content = std::string( + (std::istreambuf_iterator(ifs)), + (std::istreambuf_iterator())); + return true; +} + +IGL_INLINE std::string igl::file_contents_as_string( + const std::string file_name) +{ + std::string content; +#ifndef NDEBUG + bool ret = +#endif + file_contents_as_string(file_name,content); + assert(ret && "file_contents_as_string failed to read string from file"); + return content; +} diff --git a/src/external/libigl-2.3.0/include/igl/file_contents_as_string.h b/src/external/libigl-2.3.0/include/igl/file_contents_as_string.h new file mode 100644 index 000000000..22ce1fc53 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/file_contents_as_string.h @@ -0,0 +1,32 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_FILE_CONTENTS_AS_STRING_H +#define IGL_FILE_CONTENTS_AS_STRING_H +#include "igl_inline.h" + +#include +namespace igl +{ + // Read a files contents as plain text into a given string + // Inputs: + // file_name path to file to be read + // Outputs: + // content output string containing contents of the given file + // Returns true on succes, false on error + IGL_INLINE bool file_contents_as_string( + const std::string file_name, + std::string & content); + IGL_INLINE std::string file_contents_as_string( + const std::string file_name); +} + +#ifndef IGL_STATIC_LIBRARY +# include "file_contents_as_string.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/file_dialog_open.cpp b/src/external/libigl-2.3.0/include/igl/file_dialog_open.cpp new file mode 100644 index 000000000..037dffa90 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/file_dialog_open.cpp @@ -0,0 +1,113 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Daniele Panozzo +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "file_dialog_open.h" +#include +#include + +#ifdef _WIN32 + #include + #undef max + #undef min + + #include +#endif + +IGL_INLINE std::string igl::file_dialog_open() +{ + const int FILE_DIALOG_MAX_BUFFER = 1024; + char buffer[FILE_DIALOG_MAX_BUFFER]; + buffer[0] = '\0'; + buffer[FILE_DIALOG_MAX_BUFFER - 1] = 'x'; // Initialize last character with a char != '\0' + +#ifdef __APPLE__ + // For apple use applescript hack + FILE * output = popen( + "osascript -e \"" + " tell application \\\"System Events\\\"\n" + " activate\n" + " set existing_file to choose file\n" + " end tell\n" + " set existing_file_path to (POSIX path of (existing_file))\n" + "\" 2>/dev/null | tr -d '\n' ","r"); + if (output) + { + auto ret = fgets(buffer, FILE_DIALOG_MAX_BUFFER, output); + if (ret == NULL || ferror(output)) + { + // I/O error + buffer[0] = '\0'; + } + if (buffer[FILE_DIALOG_MAX_BUFFER - 1] == '\0') + { + // File name too long, buffer has been filled, so we return empty string instead + buffer[0] = '\0'; + } + } +#elif defined _WIN32 + + // Use native windows file dialog box + // (code contributed by Tino Weinkauf) + + OPENFILENAME ofn; // common dialog box structure + char szFile[260]; // buffer for file name + + // Initialize OPENFILENAME + ZeroMemory(&ofn, sizeof(ofn)); + ofn.lStructSize = sizeof(ofn); + ofn.hwndOwner = NULL; + ofn.lpstrFile = szFile; + // Set lpstrFile[0] to '\0' so that GetOpenFileName does not + // use the contents of szFile to initialize itself. + ofn.lpstrFile[0] = '\0'; + ofn.nMaxFile = sizeof(szFile); + ofn.lpstrFilter = "*.*\0";//off\0*.off\0obj\0*.obj\0mp\0*.mp\0"; + ofn.nFilterIndex = 1; + ofn.lpstrFileTitle = NULL; + ofn.nMaxFileTitle = 0; + ofn.lpstrInitialDir = NULL; + ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST; + + // Display the Open dialog box. + int pos = 0; + if (GetOpenFileName(&ofn)==TRUE) + { + while(ofn.lpstrFile[pos] != '\0') + { + buffer[pos] = (char)ofn.lpstrFile[pos]; + pos++; + } + } + buffer[pos] = 0; +#else + + // For linux use zenity + FILE * output = popen("/usr/bin/zenity --file-selection","r"); + if (output) + { + auto ret = fgets(buffer, FILE_DIALOG_MAX_BUFFER, output); + if (ret == NULL || ferror(output)) + { + // I/O error + buffer[0] = '\0'; + } + if (buffer[FILE_DIALOG_MAX_BUFFER - 1] == '\0') + { + // File name too long, buffer has been filled, so we return empty string instead + buffer[0] = '\0'; + } + } + + // Replace last '\n' by '\0' + if(strlen(buffer) > 0) + { + buffer[strlen(buffer)-1] = '\0'; + } + +#endif + return std::string(buffer); +} diff --git a/src/external/libigl-2.3.0/include/igl/file_dialog_open.h b/src/external/libigl-2.3.0/include/igl/file_dialog_open.h new file mode 100644 index 000000000..1b17ea4c6 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/file_dialog_open.h @@ -0,0 +1,30 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Daniele Panozzo +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_FILE_DIALOG_OPEN_H +#define IGL_FILE_DIALOG_OPEN_H +#include "igl_inline.h" + +#include + +namespace igl +{ + // Returns a string with a path to an existing file + // The string is returned empty if no file is selected + // (on Linux machines, it assumes that Zenity is installed) + // + // Usage: + // std::string str = get_open_file_path(); + IGL_INLINE std::string file_dialog_open(); +} + +#ifndef IGL_STATIC_LIBRARY +# include "file_dialog_open.cpp" +#endif + +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/file_dialog_save.cpp b/src/external/libigl-2.3.0/include/igl/file_dialog_save.cpp new file mode 100644 index 000000000..fe8715249 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/file_dialog_save.cpp @@ -0,0 +1,113 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Daniele Panozzo +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "file_dialog_save.h" +#include +#include + +#ifdef _WIN32 + #include + #include +#endif + +IGL_INLINE std::string igl::file_dialog_save() +{ + const int FILE_DIALOG_MAX_BUFFER = 1024; + char buffer[FILE_DIALOG_MAX_BUFFER]; + buffer[0] = '\0'; + buffer[FILE_DIALOG_MAX_BUFFER - 1] = 'x'; // Initialize last character with a char != '\0' + +#ifdef __APPLE__ + // For apple use applescript hack + // There is currently a bug in Applescript that strips extensions off + // of chosen existing files in the "choose file name" dialog + // I'm assuming that will be fixed soon + FILE * output = popen( + "osascript -e \"" + " tell application \\\"System Events\\\"\n" + " activate\n" + " set existing_file to choose file name\n" + " end tell\n" + " set existing_file_path to (POSIX path of (existing_file))\n" + "\" 2>/dev/null | tr -d '\n' ","r"); + if (output) + { + auto ret = fgets(buffer, FILE_DIALOG_MAX_BUFFER, output); + if (ret == NULL || ferror(output)) + { + // I/O error + buffer[0] = '\0'; + } + if (buffer[FILE_DIALOG_MAX_BUFFER - 1] == '\0') + { + // File name too long, buffer has been filled, so we return empty string instead + buffer[0] = '\0'; + } + } +#elif defined _WIN32 + + // Use native windows file dialog box + // (code contributed by Tino Weinkauf) + + OPENFILENAME ofn; // common dialog box structure + char szFile[260]; // buffer for file name + + // Initialize OPENFILENAME + ZeroMemory(&ofn, sizeof(ofn)); + ofn.lStructSize = sizeof(ofn); + ofn.hwndOwner = NULL;//hwnd; + ofn.lpstrFile = szFile; + // Set lpstrFile[0] to '\0' so that GetOpenFileName does not + // use the contents of szFile to initialize itself. + ofn.lpstrFile[0] = '\0'; + ofn.nMaxFile = sizeof(szFile); + ofn.lpstrFilter = ""; + ofn.nFilterIndex = 1; + ofn.lpstrFileTitle = NULL; + ofn.nMaxFileTitle = 0; + ofn.lpstrInitialDir = NULL; + ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST; + + // Display the Open dialog box. + int pos = 0; + if (GetSaveFileName(&ofn)==TRUE) + { + while(ofn.lpstrFile[pos] != '\0') + { + buffer[pos] = (char)ofn.lpstrFile[pos]; + pos++; + } + buffer[pos] = 0; + } + +#else + // For every other machine type use zenity + FILE * output = popen("/usr/bin/zenity --file-selection --save","r"); + if (output) + { + auto ret = fgets(buffer, FILE_DIALOG_MAX_BUFFER, output); + if (ret == NULL || ferror(output)) + { + // I/O error + buffer[0] = '\0'; + } + if (buffer[FILE_DIALOG_MAX_BUFFER - 1] == '\0') + { + // File name too long, buffer has been filled, so we return empty string instead + buffer[0] = '\0'; + } + } + + // Replace last '\n' by '\0' + if(strlen(buffer) > 0) + { + buffer[strlen(buffer)-1] = '\0'; + } + +#endif + return std::string(buffer); +} diff --git a/src/external/libigl-2.3.0/include/igl/file_dialog_save.h b/src/external/libigl-2.3.0/include/igl/file_dialog_save.h new file mode 100644 index 000000000..f04075758 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/file_dialog_save.h @@ -0,0 +1,31 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Daniele Panozzo +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_FILE_DIALOG_SAVE_H +#define IGL_FILE_DIALOG_SAVE_H +#include "igl_inline.h" + +#include + +namespace igl +{ + // Returns a string with a path to a new/existing file + // The string is returned empty if no file is selected + // (on Linux machines, it assumes that Zenity is installed) + // + // Usage: + // char buffer[FILE_DIALOG_MAX_BUFFER]; + // get_save_file_path(buffer); + IGL_INLINE std::string file_dialog_save(); +} + +#ifndef IGL_STATIC_LIBRARY +# include "file_dialog_save.cpp" +#endif + +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/file_exists.cpp b/src/external/libigl-2.3.0/include/igl/file_exists.cpp new file mode 100644 index 000000000..f1a30630b --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/file_exists.cpp @@ -0,0 +1,16 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "file_exists.h" + +#include + +IGL_INLINE bool igl::file_exists(const std::string filename) +{ + struct stat status; + return (stat(filename.c_str(),&status)==0); +} diff --git a/src/external/libigl-2.3.0/include/igl/file_exists.h b/src/external/libigl-2.3.0/include/igl/file_exists.h new file mode 100644 index 000000000..e011d977e --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/file_exists.h @@ -0,0 +1,27 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_FILE_EXISTS_H +#define IGL_FILE_EXISTS_H +#include "igl_inline.h" +#include +namespace igl +{ + // Check if a file or directory exists like PHP's file_exists function: + // http://php.net/manual/en/function.file-exists.php + // Input: + // filename path to file + // Returns true if file exists and is readable and false if file doesn't + // exist or *is not readable* + IGL_INLINE bool file_exists(const std::string filename); +} + +#ifndef IGL_STATIC_LIBRARY +# include "file_exists.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/file_utils.cpp b/src/external/libigl-2.3.0/include/igl/file_utils.cpp new file mode 100644 index 000000000..0a5d08739 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/file_utils.cpp @@ -0,0 +1,29 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2020 Jérémie Dumas +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "file_utils.h" + +#include + +namespace igl { + +IGL_INLINE void read_file_binary(FILE *fp, + std::vector &fileBufferBytes) { + if (!ferror(fp)) { + fseek(fp, 0, SEEK_END); + size_t sizeBytes = ftell(fp); + fseek(fp, 0, SEEK_SET); + fileBufferBytes.resize(sizeBytes); + + if (fread((char *)fileBufferBytes.data(), 1, sizeBytes, fp) == sizeBytes) + return; + } + + throw std::runtime_error("error reading from file"); +} + +} diff --git a/src/external/libigl-2.3.0/include/igl/file_utils.h b/src/external/libigl-2.3.0/include/igl/file_utils.h new file mode 100644 index 000000000..deffe7e9d --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/file_utils.h @@ -0,0 +1,62 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2020 Jérémie Dumas +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_FILE_UTILS_H +#define IGL_FILE_UTILS_H + +#include "igl_inline.h" + +#include +#include +#include +#include + +namespace igl { + +IGL_INLINE void read_file_binary(FILE *fp, + std::vector &fileBufferBytes); + +struct file_memory_buffer : public std::streambuf { + char *p_start{nullptr}; + char *p_end{nullptr}; + size_t size; + + file_memory_buffer(char const *first_elem, size_t size) + : p_start(const_cast(first_elem)), p_end(p_start + size), + size(size) { + setg(p_start, p_start, p_end); + } + + pos_type seekoff(off_type off, std::ios_base::seekdir dir, + std::ios_base::openmode which) override { + if (dir == std::ios_base::cur) { + gbump(static_cast(off)); + } else { + setg(p_start, (dir == std::ios_base::beg ? p_start : p_end) + off, p_end); + } + return gptr() - p_start; + } + + pos_type seekpos(pos_type pos, std::ios_base::openmode which) override { + return seekoff(pos, std::ios_base::beg, which); + } +}; + +struct file_memory_stream : virtual file_memory_buffer, public std::istream { + file_memory_stream(char const *first_elem, size_t size) + : file_memory_buffer(first_elem, size), std::istream( + static_cast( + this)) {} +}; + +} // namespace igl + +#ifndef IGL_STATIC_LIBRARY +#include "file_utils.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/find.cpp b/src/external/libigl-2.3.0/include/igl/find.cpp new file mode 100644 index 000000000..6bef11139 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/find.cpp @@ -0,0 +1,137 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "find.h" + +#include "verbose.h" +#include + +template < + typename T, + typename DerivedI, + typename DerivedJ, + typename DerivedV> +IGL_INLINE void igl::find( + const Eigen::SparseMatrix& X, + Eigen::DenseBase & I, + Eigen::DenseBase & J, + Eigen::DenseBase & V) +{ + // Resize outputs to fit nonzeros + I.derived().resize(X.nonZeros(),1); + J.derived().resize(X.nonZeros(),1); + V.derived().resize(X.nonZeros(),1); + + int i = 0; + // Iterate over outside + for(int k=0; k::InnerIterator it (X,k); it; ++it) + { + V(i) = it.value(); + I(i) = it.row(); + J(i) = it.col(); + i++; + } + } +} + +template < + typename DerivedX, + typename DerivedI, + typename DerivedJ, + typename DerivedV> +IGL_INLINE void igl::find( + const Eigen::DenseBase& X, + Eigen::PlainObjectBase & I, + Eigen::PlainObjectBase & J, + Eigen::PlainObjectBase & V) +{ + const int nnz = X.count(); + I.resize(nnz,1); + J.resize(nnz,1); + V.resize(nnz,1); + { + int k = 0; + for(int j = 0;j +IGL_INLINE void igl::find( + const Eigen::DenseBase& X, + Eigen::PlainObjectBase & I) +{ + const int nnz = X.count(); + I.resize(nnz,1); + { + int k = 0; + for(int j = 0;j +IGL_INLINE void igl::find( + const Eigen::SparseVector& X, + Eigen::Matrix & I, + Eigen::Matrix & V) +{ + // Resize outputs to fit nonzeros + I.resize(X.nonZeros()); + V.resize(X.nonZeros()); + + int i = 0; + // loop over non-zeros + for(typename Eigen::SparseVector::InnerIterator it(X); it; ++it) + { + I(i) = it.index(); + V(i) = it.value(); + i++; + } +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation + +template void igl::find, Eigen::Matrix, Eigen::Array >(Eigen::SparseMatrix const&, Eigen::DenseBase >&, Eigen::DenseBase >&, Eigen::DenseBase >&); +template void igl::find, Eigen::Matrix >(Eigen::DenseBase > const&, Eigen::PlainObjectBase >&); +template void igl::find, Eigen::Matrix, Eigen::Matrix >(Eigen::SparseMatrix const&, Eigen::DenseBase >&, Eigen::DenseBase >&, Eigen::DenseBase >&); +template void igl::find, Eigen::Matrix, Eigen::Matrix >(Eigen::SparseMatrix const&, Eigen::DenseBase >&, Eigen::DenseBase >&, Eigen::DenseBase >&); +template void igl::find, Eigen::Matrix, Eigen::Matrix >(Eigen::SparseMatrix const&, Eigen::DenseBase >&, Eigen::DenseBase >&, Eigen::DenseBase >&); +template void igl::find, Eigen::Matrix >(Eigen::DenseBase > const&, Eigen::PlainObjectBase >&); +template void igl::find, Eigen::Matrix, Eigen::Matrix >(Eigen::SparseMatrix const&, Eigen::DenseBase >&, Eigen::DenseBase >&, Eigen::DenseBase >&); +template void igl::find, Eigen::Matrix >(Eigen::DenseBase > const&, Eigen::PlainObjectBase >&); +#if EIGEN_VERSION_AT_LEAST(3,3,0) +#else +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/find.h b/src/external/libigl-2.3.0/include/igl/find.h new file mode 100644 index 000000000..85eb65770 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/find.h @@ -0,0 +1,77 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_FIND_H +#define IGL_FIND_H +#include "igl_inline.h" +#define EIGEN_YES_I_KNOW_SPARSE_MODULE_IS_NOT_STABLE_YET +#include +#include +namespace igl +{ + // Find the non-zero entries and there respective indices in a sparse matrix. + // Like matlab's [I,J,V] = find(X) + // + // Templates: + // T should be a eigen sparse matrix primitive type like int or double + // Input: + // X m by n matrix whose entries are to be found + // Outputs: + // I nnz vector of row indices of non zeros entries in X + // J nnz vector of column indices of non zeros entries in X + // V nnz vector of type T non-zeros entries in X + // + template < + typename T, + typename DerivedI, + typename DerivedJ, + typename DerivedV> + IGL_INLINE void find( + const Eigen::SparseMatrix& X, + Eigen::DenseBase & I, + Eigen::DenseBase & J, + Eigen::DenseBase & V); + template < + typename DerivedX, + typename DerivedI, + typename DerivedJ, + typename DerivedV> + IGL_INLINE void find( + const Eigen::DenseBase& X, + Eigen::PlainObjectBase & I, + Eigen::PlainObjectBase & J, + Eigen::PlainObjectBase & V); + template < + typename DerivedX, + typename DerivedI> + IGL_INLINE void find( + const Eigen::DenseBase& X, + Eigen::PlainObjectBase & I); + // Find the non-zero entries and there respective indices in a sparse vector. + // Similar to matlab's [I,J,V] = find(X), but instead of [I,J] being + // subscripts into X, since X is a vector we just return I, a list of indices + // into X + // + // Templates: + // T should be a eigen sparse matrix primitive type like int or double + // Input: + // X vector whose entries are to be found + // Outputs: + // I nnz vector of indices of non zeros entries in X + // V nnz vector of type T non-zeros entries in X + template + IGL_INLINE void find( + const Eigen::SparseVector& X, + Eigen::Matrix & I, + Eigen::Matrix & V); +} + +#ifndef IGL_STATIC_LIBRARY +# include "find.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/find_cross_field_singularities.cpp b/src/external/libigl-2.3.0/include/igl/find_cross_field_singularities.cpp new file mode 100644 index 000000000..f3e3f491d --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/find_cross_field_singularities.cpp @@ -0,0 +1,85 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Daniele Panozzo , Olga Diamanti +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +#include "find_cross_field_singularities.h" + +#include +#include +#include +#include +#include + + +template +IGL_INLINE void igl::find_cross_field_singularities(const Eigen::MatrixBase &V, + const Eigen::MatrixBase &F, + const Eigen::MatrixBase &Handle_MMatch, + Eigen::PlainObjectBase &isSingularity, + Eigen::PlainObjectBase &singularityIndex) +{ + std::vector V_border = igl::is_border_vertex(F); + + std::vector > VF; + std::vector > VFi; + igl::vertex_triangle_adjacency(V,F,VF,VFi); + + + isSingularity.setZero(V.rows(),1); + singularityIndex.setZero(V.rows(),1); + for (unsigned int vid=0;vid +IGL_INLINE void igl::find_cross_field_singularities(const Eigen::MatrixBase &V, + const Eigen::MatrixBase &F, + const Eigen::MatrixBase &PD1, + const Eigen::MatrixBase &PD2, + Eigen::PlainObjectBase &isSingularity, + Eigen::PlainObjectBase &singularityIndex, + bool isCombed) +{ + Eigen::Matrix Handle_MMatch; + + igl::cross_field_mismatch(V, F, PD1, PD2, isCombed, Handle_MMatch); + igl::find_cross_field_singularities(V, F, Handle_MMatch, isSingularity, singularityIndex); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +template void igl::find_cross_field_singularities, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::find_cross_field_singularities, Eigen::Matrix, Eigen::Matrix>(Eigen::MatrixBase> const &, Eigen::MatrixBase> const &, Eigen::MatrixBase> const &, Eigen::MatrixBase> const &, Eigen::PlainObjectBase> &, + Eigen::PlainObjectBase> &, bool); +template void igl::find_cross_field_singularities, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::find_cross_field_singularities, Eigen::Matrix, Eigen::Matrix>(Eigen::MatrixBase> const &, Eigen::MatrixBase> const &, Eigen::MatrixBase> const &, Eigen::MatrixBase> const &, Eigen::PlainObjectBase> &, Eigen::PlainObjectBase> &, bool); +template void igl::find_cross_field_singularities, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::find_cross_field_singularities, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/find_cross_field_singularities.h b/src/external/libigl-2.3.0/include/igl/find_cross_field_singularities.h new file mode 100644 index 000000000..94581d30e --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/find_cross_field_singularities.h @@ -0,0 +1,58 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Daniele Panozzo , Olga Diamanti +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef IGL_FIND_CROSS_FIELD_SINGULARITIES_H +#define IGL_FIND_CROSS_FIELD_SINGULARITIES_H +#include "igl_inline.h" +#include +namespace igl +{ + // Computes singularities of a cross field, assumed combed + + + // Inputs: + // V #V by 3 eigen Matrix of mesh vertex 3D positions + // F #F by 3 eigen Matrix of face (quad) indices + // mismatch #F by 3 eigen Matrix containing the integer mismatch of the cross field + // across all face edges + // Output: + // isSingularity #V by 1 boolean eigen Vector indicating the presence of a singularity on a vertex + // singularityIndex #V by 1 integer eigen Vector containing the singularity indices + // + template + IGL_INLINE void find_cross_field_singularities(const Eigen::MatrixBase &V, + const Eigen::MatrixBase &F, + const Eigen::MatrixBase &mismatch, + Eigen::PlainObjectBase &isSingularity, + Eigen::PlainObjectBase &singularityIndex); + + // Wrapper that calculates the mismatch if it is not provided. + // Note that the field in PD1 and PD2 MUST BE combed (see igl::comb_cross_field). + // Inputs: + // V #V by 3 eigen Matrix of mesh vertex 3D positions + // F #F by 3 eigen Matrix of face (quad) indices + // PD1 #F by 3 eigen Matrix of the first per face cross field vector + // PD2 #F by 3 eigen Matrix of the second per face cross field vector + // Output: + // isSingularity #V by 1 boolean eigen Vector indicating the presence of a singularity on a vertex + // singularityIndex #V by 1 integer eigen Vector containing the singularity indices + // + template + IGL_INLINE void find_cross_field_singularities(const Eigen::MatrixBase &V, + const Eigen::MatrixBase &F, + const Eigen::MatrixBase &PD1, + const Eigen::MatrixBase &PD2, + Eigen::PlainObjectBase &isSingularity, + Eigen::PlainObjectBase &singularityIndex, + bool isCombed = false); +} +#ifndef IGL_STATIC_LIBRARY +#include "find_cross_field_singularities.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/find_zero.cpp b/src/external/libigl-2.3.0/include/igl/find_zero.cpp new file mode 100644 index 000000000..d0a7b35e6 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/find_zero.cpp @@ -0,0 +1,48 @@ +#include "find_zero.h" +#include "for_each.h" +#include "any.h" + +template +IGL_INLINE void igl::find_zero( + const Eigen::SparseMatrix & A, + const int dim, + Eigen::PlainObjectBase & I) +{ + assert((dim == 1 || dim == 2) && "dim must be 2 or 1"); + // Get size of input + int m = A.rows(); + int n = A.cols(); + // I starts by containing guess where 0 might be + I = DerivedI::Zero(dim==1?n:m); + Eigen::Array found = + Eigen::Array::Zero(dim==1?n:m); + const auto func = [&I,&found,&dim](int i, int j, const int v) + { + if(dim == 2) + { + std::swap(i,j); + } + // Coded as if dim == 1, assuming swap for dim == 2 + // Have we already found a zero? + if(!found(j)) + { + if(I(j) != i || v == 0) + { + // either there was an implicit zero between the last element and this + // one, or this one is zero + found(j) = true; + }else + { + // If not found, then guess that next element will be zero + I(j) = I(j)+1; + } + } + }; + for_each(A,func); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::find_zero >(Eigen::SparseMatrix const&, int, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/find_zero.h b/src/external/libigl-2.3.0/include/igl/find_zero.h new file mode 100644 index 000000000..0739be1cf --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/find_zero.h @@ -0,0 +1,28 @@ +#ifndef IGL_FIND_ZERO_H +#define IGL_FIND_ZERO_H +#include "igl_inline.h" +#include +#include +namespace igl +{ + // Find the first zero (whether implicit or explicitly stored) in the + // rows/columns of a matrix. + // Inputs: + // A m by n sparse matrix + // dim dimension along which to check for any (1 or 2) + // Output: + // I n-long vector (if dim == 1) {m means no zeros found} + // or + // I m-long vector (if dim == 2) {n means no zeros found} + // + template + IGL_INLINE void find_zero( + const Eigen::SparseMatrix & A, + const int dim, + Eigen::PlainObjectBase & I); +} +#ifndef IGL_STATIC_LIBRARY +# include "find_zero.cpp" +#endif +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/fit_cubic_bezier.cpp b/src/external/libigl-2.3.0/include/igl/fit_cubic_bezier.cpp new file mode 100644 index 000000000..ad77658b1 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/fit_cubic_bezier.cpp @@ -0,0 +1,308 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2020 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "fit_cubic_bezier.h" +#include "bezier.h" +#include "EPS.h" + +// Adapted from main.c accompanying +// An Algorithm for Automatically Fitting Digitized Curves +// by Philip J. Schneider +// from "Graphics Gems", Academic Press, 1990 +IGL_INLINE void igl::fit_cubic_bezier( + const Eigen::MatrixXd & d, + const double error, + std::vector & cubics) +{ + const int nPts = d.rows(); + // Don't attempt to fit curve to single point + if(nPts==1) { return; } + // Avoid using zero tangent + const static auto tangent = []( + const Eigen::MatrixXd & d, + const int i,const int dir)->Eigen::RowVectorXd + { + int j = i; + const int nPts = d.rows(); + Eigen::RowVectorXd t; + while(true) + { + // look at next point + j += dir; + if(j < 0 || j>=nPts) + { + // All points are coincident? + // give up and use zero tangent... + return Eigen::RowVectorXd::Zero(1,d.cols()); + } + t = d.row(j)-d.row(i); + if(t.squaredNorm() > igl::DOUBLE_EPS) + { + break; + } + } + return t.normalized(); + }; + Eigen::RowVectorXd tHat1 = tangent(d,0,+1); + Eigen::RowVectorXd tHat2 = tangent(d,nPts-1,-1); + // If first and last points are identically equal, then consider closed + const bool closed = (d.row(0) - d.row(d.rows()-1)).squaredNorm() == 0; + // If closed loop make tangents match + if(closed) + { + tHat1 = (tHat1 - tHat2).eval().normalized(); + tHat2 = -tHat1; + } + cubics.clear(); + fit_cubic_bezier_substring(d,0,nPts-1,tHat1,tHat2,error,closed,cubics); +}; + +IGL_INLINE void igl::fit_cubic_bezier_substring( + const Eigen::MatrixXd & d, + const int first, + const int last, + const Eigen::RowVectorXd & tHat1, + const Eigen::RowVectorXd & tHat2, + const double error, + const bool force_split, + std::vector & cubics) +{ + // Helper functions + // Evaluate a Bezier curve at a particular parameter value + const static auto bezier_eval = [](const Eigen::MatrixXd & V, const double t) + { Eigen::RowVectorXd P; bezier(V,t,P); return P; }; + // + // Use Newton-Raphson iteration to find better root. + const static auto NewtonRaphsonRootFind = []( + const Eigen::MatrixXd & Q, + const Eigen::RowVectorXd & P, + const double u)->double + { + /* Compute Q(u) */ + Eigen::RowVectorXd Q_u = bezier_eval(Q, u); + Eigen::MatrixXd Q1(3,Q.cols()); + Eigen::MatrixXd Q2(2,Q.cols()); + /* Generate control vertices for Q' */ + for (int i = 0; i <= 2; i++) + { + Q1.row(i) = (Q.row(i+1) - Q.row(i)) * 3.0; + } + /* Generate control vertices for Q'' */ + for (int i = 0; i <= 1; i++) + { + Q2.row(i) = (Q1.row(i+1) - Q1.row(i)) * 2.0; + } + /* Compute Q'(u) and Q''(u) */ + const Eigen::RowVectorXd Q1_u = bezier_eval(Q1, u); + const Eigen::RowVectorXd Q2_u = bezier_eval(Q2, u); + /* Compute f(u)/f'(u) */ + const double numerator = ((Q_u-P).array() * Q1_u.array()).array().sum(); + const double denominator = + Q1_u.squaredNorm() + ((Q_u-P).array() * Q2_u.array()).array().sum(); + /* u = u - f(u)/f'(u) */ + return u - (numerator/denominator); + }; + const static auto ComputeMaxError = []( + const Eigen::MatrixXd & d, + const int first, + const int last, + const Eigen::MatrixXd & bezCurve, + const Eigen::VectorXd & u, + int & splitPoint)->double + { + Eigen::VectorXd E(last - (first+1)); + splitPoint = (last-first + 1)/2; + double maxDist = 0.0; + for (int i = first + 1; i < last; i++) + { + Eigen::RowVectorXd P = bezier_eval(bezCurve, u(i-first)); + const double dist = (P-d.row(i)).squaredNorm(); + E(i-(first+1)) = dist; + if (dist >= maxDist) + { + maxDist = dist; + // Worst offender + splitPoint = i; + } + } + //const double half_total = E.array().sum()/2; + //double run = 0; + //for (int i = first + 1; i < last; i++) + //{ + // run += E(i-(first+1)); + // if(run>half_total) + // { + // // When accumulated ½ the error --> more symmetric, but requires more + // // curves + // splitPoint = i; + // break; + // } + //} + return maxDist; + }; + const static auto Straight = []( + const Eigen::MatrixXd & d, + const int first, + const int last, + const Eigen::RowVectorXd & tHat1, + const Eigen::RowVectorXd & tHat2, + Eigen::MatrixXd & bezCurve) + { + bezCurve.resize(4,d.cols()); + const double dist = (d.row(last)-d.row(first)).norm()/3.0; + bezCurve.row(0) = d.row(first); + bezCurve.row(1) = d.row(first) + tHat1*dist; + bezCurve.row(2) = d.row(last) + tHat2*dist; + bezCurve.row(3) = d.row(last); + }; + const static auto GenerateBezier = []( + const Eigen::MatrixXd & d, + const int first, + const int last, + const Eigen::VectorXd & uPrime, + const Eigen::RowVectorXd & tHat1, + const Eigen::RowVectorXd & tHat2, + Eigen::MatrixXd & bezCurve) + { + bezCurve.resize(4,d.cols()); + const int nPts = last - first + 1; + const static auto B0 = [](const double u)->double + { double tmp = 1.0 - u; return (tmp * tmp * tmp);}; + const static auto B1 = [](const double u)->double + { double tmp = 1.0 - u; return (3 * u * (tmp * tmp));}; + const static auto B2 = [](const double u)->double + { double tmp = 1.0 - u; return (3 * u * u * tmp); }; + const static auto B3 = [](const double u)->double + { return (u * u * u); }; + /* Compute the A's */ + std::vector > A(nPts); + for (int i = 0; i < nPts; i++) + { + Eigen::RowVectorXd v1 = tHat1*B1(uPrime(i)); + Eigen::RowVectorXd v2 = tHat2*B2(uPrime(i)); + A[i] = {v1,v2}; + } + /* Create the C and X matrices */ + Eigen::MatrixXd C(2,2); + Eigen::VectorXd X(2); + C(0,0) = 0.0; + C(0,1) = 0.0; + C(1,0) = 0.0; + C(1,1) = 0.0; + X(0) = 0.0; + X(1) = 0.0; + for( int i = 0; i < nPts; i++) + { + C(0,0) += A[i][0].dot(A[i][0]); + C(0,1) += A[i][0].dot(A[i][1]); + C(1,0) = C(0,1); + C(1,1) += A[i][1].dot(A[i][1]); + const Eigen::RowVectorXd tmp = + d.row(first+i)-( + d.row(first)*B0(uPrime(i))+ + d.row(first)*B1(uPrime(i))+ + d.row(last)*B2(uPrime(i))+ + d.row(last)*B3(uPrime(i))); + X(0) += A[i][0].dot(tmp); + X(1) += A[i][1].dot(tmp); + } + /* Compute the determinants of C and X */ + double det_C0_C1 = C(0,0) * C(1,1) - C(1,0) * C(0,1); + const double det_C0_X = C(0,0) * X(1) - C(0,1) * X(0); + const double det_X_C1 = X(0) * C(1,1) - X(1) * C(0,1); + /* Finally, derive alpha values */ + if (det_C0_C1 == 0.0) + { + det_C0_C1 = (C(0,0) * C(1,1)) * 10e-12; + } + const double alpha_l = det_X_C1 / det_C0_C1; + const double alpha_r = det_C0_X / det_C0_C1; + /* If alpha negative, use the Wu/Barsky heuristic (see text) */ + /* (if alpha is 0, you get coincident control points that lead to + * divide by zero in any subsequent NewtonRaphsonRootFind() call. */ + if (alpha_l < 1.0e-6 || alpha_r < 1.0e-6) + { + return Straight(d,first,last,tHat1,tHat2,bezCurve); + } + bezCurve.row(0) = d.row(first); + bezCurve.row(1) = d.row(first) + tHat1*alpha_l; + bezCurve.row(2) = d.row(last) + tHat2*alpha_r; + bezCurve.row(3) = d.row(last); + }; + + const int maxIterations = 4; + // This is a bad idea if error<1 ... + //const double iterationError = error * error; + const double iterationError = 100 * error; + const int nPts = last - first + 1; + /* Use heuristic if region only has two points in it */ + if(nPts == 2) + { + Eigen::MatrixXd bezCurve; + Straight(d,first,last,tHat1,tHat2,bezCurve); + cubics.push_back(bezCurve); + return; + } + // ChordLengthParameterize + Eigen::VectorXd u(last-first+1); + u(0) = 0; + for (int i = first+1; i <= last; i++) + { + u(i-first) = u(i-first-1) + (d.row(i)-d.row(i-1)).norm(); + } + for (int i = first + 1; i <= last; i++) + { + u(i-first) = u(i-first) / u(last-first); + } + Eigen::MatrixXd bezCurve; + GenerateBezier(d, first, last, u, tHat1, tHat2, bezCurve); + + + int splitPoint; + double maxError = ComputeMaxError(d, first, last, bezCurve, u, splitPoint); + if (!force_split && maxError < error) + { + cubics.push_back(bezCurve); + return; + } + /* If error not too large, try some reparameterization */ + /* and iteration */ + if (maxError < iterationError) + { + for (int i = 0; i < maxIterations; i++) + { + Eigen::VectorXd uPrime; + // Reparameterize + uPrime.resize(last-first+1); + for (int i = first; i <= last; i++) + { + uPrime(i-first) = NewtonRaphsonRootFind(bezCurve, d.row(i), u(i- first)); + } + GenerateBezier(d, first, last, uPrime, tHat1, tHat2, bezCurve); + maxError = ComputeMaxError(d, first, last, bezCurve, uPrime, splitPoint); + if (!force_split && maxError < error) { + cubics.push_back(bezCurve); + return; + } + u = uPrime; + } + } + + /* Fitting failed -- split at max error point and fit recursively */ + const Eigen::RowVectorXd tHatCenter = + (d.row(splitPoint-1)-d.row(splitPoint+1)).normalized(); + //foobar + fit_cubic_bezier_substring( + d,first,splitPoint,tHat1,tHatCenter,error,false,cubics); + fit_cubic_bezier_substring( + d,splitPoint,last,(-tHatCenter).eval(),tHat2,error,false,cubics); +} + + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +#endif diff --git a/src/external/libigl-2.3.0/include/igl/fit_cubic_bezier.h b/src/external/libigl-2.3.0/include/igl/fit_cubic_bezier.h new file mode 100644 index 000000000..cdc4b5205 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/fit_cubic_bezier.h @@ -0,0 +1,57 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2020 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef FIT_CUBIC_BEZIER_H +#define FIT_CUBIC_BEZIER_H +#include "igl_inline.h" +#include +#include +namespace igl +{ + // Fit a cubic bezier spline (G1 continuous) to an ordered list of input + // points in any dimension, according to "An algorithm for automatically + // fitting digitized curves" [Schneider 1990]. + // + // Inputs: + // d #d by dim list of points along a curve to be fit with a cubic bezier + // spline (should probably be roughly uniformly spaced). If d(0)==d(end), + // then will treat as a closed curve. + // error maximum squared distance allowed + // Output: + // cubics #cubics list of 4 by dim lists of cubic control points + IGL_INLINE void fit_cubic_bezier( + const Eigen::MatrixXd & d, + const double error, + std::vector & cubics); + // Recursive helper function. + // + // Inputs: + // first index of first point in d of substring + // last index of last point in d of substring + // tHat1 tangent to use at beginning of spline + // tHat2 tangent to use at end of spline + // error see above + // force_split whether to force a split (i.e., force a recursive call) + // cubics running list of cubics so far + // Outputs + // cubics running list of cubics so far (new cubics appended) + IGL_INLINE void fit_cubic_bezier_substring( + const Eigen::MatrixXd & d, + const int first, + const int last, + const Eigen::RowVectorXd & tHat1, + const Eigen::RowVectorXd & tHat2, + const double error, + const bool force_split, + std::vector & cubics); +} + +#ifndef IGL_STATIC_LIBRARY +#include "fit_cubic_bezier.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/fit_plane.cpp b/src/external/libigl-2.3.0/include/igl/fit_plane.cpp new file mode 100644 index 000000000..83f11738f --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/fit_plane.cpp @@ -0,0 +1,56 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Daniele Panozzo +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +#include "fit_plane.h" +#include + +IGL_INLINE void igl::fit_plane( + const Eigen::MatrixXd & V, + Eigen::RowVector3d & N, + Eigen::RowVector3d & C) +{ + assert(V.rows()>0); + + Eigen::Vector3d sum = V.colwise().sum(); + + Eigen::Vector3d center = sum.array()/(double(V.rows())); + + C = center; + + double sumXX=0.0f,sumXY=0.0f,sumXZ=0.0f; + double sumYY=0.0f,sumYZ=0.0f; + double sumZZ=0.0f; + + for(int i=0;i es(m); + + N = es.eigenvectors().col(0); +} + +#ifdef IGL_STATIC_LIBRARY +#endif + + + diff --git a/src/external/libigl-2.3.0/include/igl/fit_plane.h b/src/external/libigl-2.3.0/include/igl/fit_plane.h new file mode 100644 index 000000000..f69ce811b --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/fit_plane.h @@ -0,0 +1,35 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Daniele Panozzo +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_FIT_PLANE_H +#define IGL_FIT_PLANE_H + +#include "igl_inline.h" +#include + +namespace igl +{ + // This function fits a plane to a point cloud. + // + // Input: + // V #Vx3 matrix. The 3D point cloud, one row for each vertex. + // Output: + // N 1x3 Vector. The normal of the fitted plane. + // C 1x3 Vector. A point that lies in the fitted plane. + // From http://missingbytes.blogspot.com/2012/06/fitting-plane-to-point-cloud.html + + IGL_INLINE void fit_plane( + const Eigen::MatrixXd & V, + Eigen::RowVector3d & N, + Eigen::RowVector3d & C); +} + +#ifndef IGL_STATIC_LIBRARY +# include "fit_plane.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/fit_rotations.cpp b/src/external/libigl-2.3.0/include/igl/fit_rotations.cpp new file mode 100644 index 000000000..bff77900f --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/fit_rotations.cpp @@ -0,0 +1,226 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "fit_rotations.h" +#include "polar_svd3x3.h" +#include "repmat.h" +#include "verbose.h" +#include "polar_dec.h" +#include "polar_svd.h" +#include "C_STR.h" +#include + +template +IGL_INLINE void igl::fit_rotations( + const Eigen::PlainObjectBase & S, + const bool single_precision, + Eigen::PlainObjectBase & R) +{ + using namespace std; + const int dim = S.cols(); + const int nr = S.rows()/dim; + assert(nr * dim == S.rows()); + assert(dim == 3); + + // resize output + R.resize(dim,dim*nr); // hopefully no op (should be already allocated) + + //std::cout<<"S=["< si;// = Eigen::Matrix3d::Identity(); + // loop over number of rotations we're computing + for(int r = 0;r Mat3; + typedef Eigen::Matrix Vec3; + Mat3 ri; + if(single_precision) + { + polar_svd3x3(si, ri); + }else + { + Mat3 ti,ui,vi; + Vec3 _; + igl::polar_svd(si,ri,ti,ui,_,vi); + } + assert(ri.determinant() >= 0); + R.block(0,r*dim,dim,dim) = ri.block(0,0,dim,dim).transpose(); + //cout< +IGL_INLINE void igl::fit_rotations_planar( + const Eigen::PlainObjectBase & S, + Eigen::PlainObjectBase & R) +{ + using namespace std; + const int dim = S.cols(); + const int nr = S.rows()/dim; + //assert(dim == 2 && "_planar input should be 2D"); + assert(nr * dim == S.rows()); + + // resize output + R.resize(dim,dim*nr); // hopefully no op (should be already allocated) + + Eigen::Matrix si; + // loop over number of rotations we're computing + for(int r = 0;r Mat2; + typedef Eigen::Matrix Vec2; + Mat2 ri,ti,ui,vi; + Vec2 _; + igl::polar_svd(si,ri,ti,ui,_,vi); +#ifndef FIT_ROTATIONS_ALLOW_FLIPS + // Check for reflection + if(ri.determinant() < 0) + { + vi.col(1) *= -1.; + ri = ui * vi.transpose(); + } + assert(ri.determinant() >= 0); +#endif + + // Not sure why polar_dec computes transpose... + R.block(0,r*dim,dim,dim).setIdentity(); + R.block(0,r*dim,2,2) = ri.transpose(); + } +} + + +#ifdef __SSE__ +IGL_INLINE void igl::fit_rotations_SSE( + const Eigen::MatrixXf & S, + Eigen::MatrixXf & R) +{ + const int cStep = 4; + + assert(S.cols() == 3); + const int dim = 3; //S.cols(); + const int nr = S.rows()/dim; + assert(nr * dim == S.rows()); + + // resize output + R.resize(dim,dim*nr); // hopefully no op (should be already allocated) + + Eigen::Matrix siBig; + // using SSE decompose cStep matrices at a time: + int r = 0; + for( ; r= nr) numMats = nr - r; + // build siBig: + for (int k=0; k ri; + polar_svd3x3_sse(siBig, ri); + + for (int k=0; k= 0); + + // Not sure why polar_dec computes transpose... + for (int k=0; k(); + Eigen::MatrixXf Rf; + fit_rotations_SSE(Sf,Rf); + R = Rf.cast(); +} +#endif + +#ifdef __AVX__ +IGL_INLINE void igl::fit_rotations_AVX( + const Eigen::MatrixXf & S, + Eigen::MatrixXf & R) +{ + const int cStep = 8; + + assert(S.cols() == 3); + const int dim = 3; //S.cols(); + const int nr = S.rows()/dim; + assert(nr * dim == S.rows()); + + // resize output + R.resize(dim,dim*nr); // hopefully no op (should be already allocated) + + Eigen::Matrix siBig; + // using SSE decompose cStep matrices at a time: + int r = 0; + for( ; r= nr) numMats = nr - r; + // build siBig: + for (int k=0; k ri; + polar_svd3x3_avx(siBig, ri); + + for (int k=0; k= 0); + + // Not sure why polar_dec computes transpose... + for (int k=0; k, Eigen::Matrix >(Eigen::PlainObjectBase > const&, bool, Eigen::PlainObjectBase >&); +template void igl::fit_rotations_planar, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&); +template void igl::fit_rotations_planar, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&); +template void igl::fit_rotations,Eigen::Matrix >(Eigen::PlainObjectBase > const &,bool,Eigen::PlainObjectBase > &); +template void igl::fit_rotations_planar, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/fit_rotations.h b/src/external/libigl-2.3.0/include/igl/fit_rotations.h new file mode 100644 index 000000000..1a18fd322 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/fit_rotations.h @@ -0,0 +1,60 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_FIT_ROTATIONS_H +#define IGL_FIT_ROTATIONS_H +#include "igl_inline.h" +#include + +namespace igl +{ + // Known issues: This seems to be implemented in Eigen/Geometry: + // Eigen::umeyama + // + // FIT_ROTATIONS Given an input mesh and new positions find rotations for + // every covariance matrix in a stack of covariance matrices + // + // Inputs: + // S nr*dim by dim stack of covariance matrices + // single_precision whether to use single precision (faster) + // Outputs: + // R dim by dim * nr list of rotations + // + template + IGL_INLINE void fit_rotations( + const Eigen::PlainObjectBase & S, + const bool single_precision, + Eigen::PlainObjectBase & R); + + // FIT_ROTATIONS Given an input mesh and new positions find 2D rotations for + // every vertex that best maps its one ring to the new one ring + // + // Inputs: + // S nr*dim by dim stack of covariance matrices, third column and every + // third row will be ignored + // Outputs: + // R dim by dim * nr list of rotations, third row and third column of each + // rotation will just be identity + // + template + IGL_INLINE void fit_rotations_planar( + const Eigen::PlainObjectBase & S, + Eigen::PlainObjectBase & R); +#ifdef __SSE__ + IGL_INLINE void fit_rotations_SSE( const Eigen::MatrixXf & S, Eigen::MatrixXf & R); + IGL_INLINE void fit_rotations_SSE( const Eigen::MatrixXd & S, Eigen::MatrixXd & R); +#endif +#ifdef __AVX__ + IGL_INLINE void fit_rotations_AVX( const Eigen::MatrixXf & S, Eigen::MatrixXf & R); +#endif +} + +#ifndef IGL_STATIC_LIBRARY +# include "fit_rotations.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/flip_avoiding_line_search.cpp b/src/external/libigl-2.3.0/include/igl/flip_avoiding_line_search.cpp new file mode 100644 index 000000000..003ef0b04 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/flip_avoiding_line_search.cpp @@ -0,0 +1,320 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Michael Rabinovich +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "flip_avoiding_line_search.h" +#include "line_search.h" +#include "PI.h" + +#include +#include + +namespace igl +{ + namespace flip_avoiding + { + //--------------------------------------------------------------------------- + // x - array of size 3 + // In case 3 real roots: => x[0], x[1], x[2], return 3 + // 2 real roots: x[0], x[1], return 2 + // 1 real root : x[0], x[1] ± i*x[2], return 1 + // http://math.ivanovo.ac.ru/dalgebra/Khashin/poly/index.html + IGL_INLINE int SolveP3(std::vector& x,double a,double b,double c) + { // solve cubic equation x^3 + a*x^2 + b*x + c + using namespace std; + double a2 = a*a; + double q = (a2 - 3*b)/9; + double r = (a*(2*a2-9*b) + 27*c)/54; + double r2 = r*r; + double q3 = q*q*q; + double A,B; + if(r2 1) t= 1; + t=acos(t); + a/=3; q=-2*sqrt(q); + x[0]=q*cos(t/3)-a; + x[1]=q*cos((t+(2*igl::PI))/3)-a; + x[2]=q*cos((t-(2*igl::PI))/3)-a; + return(3); + } + else + { + A =-pow(fabs(r)+sqrt(r2-q3),1./3); + if( r<0 ) A=-A; + B = A==0? 0 : q/A; + + a/=3; + x[0] =(A+B)-a; + x[1] =-0.5*(A+B)-a; + x[2] = 0.5*sqrt(3.)*(A-B); + if(fabs(x[2])<1e-14) + { + x[2]=x[1]; return(2); + } + return(1); + } + } + + IGL_INLINE double get_smallest_pos_quad_zero(double a,double b, double c) + { + using namespace std; + double t1, t2; + if(std::abs(a) > 1.0e-10) + { + double delta_in = pow(b, 2) - 4 * a * c; + if(delta_in <= 0) + { + return INFINITY; + } + + double delta = sqrt(delta_in); // delta >= 0 + if(b >= 0) // avoid subtracting two similar numbers + { + double bd = - b - delta; + t1 = 2 * c / bd; + t2 = bd / (2 * a); + } + else + { + double bd = - b + delta; + t1 = bd / (2 * a); + t2 = (2 * c) / bd; + } + + assert (std::isfinite(t1)); + assert (std::isfinite(t2)); + + if(a < 0) std::swap(t1, t2); // make t1 > t2 + // return the smaller positive root if it exists, otherwise return infinity + if(t1 > 0) + { + return t2 > 0 ? t2 : t1; + } + else + { + return INFINITY; + } + } + else + { + if(b == 0) return INFINITY; // just to avoid divide-by-zero + t1 = -c / b; + return t1 > 0 ? t1 : INFINITY; + } + } + + IGL_INLINE double get_min_pos_root_2D(const Eigen::MatrixXd& uv, + const Eigen::MatrixXi& F, + Eigen::MatrixXd& d, + int f) + { + using namespace std; + /* + Finding the smallest timestep t s.t a triangle get degenerated (<=> det = 0) + The following code can be derived by a symbolic expression in matlab: + + Symbolic matlab: + U11 = sym('U11'); + U12 = sym('U12'); + U21 = sym('U21'); + U22 = sym('U22'); + U31 = sym('U31'); + U32 = sym('U32'); + + V11 = sym('V11'); + V12 = sym('V12'); + V21 = sym('V21'); + V22 = sym('V22'); + V31 = sym('V31'); + V32 = sym('V32'); + + t = sym('t'); + + U1 = [U11,U12]; + U2 = [U21,U22]; + U3 = [U31,U32]; + + V1 = [V11,V12]; + V2 = [V21,V22]; + V3 = [V31,V32]; + + A = [(U2+V2*t) - (U1+ V1*t)]; + B = [(U3+V3*t) - (U1+ V1*t)]; + C = [A;B]; + + solve(det(C), t); + cf = coeffs(det(C),t); % Now cf(1),cf(2),cf(3) holds the coefficients for the polynom. at order c,b,a + */ + + int v1 = F(f,0); int v2 = F(f,1); int v3 = F(f,2); + // get quadratic coefficients (ax^2 + b^x + c) + const double& U11 = uv(v1,0); + const double& U12 = uv(v1,1); + const double& U21 = uv(v2,0); + const double& U22 = uv(v2,1); + const double& U31 = uv(v3,0); + const double& U32 = uv(v3,1); + + const double& V11 = d(v1,0); + const double& V12 = d(v1,1); + const double& V21 = d(v2,0); + const double& V22 = d(v2,1); + const double& V31 = d(v3,0); + const double& V32 = d(v3,1); + + double a = V11*V22 - V12*V21 - V11*V32 + V12*V31 + V21*V32 - V22*V31; + double b = U11*V22 - U12*V21 - U21*V12 + U22*V11 - U11*V32 + U12*V31 + U31*V12 - U32*V11 + U21*V32 - U22*V31 - U31*V22 + U32*V21; + double c = U11*U22 - U12*U21 - U11*U32 + U12*U31 + U21*U32 - U22*U31; + + return get_smallest_pos_quad_zero(a,b,c); + } + + IGL_INLINE double get_min_pos_root_3D(const Eigen::MatrixXd& uv, + const Eigen::MatrixXi& F, + Eigen::MatrixXd& direc, + int f) + { + using namespace std; + /* + Searching for the roots of: + +-1/6 * |ax ay az 1| + |bx by bz 1| + |cx cy cz 1| + |dx dy dz 1| + Every point ax,ay,az has a search direction a_dx,a_dy,a_dz, and so we add those to the matrix, and solve the cubic to find the step size t for a 0 volume + Symbolic matlab: + syms a_x a_y a_z a_dx a_dy a_dz % tetrahedera point and search direction + syms b_x b_y b_z b_dx b_dy b_dz + syms c_x c_y c_z c_dx c_dy c_dz + syms d_x d_y d_z d_dx d_dy d_dz + syms t % Timestep var, this is what we're looking for + + + a_plus_t = [a_x,a_y,a_z] + t*[a_dx,a_dy,a_dz]; + b_plus_t = [b_x,b_y,b_z] + t*[b_dx,b_dy,b_dz]; + c_plus_t = [c_x,c_y,c_z] + t*[c_dx,c_dy,c_dz]; + d_plus_t = [d_x,d_y,d_z] + t*[d_dx,d_dy,d_dz]; + + vol_mat = [a_plus_t,1;b_plus_t,1;c_plus_t,1;d_plus_t,1] + //cf = coeffs(det(vol_det),t); % Now cf(1),cf(2),cf(3),cf(4) holds the coefficients for the polynom + [coefficients,terms] = coeffs(det(vol_det),t); % terms = [ t^3, t^2, t, 1], Coefficients hold the coeff we seek + */ + int v1 = F(f,0); int v2 = F(f,1); int v3 = F(f,2); int v4 = F(f,3); + const double& a_x = uv(v1,0); + const double& a_y = uv(v1,1); + const double& a_z = uv(v1,2); + const double& b_x = uv(v2,0); + const double& b_y = uv(v2,1); + const double& b_z = uv(v2,2); + const double& c_x = uv(v3,0); + const double& c_y = uv(v3,1); + const double& c_z = uv(v3,2); + const double& d_x = uv(v4,0); + const double& d_y = uv(v4,1); + const double& d_z = uv(v4,2); + + const double& a_dx = direc(v1,0); + const double& a_dy = direc(v1,1); + const double& a_dz = direc(v1,2); + const double& b_dx = direc(v2,0); + const double& b_dy = direc(v2,1); + const double& b_dz = direc(v2,2); + const double& c_dx = direc(v3,0); + const double& c_dy = direc(v3,1); + const double& c_dz = direc(v3,2); + const double& d_dx = direc(v4,0); + const double& d_dy = direc(v4,1); + const double& d_dz = direc(v4,2); + + // Find solution for: a*t^3 + b*t^2 + c*d +d = 0 + double a = a_dx*b_dy*c_dz - a_dx*b_dz*c_dy - a_dy*b_dx*c_dz + a_dy*b_dz*c_dx + a_dz*b_dx*c_dy - a_dz*b_dy*c_dx - a_dx*b_dy*d_dz + a_dx*b_dz*d_dy + a_dy*b_dx*d_dz - a_dy*b_dz*d_dx - a_dz*b_dx*d_dy + a_dz*b_dy*d_dx + a_dx*c_dy*d_dz - a_dx*c_dz*d_dy - a_dy*c_dx*d_dz + a_dy*c_dz*d_dx + a_dz*c_dx*d_dy - a_dz*c_dy*d_dx - b_dx*c_dy*d_dz + b_dx*c_dz*d_dy + b_dy*c_dx*d_dz - b_dy*c_dz*d_dx - b_dz*c_dx*d_dy + b_dz*c_dy*d_dx; + + double b = a_dy*b_dz*c_x - a_dy*b_x*c_dz - a_dz*b_dy*c_x + a_dz*b_x*c_dy + a_x*b_dy*c_dz - a_x*b_dz*c_dy - a_dx*b_dz*c_y + a_dx*b_y*c_dz + a_dz*b_dx*c_y - a_dz*b_y*c_dx - a_y*b_dx*c_dz + a_y*b_dz*c_dx + a_dx*b_dy*c_z - a_dx*b_z*c_dy - a_dy*b_dx*c_z + a_dy*b_z*c_dx + a_z*b_dx*c_dy - a_z*b_dy*c_dx - a_dy*b_dz*d_x + a_dy*b_x*d_dz + a_dz*b_dy*d_x - a_dz*b_x*d_dy - a_x*b_dy*d_dz + a_x*b_dz*d_dy + a_dx*b_dz*d_y - a_dx*b_y*d_dz - a_dz*b_dx*d_y + a_dz*b_y*d_dx + a_y*b_dx*d_dz - a_y*b_dz*d_dx - a_dx*b_dy*d_z + a_dx*b_z*d_dy + a_dy*b_dx*d_z - a_dy*b_z*d_dx - a_z*b_dx*d_dy + a_z*b_dy*d_dx + a_dy*c_dz*d_x - a_dy*c_x*d_dz - a_dz*c_dy*d_x + a_dz*c_x*d_dy + a_x*c_dy*d_dz - a_x*c_dz*d_dy - a_dx*c_dz*d_y + a_dx*c_y*d_dz + a_dz*c_dx*d_y - a_dz*c_y*d_dx - a_y*c_dx*d_dz + a_y*c_dz*d_dx + a_dx*c_dy*d_z - a_dx*c_z*d_dy - a_dy*c_dx*d_z + a_dy*c_z*d_dx + a_z*c_dx*d_dy - a_z*c_dy*d_dx - b_dy*c_dz*d_x + b_dy*c_x*d_dz + b_dz*c_dy*d_x - b_dz*c_x*d_dy - b_x*c_dy*d_dz + b_x*c_dz*d_dy + b_dx*c_dz*d_y - b_dx*c_y*d_dz - b_dz*c_dx*d_y + b_dz*c_y*d_dx + b_y*c_dx*d_dz - b_y*c_dz*d_dx - b_dx*c_dy*d_z + b_dx*c_z*d_dy + b_dy*c_dx*d_z - b_dy*c_z*d_dx - b_z*c_dx*d_dy + b_z*c_dy*d_dx; + + double c = a_dz*b_x*c_y - a_dz*b_y*c_x - a_x*b_dz*c_y + a_x*b_y*c_dz + a_y*b_dz*c_x - a_y*b_x*c_dz - a_dy*b_x*c_z + a_dy*b_z*c_x + a_x*b_dy*c_z - a_x*b_z*c_dy - a_z*b_dy*c_x + a_z*b_x*c_dy + a_dx*b_y*c_z - a_dx*b_z*c_y - a_y*b_dx*c_z + a_y*b_z*c_dx + a_z*b_dx*c_y - a_z*b_y*c_dx - a_dz*b_x*d_y + a_dz*b_y*d_x + a_x*b_dz*d_y - a_x*b_y*d_dz - a_y*b_dz*d_x + a_y*b_x*d_dz + a_dy*b_x*d_z - a_dy*b_z*d_x - a_x*b_dy*d_z + a_x*b_z*d_dy + a_z*b_dy*d_x - a_z*b_x*d_dy - a_dx*b_y*d_z + a_dx*b_z*d_y + a_y*b_dx*d_z - a_y*b_z*d_dx - a_z*b_dx*d_y + a_z*b_y*d_dx + a_dz*c_x*d_y - a_dz*c_y*d_x - a_x*c_dz*d_y + a_x*c_y*d_dz + a_y*c_dz*d_x - a_y*c_x*d_dz - a_dy*c_x*d_z + a_dy*c_z*d_x + a_x*c_dy*d_z - a_x*c_z*d_dy - a_z*c_dy*d_x + a_z*c_x*d_dy + a_dx*c_y*d_z - a_dx*c_z*d_y - a_y*c_dx*d_z + a_y*c_z*d_dx + a_z*c_dx*d_y - a_z*c_y*d_dx - b_dz*c_x*d_y + b_dz*c_y*d_x + b_x*c_dz*d_y - b_x*c_y*d_dz - b_y*c_dz*d_x + b_y*c_x*d_dz + b_dy*c_x*d_z - b_dy*c_z*d_x - b_x*c_dy*d_z + b_x*c_z*d_dy + b_z*c_dy*d_x - b_z*c_x*d_dy - b_dx*c_y*d_z + b_dx*c_z*d_y + b_y*c_dx*d_z - b_y*c_z*d_dx - b_z*c_dx*d_y + b_z*c_y*d_dx; + + double d = a_x*b_y*c_z - a_x*b_z*c_y - a_y*b_x*c_z + a_y*b_z*c_x + a_z*b_x*c_y - a_z*b_y*c_x - a_x*b_y*d_z + a_x*b_z*d_y + a_y*b_x*d_z - a_y*b_z*d_x - a_z*b_x*d_y + a_z*b_y*d_x + a_x*c_y*d_z - a_x*c_z*d_y - a_y*c_x*d_z + a_y*c_z*d_x + a_z*c_x*d_y - a_z*c_y*d_x - b_x*c_y*d_z + b_x*c_z*d_y + b_y*c_x*d_z - b_y*c_z*d_x - b_z*c_x*d_y + b_z*c_y*d_x; + + if (std::abs(a)<=1.e-10) + { + return get_smallest_pos_quad_zero(b,c,d); + } + b/=a; c/=a; d/=a; // normalize it all + std::vector res(3); + int real_roots_num = SolveP3(res,b,c,d); + switch (real_roots_num) + { + case 1: + return (res[0] >= 0) ? res[0]:INFINITY; + case 2: + { + double max_root = std::max(res[0],res[1]); double min_root = std::min(res[0],res[1]); + if (min_root > 0) return min_root; + if (max_root > 0) return max_root; + return INFINITY; + } + case 3: + default: + { + std::sort(res.begin(),res.end()); + if (res[0] > 0) return res[0]; + if (res[1] > 0) return res[1]; + if (res[2] > 0) return res[2]; + return INFINITY; + } + } + } + + IGL_INLINE double compute_max_step_from_singularities(const Eigen::MatrixXd& uv, + const Eigen::MatrixXi& F, + Eigen::MatrixXd& d) + { + using namespace std; + double max_step = INFINITY; + + // The if statement is outside the for loops to avoid branching/ease parallelizing + if (uv.cols() == 2) + { + for (int f = 0; f < F.rows(); f++) + { + double min_positive_root = get_min_pos_root_2D(uv,F,d,f); + max_step = std::min(max_step, min_positive_root); + } + } + else + { // volumetric deformation + for (int f = 0; f < F.rows(); f++) + { + double min_positive_root = get_min_pos_root_3D(uv,F,d,f); + max_step = std::min(max_step, min_positive_root); + } + } + return max_step; + } + } +} + +IGL_INLINE double igl::flip_avoiding_line_search( + const Eigen::MatrixXi F, + Eigen::MatrixXd& cur_v, + const Eigen::MatrixXd& dst_v, + std::function energy, + double cur_energy) +{ + using namespace std; + Eigen::MatrixXd d = dst_v - cur_v; + + double min_step_to_singularity = igl::flip_avoiding::compute_max_step_from_singularities(cur_v,F,d); + double max_step_size = std::min(1., min_step_to_singularity*0.8); + + return igl::line_search(cur_v,d,max_step_size, energy, cur_energy); +} + +#ifdef IGL_STATIC_LIBRARY +#endif diff --git a/src/external/libigl-2.3.0/include/igl/flip_avoiding_line_search.h b/src/external/libigl-2.3.0/include/igl/flip_avoiding_line_search.h new file mode 100644 index 000000000..5ffda57e4 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/flip_avoiding_line_search.h @@ -0,0 +1,49 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Michael Rabinovich +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_FLIP_AVOIDING_LINE_SEARCH_H +#define IGL_FLIP_AVOIDING_LINE_SEARCH_H +#include "igl_inline.h" +#include "PI.h" + +#include + +namespace igl +{ + // A bisection line search for a mesh based energy that avoids triangle flips as suggested in + // "Bijective Parameterization with Free Boundaries" (Smith J. and Schaefer S., 2015). + // + // The user specifies an initial vertices position (that has no flips) and target one (that my have flipped triangles). + // This method first computes the largest step in direction of the destination vertices that does not incur flips, + // and then minimizes a given energy using this maximal step and a bisection linesearch (see igl::line_search). + // + // Supports both triangle and tet meshes. + // + // Inputs: + // F #F by 3/4 list of mesh faces or tets + // cur_v #V by dim list of variables + // dst_v #V by dim list of target vertices. This mesh may have flipped triangles + // energy A function to compute the mesh-based energy (return an energy that is bigger than 0) + // cur_energy(OPTIONAL) The energy at the given point. Helps save redundant computations. + // This is optional. If not specified, the function will compute it. + // Outputs: + // cur_v #V by dim list of variables at the new location + // Returns the energy at the new point + IGL_INLINE double flip_avoiding_line_search( + const Eigen::MatrixXi F, + Eigen::MatrixXd& cur_v, + const Eigen::MatrixXd& dst_v, + std::function energy, + double cur_energy = -1); + +} + +#ifndef IGL_STATIC_LIBRARY +# include "flip_avoiding_line_search.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/flip_edge.cpp b/src/external/libigl-2.3.0/include/igl/flip_edge.cpp new file mode 100644 index 000000000..7542a564b --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/flip_edge.cpp @@ -0,0 +1,168 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Qingan Zhou +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +#include "flip_edge.h" + +template < + typename DerivedF, + typename DerivedE, + typename DeriveduE, + typename DerivedEMAP, + typename uE2EType> +IGL_INLINE void igl::flip_edge( + Eigen::PlainObjectBase & F, + Eigen::PlainObjectBase & E, + Eigen::PlainObjectBase & uE, + Eigen::PlainObjectBase & EMAP, + std::vector > & uE2E, + const size_t uei) +{ + typedef typename DerivedF::Scalar Index; + const size_t num_faces = F.rows(); + assert(F.cols() == 3); + // Edge to flip [v1,v2] --> [v3,v4] + // Before: + // F(f1,:) = [v1,v2,v4] // in some cyclic order + // F(f2,:) = [v1,v3,v2] // in some cyclic order + // After: + // F(f1,:) = [v1,v3,v4] // in *this* order + // F(f2,:) = [v2,v4,v3] // in *this* order + // + // v1 v1 + // /|\ / \ + // / | \ /f1 \ + // v3 /f2|f1\ v4 => v3 /_____\ v4 + // \ | / \ f2 / + // \ | / \ / + // \|/ \ / + // v2 v2 + auto& half_edges = uE2E[uei]; + if (half_edges.size() != 2) { + throw "Cannot flip non-manifold or boundary edge"; + } + + const size_t f1 = half_edges[0] % num_faces; + const size_t f2 = half_edges[1] % num_faces; + const size_t c1 = half_edges[0] / num_faces; + const size_t c2 = half_edges[1] / num_faces; + assert(c1 < 3); + assert(c2 < 3); + + assert(f1 != f2); + const size_t v1 = F(f1, (c1+1)%3); + const size_t v2 = F(f1, (c1+2)%3); + const size_t v4 = F(f1, c1); + const size_t v3 = F(f2, c2); + assert(F(f2, (c2+2)%3) == v1); + assert(F(f2, (c2+1)%3) == v2); + + const size_t e_12 = half_edges[0]; + const size_t e_24 = f1 + ((c1 + 1) % 3) * num_faces; + const size_t e_41 = f1 + ((c1 + 2) % 3) * num_faces; + const size_t e_21 = half_edges[1]; + const size_t e_13 = f2 + ((c2 + 1) % 3) * num_faces; + const size_t e_32 = f2 + ((c2 + 2) % 3) * num_faces; + assert(E(e_12, 0) == v1); + assert(E(e_12, 1) == v2); + assert(E(e_24, 0) == v2); + assert(E(e_24, 1) == v4); + assert(E(e_41, 0) == v4); + assert(E(e_41, 1) == v1); + assert(E(e_21, 0) == v2); + assert(E(e_21, 1) == v1); + assert(E(e_13, 0) == v1); + assert(E(e_13, 1) == v3); + assert(E(e_32, 0) == v3); + assert(E(e_32, 1) == v2); + + const size_t ue_24 = EMAP(e_24); + const size_t ue_41 = EMAP(e_41); + const size_t ue_13 = EMAP(e_13); + const size_t ue_32 = EMAP(e_32); + + F(f1, 0) = v1; + F(f1, 1) = v3; + F(f1, 2) = v4; + F(f2, 0) = v2; + F(f2, 1) = v4; + F(f2, 2) = v3; + + uE(uei, 0) = v3; + uE(uei, 1) = v4; + + const size_t new_e_34 = f1; + const size_t new_e_41 = f1 + num_faces; + const size_t new_e_13 = f1 + num_faces*2; + const size_t new_e_43 = f2; + const size_t new_e_32 = f2 + num_faces; + const size_t new_e_24 = f2 + num_faces*2; + + E(new_e_34, 0) = v3; + E(new_e_34, 1) = v4; + E(new_e_41, 0) = v4; + E(new_e_41, 1) = v1; + E(new_e_13, 0) = v1; + E(new_e_13, 1) = v3; + E(new_e_43, 0) = v4; + E(new_e_43, 1) = v3; + E(new_e_32, 0) = v3; + E(new_e_32, 1) = v2; + E(new_e_24, 0) = v2; + E(new_e_24, 1) = v4; + + EMAP(new_e_34) = uei; + EMAP(new_e_43) = uei; + EMAP(new_e_41) = ue_41; + EMAP(new_e_13) = ue_13; + EMAP(new_e_32) = ue_32; + EMAP(new_e_24) = ue_24; + + auto replace = [](std::vector& array, Index old_v, Index new_v) { + std::replace(array.begin(), array.end(), old_v, new_v); + }; + replace(uE2E[uei], e_12, new_e_34); + replace(uE2E[uei], e_21, new_e_43); + replace(uE2E[ue_13], e_13, new_e_13); + replace(uE2E[ue_32], e_32, new_e_32); + replace(uE2E[ue_24], e_24, new_e_24); + replace(uE2E[ue_41], e_41, new_e_41); + +#ifndef NDEBUG + auto sanity_check = [&](size_t ue) { + const auto& adj_faces = uE2E[ue]; + if (adj_faces.size() == 2) { + const size_t first_f = adj_faces[0] % num_faces; + const size_t first_c = adj_faces[0] / num_faces; + const size_t second_f = adj_faces[1] % num_faces; + const size_t second_c = adj_faces[1] / num_faces; + const size_t vertex_0 = F(first_f, (first_c+1) % 3); + const size_t vertex_1 = F(first_f, (first_c+2) % 3); + assert(vertex_0 == F(second_f, (second_c+2) % 3)); + assert(vertex_1 == F(second_f, (second_c+1) % 3)); + } + }; + + sanity_check(uei); + sanity_check(ue_13); + sanity_check(ue_32); + sanity_check(ue_24); + sanity_check(ue_41); +#endif +} + + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::flip_edge, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, int>(Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, std::vector >, std::allocator > > >&, unsigned long); +template void igl::flip_edge, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, int>(Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, std::vector >, std::allocator > > >&, const size_t); +#ifdef WIN32 +template void igl::flip_edge, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, int>(Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, std::vector >, std::allocator > > >&, unsigned __int64); +template void igl::flip_edge,class Eigen::Matrix,class Eigen::Matrix,class Eigen::Matrix,int>(class Eigen::PlainObjectBase > &,class Eigen::PlainObjectBase > &,class Eigen::PlainObjectBase > &,class Eigen::PlainObjectBase > &,class std::vector >,class std::allocator > > > &,unsigned __int64); +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/flip_edge.h b/src/external/libigl-2.3.0/include/igl/flip_edge.h new file mode 100644 index 000000000..3c43198a6 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/flip_edge.h @@ -0,0 +1,52 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Qingan Zhou +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef IGL_FLIP_EDGE_H +#define IGL_FLIP_EDGE_H + +#include "igl_inline.h" +#include +#include + +namespace igl +{ + // Flip an edge in a triangle mesh. The edge specified by uei must have + // exactly **two** adjacent faces. Violation will result in exception. + // Another warning: edge flipping could convert manifold mesh into + // non-manifold. + // + // Inputs: + // F #F by 3 list of triangles. + // E #F*3 by 2 list of all of directed edges + // uE #uE by 2 list of unique undirected edges + // EMAP #F*3 list of indices into uE, mapping each directed edge to unique + // undirected edge + // uE2E #uE list of lists of indices into E of coexisting edges + // ue index into uE the edge to be flipped. + // + // Output: + // Updated F, E, uE, EMAP and uE2E. + template < + typename DerivedF, + typename DerivedE, + typename DeriveduE, + typename DerivedEMAP, + typename uE2EType> + IGL_INLINE void flip_edge( + Eigen::PlainObjectBase & F, + Eigen::PlainObjectBase & E, + Eigen::PlainObjectBase & uE, + Eigen::PlainObjectBase & EMAP, + std::vector > & uE2E, + const size_t uei); +} + +#ifndef IGL_STATIC_LIBRARY +# include "flip_edge.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/flipped_triangles.cpp b/src/external/libigl-2.3.0/include/igl/flipped_triangles.cpp new file mode 100644 index 000000000..775366e79 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/flipped_triangles.cpp @@ -0,0 +1,55 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Michael Rabinovich +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "flipped_triangles.h" + +#include "list_to_matrix.h" +#include +template +IGL_INLINE void igl::flipped_triangles( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + Eigen::PlainObjectBase & X) +{ + assert(V.cols() == 2 && "V should contain 2D positions"); + std::vector flip_idx; + for (int i = 0; i < F.rows(); i++) + { + // https://www.cs.cmu.edu/~quake/robust.html + typedef Eigen::Matrix RowVector2S; + RowVector2S v1_n = V.row(F(i,0)); + RowVector2S v2_n = V.row(F(i,1)); + RowVector2S v3_n = V.row(F(i,2)); + Eigen::Matrix T2_Homo; + T2_Homo.col(0) << v1_n(0),v1_n(1),1.; + T2_Homo.col(1) << v2_n(0),v2_n(1),1.; + T2_Homo.col(2) << v3_n(0),v3_n(1),1.; + double det = T2_Homo.determinant(); + assert(det == det && "det should not be NaN"); + if (det < 0) + { + flip_idx.push_back(i); + } + } + igl::list_to_matrix(flip_idx,X); +} + +template +IGL_INLINE Eigen::VectorXi igl::flipped_triangles( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F) +{ + Eigen::VectorXi X; + flipped_triangles(V,F,X); + return X; +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +template void igl::flipped_triangles, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template Eigen::Matrix igl::flipped_triangles, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/flipped_triangles.h b/src/external/libigl-2.3.0/include/igl/flipped_triangles.h new file mode 100644 index 000000000..2d119921f --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/flipped_triangles.h @@ -0,0 +1,39 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Michael Rabinovich +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_FLIPPED_TRIANGLES_H +#define IGL_FLIPPED_TRIANGLES_H +#include "igl_inline.h" + +#include +namespace igl +{ + // Finds the ids of the flipped triangles of the mesh V,F in the UV mapping uv + // + // Inputs: + // V #V by 2 list of mesh vertex positions + // F #F by 3 list of mesh faces (must be triangles) + // Outputs: + // X #flipped list of containing the indices into F of the flipped triangles + // Wrapper with return type + template + IGL_INLINE void flipped_triangles( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + Eigen::PlainObjectBase & X); + template + IGL_INLINE Eigen::VectorXi flipped_triangles( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F); + +} + +#ifndef IGL_STATIC_LIBRARY +# include "flipped_triangles.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/flood_fill.cpp b/src/external/libigl-2.3.0/include/igl/flood_fill.cpp new file mode 100644 index 000000000..3272ca1b2 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/flood_fill.cpp @@ -0,0 +1,103 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "flood_fill.h" +#include + +template +IGL_INLINE void igl::flood_fill( + const Eigen::MatrixBase& res, + Eigen::PlainObjectBase & S) +{ + using namespace Eigen; + using namespace std; + typedef typename DerivedS::Scalar Scalar; + const auto flood = [&res,&S] ( + const int xi, + const int yi, + const int zi, + const int signed_xi, + const int signed_yi, + const int signed_zi, + const Scalar s) + { + // flood fill this value back on this row + for(int bxi = xi;signed_xi<--bxi;) + { + S(bxi+int(res(0))*(yi + int(res(1))*zi)) = s; + } + // flood fill this value back on any previous rows + for(int byi = yi;signed_yi<--byi;) + { + for(int xi = 0;xi::quiet_NaN(); + for(int zi = 0;zi, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::flood_fill, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::flood_fill, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::flood_fill, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::flood_fill, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/flood_fill.h b/src/external/libigl-2.3.0/include/igl/flood_fill.h new file mode 100644 index 000000000..7eef01b3c --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/flood_fill.h @@ -0,0 +1,33 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_FLOOD_FILL_H +#define IGL_FLOOD_FILL_H +#include "igl_inline.h" +#include +namespace igl +{ + // Given a 3D array with sparse non-nan (number?) data fill in the NaNs via + // flood fill. This should ensure that, e.g., if data near 0 always has a band + // (surface) of numbered and signed data, then components of nans will be + // correctly signed. + // + // Inputs: + // res 3-long list of dimensions of grid + // S res(0)*res(1)*res(2) list of scalar values (with (many) nans), see + // output + // Outputs: + // S flood fill data in place + template + IGL_INLINE void flood_fill( + const Eigen::MatrixBase& res, + Eigen::PlainObjectBase & S); +} +#ifndef IGL_STATIC_LIBRARY +# include "flood_fill.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/floor.cpp b/src/external/libigl-2.3.0/include/igl/floor.cpp new file mode 100644 index 000000000..7538b7e01 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/floor.cpp @@ -0,0 +1,36 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "floor.h" +#include +#include + +template < typename DerivedX, typename DerivedY> +IGL_INLINE void igl::floor( + const Eigen::PlainObjectBase& X, + Eigen::PlainObjectBase& Y) +{ + using namespace std; + //Y = DerivedY::Zero(m,n); +//#pragma omp parallel for + //for(int i = 0;iScalar{return std::floor(x);}).template cast(); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +template void igl::floor, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&); +template void igl::floor, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&); +template void igl::floor, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/floor.h b/src/external/libigl-2.3.0/include/igl/floor.h new file mode 100644 index 000000000..a84d52068 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/floor.h @@ -0,0 +1,30 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_FLOOR_H +#define IGL_FLOOR_H +#include "igl_inline.h" +#include +namespace igl +{ + // Floor a given matrix to nearest integers + // + // Inputs: + // X m by n matrix of scalars + // Outputs: + // Y m by n matrix of floored integers + template < typename DerivedX, typename DerivedY> + IGL_INLINE void floor( + const Eigen::PlainObjectBase& X, + Eigen::PlainObjectBase& Y); +} + +#ifndef IGL_STATIC_LIBRARY +# include "floor.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/for_each.h b/src/external/libigl-2.3.0/include/igl/for_each.h new file mode 100644 index 000000000..6ba03ba1c --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/for_each.h @@ -0,0 +1,78 @@ +#ifndef IGL_FOR_EACH_H +#define IGL_FOR_EACH_H +#include "igl_inline.h" +#include +#include +namespace igl +{ + // FOR_EACH Call a given function for each non-zero (i.e., explicit value + // might actually be ==0) in a Sparse Matrix A _in order (of storage)_. This is + // useless unless func has _side-effects_. + // + // Inputs: + // A m by n SparseMatrix + // func function handle with prototype "compatible with" `void (Index i, + // Index j, Scalar & v)`. Return values will be ignored. + // + // See also: std::for_each + template + inline void for_each( + const Eigen::SparseMatrix & A, + const Func & func); + template + inline void for_each( + const Eigen::DenseBase & A, + const Func & func); +} + +// Implementation + +template +inline void igl::for_each( + const Eigen::SparseMatrix & A, + const Func & func) +{ + // Can **not** use parallel for because this must be _in order_ + // Iterate over outside + for(int k=0; k::InnerIterator it (A,k); it; ++it) + { + func(it.row(),it.col(),it.value()); + } + } +} + +template +inline void igl::for_each( + const Eigen::DenseBase & A, + const Func & func) +{ + // Can **not** use parallel for because this must be _in order_ + if(A.IsRowMajor) + { + for(typename DerivedA::Index i = 0;i +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "forward_kinematics.h" +#include +#include + +IGL_INLINE void igl::forward_kinematics( + const Eigen::MatrixXd & C, + const Eigen::MatrixXi & BE, + const Eigen::VectorXi & P, + const std::vector< + Eigen::Quaterniond,Eigen::aligned_allocator > & dQ, + const std::vector & dT, + std::vector< + Eigen::Quaterniond,Eigen::aligned_allocator > & vQ, + std::vector & vT) +{ + using namespace std; + using namespace Eigen; + const int m = BE.rows(); + assert(m == P.rows()); + assert(m == (int)dQ.size()); + assert(m == (int)dT.size()); + vector computed(m,false); + vQ.resize(m); + vT.resize(m); + // Dynamic programming + function fk_helper = [&] (int b) + { + if(!computed[b]) + { + if(P(b) < 0) + { + // base case for roots + vQ[b] = dQ[b]; + const Vector3d r = C.row(BE(b,0)).transpose(); + vT[b] = r-dQ[b]*r + dT[b]; + }else + { + // Otherwise first compute parent's + const int p = P(b); + fk_helper(p); + vQ[b] = vQ[p] * dQ[b]; + const Vector3d r = C.row(BE(b,0)).transpose(); + vT[b] = vT[p] - vQ[b]*r + vQ[p]*(r + dT[b]); + } + computed[b] = true; + } + }; + for(int b = 0;b > & dQ, + std::vector< + Eigen::Quaterniond,Eigen::aligned_allocator > & vQ, + std::vector & vT) +{ + std::vector dT(BE.rows(),Eigen::Vector3d(0,0,0)); + return forward_kinematics(C,BE,P,dQ,dT,vQ,vT); +} + +IGL_INLINE void igl::forward_kinematics( + const Eigen::MatrixXd & C, + const Eigen::MatrixXi & BE, + const Eigen::VectorXi & P, + const std::vector< + Eigen::Quaterniond,Eigen::aligned_allocator > & dQ, + const std::vector & dT, + Eigen::MatrixXd & T) +{ + using namespace Eigen; + using namespace std; + vector< Quaterniond,aligned_allocator > vQ; + vector< Vector3d> vT; + forward_kinematics(C,BE,P,dQ,dT,vQ,vT); + const int dim = C.cols(); + T.resize(BE.rows()*(dim+1),dim); + for(int e = 0;e > & dQ, + Eigen::MatrixXd & T) +{ + std::vector dT(BE.rows(),Eigen::Vector3d(0,0,0)); + return forward_kinematics(C,BE,P,dQ,dT,T); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +#endif diff --git a/src/external/libigl-2.3.0/include/igl/forward_kinematics.h b/src/external/libigl-2.3.0/include/igl/forward_kinematics.h new file mode 100644 index 000000000..2b3d2db6d --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/forward_kinematics.h @@ -0,0 +1,74 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_FORWARD_KINEMATICS_H +#define IGL_FORWARD_KINEMATICS_H +#include "igl_inline.h" +#include +#include +#include +#include + +namespace igl +{ + // Given a skeleton and a set of relative bone rotations compute absolute + // rigid transformations for each bone. + // + // Inputs: + // C #C by dim list of joint positions + // BE #BE by 2 list of bone edge indices + // P #BE list of parent indices into BE + // dQ #BE list of relative rotations + // dT #BE list of relative translations + // Outputs: + // vQ #BE list of absolute rotations + // vT #BE list of absolute translations + IGL_INLINE void forward_kinematics( + const Eigen::MatrixXd & C, + const Eigen::MatrixXi & BE, + const Eigen::VectorXi & P, + const std::vector< + Eigen::Quaterniond,Eigen::aligned_allocator > & dQ, + const std::vector & dT, + std::vector< + Eigen::Quaterniond,Eigen::aligned_allocator > & vQ, + std::vector & vT); + // Wrapper assuming each dT[i] == {0,0,0} + IGL_INLINE void forward_kinematics( + const Eigen::MatrixXd & C, + const Eigen::MatrixXi & BE, + const Eigen::VectorXi & P, + const std::vector< + Eigen::Quaterniond,Eigen::aligned_allocator > & dQ, + std::vector< + Eigen::Quaterniond,Eigen::aligned_allocator > & vQ, + std::vector & vT); + + // Outputs: + // T #BE*(dim+1) by dim stack of transposed transformation matrices + IGL_INLINE void forward_kinematics( + const Eigen::MatrixXd & C, + const Eigen::MatrixXi & BE, + const Eigen::VectorXi & P, + const std::vector< + Eigen::Quaterniond,Eigen::aligned_allocator > & dQ, + const std::vector & dT, + Eigen::MatrixXd & T); + IGL_INLINE void forward_kinematics( + const Eigen::MatrixXd & C, + const Eigen::MatrixXi & BE, + const Eigen::VectorXi & P, + const std::vector< + Eigen::Quaterniond,Eigen::aligned_allocator > & dQ, + Eigen::MatrixXd & T); + +}; + +#ifndef IGL_STATIC_LIBRARY +# include "forward_kinematics.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/frame_field_deformer.cpp b/src/external/libigl-2.3.0/include/igl/frame_field_deformer.cpp new file mode 100644 index 000000000..c22200f1b --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/frame_field_deformer.cpp @@ -0,0 +1,411 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Daniele Panozzo +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "frame_field_deformer.h" + +#include +#include +#include + +#include +#include +#include + +namespace igl +{ + +class Frame_field_deformer +{ +public: + + IGL_INLINE Frame_field_deformer(); + IGL_INLINE ~Frame_field_deformer(); + + // Initialize the optimizer + IGL_INLINE void init(const Eigen::MatrixXd& _V, const Eigen::MatrixXi& _F, const Eigen::MatrixXd& _D1, const Eigen::MatrixXd& _D2, double _Lambda, double _perturb_rotations, int _fixed = 1); + + // Run N optimization steps + IGL_INLINE void optimize(int N, bool reset = false); + + // Reset optimization + IGL_INLINE void reset_opt(); + + // Precomputation of all components + IGL_INLINE void precompute_opt(); + + // Precomputation for deformation energy + IGL_INLINE void precompute_ARAP(Eigen::SparseMatrix & Lff, Eigen::MatrixXd & LfcVc); + + // Precomputation for regularization + IGL_INLINE void precompute_SMOOTH(Eigen::SparseMatrix & MS, Eigen::MatrixXd & bS); + + // extracts a r x c block from sparse matrix mat into sparse matrix m1 + // (r0,c0) is upper left entry of block + IGL_INLINE void extractBlock(Eigen::SparseMatrix & mat, int r0, int c0, int r, int c, Eigen::SparseMatrix & m1); + + // computes optimal rotations for faces of m wrt current coords in mw.V + // returns a 3x3 matrix + IGL_INLINE void compute_optimal_rotations(); + + // global optimization step - linear system + IGL_INLINE void compute_optimal_positions(); + + // compute the output XField from deformation gradient + IGL_INLINE void computeXField(std::vector< Eigen::Matrix > & XF); + + // computes in WW the ideal warp at each tri to make the frame field a cross + IGL_INLINE void compute_idealWarp(std::vector< Eigen::Matrix > & WW); + + // -------------------------------- Variables ---------------------------------------------------- + + // Mesh I/O: + + Eigen::MatrixXd V; // Original mesh - vertices + Eigen::MatrixXi F; // Original mesh - faces + + std::vector > VT; // Vertex to triangle topology + std::vector > VTi; // Vertex to triangle topology + + Eigen::MatrixXd V_w; // Warped mesh - vertices + + std::vector< Eigen::Matrix > FF; // frame field FF in 3D (parallel to m.F) + std::vector< Eigen::Matrix > WW; // warping matrices to make a cross field (parallel to m.F) + std::vector< Eigen::Matrix > XF; // pseudo-cross field from solution (parallel to m.F) + + int fixed; + + double perturb_rotations; // perturbation to rotation matrices + + // Numerics + int nfree,nconst; // number of free/constrained vertices in the mesh - default all-but-1/1 + Eigen::MatrixXd C; // cotangent matrix of m + Eigen::SparseMatrix L; // Laplacian matrix of m + + Eigen::SparseMatrix M; // matrix for global optimization - pre-conditioned + Eigen::MatrixXd RHS; // pre-computed part of known term in global optimization + std::vector< Eigen::Matrix > RW; // optimal rotation-warping matrices (parallel to m.F) -- INCORPORATES WW + Eigen::SimplicialCholesky > solver; // solver for linear system in global opt. + + // Parameters +private: + double Lambda = 0.1; // weight of energy regularization + +}; + + IGL_INLINE Frame_field_deformer::Frame_field_deformer() {} + + IGL_INLINE Frame_field_deformer::~Frame_field_deformer() {} + + IGL_INLINE void Frame_field_deformer::init(const Eigen::MatrixXd& _V, + const Eigen::MatrixXi& _F, + const Eigen::MatrixXd& _D1, + const Eigen::MatrixXd& _D2, + double _Lambda, + double _perturb_rotations, + int _fixed) +{ + V = _V; + F = _F; + + assert(_D1.rows() == _D2.rows()); + + FF.clear(); + for (unsigned i=0; i < _D1.rows(); ++i) + { + Eigen::Matrix ff; + ff.col(0) = _D1.row(i); + ff.col(1) = _D2.row(i); + FF.push_back(ff); + } + + fixed = _fixed; + Lambda = _Lambda; + perturb_rotations = _perturb_rotations; + + reset_opt(); + precompute_opt(); +} + + +IGL_INLINE void Frame_field_deformer::optimize(int N, bool reset) +{ + //Reset optimization + if (reset) + reset_opt(); + + // Iterative Local/Global optimization + for (int i=0; i MA; // internal matrix for ARAP-warping energy + MatrixXd LfcVc; // RHS (partial) for ARAP-warping energy + SparseMatrix MS; // internal matrix for smoothing energy + MatrixXd bS; // RHS (full) for smoothing energy + + precompute_ARAP(MA,LfcVc); // precompute terms for the ARAP-warp part + precompute_SMOOTH(MS,bS); // precompute terms for the smoothing part + compute_idealWarp(WW); // computes the ideal warps + RW.resize(F.rows()); // init rotation matrices - global + + M = (1-Lambda)*MA + Lambda*MS; // matrix for linear system - global + + RHS = (1-Lambda)*LfcVc + Lambda*bS; // RHS (partial) for linear system - global + solver.compute(M); // system pre-conditioning + if (solver.info()!=Eigen::Success) {fprintf(stderr,"Decomposition failed in pre-conditioning!\n"); exit(-1);} + + fprintf(stdout,"Preconditioning done.\n"); + +} + +IGL_INLINE void Frame_field_deformer::precompute_ARAP(Eigen::SparseMatrix & Lff, Eigen::MatrixXd & LfcVc) +{ + using namespace Eigen; + fprintf(stdout,"Precomputing ARAP terms\n"); + SparseMatrix LL = -4*L; + Lff = SparseMatrix(nfree,nfree); + extractBlock(LL,0,0,nfree,nfree,Lff); + SparseMatrix Lfc = SparseMatrix(nfree,nconst); + extractBlock(LL,0,nfree,nfree,nconst,Lfc); + LfcVc = - Lfc * V_w.block(nfree,0,nconst,3); +} + +IGL_INLINE void Frame_field_deformer::precompute_SMOOTH(Eigen::SparseMatrix & MS, Eigen::MatrixXd & bS) +{ + using namespace Eigen; + fprintf(stdout,"Precomputing SMOOTH terms\n"); + + SparseMatrix LL = 4*L*L; + + // top-left + MS = SparseMatrix(nfree,nfree); + extractBlock(LL,0,0,nfree,nfree,MS); + + // top-right + SparseMatrix Mfc = SparseMatrix(nfree,nconst); + extractBlock(LL,0,nfree,nfree,nconst,Mfc); + + MatrixXd MfcVc = Mfc * V_w.block(nfree,0,nconst,3); + bS = (LL*V).block(0,0,nfree,3)-MfcVc; + +} + + IGL_INLINE void Frame_field_deformer::extractBlock(Eigen::SparseMatrix & mat, int r0, int c0, int r, int c, Eigen::SparseMatrix & m1) +{ + std::vector > tripletList; + for (int k=c0; k::InnerIterator it(mat,k); it; ++it) + { + if (it.row()>=r0 && it.row()(it.row()-r0,it.col()-c0,it.value())); + } + m1.setFromTriplets(tripletList.begin(), tripletList.end()); +} + +IGL_INLINE void Frame_field_deformer::compute_optimal_rotations() +{ + using namespace Eigen; + Matrix r,S,P,PP,D; + + for (int i=0;i > svd(S, Eigen::ComputeFullU | Eigen::ComputeFullV ); + Matrix su = svd.matrixU(); + Matrix sv = svd.matrixV(); + r = su*sv.transpose(); + + if (r.determinant()<0) // correct reflections + { + su(0,2)=-su(0,2); su(1,2)=-su(1,2); su(2,2)=-su(2,2); + r = su*sv.transpose(); + } + RW[i] = r*WW[i]; // RW INCORPORATES IDEAL WARP WW!!! + } +} + +IGL_INLINE void Frame_field_deformer::compute_optimal_positions() +{ + using namespace Eigen; + // compute variable RHS of ARAP-warp part of the system + MatrixXd b(nfree,3); // fx3 known term of the system + MatrixXd X; // result + int t; // triangles incident to edge (i,j) + int vi,i1,i2; // index of vertex i wrt tri t0 + + for (int i=0;i > & XF) +{ + using namespace Eigen; + Matrix P,PP,DG; + XF.resize(F.rows()); + + for (int i=0;i > & WW) +{ + using namespace Eigen; + + WW.resize(F.rows()); + for (int i=0;i<(int)FF.size();i++) + { + Vector3d v0,v1,v2; + v0 = FF[i].col(0); + v1 = FF[i].col(1); + v2=v0.cross(v1); v2.normalize(); // normal + + Matrix3d A,AI; // compute affine map A that brings: + A << v0[0], v1[0], v2[0], // first vector of FF to x unary vector + v0[1], v1[1], v2[1], // second vector of FF to xy plane + v0[2], v1[2], v2[2]; // triangle normal to z unary vector + AI = A.inverse(); + + // polar decomposition to discard rotational component (unnecessary but makes it easier) + Eigen::JacobiSVD > svd(AI, Eigen::ComputeFullU | Eigen::ComputeFullV ); + //Matrix au = svd.matrixU(); + Matrix av = svd.matrixV(); + DiagonalMatrix as(svd.singularValues()); + WW[i] = av*as*av.transpose(); + } +} + +} + + +IGL_INLINE void igl::frame_field_deformer( + const Eigen::MatrixXd& V, + const Eigen::MatrixXi& F, + const Eigen::MatrixXd& FF1, + const Eigen::MatrixXd& FF2, + Eigen::MatrixXd& V_d, + Eigen::MatrixXd& FF1_d, + Eigen::MatrixXd& FF2_d, + const int iterations, + const double lambda, + const bool perturb_initial_guess) +{ + using namespace Eigen; + // Solvers + Frame_field_deformer deformer; + + // Init optimizer + deformer.init(V, F, FF1, FF2, lambda, perturb_initial_guess ? 0.1 : 0); + + // Optimize + deformer.optimize(iterations,true); + + // Copy positions + V_d = deformer.V_w; + + // Allocate + FF1_d.resize(F.rows(),3); + FF2_d.resize(F.rows(),3); + + // Copy frame field + for(unsigned i=0; i +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_FRAME_FIELD_DEFORMER_H +#define IGL_FRAME_FIELD_DEFORMER_H +#include "igl_inline.h" + +#include + +namespace igl +{ + // Deform a mesh to transform the given per-face frame field to be as close + // as possible to a cross field, in the least square sense. + // + // Inputs: + // V #V by 3 coordinates of the vertices + // F #F by 3 list of mesh faces (must be triangles) + // FF1 #F by 3 first representative vector of the frame field + // FF2 #F by 3 second representative vector of the frame field + // lambda laplacian regularization parameter 0=no regularization 1=full regularization + // + // Outputs: + // V_d #F by 3 deformed, first representative vector + // V_d #F by 3 deformed, first representative vector + // V_d #F by 3 deformed, first representative vector + // + IGL_INLINE void frame_field_deformer( + const Eigen::MatrixXd& V, + const Eigen::MatrixXi& F, + const Eigen::MatrixXd& FF1, + const Eigen::MatrixXd& FF2, + Eigen::MatrixXd& V_d, + Eigen::MatrixXd& FF1_d, + Eigen::MatrixXd& FF2_d, + const int iterations = 50, + const double lambda = 0.1, + const bool perturb_initial_guess = true); + +} + +#ifndef IGL_STATIC_LIBRARY +# include "frame_field_deformer.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/frame_to_cross_field.cpp b/src/external/libigl-2.3.0/include/igl/frame_to_cross_field.cpp new file mode 100644 index 000000000..e4d6bc713 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/frame_to_cross_field.cpp @@ -0,0 +1,58 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Daniele Panozzo +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "frame_to_cross_field.h" +#include +#include + +IGL_INLINE void igl::frame_to_cross_field( + const Eigen::MatrixXd& V, + const Eigen::MatrixXi& F, + const Eigen::MatrixXd& FF1, + const Eigen::MatrixXd& FF2, + Eigen::MatrixXd& X) +{ + using namespace Eigen; + + // Generate local basis + MatrixXd B1, B2, B3; + + igl::local_basis(V,F,B1,B2,B3); + + // Project the frame fields in the local basis + MatrixXd d1, d2; + d1.resize(F.rows(),2); + d2.resize(F.rows(),2); + + d1 << igl::dot_row(B1,FF1), igl::dot_row(B2,FF1); + d2 << igl::dot_row(B1,FF2), igl::dot_row(B2,FF2); + + X.resize(F.rows(), 3); + + for (int i=0;i > svd(A, Eigen::ComputeFullU | Eigen::ComputeFullV ); + Matrix2d C = svd.matrixU() * svd.matrixV().transpose(); + + Vector2d v = C.col(0); + X.row(i) = v(0) * B1.row(i) + v(1) * B2.row(i); + } +} + + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +#endif diff --git a/src/external/libigl-2.3.0/include/igl/frame_to_cross_field.h b/src/external/libigl-2.3.0/include/igl/frame_to_cross_field.h new file mode 100644 index 000000000..f9bdd3d5f --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/frame_to_cross_field.h @@ -0,0 +1,39 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Daniele Panozzo +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_FRAME_TO_CROSS_FIELD_H +#define IGL_FRAME_TO_CROSS_FIELD_H +#include "igl_inline.h" + +#include + +namespace igl +{ + // Convert a frame field into its closest cross field + // Inputs: + // V #V by 3 coordinates of the vertices + // F #F by 3 list of mesh faces (must be triangles) + // FF1 #F by 3 the first representative vector of the frame field (up to permutation and sign) + // FF2 #F by 3 the second representative vector of the frame field (up to permutation and sign) + // + // Outputs: + // X #F by 3 representative vector of the closest cross field + // + IGL_INLINE void frame_to_cross_field( + const Eigen::MatrixXd& V, + const Eigen::MatrixXi& F, + const Eigen::MatrixXd& FF1, + const Eigen::MatrixXd& FF2, + Eigen::MatrixXd& X); + +} + +#ifndef IGL_STATIC_LIBRARY +# include "frame_to_cross_field.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/frustum.cpp b/src/external/libigl-2.3.0/include/igl/frustum.cpp new file mode 100644 index 000000000..2926106e6 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/frustum.cpp @@ -0,0 +1,33 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "frustum.h" +template < typename DerivedP> +IGL_INLINE void igl::frustum( + const typename DerivedP::Scalar left, + const typename DerivedP::Scalar right, + const typename DerivedP::Scalar bottom, + const typename DerivedP::Scalar top, + const typename DerivedP::Scalar nearVal, + const typename DerivedP::Scalar farVal, + Eigen::PlainObjectBase & P) +{ + P.setConstant(4,4,0.); + P(0,0) = (2.0 * nearVal) / (right - left); + P(1,1) = (2.0 * nearVal) / (top - bottom); + P(0,2) = (right + left) / (right - left); + P(1,2) = (top + bottom) / (top - bottom); + P(2,2) = -(farVal + nearVal) / (farVal - nearVal); + P(3,2) = -1.0; + P(2,3) = -(2.0 * farVal * nearVal) / (farVal - nearVal); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::frustum >(Eigen::Matrix::Scalar, Eigen::Matrix::Scalar, Eigen::Matrix::Scalar, Eigen::Matrix::Scalar, Eigen::Matrix::Scalar, Eigen::Matrix::Scalar, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/frustum.h b/src/external/libigl-2.3.0/include/igl/frustum.h new file mode 100644 index 000000000..4a92e1a81 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/frustum.h @@ -0,0 +1,44 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_FRUSTUM_H +#define IGL_FRUSTUM_H +#include "igl_inline.h" + +#include + +namespace igl +{ + // Implementation of the deprecated glFrustum function. + // + // Inputs: + // left coordinate of left vertical clipping plane + // right coordinate of right vertical clipping plane + // bottom coordinate of bottom vertical clipping plane + // top coordinate of top vertical clipping plane + // nearVal distance to near plane + // farVal distance to far plane + // Outputs: + // P 4x4 perspective matrix + template < typename DerivedP> + IGL_INLINE void frustum( + const typename DerivedP::Scalar left, + const typename DerivedP::Scalar right, + const typename DerivedP::Scalar bottom, + const typename DerivedP::Scalar top, + const typename DerivedP::Scalar nearVal, + const typename DerivedP::Scalar farVal, + Eigen::PlainObjectBase & P); +} + +#ifndef IGL_STATIC_LIBRARY +# include "frustum.cpp" +#endif + +#endif + + diff --git a/src/external/libigl-2.3.0/include/igl/gaussian_curvature.cpp b/src/external/libigl-2.3.0/include/igl/gaussian_curvature.cpp new file mode 100644 index 000000000..9a0a1f871 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/gaussian_curvature.cpp @@ -0,0 +1,56 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "gaussian_curvature.h" +#include "internal_angles.h" +#include "PI.h" +#include +template +IGL_INLINE void igl::gaussian_curvature( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + Eigen::PlainObjectBase & K) +{ + using namespace Eigen; + using namespace std; + // internal corner angles + Matrix< + typename DerivedV::Scalar, + DerivedF::RowsAtCompileTime, + DerivedF::ColsAtCompileTime> A; + internal_angles(V,F,A); + K.resize(V.rows(),1); + K.setConstant(V.rows(),1,2.*PI); + assert(A.rows() == F.rows()); + assert(A.cols() == F.cols()); + assert(K.rows() == V.rows()); + assert(F.maxCoeff() < V.rows()); + assert(K.cols() == 1); + const int Frows = F.rows(); + //K_G(x_i) = (2π - ∑θj) +//#ifndef IGL_GAUSSIAN_CURVATURE_OMP_MIN_VALUE +//# define IGL_GAUSSIAN_CURVATURE_OMP_MIN_VALUE 1000 +//#endif +//#pragma omp parallel for if (Frows>IGL_GAUSSIAN_CURVATURE_OMP_MIN_VALUE) + for(int f = 0;f, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::gaussian_curvature, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/gaussian_curvature.h b/src/external/libigl-2.3.0/include/igl/gaussian_curvature.h new file mode 100644 index 000000000..e9313cc3d --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/gaussian_curvature.h @@ -0,0 +1,35 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_GAUSSIAN_CURVATURE_H +#define IGL_GAUSSIAN_CURVATURE_H +#include "igl_inline.h" +#include +namespace igl +{ + // Compute discrete local integral gaussian curvature (angle deficit, without + // averaging by local area). + // + // Inputs: + // V #V by 3 eigen Matrix of mesh vertex 3D positions + // F #F by 3 eigen Matrix of face (triangle) indices + // Output: + // K #V by 1 eigen Matrix of discrete gaussian curvature values + // + template + IGL_INLINE void gaussian_curvature( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + Eigen::PlainObjectBase & K); +} + +#ifndef IGL_STATIC_LIBRARY +# include "gaussian_curvature.cpp" +#endif + +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/get_seconds.cpp b/src/external/libigl-2.3.0/include/igl/get_seconds.cpp new file mode 100644 index 000000000..fac4a3a69 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/get_seconds.cpp @@ -0,0 +1,15 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "get_seconds.h" +#include +IGL_INLINE double igl::get_seconds() +{ + return + std::chrono::duration( + std::chrono::system_clock::now().time_since_epoch()).count(); +} diff --git a/src/external/libigl-2.3.0/include/igl/get_seconds.h b/src/external/libigl-2.3.0/include/igl/get_seconds.h new file mode 100644 index 000000000..411d6e41d --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/get_seconds.h @@ -0,0 +1,38 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_GET_SECONDS_H +#define IGL_GET_SECONDS_H +#include "igl_inline.h" + +namespace igl +{ + // Return the current time in seconds since program start + // + // Example: + // const auto & tictoc = []() + // { + // static double t_start = igl::get_seconds(); + // double diff = igl::get_seconds()-t_start; + // t_start += diff; + // return diff; + // }; + // tictoc(); + // ... // part 1 + // cout<<"part 1: "< +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "get_seconds_hires.h" + +#if _WIN32 +# include +# include +IGL_INLINE double igl::get_seconds_hires() +{ + LARGE_INTEGER li_freq, li_current; + const bool ret = QueryPerformanceFrequency(&li_freq); + const bool ret2 = QueryPerformanceCounter(&li_current); + assert(ret && ret2); + assert(li_freq.QuadPart > 0); + return double(li_current.QuadPart) / double(li_freq.QuadPart); +} +#else +# include "get_seconds.h" +IGL_INLINE double igl::get_seconds_hires() +{ + // Sorry I've no idea how performance counters work on Mac... + return igl::get_seconds(); +} +#endif diff --git a/src/external/libigl-2.3.0/include/igl/get_seconds_hires.h b/src/external/libigl-2.3.0/include/igl/get_seconds_hires.h new file mode 100644 index 000000000..abe8956b5 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/get_seconds_hires.h @@ -0,0 +1,22 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_GET_SECONDS_HIRES_H +#define IGL_GET_SECONDS_HIRES_H +#include "igl_inline.h" + +namespace igl +{ + // Return the current time in seconds using performance counters + IGL_INLINE double get_seconds_hires(); +} + +#ifndef IGL_STATIC_LIBRARY +# include "get_seconds_hires.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/grad.cpp b/src/external/libigl-2.3.0/include/igl/grad.cpp new file mode 100644 index 000000000..ab1a52fa0 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/grad.cpp @@ -0,0 +1,240 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "grad.h" +#include +#include + +#include "PI.h" +#include "per_face_normals.h" +#include "volume.h" +#include "doublearea.h" + +namespace igl { + +namespace { + +template +IGL_INLINE void grad_tet( + const Eigen::MatrixBase&V, + const Eigen::MatrixBase&T, + Eigen::SparseMatrix &G, + bool uniform) +{ + using namespace Eigen; + assert(T.cols() == 4); + const int n = V.rows(); int m = T.rows(); + + /* + F = [ ... + T(:,1) T(:,2) T(:,3); ... + T(:,1) T(:,3) T(:,4); ... + T(:,1) T(:,4) T(:,2); ... + T(:,2) T(:,4) T(:,3)]; */ + MatrixXi F(4*m,3); + for (int i = 0; i < m; i++) { + F.row(0*m + i) << T(i,0), T(i,1), T(i,2); + F.row(1*m + i) << T(i,0), T(i,2), T(i,3); + F.row(2*m + i) << T(i,0), T(i,3), T(i,1); + F.row(3*m + i) << T(i,1), T(i,3), T(i,2); + } + // compute volume of each tet + Eigen::Matrix vol; + igl::volume(V,T,vol); + + Eigen::Matrix A(F.rows()); + Eigen::Matrix N(F.rows(),3); + if (!uniform) { + // compute tetrahedron face normals + igl::per_face_normals(V,F,N); int norm_rows = N.rows(); + for (int i = 0; i < norm_rows; i++) + N.row(i) /= N.row(i).norm(); + igl::doublearea(V,F,A); A/=2.; + } else { + // Use a uniform tetrahedra as a reference, with the same volume as the original one: + // + // Use normals of the uniform tet (V = h*[0,0,0;1,0,0;0.5,sqrt(3)/2.,0;0.5,sqrt(3)/6.,sqrt(2)/sqrt(3)]) + // 0 0 1.0000 + // 0.8165 -0.4714 -0.3333 + // 0 0.9428 -0.3333 + // -0.8165 -0.4714 -0.3333 + for (int i = 0; i < m; i++) { + N.row(0*m+i) << 0,0,1; + double a = sqrt(2)*std::cbrt(3*vol(i)); // area of a face in a uniform tet with volume = vol(i) + A(0*m+i) = (pow(a,2)*sqrt(3))/4.; + } + for (int i = 0; i < m; i++) { + N.row(1*m+i) << 0.8165,-0.4714,-0.3333; + double a = sqrt(2)*std::cbrt(3*vol(i)); + A(1*m+i) = (pow(a,2)*sqrt(3))/4.; + } + for (int i = 0; i < m; i++) { + N.row(2*m+i) << 0,0.9428,-0.3333; + double a = sqrt(2)*std::cbrt(3*vol(i)); + A(2*m+i) = (pow(a,2)*sqrt(3))/4.; + } + for (int i = 0; i < m; i++) { + N.row(3*m+i) << -0.8165,-0.4714,-0.3333; + double a = sqrt(2)*std::cbrt(3*vol(i)); + A(3*m+i) = (pow(a,2)*sqrt(3))/4.; + } + + } + + /* G = sparse( ... + [0*m + repmat(1:m,1,4) ... + 1*m + repmat(1:m,1,4) ... + 2*m + repmat(1:m,1,4)], ... + repmat([T(:,4);T(:,2);T(:,3);T(:,1)],3,1), ... + repmat(A./(3*repmat(vol,4,1)),3,1).*N(:), ... + 3*m,n);*/ + std::vector > G_t; + for (int i = 0; i < 4*m; i++) { + int T_j; // j indexes : repmat([T(:,4);T(:,2);T(:,3);T(:,1)],3,1) + switch (i/m) { + case 0: + T_j = 3; + break; + case 1: + T_j = 1; + break; + case 2: + T_j = 2; + break; + case 3: + T_j = 0; + break; + } + int i_idx = i%m; + int j_idx = T(i_idx,T_j); + + double val_before_n = A(i)/(3*vol(i_idx)); + G_t.push_back(Triplet(0*m+i_idx, j_idx, val_before_n * N(i,0))); + G_t.push_back(Triplet(1*m+i_idx, j_idx, val_before_n * N(i,1))); + G_t.push_back(Triplet(2*m+i_idx, j_idx, val_before_n * N(i,2))); + } + G.resize(3*m,n); + G.setFromTriplets(G_t.begin(), G_t.end()); +} + +template +IGL_INLINE void grad_tri( + const Eigen::MatrixBase&V, + const Eigen::MatrixBase&F, + Eigen::SparseMatrix &G, + bool uniform) +{ + // Number of faces + const int m = F.rows(); + // Number of vertices + const int nv = V.rows(); + // Number of dimensions + const int dims = V.cols(); + Eigen::Matrix + eperp21(m,3), eperp13(m,3); + + for (int i=0;i RowVector3S; + RowVector3S v32 = RowVector3S::Zero(1,3); + RowVector3S v13 = RowVector3S::Zero(1,3); + RowVector3S v21 = RowVector3S::Zero(1,3); + v32.head(V.cols()) = V.row(i3) - V.row(i2); + v13.head(V.cols()) = V.row(i1) - V.row(i3); + v21.head(V.cols()) = V.row(i2) - V.row(i1); + RowVector3S n = v32.cross(v13); + // area of parallelogram is twice area of triangle + // area of parallelogram is || v1 x v2 || + // This does correct l2 norm of rows, so that it contains #F list of twice + // triangle areas + double dblA = std::sqrt(n.dot(n)); + Eigen::Matrix u(0,0,1); + if (!uniform) { + // now normalize normals to get unit normals + u = n / dblA; + } else { + // Abstract equilateral triangle v1=(0,0), v2=(h,0), v3=(h/2, (sqrt(3)/2)*h) + + // get h (by the area of the triangle) + double h = sqrt( (dblA)/sin(igl::PI / 3.0)); // (h^2*sin(60))/2. = Area => h = sqrt(2*Area/sin_60) + + Eigen::Matrix v1,v2,v3; + v1 << 0,0,0; + v2 << h,0,0; + v3 << h/2.,(sqrt(3)/2.)*h,0; + + // now fix v32,v13,v21 and the normal + v32 = v3-v2; + v13 = v1-v3; + v21 = v2-v1; + n = v32.cross(v13); + } + + // rotate each vector 90 degrees around normal + double norm21 = std::sqrt(v21.dot(v21)); + double norm13 = std::sqrt(v13.dot(v13)); + eperp21.row(i) = u.cross(v21); + eperp21.row(i) = eperp21.row(i) / std::sqrt(eperp21.row(i).dot(eperp21.row(i))); + eperp21.row(i) *= norm21 / dblA; + eperp13.row(i) = u.cross(v13); + eperp13.row(i) = eperp13.row(i) / std::sqrt(eperp13.row(i).dot(eperp13.row(i))); + eperp13.row(i) *= norm13 / dblA; + } + + // create sparse gradient operator matrix + G.resize(dims*m,nv); + std::vector > Gijv; + Gijv.reserve(4*dims*m); + for(int f = 0;f +IGL_INLINE void igl::grad( + const Eigen::MatrixBase&V, + const Eigen::MatrixBase&F, + Eigen::SparseMatrix &G, + bool uniform) +{ + assert(F.cols() == 3 || F.cols() == 4); + switch(F.cols()) + { + case 3: + return grad_tri(V,F,G,uniform); + case 4: + return grad_tet(V,F,G,uniform); + default: + assert(false); + } +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::grad, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::SparseMatrix::Scalar, 0, int>&, bool); +template void igl::grad, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::SparseMatrix::Scalar, 0, int>&, bool); +template void igl::grad, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::SparseMatrix::Scalar, 0, int>&, bool); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/grad.h b/src/external/libigl-2.3.0/include/igl/grad.h new file mode 100644 index 000000000..ff621b88d --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/grad.h @@ -0,0 +1,47 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_GRAD_H +#define IGL_GRAD_H +#include "igl_inline.h" + +#include +#include + +namespace igl { + // GRAD + // G = grad(V,F) + // + // Compute the numerical gradient operator + // + // Inputs: + // V #vertices by 3 list of mesh vertex positions + // F #faces by 3 list of mesh face indices [or a #faces by 4 list of tetrahedral indices] + // uniform boolean (default false) - Use a uniform mesh instead of the vertices V + // Outputs: + // G #faces*dim by #V Gradient operator + // + + // Gradient of a scalar function defined on piecewise linear elements (mesh) + // is constant on each triangle [tetrahedron] i,j,k: + // grad(Xijk) = (Xj-Xi) * (Vi - Vk)^R90 / 2A + (Xk-Xi) * (Vj - Vi)^R90 / 2A + // where Xi is the scalar value at vertex i, Vi is the 3D position of vertex + // i, and A is the area of triangle (i,j,k). ^R90 represent a rotation of + // 90 degrees + // + template + IGL_INLINE void grad( + const Eigen::MatrixBase&V, + const Eigen::MatrixBase&F, + Eigen::SparseMatrix &G, + bool uniform = false); +} +#ifndef IGL_STATIC_LIBRARY +# include "grad.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/grad_intrinsic.cpp b/src/external/libigl-2.3.0/include/igl/grad_intrinsic.cpp new file mode 100644 index 000000000..001b2d2f3 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/grad_intrinsic.cpp @@ -0,0 +1,78 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2018 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "grad_intrinsic.h" +#include "grad.h" + +template +IGL_INLINE void igl::grad_intrinsic( + const Eigen::MatrixBase&l, + const Eigen::MatrixBase&F, + Eigen::SparseMatrix &G) +{ + assert(F.cols() ==3 && "Only triangles supported"); + // number of vertices + const int n = F.maxCoeff()+1; + // number of faces + const int m = F.rows(); + // JD: There is a pretty subtle bug when using a fixed column size for this matrix. + // When calling igl::grad(V, ...), the two code paths `grad_tet` and `grad_tri` + // will be compiled. It turns out that `igl::grad_tet` calls `igl::volume`, which + // reads the coordinates of the `V` matrix into `RowVector3d`. If the matrix `V` + // has a known compile-time size of 2, this produces a compilation error when + // libigl is compiled in header-only mode. In static mode this doesn't happen + // because the matrix `V` is probably implicitly copied into a `Eigen::MatrixXd`. + // This is a situation that could be solved using `if constexpr` in C++17. + // In C++11, the alternative is to use SFINAE and `std::enable_if` (ugh). + typedef Eigen::Matrix MatrixX2S; + MatrixX2S V2 = MatrixX2S::Zero(3*m,2); + // 1=[x,y] + // /\ + // l3 / \ l2 + // / \ + // / \ + // 2-----------3 + // l1 + // + // x = (l2²-l1²-l3²)/(-2*l1) + // y = sqrt(l3² - x²) + // + // + // Place 3rd vertex at [l(:,1) 0] + V2.block(2*m,0,m,1) = l.col(0); + // Place second vertex at [0 0] + // Place third vertex at [x y] + V2.block(0,0,m,1) = + (l.col(1).cwiseAbs2()-l.col(0).cwiseAbs2()-l.col(2).cwiseAbs2()).array()/ + (-2.*l.col(0)).array(); + V2.block(0,1,m,1) = + (l.col(2).cwiseAbs2() - V2.block(0,0,m,1).cwiseAbs2()).array().sqrt(); + DerivedF F2(F.rows(),F.cols()); + std::vector > Pijv; + Pijv.reserve(F.size()); + for(int f = 0;f P(m*3,n); + P.setFromTriplets(Pijv.begin(),Pijv.end()); + Eigen::SparseMatrix G2; + grad(V2,F2,G2); + G = G2*P; +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::grad_intrinsic, Eigen::Matrix, double>(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::SparseMatrix&); +// generated by autoexplicit.sh +template void igl::grad_intrinsic, Eigen::Matrix, double>(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::SparseMatrix&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/grad_intrinsic.h b/src/external/libigl-2.3.0/include/igl/grad_intrinsic.h new file mode 100644 index 000000000..9633b8803 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/grad_intrinsic.h @@ -0,0 +1,35 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2018 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_GRAD_INTRINSIC_H +#define IGL_GRAD_INTRINSIC_H +#include "igl_inline.h" + +#include +#include + +namespace igl { + // GRAD_INTRINSIC Construct an intrinsic gradient operator. + // + // Inputs: + // l #F by 3 list of edge lengths + // F #F by 3 list of triangle indices into some vertex list V + // Outputs: + // G #F*2 by #V gradient matrix: G=[Gx;Gy] where x runs along the 23 edge and + // y runs in the counter-clockwise 90° rotation. + template + IGL_INLINE void grad_intrinsic( + const Eigen::MatrixBase&l, + const Eigen::MatrixBase&F, + Eigen::SparseMatrix &G); +} +#ifndef IGL_STATIC_LIBRARY +# include "grad_intrinsic.cpp" +#endif + +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/grid.cpp b/src/external/libigl-2.3.0/include/igl/grid.cpp new file mode 100644 index 000000000..83fb0bf37 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/grid.cpp @@ -0,0 +1,65 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "grid.h" +#include + +template < + typename Derivedres, + typename DerivedGV> +IGL_INLINE void igl::grid( + const Eigen::MatrixBase & res, + Eigen::PlainObjectBase & GV) +{ + using namespace Eigen; + typedef typename DerivedGV::Scalar Scalar; + GV.resize(res.array().prod(),res.size()); + const auto lerp = + [&res](const Scalar di, const int d)->Scalar{return di/(Scalar)(res(d)-1);}; + int gi = 0; + Derivedres sub; + sub.resizeLike(res); + sub.setConstant(0); + for(int gi = 0;gi=res(c)) + { + sub(c) = 0; + // roll over + sub(c+1)++; + } + } + for(int c = 0;c, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::grid, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::grid, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::grid, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::grid, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::grid, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::grid, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::grid, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/grid.h b/src/external/libigl-2.3.0/include/igl/grid.h new file mode 100644 index 000000000..766c3cb8d --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/grid.h @@ -0,0 +1,35 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// Copyright (C) 2018 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_GRID_H +#define IGL_GRID_H +#include "igl_inline.h" +#include +namespace igl +{ + // Construct vertices of a regular grid, suitable for input to + // `igl::marching_cubes` + // + // Inputs: + // res #res list of number of vertices along each dimension filling a unit + // #res-cube + // Outputs: + // GV res.array().prod() by #res list of mesh vertex positions. + // + // See also: triangulated_grid, quad_grid + template < + typename Derivedres, + typename DerivedGV> + IGL_INLINE void grid( + const Eigen::MatrixBase & res, + Eigen::PlainObjectBase & GV); +} +#ifndef IGL_STATIC_LIBRARY +# include "grid.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/grid_search.cpp b/src/external/libigl-2.3.0/include/igl/grid_search.cpp new file mode 100644 index 000000000..93cbc0dde --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/grid_search.cpp @@ -0,0 +1,64 @@ +#include "grid_search.h" +#include +#include + +template < + typename Scalar, + typename DerivedX, + typename DerivedLB, + typename DerivedUB, + typename DerivedI> +IGL_INLINE Scalar igl::grid_search( + const std::function< Scalar (DerivedX &) > f, + const Eigen::MatrixBase & LB, + const Eigen::MatrixBase & UB, + const Eigen::MatrixBase & I, + DerivedX & X) +{ + Scalar fval = std::numeric_limits::max(); + const int dim = LB.size(); + assert(UB.size() == dim && "UB should match LB size"); + assert(I.size() == dim && "I should match LB size"); + X.resize(dim); + + // Working X value + DerivedX Xrun(dim); + std::function looper; + int calls = 0; + looper = [&]( + const int d, + DerivedX & Xrun) + { + assert(d < dim); + Eigen::Matrix vals = + Eigen::Matrix::LinSpaced(I(d),LB(d),UB(d)); + for(int c = 0;c, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(std::function&)>, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::Matrix&); +template float igl::grid_search, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(std::function&)>, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::Matrix&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/grid_search.h b/src/external/libigl-2.3.0/include/igl/grid_search.h new file mode 100644 index 000000000..83a86663e --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/grid_search.h @@ -0,0 +1,42 @@ +#ifndef IGL_GRID_SEARCH_H +#define IGL_GRID_SEARCH_H +#include "igl_inline.h" +#include +#include +namespace igl +{ + // Solve the problem: + // + // minimize f(x) + // subject to lb ≤ x ≤ ub + // + // by exhaustive grid search. + // + // Inputs: + // f function to minimize + // LB #X vector of finite lower bounds + // UB #X vector of finite upper bounds + // I #X vector of number of steps for each variable + // Outputs: + // X #X optimal parameter vector + // Returns f(X) + // + template < + typename Scalar, + typename DerivedX, + typename DerivedLB, + typename DerivedUB, + typename DerivedI> + IGL_INLINE Scalar grid_search( + const std::function< Scalar (DerivedX &) > f, + const Eigen::MatrixBase & LB, + const Eigen::MatrixBase & UB, + const Eigen::MatrixBase & I, + DerivedX & X); +} + +#ifndef IGL_STATIC_LIBRARY +# include "grid_search.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/group_sum_matrix.cpp b/src/external/libigl-2.3.0/include/igl/group_sum_matrix.cpp new file mode 100644 index 000000000..d3cf0bff2 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/group_sum_matrix.cpp @@ -0,0 +1,46 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "group_sum_matrix.h" + +template +IGL_INLINE void igl::group_sum_matrix( + const Eigen::Matrix & G, + const int k, + Eigen::SparseMatrix& A) +{ + // number of vertices + int n = G.rows(); + assert(k > G.maxCoeff()); + + A.resize(k,n); + + // builds A such that A(i,j) = 1 where i corresponds to group i and j + // corresponds to vertex j + + // Loop over vertices + for(int j = 0;j +IGL_INLINE void igl::group_sum_matrix( + const Eigen::Matrix & G, + Eigen::SparseMatrix& A) +{ + return group_sum_matrix(G,G.maxCoeff()+1,A); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +template void igl::group_sum_matrix(Eigen::Matrix const&, int, Eigen::SparseMatrix&); +template void igl::group_sum_matrix(Eigen::Matrix const&, Eigen::SparseMatrix&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/group_sum_matrix.h b/src/external/libigl-2.3.0/include/igl/group_sum_matrix.h new file mode 100644 index 000000000..805544b0b --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/group_sum_matrix.h @@ -0,0 +1,45 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_GROUP_SUM_MATRIX_H +#define IGL_GROUP_SUM_MATRIX_H +#include "igl_inline.h" + +#include +#include + +namespace igl +{ + // GROUP_SUM_MATRIX Builds a matrix A such that A*V computes the sum of + // vertices in each group specified by G + // + // group_sum_matrix(G,k,A); + // + // Templates: + // T should be a eigen sparse matrix primitive type like int or double + // Inputs: + // G #V list of group indices (0 to k-1) for each vertex, such that vertex i + // is assigned to group G(i) + // k #groups, good choice is max(G)+1 + // Outputs: + // A #groups by #V sparse matrix such that A*V = group_sums + // + template + IGL_INLINE void group_sum_matrix( + const Eigen::Matrix & G, + const int k, + Eigen::SparseMatrix& A); + // Wrapper with k = max(G)+1 + template + IGL_INLINE void group_sum_matrix( + const Eigen::Matrix & G, + Eigen::SparseMatrix& A); +} +#ifndef IGL_STATIC_LIBRARY +# include "group_sum_matrix.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/guess_extension.cpp b/src/external/libigl-2.3.0/include/igl/guess_extension.cpp new file mode 100644 index 000000000..dc9b66375 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/guess_extension.cpp @@ -0,0 +1,100 @@ +#include "guess_extension.h" + +#include + +#include "is_stl.h" + +IGL_INLINE void igl::guess_extension(FILE * fp, std::string & guess) +{ + const auto is_off = [](FILE * fp)-> bool + { + char header[1000]; + const std::string OFF("OFF"); + const std::string NOFF("NOFF"); + const std::string COFF("COFF"); + bool f = (fscanf(fp,"%s\n",header)==1 && ( + std::string(header).compare(0, OFF.length(), OFF)==0 || + std::string(header).compare(0, COFF.length(), COFF)==0 || + std::string(header).compare(0,NOFF.length(),NOFF)==0)); + rewind(fp); + return f; + }; + const auto is_ply = [](FILE * fp) -> bool + { + char header[1000]; + const std::string PLY("ply"); + bool f = (fscanf(fp,"%s\n",header)==1 && (std::string(header).compare(0, PLY.length(), PLY)==0 )); + rewind(fp); + return f; + }; + const auto is_wrl = [](FILE * wrl_file)->bool + { + bool still_comments = true; + char line[1000]; + std::string needle("point ["); + std::string haystack; + while(still_comments) + { + if(fgets(line,1000,wrl_file) == NULL) + { + rewind(wrl_file); + return false; + } + haystack = std::string(line); + still_comments = std::string::npos == haystack.find(needle); + } + rewind(wrl_file); + return true; + }; + const auto is_mesh = [](FILE * mesh_file )->bool + { + char line[2048]; + // eat comments at beginning of file + bool still_comments= true; + while(still_comments) + { + if(fgets(line,2048,mesh_file) == NULL) + { + rewind(mesh_file); + return false; + } + still_comments = (line[0] == '#' || line[0] == '\n'); + } + char str[2048]; + sscanf(line," %s",str); + // check that first word is MeshVersionFormatted + if(0!=strcmp(str,"MeshVersionFormatted")) + { + rewind(mesh_file); + return false; + } + rewind(mesh_file); + return true; + }; + guess = "obj"; + if(is_mesh(fp)) + { + guess = "mesh"; + }else if(is_off(fp)) + { + guess = "off"; + }else if(is_ply(fp)) + { + guess = "ply"; + }else if(igl::is_stl(fp)) + { + guess = "stl"; + }else if(is_wrl(fp)) + { + guess = "wrl"; + } + // else obj + rewind(fp); +} + +IGL_INLINE std::string igl::guess_extension(FILE * fp) +{ + std::string guess; + guess_extension(fp,guess); + return guess; +} diff --git a/src/external/libigl-2.3.0/include/igl/guess_extension.h b/src/external/libigl-2.3.0/include/igl/guess_extension.h new file mode 100644 index 000000000..77df6f523 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/guess_extension.h @@ -0,0 +1,25 @@ +#ifndef IGL_GUESS_EXTENSION_H +#define IGL_GUESS_EXTENSION_H +#include "igl_inline.h" +#include +#include +namespace igl +{ + // Given a file pointer at the beginning of a "mesh" file, try to guess the + // extension of the file format it comes from. The file pointer is rewound on + // return. + // + // Inputs: + // fp file pointer (see output) + // Outputs: + // fp file pointer rewound + // guess extension as string. One of "mesh",{"obj"},"off","ply","stl", or + // "wrl" + // + IGL_INLINE void guess_extension(FILE * fp, std::string & guess); + IGL_INLINE std::string guess_extension(FILE * fp); +} +#ifndef IGL_STATIC_LIBRARY +# include "guess_extension.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/harmonic.cpp b/src/external/libigl-2.3.0/include/igl/harmonic.cpp new file mode 100644 index 000000000..139ae7fd8 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/harmonic.cpp @@ -0,0 +1,178 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "harmonic.h" +#include "adjacency_matrix.h" +#include "cotmatrix.h" +#include "diag.h" +#include "invert_diag.h" +#include "isdiag.h" +#include "massmatrix.h" +#include "min_quad_with_fixed.h" +#include "speye.h" +#include "sum.h" +#include + +template < + typename DerivedV, + typename DerivedF, + typename Derivedb, + typename Derivedbc, + typename DerivedW> +IGL_INLINE bool igl::harmonic( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const Eigen::MatrixBase & b, + const Eigen::MatrixBase & bc, + const int k, + Eigen::PlainObjectBase & W) +{ + using namespace Eigen; + typedef typename DerivedV::Scalar Scalar; + SparseMatrix L,M; + cotmatrix(V,F,L); + if(k>1) + { + massmatrix(V,F,MASSMATRIX_TYPE_DEFAULT,M); + } + return harmonic(L,M,b,bc,k,W); +} + +template < + typename DerivedF, + typename Derivedb, + typename Derivedbc, + typename DerivedW> +IGL_INLINE bool igl::harmonic( + const Eigen::MatrixBase & F, + const Eigen::MatrixBase & b, + const Eigen::MatrixBase & bc, + const int k, + Eigen::PlainObjectBase & W) +{ + using namespace Eigen; + typedef typename Derivedbc::Scalar Scalar; + SparseMatrix A; + adjacency_matrix(F,A); + // sum each row + SparseVector Asum; + sum(A,1,Asum); + // Convert row sums into diagonal of sparse matrix + SparseMatrix Adiag; + diag(Asum,Adiag); + SparseMatrix L = A-Adiag; + SparseMatrix M; + speye(L.rows(),M); + return harmonic(L,M,b,bc,k,W); +} + +template < + typename DerivedL, + typename DerivedM, + typename Derivedb, + typename Derivedbc, + typename DerivedW> +IGL_INLINE bool igl::harmonic( + const Eigen::SparseCompressedBase & L, + const Eigen::SparseCompressedBase & M, + const Eigen::MatrixBase & b, + const Eigen::MatrixBase & bc, + const int k, + Eigen::PlainObjectBase & W) +{ + const int n = L.rows(); + assert(n == L.cols() && "L must be square"); + assert((k==1 || n == M.cols() ) && "M must be same size as L"); + assert((k==1 || n == M.rows() ) && "M must be square"); + assert((k==1 || igl::isdiag(M)) && "Mass matrix should be diagonal"); + typedef typename DerivedL::Scalar Scalar; + + Eigen::SparseMatrix Q; + igl::harmonic(L,M,k,Q); + + + min_quad_with_fixed_data data; + min_quad_with_fixed_precompute(Q,b,Eigen::SparseMatrix(),true,data); + W.resize(n,bc.cols()); + typedef Eigen::Matrix VectorXS; + const VectorXS B = VectorXS::Zero(n,1); + for(int w = 0;w +IGL_INLINE void igl::harmonic( + const Eigen::SparseCompressedBase & L, + const Eigen::SparseCompressedBase & M, + const int k, + DerivedQ & Q) +{ + assert(L.rows() == L.cols()&&"L should be square"); + Q = -L; + if(k == 1) return; + assert(L.rows() == M.rows()&&"L should match M's dimensions"); + assert(M.rows() == M.cols()&&"M should be square"); + Eigen::SparseMatrix Mi; + invert_diag(M,Mi); + // This is **not** robust for k>2. See KKT system in [Jacobson et al. 2010] + // of the kharmonic function in gptoolbox + for(int p = 1;p +IGL_INLINE void igl::harmonic( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const int k, + DerivedQ & Q) +{ + DerivedQ L,M; + cotmatrix(V,F,L); + if(k>1) + { + massmatrix(V,F,MASSMATRIX_TYPE_DEFAULT,M); + } + return harmonic(L,M,k,Q); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template bool igl::harmonic, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, int, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template bool igl::harmonic, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, int, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template bool igl::harmonic, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, int, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template bool igl::harmonic, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, int, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::harmonic, Eigen::Matrix, Eigen::SparseMatrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, int, Eigen::SparseMatrix&); +// generated by autoexplicit.sh +template bool igl::harmonic, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, int, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template bool igl::harmonic, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, int, Eigen::PlainObjectBase >&); +template bool igl::harmonic, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, int, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/harmonic.h b/src/external/libigl-2.3.0/include/igl/harmonic.h new file mode 100644 index 000000000..76d699efc --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/harmonic.h @@ -0,0 +1,122 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_HARMONIC_H +#define IGL_HARMONIC_H +#include "igl_inline.h" +#include +#include +namespace igl +{ + // Compute k-harmonic weight functions "coordinates". + // + // + // Inputs: + // V #V by dim vertex positions + // F #F by simplex-size list of element indices + // b #b boundary indices into V + // bc #b by #W list of boundary values + // k power of harmonic operation (1: harmonic, 2: biharmonic, etc) + // Outputs: + // W #V by #W list of weights + // + template < + typename DerivedV, + typename DerivedF, + typename Derivedb, + typename Derivedbc, + typename DerivedW> + IGL_INLINE bool harmonic( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const Eigen::MatrixBase & b, + const Eigen::MatrixBase & bc, + const int k, + Eigen::PlainObjectBase & W); + // Compute harmonic map using uniform laplacian operator + // + // Inputs: + // F #F by simplex-size list of element indices + // b #b boundary indices into V + // bc #b by #W list of boundary values + // k power of harmonic operation (1: harmonic, 2: biharmonic, etc) + // Outputs: + // W #V by #W list of weights + // + template < + typename DerivedF, + typename Derivedb, + typename Derivedbc, + typename DerivedW> + IGL_INLINE bool harmonic( + const Eigen::MatrixBase & F, + const Eigen::MatrixBase & b, + const Eigen::MatrixBase & bc, + const int k, + Eigen::PlainObjectBase & W); + // Compute a harmonic map using a given Laplacian and mass matrix + // + // Inputs: + // L #V by #V discrete (integrated) Laplacian + // M #V by #V mass matrix + // b #b boundary indices into V + // bc #b by #W list of boundary values + // k power of harmonic operation (1: harmonic, 2: biharmonic, etc) + // Outputs: + // W #V by #V list of weights + template < + typename DerivedL, + typename DerivedM, + typename Derivedb, + typename Derivedbc, + typename DerivedW> + IGL_INLINE bool harmonic( + const Eigen::SparseCompressedBase & L, + const Eigen::SparseCompressedBase & M, + const Eigen::MatrixBase & b, + const Eigen::MatrixBase & bc, + const int k, + Eigen::PlainObjectBase & W); + // Build the discrete k-harmonic operator (computing integrated quantities). + // That is, if the k-harmonic PDE is Q x = 0, then this minimizes x' Q x + // + // Inputs: + // L #V by #V discrete (integrated) Laplacian + // M #V by #V mass matrix + // k power of harmonic operation (1: harmonic, 2: biharmonic, etc) + // Outputs: + // Q #V by #V discrete (integrated) k-Laplacian + template < + typename DerivedL, + typename DerivedM, + typename DerivedQ> + IGL_INLINE void harmonic( + const Eigen::SparseCompressedBase & L, + const Eigen::SparseCompressedBase & M, + const int k, + DerivedQ & Q); + // Inputs: + // V #V by dim vertex positions + // F #F by simplex-size list of element indices + // k power of harmonic operation (1: harmonic, 2: biharmonic, etc) + // Outputs: + // Q #V by #V discrete (integrated) k-Laplacian + template < + typename DerivedV, + typename DerivedF, + typename DerivedQ> + IGL_INLINE void harmonic( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const int k, + DerivedQ & Q); +}; + +#ifndef IGL_STATIC_LIBRARY +#include "harmonic.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/harwell_boeing.cpp b/src/external/libigl-2.3.0/include/igl/harwell_boeing.cpp new file mode 100644 index 000000000..895416510 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/harwell_boeing.cpp @@ -0,0 +1,52 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "harwell_boeing.h" + +template +IGL_INLINE void igl::harwell_boeing( + const Eigen::SparseMatrix & A, + int & num_rows, + std::vector & V, + std::vector & R, + std::vector & C) +{ + num_rows = A.rows(); + int num_cols = A.cols(); + int nnz = A.nonZeros(); + V.resize(nnz); + R.resize(nnz); + C.resize(num_cols+1); + + // Assumes outersize is columns + assert(A.cols() == A.outerSize()); + int column_pointer = 0; + int i = 0; + int k = 0; + // Iterate over outside + for(; k::InnerIterator it (A,k); it; ++it) + { + V[i] = it.value(); + R[i] = it.row(); + i++; + // Also increment column pointer + column_pointer++; + } + } + // by convention C[num_cols] = nnz + C[k] = column_pointer; +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::harwell_boeing(Eigen::SparseMatrix const&, int&, std::vector >&, std::vector >&, std::vector >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/harwell_boeing.h b/src/external/libigl-2.3.0/include/igl/harwell_boeing.h new file mode 100644 index 000000000..df166ab82 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/harwell_boeing.h @@ -0,0 +1,48 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_HARWELL_BOEING_H +#define IGL_HARWELL_BOEING_H +#include "igl_inline.h" + +#include +#include + + +namespace igl +{ + // Convert the matrix to Compressed sparse column (CSC or CCS) format, + // also known as Harwell Boeing format. As described: + // http://netlib.org/linalg/html_templates/node92.html + // or + // http://en.wikipedia.org/wiki/Sparse_matrix + // #Compressed_sparse_column_.28CSC_or_CCS.29 + // Templates: + // Scalar type of sparse matrix like double + // Inputs: + // A sparse m by n matrix + // Outputs: + // num_rows number of rows + // V non-zero values, row indices running fastest, size(V) = nnz + // R row indices corresponding to vals, size(R) = nnz + // C index in vals of first entry in each column, size(C) = num_cols+1 + // + // All indices and pointers are 0-based + template + IGL_INLINE void harwell_boeing( + const Eigen::SparseMatrix & A, + int & num_rows, + std::vector & V, + std::vector & R, + std::vector & C); +} + +#ifndef IGL_STATIC_LIBRARY +# include "harwell_boeing.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/hausdorff.cpp b/src/external/libigl-2.3.0/include/igl/hausdorff.cpp new file mode 100644 index 000000000..9a6058cb7 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/hausdorff.cpp @@ -0,0 +1,90 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "hausdorff.h" +#include "point_mesh_squared_distance.h" + +template < + typename DerivedVA, + typename DerivedFA, + typename DerivedVB, + typename DerivedFB, + typename Scalar> +IGL_INLINE void igl::hausdorff( + const Eigen::MatrixBase & VA, + const Eigen::MatrixBase & FA, + const Eigen::MatrixBase & VB, + const Eigen::MatrixBase & FB, + Scalar & d) +{ + using namespace Eigen; + assert(VA.cols() == 3 && "VA should contain 3d points"); + assert(FA.cols() == 3 && "FA should contain triangles"); + assert(VB.cols() == 3 && "VB should contain 3d points"); + assert(FB.cols() == 3 && "FB should contain triangles"); + Matrix sqr_DBA, sqr_DAB; + Matrix I; + Matrix C; + point_mesh_squared_distance(VB,VA,FA,sqr_DBA,I,C); + point_mesh_squared_distance(VA,VB,FB,sqr_DAB,I,C); + const Scalar dba = sqr_DBA.maxCoeff(); + const Scalar dab = sqr_DAB.maxCoeff(); + d = sqrt(std::max(dba,dab)); +} + +template < + typename DerivedV, + typename Scalar> +IGL_INLINE void igl::hausdorff( + const Eigen::MatrixBase& V, + const std::function & dist_to_B, + Scalar & l, + Scalar & u) +{ + // e 3-long vector of opposite edge lengths + Eigen::Matrix e; + // Maximum edge length + Scalar e_max = 0; + for(int i=0;i<3;i++) + { + e(i) = (V.row((i+1)%3)-V.row((i+2)%3)).norm(); + e_max = std::max(e_max,e(i)); + } + // Semiperimeter + const Scalar s = (e(0)+e(1)+e(2))*0.5; + // Area + const Scalar A = sqrt(s*(s-e(0))*(s-e(1))*(s-e(2))); + // Circumradius + const Scalar R = e(0)*e(1)*e(2)/(4.*A); + // inradius + const Scalar r = A/s; + // Initialize lower bound to ∞ + l = std::numeric_limits::infinity(); + // d 3-long vector of distance from each corner to B + Eigen::Matrix d; + Scalar u1 = std::numeric_limits::infinity(); + Scalar u2 = 0; + for(int i=0;i<3;i++) + { + d(i) = dist_to_B(V(i,0),V(i,1),V(i,2)); + // Lower bound is simply the max over vertex distances + l = std::max(d(i),l); + // u1 is the minimum of corner distances + maximum adjacent edge + u1 = std::min(u1,d(i) + std::max(e((i+1)%3),e((i+2)%3))); + // u2 first takes the maximum over corner distances + u2 = std::max(u2,d(i)); + } + // u2 is the distance from the circumcenter/midpoint of obtuse edge plus the + // largest corner distance + u2 += (s-r>2.*R ? R : 0.5*e_max); + u = std::min(u1,u2); +} + +#ifdef IGL_STATIC_LIBRARY +template void igl::hausdorff, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, double>(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, double&); +template void igl::hausdorff, double>(Eigen::MatrixBase > const&, std::function const&, double&, double&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/hausdorff.h b/src/external/libigl-2.3.0/include/igl/hausdorff.h new file mode 100644 index 000000000..7672f33f9 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/hausdorff.h @@ -0,0 +1,86 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_HAUSDORFF_H +#define IGL_HAUSDORFF_H +#include "igl_inline.h" + +#include +#include + +namespace igl +{ + // HAUSDORFF compute the Hausdorff distance between mesh (VA,FA) and mesh + // (VB,FB). This is the + // + // d(A,B) = max ( max min d(a,b) , max min d(b,a) ) + // a∈A b∈B b∈B a∈A + // + // Known issue: This is only computing max(min(va,B),min(vb,A)). This is + // better than max(min(va,Vb),min(vb,Va)). This (at least) is missing + // "edge-edge" cases like the distance between the two different + // triangulations of a non-planar quad in 3D. Even simpler, consider the + // Hausdorff distance between the non-convex, block letter V polygon (with 7 + // vertices) in 2D and its convex hull. The Hausdorff distance is defined by + // the midpoint in the middle of the segment across the concavity and some + // non-vertex point _on the edge_ of the V. + // Known issue: due to the issue above, this also means that unreferenced + // vertices can give unexpected results. Therefore, we assume the inputs have + // no unreferenced vertices. + // + // Inputs: + // VA #VA by 3 list of vertex positions + // FA #FA by 3 list of face indices into VA + // VB #VB by 3 list of vertex positions + // FB #FB by 3 list of face indices into VB + // Outputs: + // d hausdorff distance + // //pair 2 by 3 list of "determiner points" so that pair(1,:) is from A + // // and pair(2,:) is from B + // + template < + typename DerivedVA, + typename DerivedFA, + typename DerivedVB, + typename DerivedFB, + typename Scalar> + IGL_INLINE void hausdorff( + const Eigen::MatrixBase & VA, + const Eigen::MatrixBase & FA, + const Eigen::MatrixBase & VB, + const Eigen::MatrixBase & FB, + Scalar & d); + // Compute lower and upper bounds (l,u) on the Hausdorff distance between a triangle + // (V) and a pointset (e.g., mesh, triangle soup) given by a distance function + // handle (dist_to_B). + // + // Inputs: + // V 3 by 3 list of corner positions so that V.row(i) is the position of the + // ith corner + // dist_to_B function taking the x,y,z coordinate of a query position and + // outputting the closest-point distance to some point-set B + // Outputs: + // l lower bound on Hausdorff distance + // u upper bound on Hausdorff distance + // + template < + typename DerivedV, + typename Scalar> + IGL_INLINE void hausdorff( + const Eigen::MatrixBase& V, + const std::function< + Scalar(const Scalar &,const Scalar &, const Scalar &)> & dist_to_B, + Scalar & l, + Scalar & u); +} + +#ifndef IGL_STATIC_LIBRARY +# include "hausdorff.cpp" +#endif + +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/heat_geodesics.cpp b/src/external/libigl-2.3.0/include/igl/heat_geodesics.cpp new file mode 100644 index 000000000..c9a2a5af2 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/heat_geodesics.cpp @@ -0,0 +1,170 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2018 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +#include "heat_geodesics.h" +#include "grad.h" +#include "doublearea.h" +#include "cotmatrix.h" +#include "intrinsic_delaunay_cotmatrix.h" +#include "massmatrix.h" +#include "massmatrix_intrinsic.h" +#include "grad_intrinsic.h" +#include "boundary_facets.h" +#include "unique.h" +#include "slice.h" +#include "avg_edge_length.h" + + +template < typename DerivedV, typename DerivedF, typename Scalar > +IGL_INLINE bool igl::heat_geodesics_precompute( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + HeatGeodesicsData & data) +{ + // default t value + const Scalar h = avg_edge_length(V,F); + const Scalar t = h*h; + return heat_geodesics_precompute(V,F,t,data); +} + +template < typename DerivedV, typename DerivedF, typename Scalar > +IGL_INLINE bool igl::heat_geodesics_precompute( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const Scalar t, + HeatGeodesicsData & data) +{ + typedef Eigen::Matrix VectorXS; + typedef Eigen::Matrix MatrixXS; + Eigen::SparseMatrix L,M; + Eigen::Matrix l_intrinsic; + DerivedF F_intrinsic; + VectorXS dblA; + if(data.use_intrinsic_delaunay) + { + igl::intrinsic_delaunay_cotmatrix(V,F,L,l_intrinsic,F_intrinsic); + igl::massmatrix_intrinsic(l_intrinsic,F_intrinsic,MASSMATRIX_TYPE_DEFAULT,M); + igl::doublearea(l_intrinsic,0,dblA); + igl::grad_intrinsic(l_intrinsic,F_intrinsic,data.Grad); + }else + { + igl::cotmatrix(V,F,L); + igl::massmatrix(V,F,MASSMATRIX_TYPE_DEFAULT,M); + igl::doublearea(V,F,dblA); + igl::grad(V,F,data.Grad); + } + // div + assert(F.cols() == 3 && "Only triangles are supported"); + // number of gradient components + data.ng = data.Grad.rows() / F.rows(); + assert(data.ng == 3 || data.ng == 2); + data.Div = -0.25*data.Grad.transpose()*dblA.colwise().replicate(data.ng).asDiagonal(); + + Eigen::SparseMatrix Q = M - t*L; + Eigen::MatrixXi O; + igl::boundary_facets(F,O); + igl::unique(O,data.b); + { + Eigen::SparseMatrix _; + if(!igl::min_quad_with_fixed_precompute( + Q,Eigen::VectorXi(),_,true,data.Neumann)) + { + return false; + } + // Only need if there's a boundary + if(data.b.size()>0) + { + if(!igl::min_quad_with_fixed_precompute(Q,data.b,_,true,data.Dirichlet)) + { + return false; + } + } + const DerivedV M_diag_tr = M.diagonal().transpose(); + const Eigen::SparseMatrix Aeq = M_diag_tr.sparseView(); + L *= -0.5; + if(!igl::min_quad_with_fixed_precompute( + L,Eigen::VectorXi(),Aeq,true,data.Poisson)) + { + return false; + } + } + return true; +} + +template < typename Scalar, typename Derivedgamma, typename DerivedD> +IGL_INLINE void igl::heat_geodesics_solve( + const HeatGeodesicsData & data, + const Eigen::MatrixBase & gamma, + Eigen::PlainObjectBase & D) +{ + // number of mesh vertices + const int n = data.Grad.cols(); + // Set up delta at gamma + DerivedD u0 = DerivedD::Zero(n,1); + for(int g = 0;g0) + { + // Average Dirichelt and Neumann solutions + DerivedD uD; + igl::min_quad_with_fixed_solve( + data.Dirichlet,u0,DerivedD::Zero(data.b.size()).eval(),DerivedD(),uD); + u += uD; + u *= 0.5; + } + DerivedD grad_u = data.Grad*u; + const int m = data.Grad.rows()/data.ng; + for(int i = 0;i, Eigen::Matrix >(igl::HeatGeodesicsData const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template bool igl::heat_geodesics_precompute, Eigen::Matrix, double>(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, double, igl::HeatGeodesicsData&); +template bool igl::heat_geodesics_precompute, Eigen::Matrix, double>(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, igl::HeatGeodesicsData&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/heat_geodesics.h b/src/external/libigl-2.3.0/include/igl/heat_geodesics.h new file mode 100644 index 000000000..6189c346e --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/heat_geodesics.h @@ -0,0 +1,69 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2018 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_HEAT_GEODESICS_H +#define IGL_HEAT_GEODESICS_H +#include "igl_inline.h" +#include "min_quad_with_fixed.h" +#include +#include +namespace igl +{ + template + struct HeatGeodesicsData + { + // Gradient and Divergence operators + Eigen::SparseMatrix Grad,Div; + // Number of gradient components + int ng; + // List of boundary vertex indices + Eigen::VectorXi b; + // Solvers for Dirichet, Neumann problems + min_quad_with_fixed_data Dirichlet,Neumann,Poisson; + bool use_intrinsic_delaunay = false; + }; + // Precompute factorized solvers for computing a fast approximation of + // geodesic distances on a mesh (V,F). [Crane et al. 2013] + // + // Inputs: + // V #V by dim list of mesh vertex positions + // F #F by 3 list of mesh face indices into V + // Outputs: + // data precomputation data (see heat_geodesics_solve) + template < typename DerivedV, typename DerivedF, typename Scalar > + IGL_INLINE bool heat_geodesics_precompute( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + HeatGeodesicsData & data); + // Inputs: + // t "heat" parameter (smaller --> more accurate, less stable) + template < typename DerivedV, typename DerivedF, typename Scalar > + IGL_INLINE bool heat_geodesics_precompute( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const Scalar t, + HeatGeodesicsData & data); + // Compute fast approximate geodesic distances using precomputed data from a + // set of selected source vertices (gamma) + // + // Inputs: + // data precomputation data (see heat_geodesics_precompute) + // gamma #gamma list of indices into V of source vertices + // Outputs: + // D #V list of distances to gamma + template < typename Scalar, typename Derivedgamma, typename DerivedD> + IGL_INLINE void heat_geodesics_solve( + const HeatGeodesicsData & data, + const Eigen::MatrixBase & gamma, + Eigen::PlainObjectBase & D); +} + +#ifndef IGL_STATIC_LIBRARY +#include "heat_geodesics.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/hessian.cpp b/src/external/libigl-2.3.0/include/igl/hessian.cpp new file mode 100644 index 000000000..b53babf26 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/hessian.cpp @@ -0,0 +1,60 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2017 Alec Jacobson +// and Oded Stein +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +#include "hessian.h" +#include + +#include "grad.h" +#include "igl/doublearea.h" +#include "igl/repdiag.h" + + + +template +IGL_INLINE void igl::hessian( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + Eigen::SparseMatrix& H) +{ + typedef typename DerivedV::Scalar denseScalar; + typedef typename Eigen::Matrix VecXd; + typedef typename Eigen::SparseMatrix SparseMat; + typedef typename Eigen::DiagonalMatrix + DiagMat; + + int dim = V.cols(); + assert((dim==2 || dim==3) && + "The dimension of the vertices should be 2 or 3"); + + //Construct the combined gradient matric + SparseMat G; + igl::grad(V, + F, + G, false); + SparseMat GG(F.rows(), dim*V.rows()); + GG.reserve(G.nonZeros()); + for(int i=0; i, Eigen::Matrix, double>(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::SparseMatrix&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/hessian.h b/src/external/libigl-2.3.0/include/igl/hessian.h new file mode 100644 index 000000000..360750d2c --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/hessian.h @@ -0,0 +1,47 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2017 Alec Jacobson +// and Oded Stein +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef IGL_FEM_HESSIAN_H +#define IGL_FEM_HESSIAN_H +#include "igl_inline.h" + +#include +#include + + +namespace igl +{ + // Constructs the finite element Hessian matrix + // as described in https://arxiv.org/abs/1707.04348, + // Natural Boundary Conditions for Smoothing in Geometry Processing + // (Oded Stein, Eitan Grinspun, Max Wardetzky, Alec Jacobson) + // The interior vertices are NOT set to zero yet. + // + // Inputs: + // V #V by dim list of mesh vertex positions + // F #F by 3 list of mesh faces (must be triangles) + // Outputs: + // H #V by #V Hessian energy matrix, each column i + // corresponding to V(i,:) + // + // + // + template + IGL_INLINE void hessian( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + Eigen::SparseMatrix& H); + +} + +#ifndef IGL_STATIC_LIBRARY +# include "hessian.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/hessian_energy.cpp b/src/external/libigl-2.3.0/include/igl/hessian_energy.cpp new file mode 100644 index 000000000..556a2b39a --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/hessian_energy.cpp @@ -0,0 +1,64 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2017 Alec Jacobson +// and Oded Stein +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "hessian_energy.h" +#include + +#include "hessian.h" +#include "massmatrix.h" +#include "boundary_loop.h" + + +template +IGL_INLINE void igl::hessian_energy( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + Eigen::SparseMatrix& Q) +{ + typedef typename DerivedV::Scalar denseScalar; + typedef typename Eigen::Matrix VecXd; + typedef typename Eigen::SparseMatrix SparseMat; + typedef typename Eigen::DiagonalMatrix + DiagMat; + + int dim = V.cols(); + assert((dim==2 || dim==3) && + "The dimension of the vertices should be 2 or 3"); + + SparseMat M; + igl::massmatrix(V,F,igl::MASSMATRIX_TYPE_VORONOI,M); + + //Kill non-interior DOFs + VecXd Mint = M.diagonal(); + std::vector > bdryLoop; + igl::boundary_loop(F,bdryLoop); + for(const std::vector& loop : bdryLoop) + for(const int& bdryVert : loop) + Mint(bdryVert) = 0.; + + //Invert Mint + for(int i=0; i 0) + Mint(i) = 1./Mint(i); + + //Repeat Mint to form diaginal matrix + DiagMat stackedMinv = Mint.replicate(dim*dim,1).asDiagonal(); + + //Compute squared Hessian + SparseMat H; + igl::hessian(V,F,H); + Q = H.transpose()*stackedMinv*H; + +} + + + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +template void igl::hessian_energy, Eigen::Matrix, double>(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::SparseMatrix&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/hessian_energy.h b/src/external/libigl-2.3.0/include/igl/hessian_energy.h new file mode 100644 index 000000000..e53373580 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/hessian_energy.h @@ -0,0 +1,45 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2017 Alec Jacobson +// and Oded Stein +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_HESSIAN_ENERGY_H +#define IGL_HESSIAN_ENERGY_H +#include "igl_inline.h" + +#include +#include + + +namespace igl +{ + // Constructs the Hessian energy matrix using mixed FEM + // as described in https://arxiv.org/abs/1707.04348 + // Natural Boundary Conditions for Smoothing in Geometry Processing + // (Oded Stein, Eitan Grinspun, Max Wardetzky, Alec Jacobson) + // + // Inputs: + // V #V by dim list of mesh vertex positions + // F #F by 3 list of mesh faces (must be triangles) + // Outputs: + // Q #V by #V Hessian energy matrix, each row/column i + // corresponding to V(i,:) + // + // + // + template + IGL_INLINE void hessian_energy( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + Eigen::SparseMatrix& Q); + +} + +#ifndef IGL_STATIC_LIBRARY +# include "hessian_energy.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/histc.cpp b/src/external/libigl-2.3.0/include/igl/histc.cpp new file mode 100644 index 000000000..2b33ea3e6 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/histc.cpp @@ -0,0 +1,115 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "histc.h" +#include +#include + +template +IGL_INLINE void igl::histc( + const Eigen::MatrixBase & X, + const Eigen::MatrixBase & E, + Eigen::PlainObjectBase & N, + Eigen::PlainObjectBase & B) +{ + histc(X,E,B); + const int n = E.size(); + const int m = X.size(); + assert(m == B.size()); + N.resize(n,1); + N.setConstant(0); +#pragma omp parallel for + for(int j = 0;j= 0) + { +#pragma omp atomic + N(int(B(j)))++; + } + } +} + +template +IGL_INLINE void igl::histc( + const Eigen::MatrixBase & X, + const Eigen::MatrixBase & E, + Eigen::PlainObjectBase & B) +{ + const int m = X.size(); + using namespace std; + assert( + (E.bottomRightCorner(E.size()-1,1) - + E.topLeftCorner(E.size()-1,1)).maxCoeff() >= 0 && + "E should be monotonically increasing"); + B.resize(m,1); +#pragma omp parallel for + for(int j = 0;j E(E.size()-1)) + { + B(j) = -1; + continue; + } + // Find x in E + int l = 0; + int h = E.size()-1; + int k = l; + while((h-l)>1) + { + assert(x >= E(l)); + assert(x <= E(h)); + k = (h+l)/2; + if(x < E(k)) + { + h = k; + }else + { + l = k; + } + } + if(x == E(h)) + { + k = h; + }else + { + k = l; + } + B(j) = k; + } +} + +template +IGL_INLINE void igl::histc( + const typename DerivedE::Scalar & x, + const Eigen::MatrixBase & E, + typename DerivedE::Index & b) +{ + Eigen::Matrix X; + X(0) = x; + Eigen::Matrix B; + hist(X,E,B); + b = B(0); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +template void igl::histc, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::histc, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::histc, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::histc, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::histc, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::histc, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::histc, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::histc, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +#if EIGEN_VERSION_AT_LEAST(3,3,0) +#else +template void igl::histc, Eigen::Matrix >, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase, Eigen::Matrix > > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/histc.h b/src/external/libigl-2.3.0/include/igl/histc.h new file mode 100644 index 000000000..2f0ed9135 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/histc.h @@ -0,0 +1,56 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_HISTC_H +#define IGL_HISTC_H + +#include "igl_inline.h" +#include + +namespace igl +{ + // Like matlab's histc. Count occurrences of values in X between consecutive + // entries in E + // + // Inputs: + // X m-long Vector of values + // E n-long Monotonically increasing vector of edges + // Outputs: + // N n-long vector where N(k) reveals how many values in X fall between + // E(k) <= X < E(k+1) + // B m-long vector of bin ids so that B(j) = k if E(k) <= X(j) < E(k+1). + // B(j) = -1 if X(j) is outside of E. + // + // O(n+m*log(n)) + template + IGL_INLINE void histc( + const Eigen::MatrixBase & X, + const Eigen::MatrixBase & E, + Eigen::PlainObjectBase & N, + Eigen::PlainObjectBase & B); + // Truly O(m*log(n)) + template + IGL_INLINE void histc( + const Eigen::MatrixBase & X, + const Eigen::MatrixBase & E, + Eigen::PlainObjectBase & B); + // Scalar search wrapper + template + IGL_INLINE void histc( + const typename DerivedE::Scalar & x, + const Eigen::MatrixBase & E, + typename DerivedE::Index & b); +} + +#ifndef IGL_STATIC_LIBRARY +# include "histc.cpp" +#endif + +#endif + + + diff --git a/src/external/libigl-2.3.0/include/igl/hsv_to_rgb.cpp b/src/external/libigl-2.3.0/include/igl/hsv_to_rgb.cpp new file mode 100644 index 000000000..62d4f5a84 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/hsv_to_rgb.cpp @@ -0,0 +1,73 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "hsv_to_rgb.h" +#include + + +template +IGL_INLINE void igl::hsv_to_rgb(const T * hsv, T * rgb) +{ + igl::hsv_to_rgb( + hsv[0],hsv[1],hsv[2], + rgb[0],rgb[1],rgb[2]); +} + +template +IGL_INLINE void igl::hsv_to_rgb( + const T & h, const T & s, const T & v, + T & r, T & g, T & b) +{ + // From medit + double f,p,q,t,hh; + int i; + // shift the hue to the range [0, 360] before performing calculations + hh = ((360 + ((int)h % 360)) % 360) / 60.; + i = (int)std::floor(hh); /* largest int <= h */ + f = hh - i; /* fractional part of h */ + p = v * (1.0 - s); + q = v * (1.0 - (s * f)); + t = v * (1.0 - (s * (1.0 - f))); + + switch(i) { + case 0: r = v; g = t; b = p; break; + case 1: r = q; g = v; b = p; break; + case 2: r = p; g = v; b = t; break; + case 3: r = p; g = q; b = v; break; + case 4: r = t; g = p; b = v; break; + case 5: r = v; g = p; b = q; break; + } +} + +template +void igl::hsv_to_rgb( + const Eigen::PlainObjectBase & H, + Eigen::PlainObjectBase & R) +{ + assert(H.cols() == 3); + R.resizeLike(H); + for(typename DerivedH::Index r = 0;r, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&); +template void igl::hsv_to_rgb, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&); +template void igl::hsv_to_rgb, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&); +template void igl::hsv_to_rgb, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&); +template void igl::hsv_to_rgb(double const*, double*); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/hsv_to_rgb.h b/src/external/libigl-2.3.0/include/igl/hsv_to_rgb.h new file mode 100644 index 000000000..2abc07a92 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/hsv_to_rgb.h @@ -0,0 +1,41 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_HSV_TO_RGB_H +#define IGL_HSV_TO_RGB_H +#include "igl_inline.h" +#include +namespace igl +{ + // Convert RGB to HSV + // + // Inputs: + // h hue value (degrees: [0,360]. Values outside this range will be mapped periodically to [0,360].) + // s saturation value ([0,1]) + // v value value ([0,1]) + // Outputs: + // r red value ([0,1]) + // g green value ([0,1]) + // b blue value ([0,1]) + template + IGL_INLINE void hsv_to_rgb(const T * hsv, T * rgb); + template + IGL_INLINE void hsv_to_rgb( + const T & h, const T & s, const T & v, + T & r, T & g, T & b); + template + void hsv_to_rgb( + const Eigen::PlainObjectBase & H, + Eigen::PlainObjectBase & R); +}; + +#ifndef IGL_STATIC_LIBRARY +# include "hsv_to_rgb.cpp" +#endif + +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/igl_inline.h b/src/external/libigl-2.3.0/include/igl/igl_inline.h new file mode 100644 index 000000000..20c9630e4 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/igl_inline.h @@ -0,0 +1,18 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +// This should *NOT* be contained in a IGL_*_H ifdef, since it may be defined +// differently based on when it is included +#ifdef IGL_INLINE +#undef IGL_INLINE +#endif + +#ifndef IGL_STATIC_LIBRARY +# define IGL_INLINE inline +#else +# define IGL_INLINE +#endif diff --git a/src/external/libigl-2.3.0/include/igl/in_element.cpp b/src/external/libigl-2.3.0/include/igl/in_element.cpp new file mode 100644 index 000000000..ea7638d01 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/in_element.cpp @@ -0,0 +1,65 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "in_element.h" + +template +IGL_INLINE void igl::in_element( + const Eigen::MatrixBase & V, + const Eigen::MatrixXi & Ele, + const Eigen::MatrixBase & Q, + const AABB & aabb, + Eigen::VectorXi & I) +{ + using namespace std; + using namespace Eigen; + const int Qr = Q.rows(); + I.setConstant(Qr,1,-1); +#pragma omp parallel for if (Qr>10000) + for(int e = 0;e +IGL_INLINE void igl::in_element( + const Eigen::MatrixBase & V, + const Eigen::MatrixXi & Ele, + const Eigen::MatrixBase & Q, + const AABB & aabb, + Eigen::SparseMatrix & I) +{ + using namespace std; + using namespace Eigen; + const int Qr = Q.rows(); + std::vector > IJV; + IJV.reserve(Qr); +#pragma omp parallel for if (Qr>10000) + for(int e = 0;e(e,r,1)); + } + } + I.resize(Qr,Ele.rows()); + I.setFromTriplets(IJV.begin(),IJV.end()); +} + +#ifdef IGL_STATIC_LIBRARY +template void igl::in_element, Eigen::Matrix, 2>(Eigen::MatrixBase > const&, Eigen::Matrix const&, Eigen::MatrixBase > const&, igl::AABB, 2> const&, Eigen::Matrix&); +template void igl::in_element, Eigen::Matrix, 3>(Eigen::MatrixBase > const&, Eigen::Matrix const&, Eigen::MatrixBase > const&, igl::AABB, 3> const&, Eigen::Matrix&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/in_element.h b/src/external/libigl-2.3.0/include/igl/in_element.h new file mode 100644 index 000000000..c438f62ee --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/in_element.h @@ -0,0 +1,54 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_IN_ELEMENT_H +#define IGL_IN_ELEMENT_H + +#include "igl_inline.h" +#include "AABB.h" +#include +#include + +namespace igl +{ + // Determine whether each point in a list of points is in the elements of a + // mesh. + // + // templates: + // DIM dimension of vertices in V (# of columns) + // Inputs: + // V #V by dim list of mesh vertex positions. + // Ele #Ele by dim+1 list of mesh indices into #V. + // Q #Q by dim list of query point positions + // aabb axis-aligned bounding box tree object (see AABB.h) + // Outputs: + // I #Q list of indices into Ele of first containing element (-1 means no + // containing element) + template + IGL_INLINE void in_element( + const Eigen::MatrixBase & V, + const Eigen::MatrixXi & Ele, + const Eigen::MatrixBase & Q, + const AABB & aabb, + Eigen::VectorXi & I); + // Outputs: + // I #Q by #Ele sparse matrix revealing whether each element contains each + // point: I(q,e) means point q is in element e + template + IGL_INLINE void in_element( + const Eigen::MatrixBase & V, + const Eigen::MatrixXi & Ele, + const Eigen::MatrixBase & Q, + const AABB & aabb, + Eigen::SparseMatrix & I); +}; + +#ifndef IGL_STATIC_LIBRARY +#include "in_element.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/infinite_cost_stopping_condition.cpp b/src/external/libigl-2.3.0/include/igl/infinite_cost_stopping_condition.cpp new file mode 100644 index 000000000..8d6f15be8 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/infinite_cost_stopping_condition.cpp @@ -0,0 +1,47 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "infinite_cost_stopping_condition.h" + +IGL_INLINE void igl::infinite_cost_stopping_condition( + const decimate_cost_and_placement_callback & cost_and_placement, + decimate_stopping_condition_callback & stopping_condition) +{ + stopping_condition = + [&cost_and_placement] + ( + const Eigen::MatrixXd & V, + const Eigen::MatrixXi & F, + const Eigen::MatrixXi & E, + const Eigen::VectorXi & EMAP, + const Eigen::MatrixXi & EF, + const Eigen::MatrixXi & EI, + const igl::min_heap< std::tuple > & ,/*Q*/ + const Eigen::VectorXi & ,/*EQ*/ + const Eigen::MatrixXd & /*C*/, + const int e, + const int /*e1*/, + const int /*e2*/, + const int /*f1*/, + const int /*f2*/)->bool + { + Eigen::RowVectorXd p; + double cost; + cost_and_placement(e,V,F,E,EMAP,EF,EI,cost,p); + return std::isinf(cost); + }; +} + +IGL_INLINE igl::decimate_stopping_condition_callback + igl::infinite_cost_stopping_condition( + const decimate_cost_and_placement_callback & cost_and_placement) +{ + decimate_stopping_condition_callback stopping_condition; + infinite_cost_stopping_condition(cost_and_placement,stopping_condition); + return stopping_condition; +} + diff --git a/src/external/libigl-2.3.0/include/igl/infinite_cost_stopping_condition.h b/src/external/libigl-2.3.0/include/igl/infinite_cost_stopping_condition.h new file mode 100644 index 000000000..dad15521d --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/infinite_cost_stopping_condition.h @@ -0,0 +1,39 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_INFINITE_COST_STOPPING_CONDITION_H +#define IGL_INFINITE_COST_STOPPING_CONDITION_H +#include "igl_inline.h" +#include "decimate_callback_types.h" +#include +#include +#include +#include +namespace igl +{ + // Stopping condition function compatible with igl::decimate. The output + // function handle will return true if cost of next edge is infinite. + // + // Inputs: + // cost_and_placement handle being used by igl::collapse_edge + // Outputs: + // stopping_condition + // + IGL_INLINE void infinite_cost_stopping_condition( + const decimate_cost_and_placement_callback & cost_and_placement, + decimate_stopping_condition_callback & stopping_condition); + IGL_INLINE decimate_stopping_condition_callback + infinite_cost_stopping_condition( + const decimate_cost_and_placement_callback & cost_and_placement); +} + +#ifndef IGL_STATIC_LIBRARY +# include "infinite_cost_stopping_condition.cpp" +#endif +#endif + + diff --git a/src/external/libigl-2.3.0/include/igl/inradius.cpp b/src/external/libigl-2.3.0/include/igl/inradius.cpp new file mode 100644 index 000000000..947b16409 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/inradius.cpp @@ -0,0 +1,33 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "inradius.h" +#include "edge_lengths.h" +#include "doublearea.h" + +template < + typename DerivedV, + typename DerivedF, + typename DerivedR> +IGL_INLINE void igl::inradius( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + Eigen::PlainObjectBase & r) +{ + Eigen::Matrix l; + Eigen::Matrix R; + igl::edge_lengths(V,F,l); + // If R is the circumradius, + // R*r = (abc)/(2*(a+b+c)) + // R = abc/(4*area) + // r(abc/(4*area)) = (abc)/(2*(a+b+c)) + // r/(4*area) = 1/(2*(a+b+c)) + // r = (2*area)/(a+b+c) + DerivedR A; + igl::doublearea(l,0.,A); + r = A.array() /l.array().rowwise().sum(); +} diff --git a/src/external/libigl-2.3.0/include/igl/inradius.h b/src/external/libigl-2.3.0/include/igl/inradius.h new file mode 100644 index 000000000..e831f7de3 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/inradius.h @@ -0,0 +1,35 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_INRADIUS_H +#define IGL_INRADIUS_H +#include "igl_inline.h" +#include +namespace igl +{ + // Compute the inradius of each triangle in a mesh (V,F) + // + // Inputs: + // V #V by dim list of mesh vertex positions + // F #F by 3 list of triangle indices into V + // Outputs: + // R #F list of inradii + // + template < + typename DerivedV, + typename DerivedF, + typename DerivedR> + IGL_INLINE void inradius( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + Eigen::PlainObjectBase & R); +} +#ifndef IGL_STATIC_LIBRARY +# include "inradius.cpp" +#endif +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/internal_angles.cpp b/src/external/libigl-2.3.0/include/igl/internal_angles.cpp new file mode 100644 index 000000000..cb8014b75 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/internal_angles.cpp @@ -0,0 +1,105 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// Copyright (C) 2015 Daniele Panozzo +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "internal_angles.h" +#include "squared_edge_lengths.h" +#include "parallel_for.h" +#include "get_seconds.h" + +template +IGL_INLINE void igl::internal_angles( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + Eigen::PlainObjectBase & K) +{ + using namespace Eigen; + using namespace std; + typedef typename DerivedV::Scalar Scalar; + if(F.cols() == 3) + { + // Edge lengths + Matrix< + Scalar, + DerivedF::RowsAtCompileTime, + DerivedF::ColsAtCompileTime> L_sq; + igl::squared_edge_lengths(V,F,L_sq); + + assert(F.cols() == 3 && "F should contain triangles"); + igl::internal_angles_using_squared_edge_lengths(L_sq,K); + }else + { + assert(V.cols() == 3 && "If F contains non-triangle facets, V must be 3D"); + K.resizeLike(F); + auto corner = []( + const typename DerivedV::ConstRowXpr & x, + const typename DerivedV::ConstRowXpr & y, + const typename DerivedV::ConstRowXpr & z) + { + typedef Eigen::Matrix RowVector3S; + RowVector3S v1 = (x-y).normalized(); + RowVector3S v2 = (z-y).normalized(); + // http://stackoverflow.com/questions/10133957/signed-angle-between-two-vectors-without-a-reference-plane + Scalar s = v1.cross(v2).norm(); + Scalar c = v1.dot(v2); + return atan2(s, c); + }; + for(unsigned i=0; i +IGL_INLINE void igl::internal_angles_using_squared_edge_lengths( + const Eigen::MatrixBase& L_sq, + Eigen::PlainObjectBase & K) +{ + typedef typename DerivedL::Index Index; + assert(L_sq.cols() == 3 && "Edge-lengths should come from triangles"); + const Index m = L_sq.rows(); + K.resize(m,3); + parallel_for( + m, + [&L_sq,&K](const Index f) + { + for(size_t d = 0;d<3;d++) + { + const auto & s1 = L_sq(f,d); + const auto & s2 = L_sq(f,(d+1)%3); + const auto & s3 = L_sq(f,(d+2)%3); + K(f,d) = acos((s3 + s2 - s1)/(2.*sqrt(s3*s2))); + } + }, + 1000l); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::internal_angles, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::internal_angles, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::internal_angles, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::internal_angles, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::internal_angles, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::internal_angles, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::internal_angles, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::internal_angles, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::internal_angles, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::internal_angles_using_squared_edge_lengths, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::internal_angles_using_squared_edge_lengths, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/internal_angles.h b/src/external/libigl-2.3.0/include/igl/internal_angles.h new file mode 100644 index 000000000..1469549d9 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/internal_angles.h @@ -0,0 +1,51 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_INTERNAL_ANGLES_H +#define IGL_INTERNAL_ANGLES_H +#include "igl_inline.h" +#include "deprecated.h" +#include +namespace igl +{ + // Compute internal angles for a triangle mesh + // + // Inputs: + // V #V by dim eigen Matrix of mesh vertex nD positions + // F #F by poly-size eigen Matrix of face (triangle) indices + // Output: + // K #F by poly-size eigen Matrix of internal angles + // for triangles, columns correspond to edges [1,2],[2,0],[0,1] + // + // Known Issues: + // if poly-size ≠ 3 then dim must equal 3. + template + IGL_INLINE void internal_angles( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + Eigen::PlainObjectBase & K); + // Inputs: + // L_sq #F by 3 list of squared edge lengths + // Output: + // K #F by poly-size eigen Matrix of internal angles + // for triangles, columns correspond to edges [1,2],[2,0],[0,1] + // + // Note: + // Usage of internal_angles_using_squared_edge_lengths is preferred to internal_angles_using_squared_edge_lengths + template + IGL_INLINE void internal_angles_using_squared_edge_lengths( + const Eigen::MatrixBase& L_sq, + Eigen::PlainObjectBase & K); +} + +#ifndef IGL_STATIC_LIBRARY +# include "internal_angles.cpp" +#endif + +#endif + + diff --git a/src/external/libigl-2.3.0/include/igl/intersect.cpp b/src/external/libigl-2.3.0/include/igl/intersect.cpp new file mode 100644 index 000000000..f930fc0be --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/intersect.cpp @@ -0,0 +1,50 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "intersect.h" +template +IGL_INLINE void igl::intersect(const M & A, const M & B, M & C) +{ + // Stupid O(size(A) * size(B)) to do it + // Alec: This should be implemented by using unique and sort like `setdiff` + M dyn_C(A.size() > B.size() ? A.size() : B.size(),1); + // count of intersects + int c = 0; + // Loop over A + for(int i = 0;i +IGL_INLINE M igl::intersect(const M & A, const M & B) +{ + M C; + intersect(A,B,C); + return C; +} +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +template Eigen::Matrix igl::intersect >(Eigen::Matrix const&, Eigen::Matrix const&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/intersect.h b/src/external/libigl-2.3.0/include/igl/intersect.h new file mode 100644 index 000000000..be4da91e5 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/intersect.h @@ -0,0 +1,32 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_INTERSECT_H +#define IGL_INTERSECT_H +#include "igl_inline.h" +#include +namespace igl +{ + // Determine the intersect between two sets of coefficients using == + // Templates: + // M matrix type that implements indexing by global index M(i) + // Inputs: + // A matrix of coefficients + // B matrix of coefficients + // Output: + // C matrix of elements appearing in both A and B, C is always resized to + // have a single column + template + IGL_INLINE void intersect(const M & A, const M & B, M & C); + // Last argument as return + template + IGL_INLINE M intersect(const M & A, const M & B); +} +#ifndef IGL_STATIC_LIBRARY +#include "intersect.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/intrinsic_delaunay_cotmatrix.cpp b/src/external/libigl-2.3.0/include/igl/intrinsic_delaunay_cotmatrix.cpp new file mode 100644 index 000000000..711606011 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/intrinsic_delaunay_cotmatrix.cpp @@ -0,0 +1,54 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2018 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "intrinsic_delaunay_cotmatrix.h" +#include "edge_lengths.h" +#include "intrinsic_delaunay_triangulation.h" +#include "cotmatrix_intrinsic.h" +#include + +template +IGL_INLINE void igl::intrinsic_delaunay_cotmatrix( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + Eigen::SparseMatrix& L) +{ + Eigen::Matrix l_intrinsic; + DerivedF F_intrinsic; + return igl::intrinsic_delaunay_cotmatrix(V,F,L,l_intrinsic,F_intrinsic); +} + +template < + typename DerivedV, + typename DerivedF, + typename Scalar, + typename Derivedl_intrinsic, + typename DerivedF_intrinsic> +IGL_INLINE void igl::intrinsic_delaunay_cotmatrix( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + Eigen::SparseMatrix& L, + Eigen::PlainObjectBase & l_intrinsic, + Eigen::PlainObjectBase & F_intrinsic) +{ + assert(F.cols() == 3 && "Only triangles are supported"); + Eigen::Matrix l; + igl::edge_lengths(V,F,l); + igl::intrinsic_delaunay_triangulation(l,F,l_intrinsic,F_intrinsic); + igl::cotmatrix_intrinsic(l_intrinsic,F_intrinsic,L); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::intrinsic_delaunay_cotmatrix, Eigen::Matrix, double, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::SparseMatrix&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::intrinsic_delaunay_cotmatrix, Eigen::Matrix, double>(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::SparseMatrix&); +// generated by autoexplicit.sh +template void igl::intrinsic_delaunay_cotmatrix, Eigen::Matrix, double, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::SparseMatrix&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +#endif diff --git a/src/external/libigl-2.3.0/include/igl/intrinsic_delaunay_cotmatrix.h b/src/external/libigl-2.3.0/include/igl/intrinsic_delaunay_cotmatrix.h new file mode 100644 index 000000000..a0f6367f0 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/intrinsic_delaunay_cotmatrix.h @@ -0,0 +1,51 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2018 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_INTRINSIC_DELAUNAY_COTMATRIX_H +#define IGL_INTRINSIC_DELAUNAY_COTMATRIX_H +#include "igl_inline.h" +#include +#include +namespace igl +{ + // INTRINSIC_DELAUNAY_COTMATRIX Computes the discrete cotangent Laplacian of a + // mesh after converting it into its intrinsic Delaunay triangulation (see, + // e.g., [Fisher et al. 2007]. + // + // Inputs: + // V #V by dim list of mesh vertex positions + // F #F by 3 list of mesh elements (triangles or tetrahedra) + // Outputs: + // L #V by #V cotangent matrix, each row i corresponding to V(i,:) + // l_intrinsic #F by 3 list of intrinsic edge-lengths used to compute L + // F_intrinsic #F by 3 list of intrinsic face indices used to compute L + // + // See also: intrinsic_delaunay_triangulation, cotmatrix, cotmatrix_intrinsic + template < + typename DerivedV, + typename DerivedF, + typename Scalar, + typename Derivedl_intrinsic, + typename DerivedF_intrinsic> + IGL_INLINE void intrinsic_delaunay_cotmatrix( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + Eigen::SparseMatrix& L, + Eigen::PlainObjectBase & l_intrinsic, + Eigen::PlainObjectBase & F_intrinsic); + template + IGL_INLINE void intrinsic_delaunay_cotmatrix( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + Eigen::SparseMatrix& L); +} + +#ifndef IGL_STATIC_LIBRARY +# include "intrinsic_delaunay_cotmatrix.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/intrinsic_delaunay_triangulation.cpp b/src/external/libigl-2.3.0/include/igl/intrinsic_delaunay_triangulation.cpp new file mode 100644 index 000000000..9ed886359 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/intrinsic_delaunay_triangulation.cpp @@ -0,0 +1,198 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2018 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "intrinsic_delaunay_triangulation.h" +#include "is_intrinsic_delaunay.h" +#include "tan_half_angle.h" +#include "unique_edge_map.h" +#include "flip_edge.h" +#include "EPS.h" +#include +#include +#include + +template < + typename Derivedl_in, + typename DerivedF_in, + typename Derivedl, + typename DerivedF> +IGL_INLINE void igl::intrinsic_delaunay_triangulation( + const Eigen::MatrixBase & l_in, + const Eigen::MatrixBase & F_in, + Eigen::PlainObjectBase & l, + Eigen::PlainObjectBase & F) +{ + typedef Eigen::Matrix MatrixX2I; + typedef Eigen::Matrix VectorXI; + MatrixX2I E,uE; + VectorXI EMAP; + std::vector > uE2E; + return intrinsic_delaunay_triangulation(l_in,F_in,l,F,E,uE,EMAP,uE2E); +} + +template < + typename Derivedl_in, + typename DerivedF_in, + typename Derivedl, + typename DerivedF, + typename DerivedE, + typename DeriveduE, + typename DerivedEMAP, + typename uE2EType> +IGL_INLINE void igl::intrinsic_delaunay_triangulation( + const Eigen::MatrixBase & l_in, + const Eigen::MatrixBase & F_in, + Eigen::PlainObjectBase & l, + Eigen::PlainObjectBase & F, + Eigen::PlainObjectBase & E, + Eigen::PlainObjectBase & uE, + Eigen::PlainObjectBase & EMAP, + std::vector > & uE2E) +{ + igl::unique_edge_map(F_in, E, uE, EMAP, uE2E); + // We're going to work in place + l = l_in; + F = F_in; + typedef typename DerivedF::Scalar Index; + typedef typename Derivedl::Scalar Scalar; + const Index num_faces = F.rows(); + + // Vector is faster than queue... + std::vector Q; + Q.reserve(uE2E.size()); + for (size_t uei=0; uei inQ(uE2E.size(),1); + inQ.setConstant(false); + for(const auto uei : Q) + { + inQ(uei) = true; + } + for (Index uei=0; uei [v3,v4] + // Before: + // F(f1,:) = [v1,v2,v4] // in some cyclic order + // F(f2,:) = [v1,v3,v2] // in some cyclic order + // After: + // F(f1,:) = [v1,v3,v4] // in *this* order + // F(f2,:) = [v2,v4,v3] // in *this* order + // + // v1 v1 + // /|\ / \ + // c/ | \b c/f1 \b + // v3 /f2|f1\ v4 => v3 /__f__\ v4 + // \ e / \ f2 / + // d\ | /a d\ /a + // \|/ \ / + // v2 v2 + // + // Compute intrinsic length of oppposite edge + assert(uE2E[uei].size() == 2 && "edge should have 2 incident faces"); + const Index f1 = uE2E[uei][0]%num_faces; + const Index f2 = uE2E[uei][1]%num_faces; + const Index c1 = uE2E[uei][0]/num_faces; + const Index c2 = uE2E[uei][1]/num_faces; + assert(c1 < 3); + assert(c2 < 3); + assert(f1 != f2); + const Index v1 = F(f1, (c1+1)%3); + const Index v2 = F(f1, (c1+2)%3); + const Index v4 = F(f1, c1); + const Index v3 = F(f2, c2); + assert(F(f2, (c2+2)%3) == v1); + assert(F(f2, (c2+1)%3) == v2); + assert( std::abs(l(f1,c1)-l(f2,c2)) < igl::EPS() ); + const Scalar e = l(f1,c1); + const Scalar a = l(f1,(c1+1)%3); + const Scalar b = l(f1,(c1+2)%3); + const Scalar c = l(f2,(c2+1)%3); + const Scalar d = l(f2,(c2+2)%3); + // tan(α/2) + const Scalar tan_a_2= tan_half_angle(a,b,e); + // tan(δ/2) + const Scalar tan_d_2 = tan_half_angle(d,e,c); + // tan((α+δ)/2) + const Scalar tan_a_d_2 = (tan_a_2 + tan_d_2)/(1.0-tan_a_2*tan_d_2); + // cos(α+δ) + const Scalar cos_a_d = + (1.0 - tan_a_d_2*tan_a_d_2)/(1.0+tan_a_d_2*tan_a_d_2); + const Scalar f = sqrt(b*b + c*c - 2.0*b*c*cos_a_d); + l(f1,0) = f; + l(f1,1) = b; + l(f1,2) = c; + l(f2,0) = f; + l(f2,1) = d; + l(f2,2) = a; + // Important to grab these indices _before_ calling flip_edges (they + // will be correct after) + const size_t e_24 = f1 + ((c1 + 1) % 3) * num_faces; + const size_t e_41 = f1 + ((c1 + 2) % 3) * num_faces; + const size_t e_13 = f2 + ((c2 + 1) % 3) * num_faces; + const size_t e_32 = f2 + ((c2 + 2) % 3) * num_faces; + const size_t ue_24 = EMAP(e_24); + const size_t ue_41 = EMAP(e_41); + const size_t ue_13 = EMAP(e_13); + const size_t ue_32 = EMAP(e_32); + flip_edge(F, E, uE, EMAP, uE2E, uei); + Q.push_back(ue_24); + Q.push_back(ue_41); + Q.push_back(ue_13); + Q.push_back(ue_32); + } + } + } +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::intrinsic_delaunay_triangulation, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::intrinsic_delaunay_triangulation, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::intrinsic_delaunay_triangulation, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, int>(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, std::vector >, std::allocator > > >&); +// generated by autoexplicit.sh +template void igl::intrinsic_delaunay_triangulation, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/intrinsic_delaunay_triangulation.h b/src/external/libigl-2.3.0/include/igl/intrinsic_delaunay_triangulation.h new file mode 100644 index 000000000..b80d539bc --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/intrinsic_delaunay_triangulation.h @@ -0,0 +1,79 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2018 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_INTRINSIC_DELAUNAY_TRIANGULATION_H +#define IGL_INTRINSIC_DELAUNAY_TRIANGULATION_H +#include "igl_inline.h" +#include +#include +namespace igl +{ + // INTRINSIC_DELAUNAY_TRIANGULATION Flip edges _intrinsically_ until all are + // "intrinsic Delaunay". See "An algorithm for the construction of intrinsic + // delaunay triangulations with applications to digital geometry processing" + // [Fisher et al. 2007]. + // + // Inputs: + // l_in #F_in by 3 list of edge lengths (see edge_lengths) + // F_in #F_in by 3 list of face indices into some unspecified vertex list V + // Outputs: + // l #F by 3 list of edge lengths + // F #F by 3 list of new face indices. Note: Combinatorially F may contain + // non-manifold edges, duplicate faces and self-loops (e.g., an edge [1,1] + // or a face [1,1,1]). However, the *intrinsic geometry* is still + // well-defined and correct. See [Fisher et al. 2007] Figure 3 and 2nd to + // last paragraph of 1st page. Since F may be "non-eddge-manifold" in the + // usual combinatorial sense, it may be useful to call the more verbose + // overload below if disentangling edges will be necessary later on. + // Calling unique_edge_map on this F will give a _different_ result than + // those outputs. + // + // See also: is_intrinsic_delaunay + template < + typename Derivedl_in, + typename DerivedF_in, + typename Derivedl, + typename DerivedF> + IGL_INLINE void intrinsic_delaunay_triangulation( + const Eigen::MatrixBase & l_in, + const Eigen::MatrixBase & F_in, + Eigen::PlainObjectBase & l, + Eigen::PlainObjectBase & F); + // Outputs: + // E #F*3 by 2 list of all directed edges, such that E.row(f+#F*c) is the + // edge opposite F(f,c) + // uE #uE by 2 list of unique undirected edges + // EMAP #F*3 list of indices into uE, mapping each directed edge to unique + // undirected edge + // uE2E #uE list of lists of indices into E of coexisting edges + // + // See also: unique_edge_map + template < + typename Derivedl_in, + typename DerivedF_in, + typename Derivedl, + typename DerivedF, + typename DerivedE, + typename DeriveduE, + typename DerivedEMAP, + typename uE2EType> + IGL_INLINE void intrinsic_delaunay_triangulation( + const Eigen::MatrixBase & l_in, + const Eigen::MatrixBase & F_in, + Eigen::PlainObjectBase & l, + Eigen::PlainObjectBase & F, + Eigen::PlainObjectBase & E, + Eigen::PlainObjectBase & uE, + Eigen::PlainObjectBase & EMAP, + std::vector > & uE2E); +} + +#ifndef IGL_STATIC_LIBRARY +# include "intrinsic_delaunay_triangulation.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/invert_diag.cpp b/src/external/libigl-2.3.0/include/igl/invert_diag.cpp new file mode 100644 index 000000000..6be06786a --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/invert_diag.cpp @@ -0,0 +1,50 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "invert_diag.h" + +template +IGL_INLINE void igl::invert_diag( + const Eigen::SparseCompressedBase& X, + MatY& Y) +{ + typedef typename DerivedX::Scalar Scalar; +#ifndef NDEBUG + Eigen::SparseMatrix tmp = X; + Eigen::SparseVector dX = tmp.diagonal().sparseView(); + // Check that there are no zeros along the diagonal + assert(dX.nonZeros() == dX.size()); +#endif + // http://www.alecjacobson.com/weblog/?p=2552 + + + if((void *)&Y != (void *)&X) + { + Y = X; + } + // Iterate over outside + for(int k=0; k, Eigen::SparseMatrix >(Eigen::SparseCompressedBase> const&, Eigen::SparseMatrix&); +template void igl::invert_diag, Eigen::SparseMatrix >(Eigen::SparseCompressedBase> const&, Eigen::SparseMatrix&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/invert_diag.h b/src/external/libigl-2.3.0/include/igl/invert_diag.h new file mode 100644 index 000000000..4dd5b7389 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/invert_diag.h @@ -0,0 +1,36 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_INVERT_DIAG_H +#define IGL_INVERT_DIAG_H +#include "igl_inline.h" +#define EIGEN_YES_I_KNOW_SPARSE_MODULE_IS_NOT_STABLE_YET +#include + +namespace igl +{ + // Invert the diagonal entries of a matrix (if the matrix is a diagonal + // matrix then this amounts to inverting the matrix) + + // Templates: + // T should be a eigen sparse matrix primitive type like int or double + // Inputs: + // X an m by n sparse matrix + // Outputs: + // Y an m by n sparse matrix + template + IGL_INLINE void invert_diag( + const Eigen::SparseCompressedBase& X, + MatY& Y); +} + +#ifndef IGL_STATIC_LIBRARY +# include "invert_diag.cpp" +#endif + +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/is_border_vertex.cpp b/src/external/libigl-2.3.0/include/igl/is_border_vertex.cpp new file mode 100644 index 000000000..2bd4c60f6 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/is_border_vertex.cpp @@ -0,0 +1,37 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "is_border_vertex.h" +#include + +#include "triangle_triangle_adjacency.h" + +template +IGL_INLINE std::vector igl::is_border_vertex( + const Eigen::MatrixBase &F) +{ + Eigen::Matrix FF; + igl::triangle_triangle_adjacency(F,FF); + std::vector ret(F.maxCoeff()+1); + for(unsigned i=0; i > igl::is_border_vertex >(Eigen::MatrixBase > const&); +template std::vector > igl::is_border_vertex >(Eigen::MatrixBase > const&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/is_border_vertex.h b/src/external/libigl-2.3.0/include/igl/is_border_vertex.h new file mode 100644 index 000000000..87c6e992d --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/is_border_vertex.h @@ -0,0 +1,36 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_IS_BORDER_VERTEX_H +#define IGL_IS_BORDER_VERTEX_H +#include "igl_inline.h" +#include "deprecated.h" +#include +#include + +namespace igl +{ + // Determine vertices on open boundary of a (manifold) mesh with triangle + // faces F + // + // Inputs: + // V #V by dim list of vertex positions + // F #F by 3 list of triangle indices + // Returns #V vector of bools revealing whether vertices are on boundary + // + // Known Bugs: - assumes mesh is edge manifold + // + template + IGL_INLINE std::vector is_border_vertex( + const Eigen::MatrixBase &F); +} + +#ifndef IGL_STATIC_LIBRARY +# include "is_border_vertex.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/is_boundary_edge.cpp b/src/external/libigl-2.3.0/include/igl/is_boundary_edge.cpp new file mode 100644 index 000000000..679214bbc --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/is_boundary_edge.cpp @@ -0,0 +1,122 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "is_boundary_edge.h" +#include "unique_rows.h" +#include "sort.h" + +template < + typename DerivedF, + typename DerivedE, + typename DerivedB> +void igl::is_boundary_edge( + const Eigen::PlainObjectBase & E, + const Eigen::PlainObjectBase & F, + Eigen::PlainObjectBase & B) +{ + using namespace Eigen; + using namespace std; + // Should be triangles + assert(F.cols() == 3); + // Should be edges + assert(E.cols() == 2); + // number of faces + const int m = F.rows(); + // Collect all directed edges after E + MatrixXi EallE(E.rows()+3*m,2); + EallE.block(0,0,E.rows(),E.cols()) = E; + for(int e = 0;e<3;e++) + { + for(int f = 0;f +void igl::is_boundary_edge( + const Eigen::PlainObjectBase & F, + Eigen::PlainObjectBase & B, + Eigen::PlainObjectBase & E, + Eigen::PlainObjectBase & EMAP) +{ + using namespace Eigen; + using namespace std; + // Should be triangles + assert(F.cols() == 3); + // number of faces + const int m = F.rows(); + // Collect all directed edges after E + MatrixXi allE(3*m,2); + for(int e = 0;e<3;e++) + { + for(int f = 0;f, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&); +template void igl::is_boundary_edge, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&); +template void igl::is_boundary_edge, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&); +template void igl::is_boundary_edge, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::is_boundary_edge, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::is_boundary_edge, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/is_boundary_edge.h b/src/external/libigl-2.3.0/include/igl/is_boundary_edge.h new file mode 100644 index 000000000..f68ebb7e4 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/is_boundary_edge.h @@ -0,0 +1,51 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IS_BOUNDARY_EDGE_H +#define IS_BOUNDARY_EDGE_H +#include + +namespace igl +{ + // IS_BOUNDARY_EDGE Determine for each edge E if it is a "boundary edge" in F. + // Boundary edges are undirected edges which occur only once. + // + // Inputs: + // E #E by 2 list of edges + // F #F by 3 list of triangles + // Outputs: + // B #E list bools. true iff unoriented edge occurs exactly once in F + // (non-manifold and non-existant edges will be false) + // + template < + typename DerivedF, + typename DerivedE, + typename DerivedB> + void is_boundary_edge( + const Eigen::PlainObjectBase & E, + const Eigen::PlainObjectBase & F, + Eigen::PlainObjectBase & B); + // Wrapper where Edges should also be computed from F + // E #E by 2 list of edges + // EMAP #F*3 list of indices mapping allE to E + template < + typename DerivedF, + typename DerivedE, + typename DerivedB, + typename DerivedEMAP> + void is_boundary_edge( + const Eigen::PlainObjectBase & F, + Eigen::PlainObjectBase & B, + Eigen::PlainObjectBase & E, + Eigen::PlainObjectBase & EMAP); +} + +#ifndef IGL_STATIC_LIBRARY +# include "is_boundary_edge.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/is_delaunay.cpp b/src/external/libigl-2.3.0/include/igl/is_delaunay.cpp new file mode 100644 index 000000000..7628336a2 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/is_delaunay.cpp @@ -0,0 +1,108 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2018 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "is_delaunay.h" +#include "unique_edge_map.h" +#include + +template < + typename DerivedV, + typename DerivedF, + typename DerivedD> +IGL_INLINE void igl::is_delaunay( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + Eigen::PlainObjectBase & D) +{ + typedef typename DerivedV::Scalar Scalar; + // Should use Shewchuk's predicates instead. + const auto float_incircle = []( + const Scalar pa[2], + const Scalar pb[2], + const Scalar pc[2], + const Scalar pd[2])->short + { + // I acknowledge that I am cating to double + const Eigen::Matrix3d A = (Eigen::Matrix3d(3,3)<< + pa[0]-pd[0], pa[1]-pd[1],(pa[0]-pd[0])*(pa[0]-pd[0])+(pa[1]-pd[1])*(pa[1]-pd[1]), + pb[0]-pd[0], pb[1]-pd[1],(pb[0]-pd[0])*(pb[0]-pd[0])+(pb[1]-pd[1])*(pb[1]-pd[1]), + pc[0]-pd[0], pc[1]-pd[1],(pc[0]-pd[0])*(pc[0]-pd[0])+(pc[1]-pd[1])*(pc[1]-pd[1]) + ).finished(); + const Scalar detA = A.determinant(); + return (Scalar(0) < detA) - (detA < Scalar(0)); + }; + + typedef Eigen::Matrix MatrixX2I; + typedef Eigen::Matrix VectorXI; + MatrixX2I E,uE; + VectorXI EMAP; + std::vector > uE2E; + igl::unique_edge_map(F, E, uE, EMAP, uE2E); + const int num_faces = F.rows(); + D.setConstant(F.rows(),F.cols(),false); + // loop over all unique edges + for(int ue = 0;ue < uE2E.size(); ue++) + { + const bool ue_is_d = is_delaunay(V,F,uE2E,float_incircle,ue); + // Set for all instances + for(int e = 0;e +IGL_INLINE bool igl::is_delaunay( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const std::vector > & uE2E, + const InCircle incircle, + const ueiType uei) +{ + if(uE2E[uei].size() == 1) return true; + if(uE2E[uei].size() > 2) return false; + const int num_faces = F.rows(); + typedef typename DerivedV::Scalar Scalar; + const auto& half_edges = uE2E[uei]; + assert((half_edges.size() == 2) && "uE2E[uei].size() should be 2"); + const size_t f1 = half_edges[0] % num_faces; + const size_t f2 = half_edges[1] % num_faces; + const size_t c1 = half_edges[0] / num_faces; + const size_t c2 = half_edges[1] / num_faces; + assert(c1 < 3); + assert(c2 < 3); + assert(f1 != f2); + const size_t v1 = F(f1, (c1+1)%3); + const size_t v2 = F(f1, (c1+2)%3); + const size_t v4 = F(f1, c1); + const size_t v3 = F(f2, c2); + const Scalar p1[] = {V(v1, 0), V(v1, 1)}; + const Scalar p2[] = {V(v2, 0), V(v2, 1)}; + const Scalar p3[] = {V(v3, 0), V(v3, 1)}; + const Scalar p4[] = {V(v4, 0), V(v4, 1)}; + auto orientation = incircle(p1, p2, p4, p3); + return orientation <= 0; +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::is_delaunay, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::is_delaunay, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template bool igl::is_delaunay, Eigen::Matrix, int, short (*)(double const*, double const*, double const*, double const*), unsigned long>(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, std::vector >, std::allocator > > > const&, short (*)(double const*, double const*, double const*, double const*), unsigned long); +#ifdef WIN32 +template bool igl::is_delaunay, class Eigen::Matrix, int, short(*)(double const *, double const *, double const *, double const *), unsigned __int64>(class Eigen::MatrixBase> const &, class Eigen::MatrixBase> const &, class std::vector>, class std::allocator>>> const &, short(*const)(double const *, double const *, double const *, double const *), unsigned __int64); +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/is_delaunay.h b/src/external/libigl-2.3.0/include/igl/is_delaunay.h new file mode 100644 index 000000000..e6aa5bb18 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/is_delaunay.h @@ -0,0 +1,64 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2018 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_IS_DELAUNAY_H +#define IGL_IS_DELAUNAY_H +#include "igl_inline.h" +#include +#include +namespace igl +{ + // IS_DELAUNAY Determine if each edge in the mesh (V,F) is Delaunay. + // + // Inputs: + // V #V by dim list of vertex positions + // F #F by 3 list of triangles indices + // Outputs: + // D #F by 3 list of bools revealing whether edges corresponding 23 31 12 + // are locally Delaunay. Boundary edges are by definition Delaunay. + // Non-Manifold edges are by definition not Delaunay. + template < + typename DerivedV, + typename DerivedF, + typename DerivedD> + IGL_INLINE void is_delaunay( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + Eigen::PlainObjectBase & D); + // Determine whether a single edge is Delaunay using a provided (extrinsic) incirle + // test. + // + // Inputs: + // V #V by dim list of vertex positions + // F #F by 3 list of triangles indices + // uE2E #uE list of lists of indices into E of coexisting edges (see + // unique_edge_map) + // incircle A functor such that incircle(pa, pb, pc, pd) returns + // 1 if pd is on the positive size of circumcirle of (pa,pb,pc) + // -1 if pd is on the positive size of circumcirle of (pa,pb,pc) + // 0 if pd is cocircular with pa, pb, pc. + // (see delaunay_triangulation) + // uei index into uE2E of edge to check + // Returns true iff edge is Delaunay + template < + typename DerivedV, + typename DerivedF, + typename uE2EType, + typename InCircle, + typename ueiType> + IGL_INLINE bool is_delaunay( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const std::vector > & uE2E, + const InCircle incircle, + const ueiType uei); + +} +#ifndef IGL_STATIC_LIBRARY +#include "is_delaunay.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/is_dir.cpp b/src/external/libigl-2.3.0/include/igl/is_dir.cpp new file mode 100644 index 000000000..e025ec78b --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/is_dir.cpp @@ -0,0 +1,30 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "is_dir.h" + +#include + +#ifndef S_ISDIR +#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR) +#endif + +#ifndef S_ISREG +#define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG) +#endif + +IGL_INLINE bool igl::is_dir(const char * filename) +{ + struct stat status; + if(stat(filename,&status)!=0) + { + // path does not exist + return false; + } + // Tests whether existing path is a directory + return S_ISDIR(status.st_mode); +} diff --git a/src/external/libigl-2.3.0/include/igl/is_dir.h b/src/external/libigl-2.3.0/include/igl/is_dir.h new file mode 100644 index 000000000..68e30a564 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/is_dir.h @@ -0,0 +1,29 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_IS_DIR_H +#define IGL_IS_DIR_H +#include "igl_inline.h" +namespace igl +{ + // Act like php's is_dir function + // http://php.net/manual/en/function.is-dir.php + // Tells whether the given filename is a directory. + // Input: + // filename Path to the file. If filename is a relative filename, it will + // be checked relative to the current working directory. + // Returns TRUE if the filename exists and is a directory, FALSE + // otherwise. + IGL_INLINE bool is_dir(const char * filename); + +} + +#ifndef IGL_STATIC_LIBRARY +# include "is_dir.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/is_edge_manifold.cpp b/src/external/libigl-2.3.0/include/igl/is_edge_manifold.cpp new file mode 100644 index 000000000..f0d5fa36a --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/is_edge_manifold.cpp @@ -0,0 +1,84 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "is_edge_manifold.h" +#include "oriented_facets.h" +#include "unique_simplices.h" +#include "unique_edge_map.h" + +#include +#include + +template < + typename DerivedF, + typename DerivedEMAP, + typename DerivedBF, + typename DerivedBE> +IGL_INLINE bool igl::is_edge_manifold( + const Eigen::MatrixBase& F, + const typename DerivedF::Index ne, + const Eigen::MatrixBase& EMAP, + Eigen::PlainObjectBase& BF, + Eigen::PlainObjectBase& BE) +{ + typedef typename DerivedF::Index Index; + std::vector count(ne,0); + for(Index e = 0;e +IGL_INLINE bool igl::is_edge_manifold( + const Eigen::MatrixBase& F, + Eigen::PlainObjectBase& BF, + Eigen::PlainObjectBase& E, + Eigen::PlainObjectBase& EMAP, + Eigen::PlainObjectBase& BE) +{ + using namespace Eigen; + typedef Matrix MatrixXF2; + MatrixXF2 allE; + unique_edge_map(F,allE,E,EMAP); + return is_edge_manifold(F,E.rows(),EMAP,BF,BE); +} + +template +IGL_INLINE bool igl::is_edge_manifold( + const Eigen::MatrixBase& F) +{ + Eigen::Array BF; + Eigen::Array BE; + Eigen::MatrixXi E; + Eigen::VectorXi EMAP; + return is_edge_manifold(F,BF,E,EMAP,BE); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +template bool igl::is_edge_manifold >(Eigen::MatrixBase > const&); +template bool igl::is_edge_manifold >(Eigen::MatrixBase > const&); +template bool igl::is_edge_manifold >(Eigen::MatrixBase > const&); +template bool igl::is_edge_manifold, Eigen::Matrix, Eigen::Array, Eigen::Array >(Eigen::MatrixBase > const&, Eigen::Matrix::Index, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/is_edge_manifold.h b/src/external/libigl-2.3.0/include/igl/is_edge_manifold.h new file mode 100644 index 000000000..3ed18ceb2 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/is_edge_manifold.h @@ -0,0 +1,72 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_IS_EDGE_MANIFOLD_H +#define IGL_IS_EDGE_MANIFOLD_H +#include "igl_inline.h" + +#include + +namespace igl +{ + // check if the mesh is edge-manifold (every edge is incident one one face + // (boundary) or two oppositely oriented faces). + // + // Inputs: + // F #F by 3 list of triangle indices + // Returns true iff all edges are manifold + // + // See also: is_vertex_manifold + template + IGL_INLINE bool is_edge_manifold( + const Eigen::MatrixBase& F); + // Inputs: + // F #F by 3 list of triangle indices + // Outputs: + // BF #F by 3 list of flags revealing if edge opposite corresponding vertex + // is non-manifold. + // E #E by 2 list of unique edges + // EMAP 3*#F list of indices of opposite edges in "E" + // BE #E list of flages whether edge is non-manifold + template < + typename DerivedF, + typename DerivedBF, + typename DerivedE, + typename DerivedEMAP, + typename DerivedBE> + IGL_INLINE bool is_edge_manifold( + const Eigen::MatrixBase& F, + Eigen::PlainObjectBase& BF, + Eigen::PlainObjectBase& E, + Eigen::PlainObjectBase& EMAP, + Eigen::PlainObjectBase& BE); + // Inputs: + // F #F by 3 list of triangle indices + // ne number of edges (#E) + // EMAP 3*#F list of indices of opposite edges in "E" + // Outputs: + // BF #F by 3 list of flags revealing if edge opposite corresponding vertex + // is non-manifold. + // BE ne list of flages whether edge is non-manifold + template < + typename DerivedF, + typename DerivedEMAP, + typename DerivedBF, + typename DerivedBE> + IGL_INLINE bool is_edge_manifold( + const Eigen::MatrixBase& F, + const typename DerivedF::Index ne, + const Eigen::MatrixBase& EMAP, + Eigen::PlainObjectBase& BF, + Eigen::PlainObjectBase& BE); +} + +#ifndef IGL_STATIC_LIBRARY +# include "is_edge_manifold.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/is_file.cpp b/src/external/libigl-2.3.0/include/igl/is_file.cpp new file mode 100644 index 000000000..7d0670303 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/is_file.cpp @@ -0,0 +1,26 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "is_file.h" + +#include +#ifdef _WIN32 +# ifndef S_ISREG +# define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG) +# endif +#endif +IGL_INLINE bool igl::is_file(const char * filename) +{ + struct stat status; + if(stat(filename,&status)!=0) + { + // path does not exist + return false; + } + // Tests whether existing path is a regular file + return S_ISREG(status.st_mode); +} diff --git a/src/external/libigl-2.3.0/include/igl/is_file.h b/src/external/libigl-2.3.0/include/igl/is_file.h new file mode 100644 index 000000000..5610c7ff3 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/is_file.h @@ -0,0 +1,29 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_IS_FILE_H +#define IGL_IS_FILE_H +#include "igl_inline.h" +namespace igl +{ + // Act like php's is_file function + // http://php.net/manual/en/function.is-file.php + // Tells whether the given filename is a regular file. + // Input: + // filename Path to the file. If filename is a relative filename, it will + // be checked relative to the current working directory. + // Returns TRUE if the filename exists and is a regular file, FALSE + // otherwise. + IGL_INLINE bool is_file(const char * filename); + +} + +#ifndef IGL_STATIC_LIBRARY +# include "is_file.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/is_intrinsic_delaunay.cpp b/src/external/libigl-2.3.0/include/igl/is_intrinsic_delaunay.cpp new file mode 100644 index 000000000..84afd2996 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/is_intrinsic_delaunay.cpp @@ -0,0 +1,146 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2018 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "is_intrinsic_delaunay.h" +#include "unique_edge_map.h" +#include "tan_half_angle.h" +#include "EPS.h" +#include "cotmatrix_entries.h" +#include +#include +template < + typename Derivedl, + typename DerivedF, + typename DerivedD> +IGL_INLINE void igl::is_intrinsic_delaunay( + const Eigen::MatrixBase & l, + const Eigen::MatrixBase & F, + Eigen::PlainObjectBase & D) +{ + typedef Eigen::Matrix MatrixX2I; + typedef Eigen::Matrix VectorXI; + MatrixX2I E,uE; + VectorXI EMAP; + std::vector > uE2E; + igl::unique_edge_map(F, E, uE, EMAP, uE2E); + return is_intrinsic_delaunay(l,F,uE2E,D); +} + +template < + typename Derivedl, + typename DerivedF, + typename uE2EType, + typename DerivedD> +IGL_INLINE void igl::is_intrinsic_delaunay( + const Eigen::MatrixBase & l, + const Eigen::MatrixBase & F, + const std::vector > & uE2E, + Eigen::PlainObjectBase & D) +{ + const int num_faces = F.rows(); + D.setConstant(F.rows(),F.cols(),false); + // loop over all unique edges + for(int ue = 0;ue < uE2E.size(); ue++) + { + const bool ue_is_d = is_intrinsic_delaunay(l,uE2E,num_faces,ue); + // Set for all instances + for(int e = 0;e +IGL_INLINE bool igl::is_intrinsic_delaunay( + const Eigen::MatrixBase & l, + const std::vector > & uE2E, + const Index num_faces, + const Index uei) +{ + if(uE2E[uei].size() == 1) return true; + if(uE2E[uei].size() > 2) return false; + typedef typename Derivedl::Scalar Scalar; + + const auto cot_alpha = []( + const Scalar & a, + const Scalar & b, + const Scalar & c)->Scalar + { + // Fisher 2007 + const Scalar t = tan_half_angle(a,b,c); + return (1.0-t*t)/(2*t); + }; + + // 2 // + // /|\ // + // a/ | \d // + // / e \ // + // / | \ // + //0.α---|-f-β.3 // + // \ | / // + // \ | / // + // b\ | /c // + // \|/ // + // . // + // 1 + + // Fisher 2007 + assert(uE2E[uei].size() == 2 && "edge should have 2 incident faces"); + const Index he1 = uE2E[uei][0]; + const Index he2 = uE2E[uei][1]; + const Index f1 = he1%num_faces; + const Index c1 = he1/num_faces; + const Index f2 = he2%num_faces; + const Index c2 = he2/num_faces; + assert( std::abs(l(f1,c1)-l(f2,c2)) < igl::EPS()); + const Scalar e = l(f1,c1); + const Scalar a = l(f1,(c1+1)%3); + const Scalar b = l(f1,(c1+2)%3); + const Scalar c = l(f2,(c2+1)%3); + const Scalar d = l(f2,(c2+2)%3); + const Scalar w = cot_alpha(e,a,b) + cot_alpha(e,c,d); + + //// Test + //{ + // Eigen::MatrixXd l(2,3); + // l<1e-10) + // { + // std::cout<= 0; +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template bool igl::is_intrinsic_delaunay, int, int>(Eigen::MatrixBase > const&, std::vector >, std::allocator > > > const&, int, int); +// generated by autoexplicit.sh +template bool igl::is_intrinsic_delaunay, int, int>(Eigen::MatrixBase > const&, std::vector >, std::allocator > > > const&, int, int); +// generated by autoexplicit.sh +template void igl::is_intrinsic_delaunay, Eigen::Matrix, int, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, std::vector >, std::allocator > > > const&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::is_intrinsic_delaunay, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::is_intrinsic_delaunay, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/is_intrinsic_delaunay.h b/src/external/libigl-2.3.0/include/igl/is_intrinsic_delaunay.h new file mode 100644 index 000000000..ca9cc04cf --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/is_intrinsic_delaunay.h @@ -0,0 +1,69 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2018 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_IS_INTRINSIC_DELAUNAY_H +#define IGL_IS_INTRINSIC_DELAUNAY_H +#include "igl_inline.h" +#include +#include +namespace igl +{ + // IS_INTRINSIC_DELAUNAY Determine if each edge in the mesh (V,F) is Delaunay. + // + // Inputs: + // l #l by dim list of edge lengths + // F #F by 3 list of triangles indices + // Outputs: + // D #F by 3 list of bools revealing whether edges corresponding 23 31 12 + // are locally Delaunay. Boundary edges are by definition Delaunay. + // Non-Manifold edges are by definition not Delaunay. + template < + typename Derivedl, + typename DerivedF, + typename DerivedD> + IGL_INLINE void is_intrinsic_delaunay( + const Eigen::MatrixBase & l, + const Eigen::MatrixBase & F, + Eigen::PlainObjectBase & D); + // Inputs: + // uE2E #uE list of lists mapping unique edges to (half-)edges + template < + typename Derivedl, + typename DerivedF, + typename uE2EType, + typename DerivedD> + IGL_INLINE void is_intrinsic_delaunay( + const Eigen::MatrixBase & l, + const Eigen::MatrixBase & F, + const std::vector > & uE2E, + Eigen::PlainObjectBase & D); + // Determine whether a single edge is Delaunay using a provided (extrinsic) incirle + // test. + // + // Inputs: + // l #l by dim list of edge lengths + // uE2E #uE list of lists of indices into E of coexisting edges (see + // unique_edge_map) + // num_faces number of faces (==#F) + // uei index into uE2E of edge to check + // Returns true iff edge is Delaunay + template < + typename Derivedl, + typename uE2EType, + typename Index> + IGL_INLINE bool is_intrinsic_delaunay( + const Eigen::MatrixBase & l, + const std::vector > & uE2E, + const Index num_faces, + const Index uei); + +} +#ifndef IGL_STATIC_LIBRARY +#include "is_intrinsic_delaunay.cpp" +#endif +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/is_irregular_vertex.cpp b/src/external/libigl-2.3.0/include/igl/is_irregular_vertex.cpp new file mode 100644 index 000000000..edd91b057 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/is_irregular_vertex.cpp @@ -0,0 +1,44 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Daniele Panozzo +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "is_irregular_vertex.h" +#include + +#include "is_border_vertex.h" + +template +IGL_INLINE std::vector igl::is_irregular_vertex(const Eigen::MatrixBase &V, const Eigen::MatrixBase &F) +{ + Eigen::VectorXi count = Eigen::VectorXi::Zero(F.maxCoeff()+1); + + for(unsigned i=0; i border = is_border_vertex(F); + + std::vector res(count.size()); + + for (unsigned i=0; i > igl::is_irregular_vertex, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&); +template std::vector > igl::is_irregular_vertex, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/is_irregular_vertex.h b/src/external/libigl-2.3.0/include/igl/is_irregular_vertex.h new file mode 100644 index 000000000..d46fe07a9 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/is_irregular_vertex.h @@ -0,0 +1,33 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Daniele Panozzo +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_IS_IRREGULAR_VERTEX_H +#define IGL_IS_IRREGULAR_VERTEX_H +#include "igl_inline.h" + +#include +#include + +namespace igl +{ + // Determine if a vertex is irregular, i.e. it has more than 6 (triangles) + // or 4 (quads) incident edges. Vertices on the boundary are ignored. + // + // Inputs: + // V #V by dim list of vertex positions + // F #F by 3[4] list of triangle[quads] indices + // Returns #V vector of bools revealing whether vertices are singular + // + template + IGL_INLINE std::vector is_irregular_vertex(const Eigen::MatrixBase &V, const Eigen::MatrixBase &F); +} + +#ifndef IGL_STATIC_LIBRARY +# include "is_irregular_vertex.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/is_planar.cpp b/src/external/libigl-2.3.0/include/igl/is_planar.cpp new file mode 100644 index 000000000..6058a03d4 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/is_planar.cpp @@ -0,0 +1,18 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "is_planar.h" +IGL_INLINE bool igl::is_planar(const Eigen::MatrixXd & V) +{ + if(V.size() == 0) return false; + if(V.cols() == 2) return true; + for(int i = 0;i +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_IS_PLANAR_H +#define IGL_IS_PLANAR_H +#include "igl_inline.h" + +#include + +namespace igl +{ + // Determine if a set of points lies on the XY plane + // + // Inputs: + // V #V by dim list of vertex positions + // Return true if a mesh has constant value of 0 in z coordinate + // + // Known bugs: Doesn't determine if vertex is flat if it doesn't lie on the + // XY plane. + IGL_INLINE bool is_planar(const Eigen::MatrixXd & V); +} + +#ifndef IGL_STATIC_LIBRARY +# include "is_planar.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/is_readable.cpp b/src/external/libigl-2.3.0/include/igl/is_readable.cpp new file mode 100644 index 000000000..eb5e95347 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/is_readable.cpp @@ -0,0 +1,55 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "is_readable.h" + +#ifdef _WIN32 +# include +IGL_INLINE bool igl::is_readable(const char* filename) +{ + FILE * f = fopen(filename,"r"); + if(f == NULL) + { + return false; + } + fclose(f); + return true; +} +#else +# include +# include +# include +IGL_INLINE bool igl::is_readable(const char* filename) +{ + // Check if file already exists + struct stat status; + if(stat(filename,&status)!=0) + { + return false; + } + + // Get current users uid and gid + uid_t this_uid = getuid(); + gid_t this_gid = getgid(); + + // Dealing with owner + if( this_uid == status.st_uid ) + { + return S_IRUSR & status.st_mode; + } + + // Dealing with group member + if( this_gid == status.st_gid ) + { + return S_IRGRP & status.st_mode; + } + + // Dealing with other + return S_IROTH & status.st_mode; + +} +#endif diff --git a/src/external/libigl-2.3.0/include/igl/is_readable.h b/src/external/libigl-2.3.0/include/igl/is_readable.h new file mode 100644 index 000000000..689701285 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/is_readable.h @@ -0,0 +1,28 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_IS_READABLE_H +#define IGL_IS_READABLE_H +#include "igl_inline.h" +namespace igl +{ + // Check if a file is reabable like PHP's is_readable function: + // http://www.php.net/manual/en/function.is-readable.php + // Input: + // filename path to file + // Returns true if file exists and is readable and false if file doesn't + // exist or *is not readable* + // + // Note: Windows version will not check user or group ids + IGL_INLINE bool is_readable(const char * filename); +} + +#ifndef IGL_STATIC_LIBRARY +# include "is_readable.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/is_sparse.cpp b/src/external/libigl-2.3.0/include/igl/is_sparse.cpp new file mode 100644 index 000000000..507393d85 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/is_sparse.cpp @@ -0,0 +1,28 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "is_sparse.h" +template +IGL_INLINE bool igl::is_sparse( + const Eigen::SparseMatrix & A) +{ + return true; +} +template +IGL_INLINE bool igl::is_sparse( + const Eigen::PlainObjectBase& A) +{ + return false; +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template bool igl::is_sparse(Eigen::SparseMatrix const&); +// generated by autoexplicit.sh +template bool igl::is_sparse >(Eigen::PlainObjectBase > const&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/is_sparse.h b/src/external/libigl-2.3.0/include/igl/is_sparse.h new file mode 100644 index 000000000..9547bb8e8 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/is_sparse.h @@ -0,0 +1,36 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_IS_SPARSE_H +#define IGL_IS_SPARSE_H +#include "igl_inline.h" +#define EIGEN_YES_I_KNOW_SPARSE_MODULE_IS_NOT_STABLE_YET +#include +#include +namespace igl +{ + // Determine if a matrix A is sparse + // + // Template: + // T,DerivedA defines scalar type + // Inputs: + // A matrix in question + // Returns true if A is represented with a sparse matrix + template + IGL_INLINE bool is_sparse( + const Eigen::SparseMatrix & A); + template + IGL_INLINE bool is_sparse( + const Eigen::PlainObjectBase& A); +} + +#ifndef IGL_STATIC_LIBRARY +# include "is_sparse.cpp" +#endif + +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/is_stl.cpp b/src/external/libigl-2.3.0/include/igl/is_stl.cpp new file mode 100644 index 000000000..adaea0c70 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/is_stl.cpp @@ -0,0 +1,66 @@ +#include "is_stl.h" +#include +IGL_INLINE bool igl::is_stl(FILE * stl_file, bool & is_ascii) +{ + + // solid? + // YES NO + // / if .stl, definitely binary + // / + // perfect size? + // YES NO + // + const auto perfect_size = [](FILE * stl_file)->bool + { + //stl_file = freopen(NULL,"rb",stl_file); + // Read 80 header + char header[80]; + if(fread(header,sizeof(char),80,stl_file)!=80) + { + return false; + } + // Read number of triangles + unsigned int num_tri; + if(fread(&num_tri,sizeof(unsigned int),1,stl_file)!=1) + { + return false; + } + fseek(stl_file,0,SEEK_END); + int file_size = ftell(stl_file); + fseek(stl_file,0,SEEK_SET); + //stl_file = freopen(NULL,"r",stl_file); + return (file_size == 80 + 4 + (4*12 + 2) * num_tri); + }; + // Specifically 80 character header + char header[80]; + char solid[80]; + is_ascii = true; + bool f = true; + if(fread(header,1,80,stl_file) != 80) + { + f = false; + goto finish; + } + // make sure sscanf doesn't read past the end of the header, overwriting stack + header[sizeof(header)-1]='\0'; + + sscanf(header,"%s",solid); + if(std::string("solid") == solid) + { + f = true; + is_ascii = !perfect_size(stl_file); + }else + { + is_ascii = false; + f = perfect_size(stl_file); + } +finish: + rewind(stl_file); + return f; +} + +IGL_INLINE bool igl::is_stl(FILE * stl_file) +{ + bool is_ascii; + return is_stl(stl_file,is_ascii); +} diff --git a/src/external/libigl-2.3.0/include/igl/is_stl.h b/src/external/libigl-2.3.0/include/igl/is_stl.h new file mode 100644 index 000000000..e8f78df1a --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/is_stl.h @@ -0,0 +1,21 @@ +#ifndef IGL_IS_STL_H +#define IGL_IS_STL_H +#include "igl_inline.h" +#include +namespace igl +{ + // Given a file pointer, determine if it contains an .stl file and then + // rewind it. + // + // Inputs: + // stl_file pointer to file + // Outputs: + // is_ascii flag whether stl is ascii + // Returns whether stl_file is an .stl file + IGL_INLINE bool is_stl(FILE * stl_file, bool & is_ascii); + IGL_INLINE bool is_stl(FILE * stl_file); +}; +#ifndef IGL_STATIC_LIBRARY +# include "is_stl.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/is_symmetric.cpp b/src/external/libigl-2.3.0/include/igl/is_symmetric.cpp new file mode 100644 index 000000000..f40473b66 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/is_symmetric.cpp @@ -0,0 +1,73 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "is_symmetric.h" +#include "find.h" + +template +IGL_INLINE bool igl::is_symmetric(const Eigen::SparseMatrix& A) +{ + if(A.rows() != A.cols()) + { + return false; + } + assert(A.size() != 0); + Eigen::SparseMatrix AT = A.transpose(); + Eigen::SparseMatrix AmAT = A-AT; + //// Eigen screws up something with LLT if you try to do + //SparseMatrix AmAT = A-A.transpose(); + //// Eigen crashes at runtime if you try to do + // return (A-A.transpose()).nonZeros() == 0; + return AmAT.nonZeros() == 0; +} + +template +IGL_INLINE bool igl::is_symmetric( + const Eigen::PlainObjectBase& A) +{ + if(A.rows() != A.cols()) + { + return false; + } + assert(A.size() != 0); + return (A-A.transpose()).eval().nonZeros() == 0; +} + +template +IGL_INLINE bool igl::is_symmetric( + const Eigen::SparseMatrix& A, + const epsilonT epsilon) +{ + using namespace Eigen; + using namespace std; + if(A.rows() != A.cols()) + { + return false; + } + assert(A.size() != 0); + SparseMatrix AT = A.transpose(); + SparseMatrix AmAT = A-AT; + VectorXi AmATI,AmATJ; + Matrix AmATV; + find(AmAT,AmATI,AmATJ,AmATV); + if(AmATI.size() == 0) + { + return true; + } + + return AmATV.maxCoeff() < epsilon && AmATV.minCoeff() > -epsilon; +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template bool igl::is_symmetric >(Eigen::PlainObjectBase > const&); +// generated by autoexplicit.sh +template bool igl::is_symmetric(Eigen::SparseMatrix const&); +template bool igl::is_symmetric(Eigen::SparseMatrix const&, double); +template bool igl::is_symmetric(Eigen::SparseMatrix const&, int); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/is_symmetric.h b/src/external/libigl-2.3.0/include/igl/is_symmetric.h new file mode 100644 index 000000000..31725298e --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/is_symmetric.h @@ -0,0 +1,34 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_IS_SYMMETRIC_H +#define IGL_IS_SYMMETRIC_H +#include "igl_inline.h" +#define EIGEN_YES_I_KNOW_SPARSE_MODULE_IS_NOT_STABLE_YET +#include +namespace igl +{ + // Returns true if the given matrix is symmetric + // Inputs: + // A m by m matrix + // Returns true if the matrix is square and symmetric + template + IGL_INLINE bool is_symmetric(const Eigen::SparseMatrix& A); + // Inputs: + // epsilon threshold on L1 difference between A and A' + template + IGL_INLINE bool is_symmetric(const Eigen::SparseMatrix& A, const epsilonT epsilon); + template + IGL_INLINE bool is_symmetric( + const Eigen::PlainObjectBase& A); +} + +#ifndef IGL_STATIC_LIBRARY +# include "is_symmetric.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/is_vertex_manifold.cpp b/src/external/libigl-2.3.0/include/igl/is_vertex_manifold.cpp new file mode 100644 index 000000000..d266ebab7 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/is_vertex_manifold.cpp @@ -0,0 +1,101 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "is_vertex_manifold.h" +#include "triangle_triangle_adjacency.h" +#include "vertex_triangle_adjacency.h" +#include "unique.h" +#include +#include +#include +#include +#include + +template +IGL_INLINE bool igl::is_vertex_manifold( + const Eigen::PlainObjectBase& F, + Eigen::PlainObjectBase& B) +{ + using namespace std; + using namespace Eigen; + assert(F.cols() == 3 && "F must contain triangles"); + typedef typename DerivedF::Scalar Index; + typedef typename DerivedF::Index FIndex; + const FIndex m = F.rows(); + const Index n = F.maxCoeff()+1; + vector > > TT; + vector > > TTi; + triangle_triangle_adjacency(F,TT,TTi); + + vector > V2F,_1; + vertex_triangle_adjacency(n,F,V2F,_1); + + const auto & check_vertex = [&](const Index v)->bool + { + vector uV2Fv; + { + vector _1,_2; + unique(V2F[v],uV2Fv,_1,_2); + } + const FIndex one_ring_size = uV2Fv.size(); + if(one_ring_size == 0) + { + return false; + } + const FIndex g = uV2Fv[0]; + queue Q; + Q.push(g); + map seen; + while(!Q.empty()) + { + const FIndex f = Q.front(); + Q.pop(); + if(seen.count(f)==1) + { + continue; + } + seen[f] = true; + // Face f's neighbor lists opposite opposite each corner + for(const auto & c : TT[f]) + { + // Each neighbor + for(const auto & n : c) + { + bool contains_v = false; + for(Index nc = 0;nc, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&); +template bool igl::is_vertex_manifold, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/is_vertex_manifold.h b/src/external/libigl-2.3.0/include/igl/is_vertex_manifold.h new file mode 100644 index 000000000..bf9caded6 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/is_vertex_manifold.h @@ -0,0 +1,39 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_IS_VERTEX_MANIFOLD_H +#define IGL_IS_VERTEX_MANIFOLD_H +#include "igl_inline.h" + +#include + +namespace igl +{ + // Check if a mesh is vertex-manifold. This only checks whether the faces + // incident on each vertex form exactly one connected component. Vertices + // incident on non-manifold edges are not consider non-manifold by this + // function (see is_edge_manifold.h). Unreferenced verties are considered + // non-manifold (zero components). + // + // Inputs: + // F #F by 3 list of triangle indices + // Outputs: + // B #V list indicate whether each vertex is locally manifold. + // Returns whether mesh is vertex manifold. + // + // See also: is_edge_manifold + template + IGL_INLINE bool is_vertex_manifold( + const Eigen::PlainObjectBase& F, + Eigen::PlainObjectBase& B); +} + +#ifndef IGL_STATIC_LIBRARY +# include "is_vertex_manifold.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/is_writable.cpp b/src/external/libigl-2.3.0/include/igl/is_writable.cpp new file mode 100644 index 000000000..f266b0078 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/is_writable.cpp @@ -0,0 +1,58 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "is_writable.h" + +#ifdef _WIN32 +#include +#ifndef S_IWUSR +# define S_IWUSR S_IWRITE +#endif +IGL_INLINE bool is_writable(const char* filename) +{ + // Check if file already exists + struct stat status; + if(stat(filename,&status)!=0) + { + return false; + } + + return S_IWUSR & status.st_mode; +} +#else +#include +#include + +IGL_INLINE bool igl::is_writable(const char* filename) +{ + // Check if file already exists + struct stat status; + if(stat(filename,&status)!=0) + { + return false; + } + + // Get current users uid and gid + uid_t this_uid = getuid(); + gid_t this_gid = getgid(); + + // Dealing with owner + if( this_uid == status.st_uid ) + { + return S_IWUSR & status.st_mode; + } + + // Dealing with group member + if( this_gid == status.st_gid ) + { + return S_IWGRP & status.st_mode; + } + + // Dealing with other + return S_IWOTH & status.st_mode; +} +#endif diff --git a/src/external/libigl-2.3.0/include/igl/is_writable.h b/src/external/libigl-2.3.0/include/igl/is_writable.h new file mode 100644 index 000000000..8834e8afb --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/is_writable.h @@ -0,0 +1,28 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_IS_WRITABLE_H +#define IGL_IS_WRITABLE_H +#include "igl_inline.h" +namespace igl +{ + // Check if a file exists *and* is writable like PHP's is_writable function: + // http://www.php.net/manual/en/function.is-writable.php + // Input: + // filename path to file + // Returns true if file exists and is writable and false if file doesn't + // exist or *is not writable* + // + // Note: Windows version will not test group and user id + IGL_INLINE bool is_writable(const char * filename); +} + +#ifndef IGL_STATIC_LIBRARY +# include "is_writable.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/isdiag.cpp b/src/external/libigl-2.3.0/include/igl/isdiag.cpp new file mode 100644 index 000000000..b7e343ee6 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/isdiag.cpp @@ -0,0 +1,32 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "isdiag.h" + +template +IGL_INLINE bool igl::isdiag(const Eigen::SparseCompressedBase & A) +{ + // Iterate over outside of A + for(int k=0; k>(Eigen::SparseCompressedBase> const &); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/isdiag.h b/src/external/libigl-2.3.0/include/igl/isdiag.h new file mode 100644 index 000000000..48b359245 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/isdiag.h @@ -0,0 +1,26 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_ISDIAG_H +#define IGL_ISDIAG_H +#include "igl_inline.h" +#include +namespace igl +{ + // Determine if a given matrix is diagonal: all non-zeros lie on the + // main diagonal. + // + // Inputs: + // A m by n sparse matrix + // Returns true iff and only if the matrix is diagonal. + template + IGL_INLINE bool isdiag(const Eigen::SparseCompressedBase & A); +}; +#ifndef IGL_STATIC_LIBRARY +# include "isdiag.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/ismember.cpp b/src/external/libigl-2.3.0/include/igl/ismember.cpp new file mode 100644 index 000000000..e3c3fd492 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/ismember.cpp @@ -0,0 +1,185 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "ismember.h" +#include "colon.h" +#include "list_to_matrix.h" +#include "sort.h" +#include "sortrows.h" +#include "unique.h" +#include "unique_rows.h" +#include + +template < + typename DerivedA, + typename DerivedB, + typename DerivedIA, + typename DerivedLOCB> +IGL_INLINE void igl::ismember( + const Eigen::MatrixBase & A, + const Eigen::MatrixBase & B, + Eigen::PlainObjectBase & IA, + Eigen::PlainObjectBase & LOCB) +{ + using namespace Eigen; + using namespace std; + IA.resizeLike(A); + IA.setConstant(false); + LOCB.resizeLike(A); + LOCB.setConstant(-1); + // boring base cases + if(A.size() == 0) + { + return; + } + if(B.size() == 0) + { + return; + } + + // Get rid of any duplicates + typedef Matrix VectorA; + typedef Matrix VectorB; + const VectorA vA(Eigen::Map(DerivedA(A).data(), A.cols()*A.rows(),1)); + const VectorB vB(Eigen::Map(DerivedB(B).data(), B.cols()*B.rows(),1)); + VectorA uA; + VectorB uB; + Eigen::Matrix uIA,uIuA,uIB,uIuB; + unique(vA,uA,uIA,uIuA); + unique(vB,uB,uIB,uIuB); + // Sort both + VectorA sA; + VectorB sB; + Eigen::Matrix sIA,sIB; + sort(uA,1,true,sA,sIA); + sort(uB,1,true,sB,sIB); + + Eigen::Matrix uF = + Eigen::Matrix::Zero(sA.size(),1); + Eigen::Matrix uLOCB = + Eigen::Matrix:: + Constant(sA.size(),1,-1); + { + int bi = 0; + // loop over sA + bool past = false; + for(int a = 0;asB(bi)) + { + bi++; + past = bi>=sB.size(); + } + if(!past && sA(a)==sB(bi)) + { + uF(sIA(a)) = true; + uLOCB(sIA(a)) = uIB(sIB(bi)); + } + } + } + + Map< Matrix > + vIA(IA.data(),IA.cols()*IA.rows(),1); + Map< Matrix > + vLOCB(LOCB.data(),LOCB.cols()*LOCB.rows(),1); + for(int a = 0;a +IGL_INLINE void igl::ismember_rows( + const Eigen::MatrixBase & A, + const Eigen::MatrixBase & B, + Eigen::PlainObjectBase & IA, + Eigen::PlainObjectBase & LOCB) +{ + using namespace Eigen; + using namespace std; + assert(A.cols() == B.cols() && "number of columns must match"); + IA.resize(A.rows(),1); + IA.setConstant(false); + LOCB.resize(A.rows(),1); + LOCB.setConstant(-1); + // boring base cases + if(A.size() == 0) + { + return; + } + if(B.size() == 0) + { + return; + } + + // Get rid of any duplicates + DerivedA uA; + DerivedB uB; + Eigen::Matrix uIA,uIuA,uIB,uIuB; + unique_rows(A,uA,uIA,uIuA); + unique_rows(B,uB,uIB,uIuB); + // Sort both + DerivedA sA; + DerivedB sB; + Eigen::Matrix sIA,sIB; + sortrows(uA,true,sA,sIA); + sortrows(uB,true,sB,sIB); + + Eigen::Matrix uF = + Eigen::Matrix::Zero(sA.size(),1); + Eigen::Matrix uLOCB = + Eigen::Matrix:: + Constant(sA.size(),1,-1); + const auto & row_greater_than = [&sA,&sB](const int a, const int b) + { + for(int c = 0;c sB(b,c)) return true; + if(sA(a,c) < sB(b,c)) return false; + } + return false; + }; + { + int bi = 0; + // loop over sA + bool past = false; + for(int a = 0;a=sB.rows(); + } + if(!past && (sA.row(a).array()==sB.row(bi).array()).all() ) + { + uF(sIA(a)) = true; + uLOCB(sIA(a)) = uIB(sIB(bi)); + } + } + } + + for(int a = 0;a, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::ismember_rows, Eigen::Matrix, Eigen::Array, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::ismember_rows, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::ismember_rows, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::ismember_rows, Eigen::Matrix, Eigen::Array, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/ismember.h b/src/external/libigl-2.3.0/include/igl/ismember.h new file mode 100644 index 000000000..72be6006d --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/ismember.h @@ -0,0 +1,52 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_ISMEMBER_H +#define IGL_ISMEMBER_H +#include "igl_inline.h" +#include +namespace igl +{ + // Determine if elements of A exist in elements of B + // + // Inputs: + // A ma by na matrix + // B mb by nb matrix + // Outputs: + // IA ma by na matrix of flags whether corresponding element of A exists in + // B + // LOCB ma by na matrix of indices in B locating matching element (-1 if + // not found), indices assume column major ordering + // + template < + typename DerivedA, + typename DerivedB, + typename DerivedIA, + typename DerivedLOCB> + IGL_INLINE void ismember( + const Eigen::MatrixBase & A, + const Eigen::MatrixBase & B, + Eigen::PlainObjectBase & IA, + Eigen::PlainObjectBase & LOCB); + template < + typename DerivedA, + typename DerivedB, + typename DerivedIA, + typename DerivedLOCB> + IGL_INLINE void ismember_rows( + const Eigen::MatrixBase & A, + const Eigen::MatrixBase & B, + Eigen::PlainObjectBase & IA, + Eigen::PlainObjectBase & LOCB); + +} + +#ifndef IGL_STATIC_LIBRARY +# include "ismember.cpp" +#endif +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/isolines.cpp b/src/external/libigl-2.3.0/include/igl/isolines.cpp new file mode 100644 index 000000000..e2fd69873 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/isolines.cpp @@ -0,0 +1,116 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2017 Oded Stein +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + + +#include "isolines.h" + +#include +#include +#include + +#include "remove_duplicate_vertices.h" + + +template +IGL_INLINE void igl::isolines( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + const Eigen::MatrixBase& z, + const int n, + Eigen::PlainObjectBase& isoV, + Eigen::PlainObjectBase& isoE) +{ + //Constants + const int dim = V.cols(); + assert(dim==2 || dim==3); + const int nVerts = V.rows(); + assert(z.rows() == nVerts && + "There must be as many function entries as vertices"); + const int nFaces = F.rows(); + const int np1 = n+1; + const double min = z.minCoeff(), max = z.maxCoeff(); + + + //Following http://www.alecjacobson.com/weblog/?p=2529 + typedef typename DerivedZ::Scalar Scalar; + typedef Eigen::Matrix Vec; + Vec iso(np1); + for(int i=0; i Matrix; + std::array t{{Matrix(nFaces, np1), + Matrix(nFaces, np1), Matrix(nFaces, np1)}}; + for(int i=0; i1) + t[k](i,j) = std::numeric_limits::quiet_NaN(); + } + } + } + + std::array,3> Fij, Iij; + for(int i=0; i LIVec; + typedef Eigen::Matrix LMat; + typedef Eigen::Matrix LIMat; + LIVec dummy1, dummy2; + igl::remove_duplicate_vertices(LMat(isoV), LIMat(isoE), + 2.2204e-15, isoV, dummy1, dummy2, isoE); + +} + + + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +template void igl::isolines, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, int const, Eigen::PlainObjectBase > &, Eigen::PlainObjectBase > &); +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/isolines.h b/src/external/libigl-2.3.0/include/igl/isolines.h new file mode 100644 index 000000000..3b5199b6a --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/isolines.h @@ -0,0 +1,52 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2017 Oded Stein +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + + +#ifndef IGL_ISOLINES_H +#define IGL_ISOLINES_H +#include "igl_inline.h" + +#include +#include + + +namespace igl +{ + // Constructs isolines for a function z given on a mesh (V,F) + // + // + // Inputs: + // V #V by dim list of mesh vertex positions + // F #F by 3 list of mesh faces (must be triangles) + // z #V by 1 list of function values evaluated at vertices + // n the number of desired isolines + // Outputs: + // isoV #isoV by dim list of isoline vertex positions + // isoE #isoE by 2 list of isoline edge positions + // + // + + template + IGL_INLINE void isolines( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + const Eigen::MatrixBase& z, + const int n, + Eigen::PlainObjectBase& isoV, + Eigen::PlainObjectBase& isoE); +} + +#ifndef IGL_STATIC_LIBRARY +# include "isolines.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/isolines_map.cpp b/src/external/libigl-2.3.0/include/igl/isolines_map.cpp new file mode 100644 index 000000000..a14cf361f --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/isolines_map.cpp @@ -0,0 +1,52 @@ +#include "isolines_map.h" +#include + +template < + typename DerivedCM, + typename Derivediso_color, + typename DerivedICM + > +IGL_INLINE void igl::isolines_map( + const Eigen::MatrixBase & CM, + const Eigen::MatrixBase & iso_color, + const int interval_thickness, + const int iso_thickness, + Eigen::PlainObjectBase & ICM) +{ + ICM.resize(CM.rows()*interval_thickness+(CM.rows()-1)*iso_thickness,3); + { + int k = 0; + for(int c = 0;c +IGL_INLINE void igl::isolines_map( + const Eigen::MatrixBase & CM, + Eigen::PlainObjectBase & ICM) +{ + return isolines_map( + CM, Eigen::Matrix(0,0,0), 10, 1, ICM); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +template void igl::isolines_map, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/isolines_map.h b/src/external/libigl-2.3.0/include/igl/isolines_map.h new file mode 100644 index 000000000..2b6f1ac7c --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/isolines_map.h @@ -0,0 +1,41 @@ +#ifndef IGL_ISOLINES_MAP_H +#define IGL_ISOLINES_MAP_H +#include "igl_inline.h" +#include + +namespace igl +{ + // Inject a given colormap with evenly spaced isolines. + // + // Inputs: + // CM #CM by 3 list of colors + // ico_color 1 by 3 isoline color + // interval_thickness number of times to repeat intervals (original colors) + // iso_thickness number of times to repeat isoline color (in between + // intervals) + // Outputs: + // ICM #CM*interval_thickness + (#CM-1)*iso_thickness by 3 list of outputs + // colors + template < + typename DerivedCM, + typename Derivediso_color, + typename DerivedICM > + IGL_INLINE void isolines_map( + const Eigen::MatrixBase & CM, + const Eigen::MatrixBase & iso_color, + const int interval_thickness, + const int iso_thickness, + Eigen::PlainObjectBase & ICM); + template < + typename DerivedCM, + typename DerivedICM> + IGL_INLINE void isolines_map( + const Eigen::MatrixBase & CM, + Eigen::PlainObjectBase & ICM); +} + +#ifndef IGL_STATIC_LIBRARY +# include "isolines_map.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/iterative_closest_point.cpp b/src/external/libigl-2.3.0/include/igl/iterative_closest_point.cpp new file mode 100644 index 000000000..bf947e0f6 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/iterative_closest_point.cpp @@ -0,0 +1,120 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2019 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "iterative_closest_point.h" +#include "AABB.h" +#include "per_face_normals.h" +#include "slice.h" +#include "random_points_on_mesh.h" +#include "rigid_alignment.h" +#include +#include + +template < + typename DerivedVX, + typename DerivedFX, + typename DerivedVY, + typename DerivedFY, + typename DerivedR, + typename Derivedt + > +IGL_INLINE void igl::iterative_closest_point( + const Eigen::MatrixBase & VX, + const Eigen::MatrixBase & FX, + const Eigen::MatrixBase & VY, + const Eigen::MatrixBase & FY, + const int num_samples, + const int max_iters, + Eigen::PlainObjectBase & R, + Eigen::PlainObjectBase & t) +{ + + assert(VX.cols() == 3 && "X should be a mesh in 3D"); + assert(VY.cols() == 3 && "Y should be a mesh in 3D"); + + typedef typename DerivedVX::Scalar Scalar; + typedef Eigen::Matrix MatrixXS; + typedef Eigen::Matrix VectorXS; + typedef Eigen::Matrix Matrix3S; + typedef Eigen::Matrix RowVector3S; + + // Precompute BVH on Y + AABB Ytree; + Ytree.init(VY,FY); + MatrixXS NY; + per_face_normals(VY,FY,NY); + return iterative_closest_point( + VX,FX,VY,FY,Ytree,NY,num_samples,max_iters,R,t); +} + +template < + typename DerivedVX, + typename DerivedFX, + typename DerivedVY, + typename DerivedFY, + typename DerivedNY, + typename DerivedR, + typename Derivedt + > +IGL_INLINE void igl::iterative_closest_point( + const Eigen::MatrixBase & VX, + const Eigen::MatrixBase & FX, + const Eigen::MatrixBase & VY, + const Eigen::MatrixBase & FY, + const igl::AABB & Ytree, + const Eigen::MatrixBase & NY, + const int num_samples, + const int max_iters, + Eigen::PlainObjectBase & R, + Eigen::PlainObjectBase & t) +{ + typedef typename DerivedVX::Scalar Scalar; + typedef Eigen::Matrix MatrixXS; + typedef Eigen::Matrix VectorXS; + typedef Eigen::Matrix Matrix3S; + typedef Eigen::Matrix RowVector3S; + R.setIdentity(3,3); + t.setConstant(1,3,0); + + for(int iter = 0;iter, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, int, int, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/iterative_closest_point.h b/src/external/libigl-2.3.0/include/igl/iterative_closest_point.h new file mode 100644 index 000000000..0065c8923 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/iterative_closest_point.h @@ -0,0 +1,83 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2019 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_ITERATIVE_CLOSEST_POINT_H +#define IGL_ITERATIVE_CLOSEST_POINT_H +#include "igl_inline.h" +#include +#include "AABB.h" + +namespace igl +{ + // Solve for the rigid transformation that places mesh X onto mesh Y using the + // iterative closest point method. In particular, optimize: + // + // min ∫_X inf ‖x*R+t - y‖² dx + // R∈SO(3) y∈Y + // t∈R³ + // + // Typically optimization strategies include using Gauss Newton + // ("point-to-plane" linearization) and stochastic descent (sparse random + // sampling each iteration). + // + // Inputs: + // VX #VX by 3 list of mesh X vertices + // FX #FX by 3 list of mesh X triangle indices into rows of VX + // VY #VY by 3 list of mesh Y vertices + // FY #FY by 3 list of mesh Y triangle indices into rows of VY + // num_samples number of random samples to use (larger --> more accurate, + // but also more suceptible to sticking to local minimum) + // Outputs: + // R 3x3 rotation matrix so that (VX*R+t,FX) ~~ (VY,FY) + // t 1x3 translation row vector + template < + typename DerivedVX, + typename DerivedFX, + typename DerivedVY, + typename DerivedFY, + typename DerivedR, + typename Derivedt + > + IGL_INLINE void iterative_closest_point( + const Eigen::MatrixBase & VX, + const Eigen::MatrixBase & FX, + const Eigen::MatrixBase & VY, + const Eigen::MatrixBase & FY, + const int num_samples, + const int max_iters, + Eigen::PlainObjectBase & R, + Eigen::PlainObjectBase & t); + // Inputs: + // Ytree precomputed AABB tree for accelerating closest point queries + // NY #FY by 3 list of precomputed unit face normals + template < + typename DerivedVX, + typename DerivedFX, + typename DerivedVY, + typename DerivedFY, + typename DerivedNY, + typename DerivedR, + typename Derivedt + > + IGL_INLINE void iterative_closest_point( + const Eigen::MatrixBase & VX, + const Eigen::MatrixBase & FX, + const Eigen::MatrixBase & VY, + const Eigen::MatrixBase & FY, + const igl::AABB & Ytree, + const Eigen::MatrixBase & NY, + const int num_samples, + const int max_iters, + Eigen::PlainObjectBase & R, + Eigen::PlainObjectBase & t); +} + +#ifndef IGL_STATIC_LIBRARY +# include "iterative_closest_point.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/jet.cpp b/src/external/libigl-2.3.0/include/igl/jet.cpp new file mode 100644 index 000000000..ec74bcd79 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/jet.cpp @@ -0,0 +1,58 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "jet.h" +#include "colormap.h" + +template +IGL_INLINE void igl::jet(const T x, T * rgb) +{ + igl::colormap(igl::COLOR_MAP_TYPE_JET,x, rgb); +} + +template +IGL_INLINE void igl::jet(const T f, T & r, T & g, T & b) +{ + igl::colormap(igl::COLOR_MAP_TYPE_JET, f, r, g, b); +} + +template +IGL_INLINE void igl::jet( + const Eigen::MatrixBase & Z, + const bool normalize, + Eigen::PlainObjectBase & C) +{ + igl::colormap(igl::COLOR_MAP_TYPE_JET,Z, normalize, C); +} + +template +IGL_INLINE void igl::jet( + const Eigen::MatrixBase & Z, + const double min_z, + const double max_z, + Eigen::PlainObjectBase & C) +{ + igl::colormap(igl::COLOR_MAP_TYPE_JET, Z, min_z, max_z, C); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::jet, Eigen::Matrix >(Eigen::MatrixBase > const&, bool, Eigen::PlainObjectBase >&); +template void igl::jet(double, double*); +template void igl::jet(double, double&, double&, double&); +template void igl::jet(float, float*); +template void igl::jet, Eigen::Matrix >(Eigen::MatrixBase > const&, bool, Eigen::PlainObjectBase >&); +template void igl::jet, Eigen::Matrix >(Eigen::MatrixBase > const&, bool, Eigen::PlainObjectBase >&); +template void igl::jet, Eigen::Matrix >(Eigen::MatrixBase > const&, bool, Eigen::PlainObjectBase >&); +template void igl::jet(float, float&, float&, float&); +template void igl::jet, Eigen::Matrix >(Eigen::MatrixBase > const&, double, double, Eigen::PlainObjectBase >&); +template void igl::jet, Eigen::Matrix >(Eigen::MatrixBase > const&, double, double, Eigen::PlainObjectBase >&); +template void igl::jet, Eigen::Matrix >(Eigen::MatrixBase > const&, double, double, Eigen::PlainObjectBase >&); + +template void igl::jet, Eigen::Matrix >(Eigen::MatrixBase > const&, bool, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/jet.h b/src/external/libigl-2.3.0/include/igl/jet.h new file mode 100644 index 000000000..a681ca295 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/jet.h @@ -0,0 +1,67 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_JET_H +#define IGL_JET_H +#include "igl_inline.h" +//#ifndef IGL_NO_EIGEN +# include +//#endif +namespace igl +{ + // JET like MATLAB's jet. + // + // Note that we actually use the Turbo colormap instead, since jet is a bad colormap: + // https://ai.googleblog.com/2019/08/turbo-improved-rainbow-colormap-for.html + // + // Inputs: + // m number of colors + // Outputs: + // J m by list of RGB colors between 0 and 1 + // +//#ifndef IGL_NO_EIGEN +// void jet(const int m, Eigen::MatrixXd & J); +//#endif + // Wrapper for directly computing [r,g,b] values for a given factor f between + // 0 and 1 + // + // Inputs: + // f factor determining color value as if 0 was min and 1 was max + // Outputs: + // r red value + // g green value + // b blue value + template + IGL_INLINE void jet(const T f, T * rgb); + template + IGL_INLINE void jet(const T f, T & r, T & g, T & b); + // Inputs: + // Z #Z list of factors + // normalize whether to normalize Z to be tightly between [0,1] + // Outputs: + // C #C by 3 list of rgb colors + template + IGL_INLINE void jet( + const Eigen::MatrixBase & Z, + const bool normalize, + Eigen::PlainObjectBase & C); + // Inputs: + // min_z value at blue + // max_z value at red + template + IGL_INLINE void jet( + const Eigen::MatrixBase & Z, + const double min_Z, + const double max_Z, + Eigen::PlainObjectBase & C); +}; + +#ifndef IGL_STATIC_LIBRARY +# include "jet.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/kelvinlets.cpp b/src/external/libigl-2.3.0/include/igl/kelvinlets.cpp new file mode 100644 index 000000000..28c6ed146 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/kelvinlets.cpp @@ -0,0 +1,246 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can + +#include "kelvinlets.h" +#include "PI.h" +#include "parallel_for.h" + +namespace igl { + +// Performs the deformation of a single point based on the regularized +// kelvinlets +// +// Inputs: +// dt delta time used to calculate brush tip displacement +// x dim-vector of point to be deformed +// x0 dim-vector of brush tip +// f dim-vector of brush force (translation) +// F dim by dim matrix of brush force matrix (linear) +// kp parameters for the kelvinlet brush like brush radius, scale etc +// Returns: +// X dim-vector of the new point x gets displaced to post deformation +template +IGL_INLINE auto kelvinlet_evaluator(const Scalar dt, + const Eigen::MatrixBase& x, + const Eigen::MatrixBase& x0, + const Eigen::MatrixBase& f, + const Eigen::MatrixBase& F, + const igl::KelvinletParams& kp) + -> Eigen::Matrix +{ + static constexpr double POISSON_RATIO = 0.5; + static constexpr double SHEAR_MODULUS = 1; + static constexpr double a = 1 / (4 * igl::PI * SHEAR_MODULUS); + static constexpr double b = a / (4 * (1 - POISSON_RATIO)); + static constexpr double c = 2 / (3 * a - 2 * b); + + const auto linearVelocity = f / c / kp.epsilon; + + const auto originAdjusted = x0 + linearVelocity * dt; + const auto r = x - originAdjusted; + const auto r_norm_sq = r.squaredNorm(); + + std::function(const Scalar&)> kelvinlet; + + switch (kp.brushType) { + case igl::BrushType::GRAB: { + // Regularized Kelvinlets: Formula (6) + kelvinlet = [&r, &f, &r_norm_sq](const Scalar& epsilon) { + const auto r_epsilon = sqrt(r_norm_sq + epsilon * epsilon); + const auto r_epsilon_3 = r_epsilon * r_epsilon * r_epsilon; + auto t1 = ((a - b) / r_epsilon) * f; + auto t2 = ((b / r_epsilon_3) * r * r.transpose()) * f; + auto t3 = ((a * epsilon * epsilon) / (2 * r_epsilon_3)) * f; + return t1 + t2 + t3; + }; + break; + } + case igl::BrushType::TWIST: { + // Regularized Kelvinlets: Formula (15) + kelvinlet = [&r, &F, &r_norm_sq](const Scalar& epsilon) { + const auto r_epsilon = sqrt(r_norm_sq + epsilon * epsilon); + const auto r_epsilon_3 = r_epsilon * r_epsilon * r_epsilon; + return -a * + (1 / (r_epsilon_3) + + 3 * epsilon * epsilon / + (2 * r_epsilon_3 * r_epsilon * r_epsilon)) * + F * r; + }; + break; + } + case igl::BrushType::SCALE: { + // Regularized Kelvinlets: Formula (16) + kelvinlet = [&r, &F, &r_norm_sq](const Scalar& epsilon) { + static constexpr auto b_compressible = a / 4; // assumes poisson ratio 0 + const auto r_epsilon = sqrt(r_norm_sq + epsilon * epsilon); + const auto r_epsilon_3 = r_epsilon * r_epsilon * r_epsilon; + auto coeff = + (2 * b_compressible - a) * + (1 / (r_epsilon_3) + + 3 * (epsilon * epsilon) / (2 * r_epsilon_3 * r_epsilon * r_epsilon)); + return coeff * F * r; + }; + break; + } + case igl::BrushType::PINCH: { + // Regularized Kelvinlets: Formula (17) + kelvinlet = [&r, &F, &r_norm_sq, &kp](const Scalar& epsilon) { + const auto r_epsilon = sqrt(r_norm_sq + kp.epsilon * kp.epsilon); + const auto r_epsilon_3 = r_epsilon * r_epsilon * r_epsilon; + auto t1 = ((2 * b - a) / r_epsilon_3) * F * r; + auto t2_coeff = 3 / (2 * r_epsilon * r_epsilon * r_epsilon_3); + auto t2 = t2_coeff * (2 * b * (r.transpose().dot(F * r)) * r + + a * epsilon * epsilon * epsilon * F * r); + return t1 - t2; + }; + break; + } + } + + if (kp.scale == 1) { + return kelvinlet(kp.ep[0]); + } else if (kp.scale == 2) { + // Regularized Kelvinlets: Formula (8) + return (kelvinlet(kp.ep[0]) - kelvinlet(kp.ep[1])) * 10; + } + // Regularized Kelvinlets: Formula (10) + return (kp.w[0] * kelvinlet(kp.ep[0]) + kp.w[1] * kelvinlet(kp.ep[1]) + + kp.w[2] * kelvinlet(kp.ep[2])) * + 20; +}; + +// Implements the Bogacki-Shrampine ODE Solver +// https://en.wikipedia.org/wiki/Bogacki%E2%80%93Shampine_method +// +// It calculates the second and third order approximations which can be used to +// estimate the error in the integration step +// +// Inputs: +// t starting time +// dt delta time used to calculate brush tip displacement +// x dim-vector of point to be deformed +// x0 dim-vector of brush tip +// f dim-vector of brush force (translation) +// F dim by dim matrix of brush force matrix (linear) +// kp parameters for the kelvinlet brush like brush radius, scale etc +// Outputs: +// result dim vector holding the third order approximation result +// error The euclidean distance between the second and third order +// approximations +template +IGL_INLINE void integrate(const Scalar t, + const Scalar dt, + const Eigen::MatrixBase& x, + const Eigen::MatrixBase& x0, + const Eigen::MatrixBase& f, + const Eigen::MatrixBase& F, + const igl::KelvinletParams& kp, + Eigen::MatrixBase& result, + Scalar& error) +{ + constexpr Scalar a1 = 0; + constexpr Scalar a2 = 1 / 2.0f; + constexpr Scalar a3 = 3 / 4.0f; + constexpr Scalar a4 = 1.0f; + + constexpr Scalar b21 = 1 / 2.0f; + constexpr Scalar b31 = 0; + constexpr Scalar b32 = 3 / 4.0f; + constexpr Scalar b41 = 2 / 9.0f; + constexpr Scalar b42 = 1 / 3.0f; + constexpr Scalar b43 = 4 / 9.0f; + + constexpr Scalar c1 = 2 / 9.0f; // third order answer + constexpr Scalar c2 = 1 / 3.0f; + constexpr Scalar c3 = 4 / 9.0f; + + constexpr Scalar d1 = 7 / 24.0f; // second order answer + constexpr Scalar d2 = 1 / 4.0f; + constexpr Scalar d3 = 1 / 3.0f; + constexpr Scalar d4 = 1 / 8.0f; + + auto k1 = dt * kelvinlet_evaluator(t + dt * a1, x, x0, f, F, kp); + auto k2 = dt * kelvinlet_evaluator(t + dt * a2, x + k1 * b21, x0, f, F, kp); + auto k3 = dt * kelvinlet_evaluator( + t + dt * a3, x + k1 * b31 + k2 * b32, x0, f, F, kp); + auto k4 = + dt * kelvinlet_evaluator( + t + dt * a4, x + k1 * b41 + k2 * b42 + k3 * b43, x0, f, F, kp); + auto r1 = x + k1 * d1 + k2 * d2 + k3 * d3 + k4 * d4; + auto r2 = x + k1 * c1 + k2 * c2 + k3 * c3; + result = r2; + error = (r2 - r1).norm() / dt; +}; + +template +IGL_INLINE void kelvinlets( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& x0, + const Eigen::MatrixBase& f, + const Eigen::MatrixBase& F, + const KelvinletParams& params, + Eigen::PlainObjectBase& U) +{ + using Scalar = typename DerivedV::Scalar; + constexpr auto max_error = 0.001f; + constexpr Scalar safety = 0.9; + + const auto calc_displacement = [&](const int index) { + Scalar dt = 0.1; + Scalar t = 0; + + Eigen::Matrix x = V.row(index).transpose(); + decltype(x) result; + Scalar error; + // taking smaller steps seems to prevents weird inside-out artifacts in the + // final result. This implementation used an adaptive time step solver to + // numerically integrate the ODEs + while (t < 1) { + dt = std::min(dt, 1 - t); + integrate(t, dt, x, x0, f, F, params, result, error); + auto new_dt = dt * safety * std::pow(max_error / error, 1 / 3.0); + if (error <= max_error || dt <= 0.001) { + x = result; + t += dt; + dt = new_dt; + } else { + dt = std::max(abs(new_dt - dt) < 0.001 ? dt / 2.f : new_dt, 0.001); + } + } + U.row(index) = x.transpose(); + }; + + const int n = V.rows(); + U.resize(n, V.cols()); + igl::parallel_for(n, calc_displacement, 1000); +} +} +#ifdef IGL_STATIC_LIBRARY +template void igl::kelvinlets, + Eigen::Matrix, + Eigen::Matrix, + Eigen::Matrix, + Eigen::Matrix>( + Eigen::MatrixBase> const&, + Eigen::MatrixBase> const&, + Eigen::MatrixBase> const&, + Eigen::MatrixBase> const&, + igl::KelvinletParams const&, + Eigen::PlainObjectBase>&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/kelvinlets.h b/src/external/libigl-2.3.0/include/igl/kelvinlets.h new file mode 100644 index 000000000..3a1bd24f8 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/kelvinlets.h @@ -0,0 +1,76 @@ +#ifndef IGL_KELVINLETS_H +#define IGL_KELVINLETS_H + +#include +#include +#include + +namespace igl { + +enum class BrushType : int +{ + GRAB, + SCALE, + TWIST, + PINCH, +}; + +template +struct KelvinletParams +{ + const Scalar epsilon; + const int scale; + const BrushType brushType; + std::array ep{}, w{}; + + KelvinletParams(const Scalar& epsilon, + const int falloff, + const BrushType& type) + : epsilon(epsilon) + , scale(falloff) + , brushType(type) + { + static constexpr std::array brush_scaling_params{ 1.0f, + 1.1f, + 1.21f }; + for (int i = 0; i < 3; i++) { + ep[i] = epsilon * brush_scaling_params[i]; + } + w[0] = 1; + w[1] = -((ep[2] * ep[2] - ep[0] * ep[0]) / (ep[2] * ep[2] - ep[1] * ep[1])); + w[2] = (ep[1] * ep[1] - ep[0] * ep[0]) / (ep[2] * ep[2] - ep[1] * ep[1]); + } +}; + +// Implements Pixar's Regularized Kelvinlets (Pixar Technical Memo #17-03): +// Sculpting Brushes based on Fundamental Solutions of Elasticity, a technique +// for real-time physically based volume sculpting of virtual elastic materials +// +// Inputs: +// V #V by dim list of input points in space +// x0 dim-vector of brush tip +// f dim-vector of brush force (translation) +// F dim by dim matrix of brush force matrix (linear) +// params parameters for the kelvinlet brush like brush radius, scale etc +// Outputs: +// X #V by dim list of output points in space +template +IGL_INLINE void kelvinlets( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& x0, + const Eigen::MatrixBase& f, + const Eigen::MatrixBase& F, + const KelvinletParams& params, + Eigen::PlainObjectBase& U); + +} + +#ifndef IGL_STATIC_LIBRARY + +#include "kelvinlets.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/kkt_inverse.cpp b/src/external/libigl-2.3.0/include/igl/kkt_inverse.cpp new file mode 100644 index 000000000..a3c3c8b57 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/kkt_inverse.cpp @@ -0,0 +1,97 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "kkt_inverse.h" + +#include +#include +#include "EPS.h" +#include + +template +IGL_INLINE void igl::kkt_inverse( + const Eigen::Matrix& A, + const Eigen::Matrix& Aeq, + const bool use_lu_decomposition, + Eigen::Matrix& S) +{ + typedef Eigen::Matrix Mat; + // This threshold seems to matter a lot but I'm not sure how to + // set it + const T treshold = igl::FLOAT_EPS; + //const T treshold = igl::DOUBLE_EPS; + + const int n = A.rows(); + assert(A.cols() == n); + const int m = Aeq.rows(); + assert(Aeq.cols() == n); + + // Lagrange multipliers method: + Eigen::Matrix LM(n + m, n + m); + LM.block(0, 0, n, n) = A; + LM.block(0, n, n, m) = Aeq.transpose(); + LM.block(n, 0, m, n) = Aeq; + LM.block(n, n, m, m).setZero(); + + Mat LMpinv; + if(use_lu_decomposition) + { + // if LM is close to singular, use at your own risk :) + LMpinv = LM.inverse(); + }else + { + // use SVD + typedef Eigen::Matrix Vec; + Vec singValues; + Eigen::JacobiSVD svd; + svd.compute(LM, Eigen::ComputeFullU | Eigen::ComputeFullV ); + const Mat& u = svd.matrixU(); + const Mat& v = svd.matrixV(); + const Vec& singVals = svd.singularValues(); + + Vec pi_singVals(n + m); + int zeroed = 0; + for (int i=0; i= 0); + // printf("sv: %lg ? %lg\n",(double) sv,(double)treshold); + if (sv > treshold) pi_singVals(i, 0) = T(1) / sv; + else + { + pi_singVals(i, 0) = T(0); + zeroed++; + } + } + + printf("kkt_inverse : %i singular values zeroed (threshold = %e)\n", zeroed, treshold); + Eigen::DiagonalMatrix pi_diag(pi_singVals); + + LMpinv = v * pi_diag * u.transpose(); + } + S = LMpinv.block(0, 0, n, n + m); + + //// debug: + //mlinit(&g_pEngine); + // + //mlsetmatrix(&g_pEngine, "A", A); + //mlsetmatrix(&g_pEngine, "Aeq", Aeq); + //mlsetmatrix(&g_pEngine, "LM", LM); + //mlsetmatrix(&g_pEngine, "u", u); + //mlsetmatrix(&g_pEngine, "v", v); + //MatrixXd svMat = singVals; + //mlsetmatrix(&g_pEngine, "singVals", svMat); + //mlsetmatrix(&g_pEngine, "LMpinv", LMpinv); + //mlsetmatrix(&g_pEngine, "S", S); + + //int hu = 1; +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +template void igl::kkt_inverse(Eigen::Matrix const&, Eigen::Matrix const&, bool, Eigen::Matrix&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/kkt_inverse.h b/src/external/libigl-2.3.0/include/igl/kkt_inverse.h new file mode 100644 index 000000000..40f208a70 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/kkt_inverse.h @@ -0,0 +1,65 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_KKT_INVERSE_H +#define IGL_KKT_INVERSE_H +#include "igl_inline.h" + +#include + +//// debug +//#include +//Engine *g_pEngine; + + +namespace igl +{ + // Systems of the form: + // + // / A Aeqᵀ \ / x \ = / b \ + // \ Aeq 0 / \ λ / \ beq / + // \_____.______/\__.__/ \___.___/ + // M z c + // + // Arise, for example, when solve convex, linear equality constrained + // quadratic minimization problems: + // + // min ½ xᵀ A x - xᵀb subject to Aeq x = beq + // + // This function constructs a matrix S such that x = S c solves the system + // above. That is: + // + // S = [In 0] M⁻¹ + // + // so that + // + // x = S c + // + // Templates: + // T should be a eigen matrix primitive type like float or double + // Inputs: + // A n by n matrix of quadratic coefficients + // B n by 1 column of linear coefficients + // Aeq m by n list of linear equality constraint coefficients + // Beq m by 1 list of linear equality constraint constant values + // use_lu_decomposition use lu rather than SVD + // Outputs: + // S n by (n + m) "solve" matrix, such that S*[B', Beq'] is a solution + // Returns true on success, false on error + template + IGL_INLINE void kkt_inverse( + const Eigen::Matrix& A, + const Eigen::Matrix& Aeq, + const bool use_lu_decomposition, + Eigen::Matrix& S); +} + +#ifndef IGL_STATIC_LIBRARY +# include "kkt_inverse.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/knn.cpp b/src/external/libigl-2.3.0/include/igl/knn.cpp new file mode 100644 index 000000000..689e2f599 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/knn.cpp @@ -0,0 +1,148 @@ +#include "knn.h" +#include "sort.h" +#include "parallel_for.h" + +#include +#include +#include +#include + +namespace igl { + template + IGL_INLINE void knn(const Eigen::MatrixBase& P, + size_t k, + const std::vector > & point_indices, + const Eigen::MatrixBase& CH, + const Eigen::MatrixBase& CN, + const Eigen::MatrixBase& W, + Eigen::PlainObjectBase & I) { + knn(P,P,k,point_indices,CH,CN,W,I); + } + + template + IGL_INLINE void knn( + const Eigen::MatrixBase& P, + const Eigen::MatrixBase& V, + size_t k, + const std::vector > & point_indices, + const Eigen::MatrixBase& CH, + const Eigen::MatrixBase& CN, + const Eigen::MatrixBase& W, + Eigen::PlainObjectBase & I) { + typedef typename DerivedCN::Scalar CentersType; + typedef typename DerivedW::Scalar WidthsType; + + using Scalar = typename DerivedP::Scalar; + typedef Eigen::Matrix RowVector3PType; + + + const size_t Psize = P.rows(); + const size_t Vsize = V.rows(); + if(Vsize <= k) { + I.resize(Psize,Vsize); + for(size_t i = 0; i < Psize; ++i) { + Eigen::Matrix D = (V.rowwise() - P.row(i)).rowwise().norm(); + Eigen::Matrix S; + Eigen::VectorXi R; + igl::sort(D,1,true,S,R); + I.row(i) = R.transpose(); + } + return; + } + + I.resize(Psize,k); + + + auto distance_to_width_one_cube = [](const RowVector3PType& point) -> Scalar { + return std::sqrt(std::pow(std::max(std::abs(point(0))-1,0.0),2) + + std::pow(std::max(std::abs(point(1))-1,0.0),2) + + std::pow(std::max(std::abs(point(2))-1,0.0),2)); + }; + + auto distance_to_cube = [&distance_to_width_one_cube] + (const RowVector3PType& point, + Eigen::Matrix cube_center, + WidthsType cube_width) -> Scalar { + RowVector3PType transformed_point = (point-cube_center)/cube_width; + return cube_width*distance_to_width_one_cube(transformed_point); + }; + + + igl::parallel_for(Psize,[&](size_t i) + { + int points_found = 0; + RowVector3PType point_of_interest = P.row(i); + + //To make my priority queue take both points and octree cells, + //I use the indices 0 to n-1 for the n points, + // and the indices n to n+m-1 for the m octree cells + + // Using lambda to compare elements. + auto cmp = [&point_of_interest, &V, &CN, &W, + Vsize, &distance_to_cube](int left, int right) { + Scalar leftdistance, rightdistance; + if(left < Vsize){ //left is a point index + leftdistance = (V.row(left) - point_of_interest).norm(); + } else { //left is an octree cell + leftdistance = distance_to_cube(point_of_interest, + CN.row(left-Vsize), + W(left-Vsize)); + } + + if(right < Vsize){ //left is a point index + rightdistance = (V.row(right) - point_of_interest).norm(); + } else { //left is an octree cell + rightdistance = distance_to_cube(point_of_interest, + CN.row(right-Vsize), + W(right-Vsize)); + } + return leftdistance > rightdistance; + }; + + std::priority_queue, + decltype(cmp)> queue(cmp); + + queue.push(Vsize); //This is the 0th octree cell (ie the root) + while(points_found < k){ + IndexType curr_cell_or_point = queue.top(); + queue.pop(); + if(curr_cell_or_point < Vsize){ //current index is for is a point + I(i,points_found) = curr_cell_or_point; + points_found++; + } else { + IndexType curr_cell = curr_cell_or_point - Vsize; + if(CH(curr_cell,0) == -1){ //In the case of a leaf + if(point_indices.at(curr_cell).size() > 0){ + //Assumption: Leaves either have one point, or none + queue.push(point_indices.at(curr_cell).at(0)); + } + } else { //Not a leaf + for(int j = 0; j < 8; j++){ + //+n to adjust for the octree cells + queue.push(CH(curr_cell,j)+Vsize); + } + } + } + } + },1000); + } +} + + + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh + +template void igl::knn, Eigen::Matrix, int, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, unsigned long, std::vector >, std::allocator > > > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::knn, int, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, unsigned long, std::vector >, std::allocator > > > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +#ifdef WIN32 +template void igl::knn,int,Eigen::Matrix,Eigen::Matrix,Eigen::Matrix,Eigen::Matrix >(Eigen::MatrixBase > const &,unsigned __int64,std::vector >,std::allocator > > > const &,Eigen::MatrixBase > const &,Eigen::MatrixBase > const &,Eigen::MatrixBase > const &,Eigen::PlainObjectBase > &); +template void igl::knn,Eigen::Matrix,int,Eigen::Matrix,Eigen::Matrix,Eigen::Matrix,Eigen::Matrix >(Eigen::MatrixBase > const &,Eigen::MatrixBase > const &,unsigned __int64,std::vector >,std::allocator > > > const &,Eigen::MatrixBase > const &,Eigen::MatrixBase > const &,Eigen::MatrixBase > const &,Eigen::PlainObjectBase > &); +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/knn.h b/src/external/libigl-2.3.0/include/igl/knn.h new file mode 100644 index 000000000..5d295902f --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/knn.h @@ -0,0 +1,88 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2018 Gavin Barill +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/ + +#ifndef IGL_KNN_H +#define IGL_KNN_H +#include "igl_inline.h" +#include +#include + +namespace igl +{ + // Given a 3D set of points P, an whole number k, and an octree + // find the indicies of the k nearest neighbors for each point in P. + // Note that each point is its own neighbor. + // + // The octree data structures used in this function are intended to be the + // same ones output from igl::octree + // + // Inputs: + // P #P by 3 list of point locations + // k number of neighbors to find + // point_indices a vector of vectors, where the ith entry is a vector of + // the indices into P that are the ith octree cell's points + // CH #OctreeCells by 8, where the ith row is the indices of + // the ith octree cell's children + // CN #OctreeCells by 3, where the ith row is a 3d row vector + // representing the position of the ith cell's center + // W #OctreeCells, a vector where the ith entry is the width + // of the ith octree cell + // Outputs: + // I #P by k list of k-nearest-neighbor indices into P + template < + typename DerivedP, + typename IndexType, + typename DerivedCH, + typename DerivedCN, + typename DerivedW, + typename DerivedI> + IGL_INLINE void knn( + const Eigen::MatrixBase& P, + size_t k, + const std::vector > & point_indices, + const Eigen::MatrixBase& CH, + const Eigen::MatrixBase& CN, + const Eigen::MatrixBase& W, + Eigen::PlainObjectBase & I); + // Inputs: + // P #P by 3 list of point locations for which which we want the neighbors of + // V #V by 3 list of point locations for which may be neighbors + // k number of neighbors to find + // point_indices a vector of vectors, where the ith entry is a vector of + // the indices into P that are the ith octree cell's points + // CH #OctreeCells by 8, where the ith row is the indices of + // the ith octree cell's children + // CN #OctreeCells by 3, where the ith row is a 3d row vector + // representing the position of the ith cell's center + // W #OctreeCells, a vector where the ith entry is the width + // of the ith octree cell + // Outputs: + // I #P by k list of k-nearest-neighbor indices into V + template < + typename DerivedP, + typename DerivedV, + typename IndexType, + typename DerivedCH, + typename DerivedCN, + typename DerivedW, + typename DerivedI> + IGL_INLINE void knn( + const Eigen::MatrixBase& P, + const Eigen::MatrixBase& V, + size_t k, + const std::vector > & point_indices, + const Eigen::MatrixBase& CH, + const Eigen::MatrixBase& CN, + const Eigen::MatrixBase& W, + Eigen::PlainObjectBase & I); +} +#ifndef IGL_STATIC_LIBRARY +# include "knn.cpp" +#endif +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/launch_medit.cpp b/src/external/libigl-2.3.0/include/igl/launch_medit.cpp new file mode 100644 index 000000000..f336dd7d0 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/launch_medit.cpp @@ -0,0 +1,70 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "launch_medit.h" +#include "writeMESH.h" +#include +#include +#include +#include + +#define MEDIT_PATH "/opt/local/bin/medit" +#define TEMP_MESH_FILE "/var/tmp/temp.mesh" +#define TEMP_MEDIT_FILE "/var/tmp/temp.medit" + +template +IGL_INLINE int igl::launch_medit( + const Eigen::PlainObjectBase & V, + const Eigen::PlainObjectBase & T, + const Eigen::PlainObjectBase & F, + const bool wait) +{ + using namespace std; + // Build medit command, end with & so command returns without waiting + stringstream command; + command<, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, bool); +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/launch_medit.h b/src/external/libigl-2.3.0/include/igl/launch_medit.h new file mode 100644 index 000000000..8a324bb22 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/launch_medit.h @@ -0,0 +1,44 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_LAUNCH_MEDIT_H +#define IGL_LAUNCH_MEDIT_H +#include "igl_inline.h" + +#include + +namespace igl +{ + // Writes the tetmesh in (V,T,F) to a temporary file, opens it with medit + // (forking with a system call) and returns + // + // + // Templates: + // DerivedV real-value: i.e. from MatrixXd + // DerivedT integer-value: i.e. from MatrixXi + // DerivedF integer-value: i.e. from MatrixXi + // Inputs: + // V double matrix of vertex positions #V by 3 + // T #T list of tet indices into vertex positions + // F #F list of face indices into vertex positions + // wait whether to wait for medit process to finish before returning + // Returns returned value of system call (probably not useful if wait=false + // because of the fork) + template + IGL_INLINE int launch_medit( + const Eigen::PlainObjectBase & V, + const Eigen::PlainObjectBase & T, + const Eigen::PlainObjectBase & F, + const bool wait); +} + +#ifndef IGL_STATIC_LIBRARY +# include "launch_medit.cpp" +#endif + +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/lbs_matrix.cpp b/src/external/libigl-2.3.0/include/igl/lbs_matrix.cpp new file mode 100644 index 000000000..a80f74be0 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/lbs_matrix.cpp @@ -0,0 +1,184 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "lbs_matrix.h" + +IGL_INLINE void igl::lbs_matrix( + const Eigen::MatrixXd & V, + const Eigen::MatrixXd & W, + Eigen::MatrixXd & M) +{ + using namespace Eigen; + // Number of dimensions + const int dim = V.cols(); + // Number of model points + const int n = V.rows(); + // Number of skinning transformations/weights + const int m = W.cols(); + + // Assumes that first n rows of weights correspond to V + assert(W.rows() >= n); + + M.resize(n,(dim+1)*m); + for(int j = 0;j& M) +{ + // number of mesh vertices + int n = V.rows(); + assert(n == W.rows()); + // dimension of mesh + int dim = V.cols(); + // number of handles + int m = W.cols(); + + M.resize(n*dim,m*dim*(dim+1)); + + // loop over coordinates of mesh vertices + for(int x = 0; x < dim; x++) + { + // loop over mesh vertices + for(int j = 0; j < n; j++) + { + // loop over handles + for(int i = 0; i < m; i++) + { + // loop over cols of affine transformations + for(int c = 0; c < (dim+1); c++) + { + double value = W(j,i); + if(c& M) +{ + // number of mesh vertices + int n = V.rows(); + assert(n == W.rows()); + assert(n == WI.rows()); + // dimension of mesh + int dim = V.cols(); + // number of handles + int m = WI.maxCoeff()+1; + // max number of influencing handles + int k = W.cols(); + assert(k == WI.cols()); + + M.resize(n*dim,m*dim*(dim+1)); + + // loop over coordinates of mesh vertices + for(int x = 0; x < dim; x++) + { + // loop over mesh vertices + for(int j = 0; j < n; j++) + { + // loop over handles + for(int i = 0; i < k; i++) + { + // loop over cols of affine transformations + for(int c = 0; c < (dim+1); c++) + { + double value = W(j,i); + if(c sM; + lbs_matrix_column(V,W,WI,sM); + M = MatrixXd(sM); +} diff --git a/src/external/libigl-2.3.0/include/igl/lbs_matrix.h b/src/external/libigl-2.3.0/include/igl/lbs_matrix.h new file mode 100644 index 000000000..307273d20 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/lbs_matrix.h @@ -0,0 +1,94 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_LBS_MATRIX_H +#define IGL_LBS_MATRIX_H +#include "igl_inline.h" + +#include +#include + +namespace igl +{ + // LBS_MATRIX Linear blend skinning can be expressed by V' = M * T where V' is + // a #V by dim matrix of deformed vertex positions (one vertex per row), M is a + // #V by (dim+1)*#T (composed of weights and rest positions) and T is a + // #T*(dim+1) by dim matrix of #T stacked transposed transformation matrices. + // See equations (1) and (2) in "Fast Automatic Skinning Transformations" + // [Jacobson et al 2012] + // + // Inputs: + // V #V by dim list of rest positions + // W #V+ by #T list of weights + // Outputs: + // M #V by #T*(dim+1) + // + // In MATLAB: + // kron(ones(1,size(W,2)),[V ones(size(V,1),1)]).*kron(W,ones(1,size(V,2)+1)) + IGL_INLINE void lbs_matrix( + const Eigen::MatrixXd & V, + const Eigen::MatrixXd & W, + Eigen::MatrixXd & M); + // LBS_MATRIX construct a matrix that when multiplied against a column of + // affine transformation entries computes new coordinates of the vertices + // + // I'm not sure it makes since that the result is stored as a sparse matrix. + // The number of non-zeros per row *is* dependent on the number of mesh + // vertices and handles. + // + // Inputs: + // V #V by dim list of vertex rest positions + // W #V by #handles list of correspondence weights + // Output: + // M #V * dim by #handles * dim * (dim+1) matrix such that + // new_V(:) = LBS(V,W,A) = reshape(M * A,size(V)), where A is a column + // vectors formed by the entries in each handle's dim by dim+1 + // transformation matrix. Specifcally, A = + // reshape(permute(Astack,[3 1 2]),n*dim*(dim+1),1) + // or A = [Lxx;Lyx;Lxy;Lyy;tx;ty], and likewise for other dim + // if Astack(:,:,i) is the dim by (dim+1) transformation at handle i + IGL_INLINE void lbs_matrix_column( + const Eigen::MatrixXd & V, + const Eigen::MatrixXd & W, + Eigen::SparseMatrix& M); + IGL_INLINE void lbs_matrix_column( + const Eigen::MatrixXd & V, + const Eigen::MatrixXd & W, + Eigen::MatrixXd & M); + // Same as LBS_MATRIX above but instead of giving W as a full matrix of weights + // (each vertex has #handles weights), a constant number of weights are given + // for each vertex. + // + // Inputs: + // V #V by dim list of vertex rest positions + // W #V by k list of k correspondence weights per vertex + // WI #V by k list of k correspondence weight indices per vertex. Such that + // W(j,WI(i)) gives the ith most significant correspondence weight on vertex j + // Output: + // M #V * dim by #handles * dim * (dim+1) matrix such that + // new_V(:) = LBS(V,W,A) = reshape(M * A,size(V)), where A is a column + // vectors formed by the entries in each handle's dim by dim+1 + // transformation matrix. Specifcally, A = + // reshape(permute(Astack,[3 1 2]),n*dim*(dim+1),1) + // or A = [Lxx;Lyx;Lxy;Lyy;tx;ty], and likewise for other dim + // if Astack(:,:,i) is the dim by (dim+1) transformation at handle i + // + IGL_INLINE void lbs_matrix_column( + const Eigen::MatrixXd & V, + const Eigen::MatrixXd & W, + const Eigen::MatrixXi & WI, + Eigen::SparseMatrix& M); + IGL_INLINE void lbs_matrix_column( + const Eigen::MatrixXd & V, + const Eigen::MatrixXd & W, + const Eigen::MatrixXi & WI, + Eigen::MatrixXd & M); +} +#ifndef IGL_STATIC_LIBRARY +#include "lbs_matrix.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/lexicographic_triangulation.cpp b/src/external/libigl-2.3.0/include/igl/lexicographic_triangulation.cpp new file mode 100644 index 000000000..ceb07de97 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/lexicographic_triangulation.cpp @@ -0,0 +1,131 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// Qingan Zhou +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +#include "lexicographic_triangulation.h" +#include "sortrows.h" + +#include +#include + +template< + typename DerivedP, + typename Orient2D, + typename DerivedF + > +IGL_INLINE void igl::lexicographic_triangulation( + const Eigen::MatrixBase& P, + Orient2D orient2D, + Eigen::PlainObjectBase& F) +{ + typedef typename DerivedP::Scalar Scalar; + const size_t num_pts = P.rows(); + if (num_pts < 3) { + throw "At least 3 points are required for triangulation!"; + } + + // Sort points in lexicographic order. + DerivedP ordered_P; + Eigen::VectorXi order; + igl::sortrows(P, true, ordered_P, order); + + std::vector faces; + std::list boundary; + const Scalar p0[] = {ordered_P(0, 0), ordered_P(0, 1)}; + const Scalar p1[] = {ordered_P(1, 0), ordered_P(1, 1)}; + for (size_t i=2; i 0) { + for (size_t j=0; j<=i-2; j++) { + faces.push_back({order[j], order[j+1], order[i]}); + } + } else if (orientation < 0) { + for (size_t j=0; j<=i-2; j++) { + faces.push_back({order[j+1], order[j], order[i]}); + } + } + // Initialize current boundary. + boundary.insert(boundary.end(), order.data(), order.data()+i+1); + if (orientation < 0) { + boundary.reverse(); + } + } + } else { + const size_t bd_size = boundary.size(); + assert(bd_size >= 3); + std::vector orientations; + for (auto itr=boundary.begin(); itr!=boundary.end(); itr++) { + auto next_itr = std::next(itr, 1); + if (next_itr == boundary.end()) { + next_itr = boundary.begin(); + } + const Scalar bd_p0[] = {P(*itr, 0), P(*itr, 1)}; + const Scalar bd_p1[] = {P(*next_itr, 0), P(*next_itr, 1)}; + auto orientation = orient2D(bd_p0, bd_p1, curr_p); + if (orientation < 0) { + faces.push_back({*next_itr, *itr, order[i]}); + } + orientations.push_back(orientation); + } + + auto left_itr = boundary.begin(); + auto right_itr = boundary.begin(); + auto curr_itr = boundary.begin(); + for (size_t j=0; j= 0 && orientations[prev] < 0) { + right_itr = curr_itr; + } else if (orientations[j] < 0 && orientations[prev] >= 0) { + left_itr = curr_itr; + } + } + assert(left_itr != right_itr); + + for (auto itr=left_itr; itr!=right_itr; itr++) { + if (itr == boundary.end()) itr = boundary.begin(); + if (itr == right_itr) break; + if (itr == left_itr) continue; + itr = boundary.erase(itr); + if (itr == boundary.begin()) { + itr = boundary.end(); + } + itr--; + } + + if (right_itr == boundary.begin()) { + assert(std::next(left_itr, 1) == boundary.end()); + boundary.insert(boundary.end(), order[i]); + } else { + assert(std::next(left_itr, 1) == right_itr); + boundary.insert(right_itr, order[i]); + } + } + } + + const size_t num_faces = faces.size(); + if (num_faces == 0) { + // All input points are collinear. + // Do nothing here. + } else { + F.resize(num_faces, 3); + for (size_t i=0; i, short (*)(double const*, double const*, double const*), Eigen::Matrix >(Eigen::MatrixBase > const&, short (*)(double const*, double const*, double const*), Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/lexicographic_triangulation.h b/src/external/libigl-2.3.0/include/igl/lexicographic_triangulation.h new file mode 100644 index 000000000..635f35e53 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/lexicographic_triangulation.h @@ -0,0 +1,47 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// Qingan Zhou +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef IGL_LEXICOGRAPHIC_TRIANGULATION_H +#define IGL_LEXICOGRAPHIC_TRIANGULATION_H +#include "igl_inline.h" +#include + +namespace igl +{ + // Given a set of points in 2D, return a lexicographic triangulation of these + // points. + // + // Inputs: + // P #P by 2 list of vertex positions + // orient2D A functor such that orient2D(pa, pb, pc) returns + // 1 if pa,pb,pc forms a conterclockwise triangle. + // -1 if pa,pb,pc forms a clockwise triangle. + // 0 if pa,pb,pc are collinear. + // where the argument pa,pb,pc are of type Scalar[2]. + // + // Outputs: + // F #F by 3 of faces in lexicographic triangulation. + template< + typename DerivedP, + typename Orient2D, + typename DerivedF + > + IGL_INLINE void lexicographic_triangulation( + const Eigen::MatrixBase& P, + Orient2D orient2D, + Eigen::PlainObjectBase& F); +} + + + + +#ifndef IGL_STATIC_LIBRARY +# include "lexicographic_triangulation.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/limit_faces.cpp b/src/external/libigl-2.3.0/include/igl/limit_faces.cpp new file mode 100644 index 000000000..e54c40b45 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/limit_faces.cpp @@ -0,0 +1,63 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "limit_faces.h" + +#include +#include + +template +IGL_INLINE void igl::limit_faces( + const MatF & F, + const VecL & L, + const bool exclusive, + MatF & LF) +{ + using namespace std; + using namespace Eigen; + vector in(F.rows(),false); + int num_in = 0; + // loop over faces + for(int i = 0;i +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_LIMIT_FACES_H +#define IGL_LIMIT_FACES_H +#include "igl_inline.h" +namespace igl +{ + // LIMIT_FACES limit given faces F to those which contain (only) indices found + // in L. + // + // [LF] = limit_faces(F,L,exclusive); + // [LF,in] = limit_faces(F,L,exclusive); + // + // Templates: + // MatF matrix type of faces, matrixXi + // VecL matrix type of vertex indices, VectorXi + // Inputs: + // F #F by 3 list of face indices + // L #L by 1 list of allowed indices + // exclusive flag specifying whether a face is included only if all its + // indices are in L, default is false + // Outputs: + // LF #LF by 3 list of remaining faces after limiting + // in #F list of whether given face was included + // + template + IGL_INLINE void limit_faces( + const MatF & F, + const VecL & L, + const bool exclusive, + MatF & LF); +} + +#ifndef IGL_STATIC_LIBRARY +# include "limit_faces.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/line_field_mismatch.cpp b/src/external/libigl-2.3.0/include/igl/line_field_mismatch.cpp new file mode 100644 index 000000000..27a2dd2e6 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/line_field_mismatch.cpp @@ -0,0 +1,144 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Nico Pietroni +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +#include "line_field_mismatch.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace igl { +template +class MismatchCalculatorLine +{ +public: + + const Eigen::PlainObjectBase &V; + const Eigen::PlainObjectBase &F; + const Eigen::PlainObjectBase &PD1; + const Eigen::PlainObjectBase &PD2; + DerivedV N; + +private: + // internal + std::vector V_border; // bool + std::vector > VF; + std::vector > VFi; + DerivedF TT; + DerivedF TTi; + + +private: + + //compute the mismatch between 2 faces + inline int mismatchByLine(const int f0, + const int f1) + { + Eigen::Matrix dir0 = PD1.row(f0); + Eigen::Matrix dir1 = PD1.row(f1); + Eigen::Matrix n0 = N.row(f0); + Eigen::Matrix n1 = N.row(f1); + + Eigen::Matrix dir1Rot = igl::rotation_matrix_from_directions(n1,n0)*dir1; + dir1Rot.normalize(); + + // TODO: this should be equivalent to the other code below, to check! + // Compute the angle between the two vectors + // double a0 = atan2(dir0.dot(B2.row(f0)),dir0.dot(B1.row(f0))); + // double a1 = atan2(dir1Rot.dot(B2.row(f0)),dir1Rot.dot(B1.row(f0))); + // + // double angle_diff = a1-a0; //VectToAngle(f0,dir1Rot); + + double angle_diff = atan2(dir1Rot.dot(PD2.row(f0)),dir1Rot.dot(PD1.row(f0))); + + double step=igl::PI; + int i=(int)std::floor((angle_diff/step)+0.5); + assert((i>=-2)&&(i<=2)); + int k=0; + if (i>=0) + k=i%2; + else + k=(2+i)%2; + + assert((k==0)||(k==1)); + return (k*2); + } + +public: + + inline MismatchCalculatorLine(const Eigen::PlainObjectBase &_V, + const Eigen::PlainObjectBase &_F, + const Eigen::PlainObjectBase &_PD1, + const Eigen::PlainObjectBase &_PD2 + ): + V(_V), + F(_F), + PD1(_PD1), + PD2(_PD2) + { + igl::per_face_normals(V,F,N); + V_border = igl::is_border_vertex(F); + igl::vertex_triangle_adjacency(V,F,VF,VFi); + igl::triangle_triangle_adjacency(F,TT,TTi); + } + + inline void calculateMismatchLine(Eigen::PlainObjectBase &Handle_MMatch) + { + Handle_MMatch.setConstant(F.rows(),3,-1); + for (unsigned int i=0;i +IGL_INLINE void igl::line_field_mismatch(const Eigen::PlainObjectBase &V, + const Eigen::PlainObjectBase &F, + const Eigen::PlainObjectBase &PD1, + const bool isCombed, + Eigen::PlainObjectBase &mismatch) +{ + DerivedV PD1_combed; + DerivedV PD2_combed; + + if (!isCombed) + igl::comb_line_field(V,F,PD1,PD1_combed); + else + { + PD1_combed = PD1; + } + Eigen::MatrixXd B1,B2,B3; + igl::local_basis(V,F,B1,B2,B3); + PD2_combed = igl::rotate_vectors(PD1_combed, Eigen::VectorXd::Constant(1,igl::PI/2), B1, B2); + igl::MismatchCalculatorLine sf(V, F, PD1_combed, PD2_combed); + sf.calculateMismatchLine(mismatch); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +#endif diff --git a/src/external/libigl-2.3.0/include/igl/line_field_mismatch.h b/src/external/libigl-2.3.0/include/igl/line_field_mismatch.h new file mode 100644 index 000000000..694272dd7 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/line_field_mismatch.h @@ -0,0 +1,42 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Nico Pietroni +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef IGL_LINE_FIELD_MISSMATCH_H +#define IGL_LINE_FIELD_MISSMATCH_H +#include "igl_inline.h" +#include +namespace igl +{ + // Calculates the mismatch (integer), at each face edge, of a cross field defined on the mesh faces. + // The integer mismatch is a multiple of pi/2 that transforms the cross on one side of the edge to + // the cross on the other side. It represents the deviation from a Lie connection across the edge. + + // Inputs: + // V #V by 3 eigen Matrix of mesh vertex 3D positions + // F #F by 3 eigen Matrix of face (quad) indices + // PD1 #F by 3 eigen Matrix of the first per face cross field vector + // PD2 #F by 3 eigen Matrix of the second per face cross field vector + // isCombed boolean, specifying whether the field is combed (i.e. matching has been precomputed. + // If not, the field is combed first. + // Output: + // mismatch #F by 3 eigen Matrix containing the integer mismatch of the cross field + // across all face edges + // + + template + IGL_INLINE void line_field_mismatch(const Eigen::PlainObjectBase &V, + const Eigen::PlainObjectBase &F, + const Eigen::PlainObjectBase &PD1, + const bool isCombed, + Eigen::PlainObjectBase &mismatch); +} +#ifndef IGL_STATIC_LIBRARY +#include "line_field_mismatch.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/line_search.cpp b/src/external/libigl-2.3.0/include/igl/line_search.cpp new file mode 100644 index 000000000..c94eeaa52 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/line_search.cpp @@ -0,0 +1,50 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Michael Rabinovich +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "line_search.h" + +IGL_INLINE double igl::line_search( + Eigen::MatrixXd& x, + const Eigen::MatrixXd& d, + double step_size, + std::function energy, + double cur_energy) +{ + double old_energy; + if (cur_energy > 0) + { + old_energy = cur_energy; + } + else + { + old_energy = energy(x); // no energy was given -> need to compute the current energy + } + double new_energy = old_energy; + int cur_iter = 0; int MAX_STEP_SIZE_ITER = 12; + + while (new_energy >= old_energy && cur_iter < MAX_STEP_SIZE_ITER) + { + Eigen::MatrixXd new_x = x + step_size * d; + + double cur_e = energy(new_x); + if ( cur_e >= old_energy) + { + step_size /= 2; + } + else + { + x = new_x; + new_energy = cur_e; + } + cur_iter++; + } + return new_energy; +} + + +#ifdef IGL_STATIC_LIBRARY +#endif diff --git a/src/external/libigl-2.3.0/include/igl/line_search.h b/src/external/libigl-2.3.0/include/igl/line_search.h new file mode 100644 index 000000000..057c6a43f --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/line_search.h @@ -0,0 +1,42 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Michael Rabinovich +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_LINE_SEARCH_H +#define IGL_LINE_SEARCH_H +#include "igl_inline.h" + +#include + +namespace igl +{ + // Implement a bisection linesearch to minimize a mesh-based energy on vertices given at 'x' at a search direction 'd', + // with initial step size. Stops when a point with lower energy is found, or after maximal iterations have been reached. + // + // Inputs: + // x #X by dim list of variables + // d #X by dim list of a given search direction + // i_step_size initial step size + // energy A function to compute the mesh-based energy (return an energy that is bigger than 0) + // cur_energy(OPTIONAL) The energy at the given point. Helps save redundant computations. + // This is optional. If not specified, the function will compute it. + // Outputs: + // x #X by dim list of variables at the new location + // Returns the energy at the new point 'x' + IGL_INLINE double line_search( + Eigen::MatrixXd& x, + const Eigen::MatrixXd& d, + double i_step_size, + std::function energy, + double cur_energy = -1); + +} + +#ifndef IGL_STATIC_LIBRARY +# include "line_search.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/line_segment_in_rectangle.cpp b/src/external/libigl-2.3.0/include/igl/line_segment_in_rectangle.cpp new file mode 100644 index 000000000..6f47c7d4c --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/line_segment_in_rectangle.cpp @@ -0,0 +1,103 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "line_segment_in_rectangle.h" + +IGL_INLINE bool igl::line_segment_in_rectangle( + const Eigen::Vector2d & s, + const Eigen::Vector2d & d, + const Eigen::Vector2d & A, + const Eigen::Vector2d & B) +{ + using namespace std; + using namespace Eigen; + // http://stackoverflow.com/a/100165/148668 + const auto SegmentIntersectRectangle = [](double a_rectangleMinX, + double a_rectangleMinY, + double a_rectangleMaxX, + double a_rectangleMaxY, + double a_p1x, + double a_p1y, + double a_p2x, + double a_p2y)->bool + { + // Find min and max X for the segment + + double minX = a_p1x; + double maxX = a_p2x; + + if(a_p1x > a_p2x) + { + minX = a_p2x; + maxX = a_p1x; + } + + // Find the intersection of the segment's and rectangle's x-projections + + if(maxX > a_rectangleMaxX) + { + maxX = a_rectangleMaxX; + } + + if(minX < a_rectangleMinX) + { + minX = a_rectangleMinX; + } + + if(minX > maxX) // If their projections do not intersect return false + { + return false; + } + + // Find corresponding min and max Y for min and max X we found before + + double minY = a_p1y; + double maxY = a_p2y; + + double dx = a_p2x - a_p1x; + + if(fabs(dx) > 0.0000001) + { + double a = (a_p2y - a_p1y) / dx; + double b = a_p1y - a * a_p1x; + minY = a * minX + b; + maxY = a * maxX + b; + } + + if(minY > maxY) + { + double tmp = maxY; + maxY = minY; + minY = tmp; + } + + // Find the intersection of the segment's and rectangle's y-projections + + if(maxY > a_rectangleMaxY) + { + maxY = a_rectangleMaxY; + } + + if(minY < a_rectangleMinY) + { + minY = a_rectangleMinY; + } + + if(minY > maxY) // If Y-projections do not intersect return false + { + return false; + } + + return true; + }; + const double minX = std::min(A(0),B(0)); + const double minY = std::min(A(1),B(1)); + const double maxX = std::max(A(0),B(0)); + const double maxY = std::max(A(1),B(1)); + bool ret = SegmentIntersectRectangle(minX,minY,maxX,maxY,s(0),s(1),d(0),d(1)); + return ret; +} diff --git a/src/external/libigl-2.3.0/include/igl/line_segment_in_rectangle.h b/src/external/libigl-2.3.0/include/igl/line_segment_in_rectangle.h new file mode 100644 index 000000000..6d7eaf404 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/line_segment_in_rectangle.h @@ -0,0 +1,33 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_LINE_SEGMENT_IN_RECTANGLE_H +#define IGL_LINE_SEGMENT_IN_RECTANGLE_H +#include "igl_inline.h" +#include +namespace igl +{ + // Determine whether a line segment overlaps with a rectangle. + // + // Inputs: + // s source point of line segment + // d dest point of line segment + // A first corner of rectangle + // B opposite corner of rectangle + // Returns true if line segment is at all inside rectangle + IGL_INLINE bool line_segment_in_rectangle( + const Eigen::Vector2d & s, + const Eigen::Vector2d & d, + const Eigen::Vector2d & A, + const Eigen::Vector2d & B); +} + +#ifndef IGL_STATIC_LIBRARY +# include "line_segment_in_rectangle.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/linprog.cpp b/src/external/libigl-2.3.0/include/igl/linprog.cpp new file mode 100644 index 000000000..b73ffc513 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/linprog.cpp @@ -0,0 +1,302 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "linprog.h" +#include "slice.h" +#include "slice_into.h" +#include "find.h" +#include "colon.h" +#include + +//#define IGL_LINPROG_VERBOSE +IGL_INLINE bool igl::linprog( + const Eigen::VectorXd & c, + const Eigen::MatrixXd & _A, + const Eigen::VectorXd & b, + const int k, + Eigen::VectorXd & x) +{ + // This is a very literal translation of + // http://www.mathworks.com/matlabcentral/fileexchange/2166-introduction-to-linear-algebra/content/strang/linprog.m + using namespace Eigen; + using namespace std; + bool success = true; + // number of constraints + const int m = _A.rows(); + // number of original variables + const int n = _A.cols(); + // number of iterations + int it = 0; + // maximum number of iterations + //const int MAXIT = 10*m; + const int MAXIT = 100*m; + // residual tolerance + const double tol = 1e-10; + const auto & sign = [](const Eigen::VectorXd & B) -> Eigen::VectorXd + { + Eigen::VectorXd Bsign(B.size()); + for(int i = 0;i0?1:(B(i)<0?-1:0); + } + return Bsign; + }; + // initial (inverse) basis matrix + VectorXd Dv = sign(sign(b).array()+0.5); + Dv.head(k).setConstant(1.); + MatrixXd D = Dv.asDiagonal(); + // Incorporate slack variables + MatrixXd A(_A.rows(),_A.cols()+D.cols()); + A<<_A,D; + // Initial basis + VectorXi B = igl::colon(n,n+m-1); + // non-basis, may turn out that vector<> would be better here + VectorXi N = igl::colon(0,n-1); + int j; + double bmin = b.minCoeff(&j); + int phase; + VectorXd xb; + VectorXd s; + VectorXi J; + if(k>0 && bmin<0) + { + phase = 1; + xb = VectorXd::Ones(m); + // super cost + s.resize(n+m+1); + s<(0,n-1),B(j); + J.resize(B.size()-1); + // [0 1 2 3 4] + // ^ + // [0 1] + // [3 4] + J.head(j) = B.head(j); + J.tail(B.size()-j-1) = B.tail(B.size()-j-1); + B(j) = n+m; + MatrixXd AJ; + igl::slice(A,J,2,AJ); + const VectorXd a = b - AJ.rowwise().sum(); + { + MatrixXd old_A = A; + A.resize(A.rows(),A.cols()+a.cols()); + A<=0 + { + phase = 1; + xb = b.array().abs(); + s.resize(n+m); + // super cost + s<::max(); + // Lagrange mutipliers fro Ax=b + VectorXd yb = D.transpose() * igl::slice(s,B); + while(true) + { + if(MAXIT>0 && it>=MAXIT) + { +#ifdef IGL_LINPROG_VERBOSE + cerr<<"linprog: warning! maximum iterations without convergence."<=-tol*(sN.array().abs().maxCoeff()+1)) + { + break; + } + // increment iteration count + it++; + // apply Bland's rule to avoid cycling + if(df>=0) + { + if(MAXIT == -1) + { +#ifdef IGL_LINPROG_VERBOSE + cerr<<"linprog: warning! degenerate vertex"<().maxCoeff(&q); + } + VectorXd d = D*A.col(N(q)); + VectorXi I; + igl::find((d.array()>tol).eval(),I); + if(I.size() == 0) + { +#ifdef IGL_LINPROG_VERBOSE + cerr<<"linprog: warning! solution is unbounded"<=0) + { + igl::find((xbd.array()==r).eval(),J); + double Bp = igl::slice(B,igl::slice(I,J)).minCoeff(); + // idiotic way of finding index in B of Bp + // code down the line seems to assume p is a scalar though the matlab + // code could find a vector of matches) + (B.array()==Bp).cast().maxCoeff(&p); + } + // update x + xb -= r*d; + xb(p) = r; + // change in f + df = r*rmin; + } + // row vector + RowVectorXd v = D.row(p)/d(p); + yb += v.transpose() * (s(N(q)) - d.transpose()*igl::slice(s,B)); + d(p)-=1; + // update inverse basis matrix + D = D - d*v; + t = B(p); + B(p) = N(q); + if(t>(n+k-1)) + { + // remove qth entry from N + VectorXi old_N = N; + N.resize(N.size()-1); + N.head(q) = old_N.head(q); + N.head(q) = old_N.head(q); + N.tail(old_N.size()-q-1) = old_N.tail(old_N.size()-q-1); + }else + { + N(q) = t; + } + } + // iterative refinement + xb = (xb+D*(b-igl::slice(A,B,2)*xb)).eval(); + // must be due to rounding + VectorXi I; + igl::find((xb.array()<0).eval(),I); + if(I.size()>0) + { + // so correct + VectorXd Z = VectorXd::Zero(I.size(),1); + igl::slice_into(Z,I,xb); + } + // B, xb,n,m,res=A(:,B)*xb-b + if(phase == 2 || it<0) + { + break; + } + if(xb.transpose()*igl::slice(s,B) > tol) + { + it = -it; +#ifdef IGL_LINPROG_VERBOSE + cerr<<"linprog: warning, no feasible solution"<double + { + return (x<0?-1:(x>0?1:0)); + }; + AS.row(i) *= sign(b(i)); + } + MatrixXd In = MatrixXd::Identity(n,n); + MatrixXd P(n+m,2*n+m); + P<< In, -In, MatrixXd::Zero(n,m), + MatrixXd::Zero(m,2*n), Im; + MatrixXd ASP = AS*P; + MatrixXd BSP(0,2*n+m); + if(p>0) + { + MatrixXd BS(p,2*n); + BS< +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_LINPROG_H +#define IGL_LINPROG_H +#include "igl_inline.h" +#include +namespace igl +{ + // Solve a linear program given in "standard form" + // + // min f'x + // s.t. A( 1:k,:) x <= b(1:k) + // A(k+1:end,:) x = b(k+1:end) + // ** x >= 0 ** + // + // In contrast to other APIs the entries in b may be negative. + // + // Inputs: + // c #x list of linear coefficients + // A #A by #x matrix of linear constraint coefficients + // b #A list of linear constraint right-hand sides + // k number of inequality constraints as first rows of A,b + // Outputs: + // x #x solution vector + // + IGL_INLINE bool linprog( + const Eigen::VectorXd & c, + const Eigen::MatrixXd & A, + const Eigen::VectorXd & b, + const int k, + Eigen::VectorXd & f); + + // Wrapper in friendlier general form (no implicit bounds on x) + // + // min f'x + // s.t. A x <= b + // B x = c + // + // Inputs: + // f #x list of linear coefficients + // A #A by #x matrix of linear inequality constraint coefficients + // b #A list of linear constraint right-hand sides + // B #B by #x matrix of linear equality constraint coefficients + // c #B list of linear constraint right-hand sides + // Outputs: + // x #x solution vector + // + IGL_INLINE bool linprog( + const Eigen::VectorXd & f, + const Eigen::MatrixXd & A, + const Eigen::VectorXd & b, + const Eigen::MatrixXd & B, + const Eigen::VectorXd & c, + Eigen::VectorXd & x); +} + +#ifndef IGL_STATIC_LIBRARY +# include "linprog.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/list_to_matrix.cpp b/src/external/libigl-2.3.0/include/igl/list_to_matrix.cpp new file mode 100644 index 000000000..bf60e9440 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/list_to_matrix.cpp @@ -0,0 +1,231 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "list_to_matrix.h" + +#include +#include + +#include + +#include "max_size.h" +#include "min_size.h" + +template +IGL_INLINE bool igl::list_to_matrix(const std::vector > & V,Eigen::PlainObjectBase& M) +{ + // number of rows + int m = V.size(); + if(m == 0) + { + M.resize( + Derived::RowsAtCompileTime>=0?Derived::RowsAtCompileTime:0 + , + Derived::ColsAtCompileTime>=0?Derived::ColsAtCompileTime:0 + ); + return true; + } + // number of columns + int n = igl::min_size(V); + if(n != igl::max_size(V)) + { + return false; + } + assert(n != -1); + // Resize output + M.resize(m,n); + + // Loop over rows + for(int i = 0;i +IGL_INLINE bool igl::list_to_matrix(const std::vector > & V,Eigen::PlainObjectBase& M) +{ + // number of rows + int m = V.size(); + if(m == 0) + { + M.resize( + Derived::RowsAtCompileTime>=0?Derived::RowsAtCompileTime:0 + , + Derived::ColsAtCompileTime>=0?Derived::ColsAtCompileTime:0 + ); + return true; + } + // number of columns + int n = static_cast(N); + assert(n != -1); + // Resize output + M.resize(m,n); + + // Loop over rows + for(int i = 0;i +IGL_INLINE bool igl::list_to_matrix( + const std::vector > & V, + const int n, + const T & padding, + Eigen::PlainObjectBase& M) +{ + const int m = V.size(); + M.resize(m,n); + for(int i = 0;in) + { + return false; + } + int j = 0; + for(;j +IGL_INLINE bool igl::list_to_matrix(const std::vector & V,Eigen::PlainObjectBase& M) +{ + // number of rows + int m = V.size(); + if(m == 0) + { + //fprintf(stderr,"Error: list_to_matrix() list is empty()\n"); + //return false; + if(Derived::ColsAtCompileTime == 1) + { + M.resize(0,1); + }else if(Derived::RowsAtCompileTime == 1) + { + M.resize(1,0); + }else + { + M.resize(0,0); + } + return true; + } + // Resize output + if(Derived::RowsAtCompileTime == 1) + { + M.resize(1,m); + }else + { + M.resize(m,1); + } + + // Loop over rows + for(int i = 0;i >(std::vector >, std::allocator > > > const&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template bool igl::list_to_matrix >(std::vector >, std::allocator > > > const&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template bool igl::list_to_matrix >(std::vector >, std::allocator > > > const&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template bool igl::list_to_matrix >(std::vector >, std::allocator > > > const&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +// generated by autoexplicit.sh +// generated by autoexplicit.sh +template bool igl::list_to_matrix >(std::vector >, std::allocator > > > const&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template bool igl::list_to_matrix >(std::vector >, std::allocator > > > const&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template bool igl::list_to_matrix >(std::vector >, std::allocator > > > const&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template bool igl::list_to_matrix >(std::vector >, std::allocator > > > const&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template bool igl::list_to_matrix >(std::vector >, std::allocator > > > const&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template bool igl::list_to_matrix >(std::vector > const&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template bool igl::list_to_matrix >(std::vector > const&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template bool igl::list_to_matrix >(std::vector > const&, Eigen::PlainObjectBase >&); +template bool igl::list_to_matrix >(std::vector >, std::allocator > > > const&, Eigen::PlainObjectBase >&); +template bool igl::list_to_matrix >(std::vector >, std::allocator > > > const&, Eigen::PlainObjectBase >&); +template bool igl::list_to_matrix >(std::vector >, std::allocator > > > const&, Eigen::PlainObjectBase >&); +template bool igl::list_to_matrix >(std::vector >, std::allocator > > > const&, Eigen::PlainObjectBase >&); +template bool igl::list_to_matrix >(std::vector >, std::allocator > > > const&, Eigen::PlainObjectBase >&); +template bool igl::list_to_matrix >(std::vector >, std::allocator > > > const&, Eigen::PlainObjectBase >&); +template bool igl::list_to_matrix >(std::vector >, std::allocator > > > const&, Eigen::PlainObjectBase >&); +template bool igl::list_to_matrix >(std::vector >, std::allocator > > > const&, Eigen::PlainObjectBase >&); +template bool igl::list_to_matrix >(std::vector >, std::allocator > > > const&, Eigen::PlainObjectBase >&); +template bool igl::list_to_matrix >(std::vector > const&, Eigen::PlainObjectBase >&); +template bool igl::list_to_matrix >(std::vector > const&, Eigen::PlainObjectBase >&); +template bool igl::list_to_matrix >(std::vector >, std::allocator > > > const&, Eigen::PlainObjectBase >&); +template bool igl::list_to_matrix >(std::vector > const&, Eigen::PlainObjectBase >&); +template bool igl::list_to_matrix >(std::vector >, std::allocator > > > const&, Eigen::PlainObjectBase >&); +template bool igl::list_to_matrix >(std::vector > const&, Eigen::PlainObjectBase >&); +template bool igl::list_to_matrix >(std::vector >, std::allocator > > > const&, Eigen::PlainObjectBase >&); +template bool igl::list_to_matrix >(std::vector > const&, Eigen::PlainObjectBase >&); +template bool igl::list_to_matrix >(std::vector > const&, Eigen::PlainObjectBase >&); +template bool igl::list_to_matrix >(std::vector > const&, Eigen::PlainObjectBase >&); +template bool igl::list_to_matrix >(std::vector > const&, Eigen::PlainObjectBase >&); +template bool igl::list_to_matrix >(std::vector >, std::allocator > > > const&, Eigen::PlainObjectBase >&); +template bool igl::list_to_matrix >(std::vector > const&, Eigen::PlainObjectBase >&); +template bool igl::list_to_matrix >(std::vector > const&, Eigen::PlainObjectBase >&); + +template bool igl::list_to_matrix >(std::vector, std::allocator > > const&, Eigen::PlainObjectBase >&); +template bool igl::list_to_matrix >(std::vector, std::allocator > > const&, Eigen::PlainObjectBase >&); +template bool igl::list_to_matrix >(std::vector, std::allocator > > const&, Eigen::PlainObjectBase >&); +template bool igl::list_to_matrix >(std::vector, std::allocator > > const&, Eigen::PlainObjectBase >&); +template bool igl::list_to_matrix >(std::vector, std::allocator > > const&, Eigen::PlainObjectBase >&); +template bool igl::list_to_matrix >(std::vector, std::allocator > > const&, Eigen::PlainObjectBase >&); +template bool igl::list_to_matrix >(std::vector, std::allocator > > const&, Eigen::PlainObjectBase >&); +template bool igl::list_to_matrix >(std::vector, std::allocator > > const&, Eigen::PlainObjectBase >&); +template bool igl::list_to_matrix >(std::vector, std::allocator > > const&, Eigen::PlainObjectBase >&); +template bool igl::list_to_matrix >(std::vector, std::allocator > > const&, Eigen::PlainObjectBase >&); +template bool igl::list_to_matrix >(std::vector, std::allocator > > const&, Eigen::PlainObjectBase >&); + +#ifdef WIN32 +template bool igl::list_to_matrix >(std::vector > const&, Eigen::PlainObjectBase >&); +template bool igl::list_to_matrix >(std::vector > const&, Eigen::PlainObjectBase >&); +template bool igl::list_to_matrix >(std::vector > const&, Eigen::PlainObjectBase >&); +template bool igl::list_to_matrix >(std::vector > const&, Eigen::PlainObjectBase >&); +template bool igl::list_to_matrix >(class std::vector > const &, class Eigen::PlainObjectBase > &); +template bool igl::list_to_matrix >(class std::vector > const &,class Eigen::PlainObjectBase > &); +template bool igl::list_to_matrix >(class std::vector > const &,class Eigen::PlainObjectBase > &); +template bool igl::list_to_matrix >(class std::vector > const &,class Eigen::PlainObjectBase > &); +template bool igl::list_to_matrix >(std::vector > const&, Eigen::PlainObjectBase >&); +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/list_to_matrix.h b/src/external/libigl-2.3.0/include/igl/list_to_matrix.h new file mode 100644 index 000000000..34981b257 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/list_to_matrix.h @@ -0,0 +1,62 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_LIST_TO_MATRIX_H +#define IGL_LIST_TO_MATRIX_H +#include "igl_inline.h" +#include +#include +#include + +namespace igl +{ + // Convert a list (std::vector) of row vectors of the same length to a matrix + // Template: + // T type that can be safely cast to type in Mat via '=' + // Mat Matrix type, must implement: + // .resize(m,n) + // .row(i) = Row + // Inputs: + // V a m-long list of vectors of size n + // Outputs: + // M an m by n matrix + // Returns true on success, false on errors + template + IGL_INLINE bool list_to_matrix( + const std::vector > & V, + Eigen::PlainObjectBase& M); + + template + IGL_INLINE bool list_to_matrix( + const std::vector > & V, + Eigen::PlainObjectBase& M); + + // Convert a list of row vectors of `n` or less to a matrix and pad on + // the right with `padding`: + // + // Inputs: + // V a m-long list of vectors of size <=n + // n number of columns + // padding value to fill in from right for short rows + // Outputs: + // M an m by n matrix + template + IGL_INLINE bool list_to_matrix( + const std::vector > & V, + const int n, + const T & padding, + Eigen::PlainObjectBase& M); + // Vector wrapper + template + IGL_INLINE bool list_to_matrix(const std::vector & V,Eigen::PlainObjectBase& M); +} + +#ifndef IGL_STATIC_LIBRARY +# include "list_to_matrix.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/local_basis.cpp b/src/external/libigl-2.3.0/include/igl/local_basis.cpp new file mode 100644 index 000000000..1b40ba0dc --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/local_basis.cpp @@ -0,0 +1,51 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "local_basis.h" + +#include +#include +#include + +#include +#include + + +template +IGL_INLINE void igl::local_basis( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + Eigen::PlainObjectBase& B1, + Eigen::PlainObjectBase& B2, + Eigen::PlainObjectBase& B3 + ) +{ + using namespace Eigen; + using namespace std; + B1.resize(F.rows(),3); + B2.resize(F.rows(),3); + B3.resize(F.rows(),3); + + for (unsigned i=0;i v1 = (V.row(F(i,1)) - V.row(F(i,0))).normalized(); + Eigen::Matrix t = V.row(F(i,2)) - V.row(F(i,0)); + Eigen::Matrix v3 = v1.cross(t).normalized(); + Eigen::Matrix v2 = v1.cross(v3).normalized(); + + B1.row(i) = v1; + B2.row(i) = -v2; + B3.row(i) = v3; + } +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::local_basis, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::local_basis, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/local_basis.h b/src/external/libigl-2.3.0/include/igl/local_basis.h new file mode 100644 index 000000000..5eb2cabaf --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/local_basis.h @@ -0,0 +1,46 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_LOCALBASIS_H +#define IGL_LOCALBASIS_H + +#include "igl_inline.h" +#include +#include +#include + +namespace igl +{ + // Compute a local orthogonal reference system for each triangle in the given mesh + // Templates: + // DerivedV derived from vertex positions matrix type: i.e. MatrixXd + // DerivedF derived from face indices matrix type: i.e. MatrixXi + // Inputs: + // V eigen matrix #V by 3 + // F #F by 3 list of mesh faces (must be triangles) + // Outputs: + // B1 eigen matrix #F by 3, each vector is tangent to the triangle + // B2 eigen matrix #F by 3, each vector is tangent to the triangle and perpendicular to B1 + // B3 eigen matrix #F by 3, normal of the triangle + // + // See also: adjacency_matrix + template + IGL_INLINE void local_basis( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + Eigen::PlainObjectBase& B1, + Eigen::PlainObjectBase& B2, + Eigen::PlainObjectBase& B3 + ); + +} + +#ifndef IGL_STATIC_LIBRARY +# include "local_basis.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/look_at.cpp b/src/external/libigl-2.3.0/include/igl/look_at.cpp new file mode 100644 index 000000000..c55c9b2ec --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/look_at.cpp @@ -0,0 +1,44 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "look_at.h" + +template < + typename Derivedeye, + typename Derivedcenter, + typename Derivedup, + typename DerivedR> +IGL_INLINE void igl::look_at( + const Eigen::PlainObjectBase & eye, + const Eigen::PlainObjectBase & center, + const Eigen::PlainObjectBase & up, + Eigen::PlainObjectBase & R) +{ + typedef Eigen::Matrix Vector3S; + Vector3S f = (center - eye).normalized(); + Vector3S s = f.cross(up).normalized(); + Vector3S u = s.cross(f); + R = Eigen::Matrix::Identity(); + R(0,0) = s(0); + R(0,1) = s(1); + R(0,2) = s(2); + R(1,0) = u(0); + R(1,1) = u(1); + R(1,2) = u(2); + R(2,0) =-f(0); + R(2,1) =-f(1); + R(2,2) =-f(2); + R(0,3) =-s.transpose() * eye; + R(1,3) =-u.transpose() * eye; + R(2,3) = f.transpose() * eye; +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::look_at, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/look_at.h b/src/external/libigl-2.3.0/include/igl/look_at.h new file mode 100644 index 000000000..883cbf94e --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/look_at.h @@ -0,0 +1,42 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_LOOK_AT_H +#define IGL_LOOK_AT_H +#include "igl_inline.h" + +#include + +namespace igl +{ + // Implementation of the deprecated gluLookAt function. + // + // Inputs: + // eye 3-vector of eye position + // center 3-vector of center reference point + // up 3-vector of up vector + // Outputs: + // R 4x4 rotation matrix + // + template < + typename Derivedeye, + typename Derivedcenter, + typename Derivedup, + typename DerivedR > + IGL_INLINE void look_at( + const Eigen::PlainObjectBase & eye, + const Eigen::PlainObjectBase & center, + const Eigen::PlainObjectBase & up, + Eigen::PlainObjectBase & R); +} + +#ifndef IGL_STATIC_LIBRARY +# include "look_at.cpp" +#endif + +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/loop.cpp b/src/external/libigl-2.3.0/include/igl/loop.cpp new file mode 100644 index 000000000..e353e4643 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/loop.cpp @@ -0,0 +1,173 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Oded Stein +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +#include "loop.h" + +#include +#include +#include + +#include + +template < + typename DerivedF, + typename SType, + typename DerivedNF> +IGL_INLINE void igl::loop( + const int n_verts, + const Eigen::MatrixBase & F, + Eigen::SparseMatrix& S, + Eigen::PlainObjectBase & NF) +{ + typedef Eigen::SparseMatrix SparseMat; + typedef Eigen::Triplet Triplet_t; + + //Ref. https://graphics.stanford.edu/~mdfisher/subdivision.html + //Heavily borrowing from igl::upsample + + Eigen::Matrix FF, FFi; + triangle_triangle_adjacency(F, FF, FFi); + std::vector> adjacencyList; + adjacency_list(F, adjacencyList, true); + + //Compute the number and positions of the vertices to insert (on edges) + Eigen::MatrixXi NI = Eigen::MatrixXi::Constant(FF.rows(), FF.cols(), -1); + Eigen::MatrixXi NIdoubles = Eigen::MatrixXi::Zero(FF.rows(), FF.cols()); + Eigen::VectorXi vertIsOnBdry = Eigen::VectorXi::Zero(n_verts); + int counter = 0; + for(int i=0; i tripletList; + for(int i=0; i VI(6); + VI << F(i,0), F(i,1), F(i,2), NI(i,0) + n_odd, NI(i,1) + n_odd, NI(i,2) + n_odd; + + Eigen::Matrix f0(3), f1(3), f2(3), f3(3); + f0 << VI(0), VI(3), VI(5); + f1 << VI(1), VI(4), VI(3); + f2 << VI(3), VI(4), VI(5); + f3 << VI(4), VI(2), VI(5); + + NF.row((i*4)+0) = f0; + NF.row((i*4)+1) = f1; + NF.row((i*4)+2) = f2; + NF.row((i*4)+3) = f3; + } +} + +template < + typename DerivedV, + typename DerivedF, + typename DerivedNV, + typename DerivedNF> +IGL_INLINE void igl::loop( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + Eigen::PlainObjectBase& NV, + Eigen::PlainObjectBase& NF, + const int number_of_subdivs) +{ + NV = V; + NF = F; + for(int i=0; i S; + loop(NV.rows(), tempF, S, NF); + // This .eval is super important + NV = (S*NV).eval(); + } +} + +#ifdef IGL_STATIC_LIBRARY +template void igl::loop, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix>(Eigen::MatrixBase> const &, Eigen::MatrixBase> const &, Eigen::PlainObjectBase> &, Eigen::PlainObjectBase> &, int); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/loop.h b/src/external/libigl-2.3.0/include/igl/loop.h new file mode 100644 index 000000000..8e70a40b1 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/loop.h @@ -0,0 +1,63 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Oded Stein +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef IGL_LOOP_H +#define IGL_LOOP_H + +#include +#include +#include + +namespace igl +{ + // LOOP Given the triangle mesh [V, F], where n_verts = V.rows(), computes + // newV and a sparse matrix S s.t. [newV, newF] is the subdivided mesh where + // newV = S*V. + // + // Inputs: + // n_verts an integer (number of mesh vertices) + // F an m by 3 matrix of integers of triangle faces + // Outputs: + // S a sparse matrix (will become the subdivision matrix) + // newF a matrix containing the new faces + template < + typename DerivedF, + typename SType, + typename DerivedNF> + IGL_INLINE void loop( + const int n_verts, + const Eigen::MatrixBase & F, + Eigen::SparseMatrix& S, + Eigen::PlainObjectBase & NF); + // LOOP Given the triangle mesh [V, F], computes number_of_subdivs steps of loop subdivision and outputs the new mesh [newV, newF] + // + // Inputs: + // V an n by 3 matrix of vertices + // F an m by 3 matrix of integers of triangle faces + // number_of_subdivs an integer that specifies how many subdivision steps to do + // Outputs: + // NV a matrix containing the new vertices + // NF a matrix containing the new faces + template < + typename DerivedV, + typename DerivedF, + typename DerivedNV, + typename DerivedNF> + IGL_INLINE void loop( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + Eigen::PlainObjectBase& NV, + Eigen::PlainObjectBase& NF, + const int number_of_subdivs = 1); +} + +#ifndef IGL_STATIC_LIBRARY +# include "loop.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/lscm.cpp b/src/external/libigl-2.3.0/include/igl/lscm.cpp new file mode 100644 index 000000000..6932f94d4 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/lscm.cpp @@ -0,0 +1,72 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Daniele Panozzo +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "lscm.h" + +#include "vector_area_matrix.h" +#include "cotmatrix.h" +#include "repdiag.h" +#include "min_quad_with_fixed.h" +#include + +IGL_INLINE bool igl::lscm( + const Eigen::MatrixXd& V, + const Eigen::MatrixXi& F, + const Eigen::VectorXi& b, + const Eigen::MatrixXd& bc, + Eigen::MatrixXd & V_uv) +{ + using namespace Eigen; + using namespace std; + + // Assemble the area matrix (note that A is #Vx2 by #Vx2) + SparseMatrix A; + igl::vector_area_matrix(F,A); + + // Assemble the cotan laplacian matrix + SparseMatrix L; + igl::cotmatrix(V,F,L); + + SparseMatrix L_flat; + repdiag(L,2,L_flat); + + VectorXi b_flat(b.size()*bc.cols(),1); + VectorXd bc_flat(bc.size(),1); + for(int c = 0;c Q = -L_flat + 2.*A; + const VectorXd B_flat = VectorXd::Zero(V.rows()*2); + igl::min_quad_with_fixed_data data; + if(!igl::min_quad_with_fixed_precompute(Q,b_flat,SparseMatrix(),true,data)) + { + return false; + } + + MatrixXd W_flat; + if(!min_quad_with_fixed_solve(data,B_flat,bc_flat,VectorXd(),W_flat)) + { + return false; + } + + + assert(W_flat.rows() == V.rows()*2); + V_uv.resize(V.rows(),2); + for (unsigned i=0;i +// 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_LSCM_H +#define IGL_LSCM_H +#include "igl_inline.h" + +#include +#include + +namespace igl +{ + // Compute a Least-squares conformal map parametrization (equivalently + // derived in "Intrinsic Parameterizations of Surface Meshes" [Desbrun et al. + // 2002] and "Least Squares Conformal Maps for Automatic Texture Atlas + // Generation" [Lévy et al. 2002]), though this implementation follows the + // derivation in: "Spectral Conformal Parameterization" [Mullen et al. 2008] + // (note, this does **not** implement the Eigen-decomposition based method in + // [Mullen et al. 2008], which is not equivalent). Input should be a manifold + // mesh (also no unreferenced vertices) and "boundary" (fixed vertices) `b` + // should contain at least two vertices per connected component. + // + // Inputs: + // V #V by 3 list of mesh vertex positions + // F #F by 3 list of mesh faces (must be triangles) + // b #b boundary indices into V + // bc #b by 3 list of boundary values + // Outputs: + // UV #V by 2 list of 2D mesh vertex positions in UV space + // Returns true only on solver success. + // + IGL_INLINE bool lscm( + const Eigen::MatrixXd& V, + const Eigen::MatrixXi& F, + const Eigen::VectorXi& b, + const Eigen::MatrixXd& bc, + Eigen::MatrixXd& V_uv); +} + +#ifndef IGL_STATIC_LIBRARY +# include "lscm.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/map_vertices_to_circle.cpp b/src/external/libigl-2.3.0/include/igl/map_vertices_to_circle.cpp new file mode 100644 index 000000000..233613936 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/map_vertices_to_circle.cpp @@ -0,0 +1,54 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Stefan Brugger +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +#include "map_vertices_to_circle.h" +#include "PI.h" + +IGL_INLINE void igl::map_vertices_to_circle( + const Eigen::MatrixXd& V, + const Eigen::VectorXi& bnd, + Eigen::MatrixXd& UV) +{ + // Get sorted list of boundary vertices + std::vector interior,map_ij; + map_ij.resize(V.rows()); + + std::vector isOnBnd(V.rows(),false); + for (int i = 0; i < bnd.size(); i++) + { + isOnBnd[bnd[i]] = true; + map_ij[bnd[i]] = i; + } + + for (int i = 0; i < (int)isOnBnd.size(); i++) + { + if (!isOnBnd[i]) + { + map_ij[i] = interior.size(); + interior.push_back(i); + } + } + + // Map boundary to unit circle + std::vector len(bnd.size()); + len[0] = 0.; + + for (int i = 1; i < bnd.size(); i++) + { + len[i] = len[i-1] + (V.row(bnd[i-1]) - V.row(bnd[i])).norm(); + } + double total_len = len[len.size()-1] + (V.row(bnd[0]) - V.row(bnd[bnd.size()-1])).norm(); + + UV.resize(bnd.size(),2); + for (int i = 0; i < bnd.size(); i++) + { + double frac = len[i] * 2. * igl::PI / total_len; + UV.row(map_ij[bnd[i]]) << cos(frac), sin(frac); + } + +} diff --git a/src/external/libigl-2.3.0/include/igl/map_vertices_to_circle.h b/src/external/libigl-2.3.0/include/igl/map_vertices_to_circle.h new file mode 100644 index 000000000..54743717f --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/map_vertices_to_circle.h @@ -0,0 +1,38 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Stefan Brugger +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_MAP_VERTICES_TO_CIRCLE_H +#define IGL_MAP_VERTICES_TO_CIRCLE_H +#include "igl_inline.h" +#include "PI.h" + +#include +#include + +namespace igl +{ + + // Map the vertices whose indices are in a given boundary loop (bnd) on the + // unit circle with spacing proportional to the original boundary edge + // lengths. + // + // Inputs: + // V #V by dim list of mesh vertex positions + // b #W list of vertex ids + // Outputs: + // UV #W by 2 list of 2D position on the unit circle for the vertices in b + IGL_INLINE void map_vertices_to_circle( + const Eigen::MatrixXd& V, + const Eigen::VectorXi& bnd, + Eigen::MatrixXd& UV); +} + +#ifndef IGL_STATIC_LIBRARY +# include "map_vertices_to_circle.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/mapping_energy_with_jacobians.cpp b/src/external/libigl-2.3.0/include/igl/mapping_energy_with_jacobians.cpp new file mode 100644 index 000000000..791e01f89 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/mapping_energy_with_jacobians.cpp @@ -0,0 +1,141 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2018 Zhongshi Jiang +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +#include "mapping_energy_with_jacobians.h" +#include "polar_svd.h" + +IGL_INLINE double igl::mapping_energy_with_jacobians( + const Eigen::MatrixXd &Ji, + const Eigen::VectorXd &areas, + igl::MappingEnergyType slim_energy, + double exp_factor){ + + double energy = 0; + if (Ji.cols() == 4) + { + Eigen::Matrix ji; + for (int i = 0; i < Ji.rows(); i++) + { + ji(0, 0) = Ji(i, 0); + ji(0, 1) = Ji(i, 1); + ji(1, 0) = Ji(i, 2); + ji(1, 1) = Ji(i, 3); + + typedef Eigen::Matrix Mat2; + typedef Eigen::Matrix Vec2; + Mat2 ri, ti, ui, vi; + Vec2 sing; + igl::polar_svd(ji, ri, ti, ui, sing, vi); + double s1 = sing(0); + double s2 = sing(1); + + switch (slim_energy) + { + case igl::MappingEnergyType::ARAP: + { + energy += areas(i) * (pow(s1 - 1, 2) + pow(s2 - 1, 2)); + break; + } + case igl::MappingEnergyType::SYMMETRIC_DIRICHLET: + { + energy += areas(i) * (pow(s1, 2) + pow(s1, -2) + pow(s2, 2) + pow(s2, -2)); + break; + } + case igl::MappingEnergyType::EXP_SYMMETRIC_DIRICHLET: + { + energy += areas(i) * exp(exp_factor * (pow(s1, 2) + pow(s1, -2) + pow(s2, 2) + pow(s2, -2))); + break; + } + case igl::MappingEnergyType::LOG_ARAP: + { + energy += areas(i) * (pow(log(s1), 2) + pow(log(s2), 2)); + break; + } + case igl::MappingEnergyType::CONFORMAL: + { + energy += areas(i) * ((pow(s1, 2) + pow(s2, 2)) / (2 * s1 * s2)); + break; + } + case igl::MappingEnergyType::EXP_CONFORMAL: + { + energy += areas(i) * exp(exp_factor * ((pow(s1, 2) + pow(s2, 2)) / (2 * s1 * s2))); + break; + } + + } + + } + } + else + { + Eigen::Matrix ji; + for (int i = 0; i < Ji.rows(); i++) + { + ji(0, 0) = Ji(i, 0); + ji(0, 1) = Ji(i, 1); + ji(0, 2) = Ji(i, 2); + ji(1, 0) = Ji(i, 3); + ji(1, 1) = Ji(i, 4); + ji(1, 2) = Ji(i, 5); + ji(2, 0) = Ji(i, 6); + ji(2, 1) = Ji(i, 7); + ji(2, 2) = Ji(i, 8); + + typedef Eigen::Matrix Mat3; + typedef Eigen::Matrix Vec3; + Mat3 ri, ti, ui, vi; + Vec3 sing; + igl::polar_svd(ji, ri, ti, ui, sing, vi); + double s1 = sing(0); + double s2 = sing(1); + double s3 = sing(2); + + switch (slim_energy) + { + case igl::MappingEnergyType::ARAP: + { + energy += areas(i) * (pow(s1 - 1, 2) + pow(s2 - 1, 2) + pow(s3 - 1, 2)); + break; + } + case igl::MappingEnergyType::SYMMETRIC_DIRICHLET: + { + energy += areas(i) * (pow(s1, 2) + pow(s1, -2) + pow(s2, 2) + pow(s2, -2) + pow(s3, 2) + pow(s3, -2)); + break; + } + case igl::MappingEnergyType::EXP_SYMMETRIC_DIRICHLET: + { + energy += areas(i) * exp(exp_factor * + (pow(s1, 2) + pow(s1, -2) + pow(s2, 2) + pow(s2, -2) + pow(s3, 2) + pow(s3, -2))); + break; + } + case igl::MappingEnergyType::LOG_ARAP: + { + energy += areas(i) * (pow(log(s1), 2) + pow(log(std::abs(s2)), 2) + pow(log(std::abs(s3)), 2)); + break; + } + case igl::MappingEnergyType::CONFORMAL: + { + energy += areas(i) * ((pow(s1, 2) + pow(s2, 2) + pow(s3, 2)) / (3 * pow(s1 * s2 * s3, 2. / 3.))); + break; + } + case igl::MappingEnergyType::EXP_CONFORMAL: + { + energy += areas(i) * exp((pow(s1, 2) + pow(s2, 2) + pow(s3, 2)) / (3 * pow(s1 * s2 * s3, 2. / 3.))); + break; + } + } + } + } + + return energy; +} + + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +#endif diff --git a/src/external/libigl-2.3.0/include/igl/mapping_energy_with_jacobians.h b/src/external/libigl-2.3.0/include/igl/mapping_energy_with_jacobians.h new file mode 100644 index 000000000..2952db60d --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/mapping_energy_with_jacobians.h @@ -0,0 +1,36 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2018 Zhongshi Jiang +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_MAPPING_ENERGY_WITH_JACOBIANS_H +#define IGL_MAPPING_ENERGY_WITH_JACOBIANS_H + +#include "igl_inline.h" +#include +#include "MappingEnergyType.h" + +namespace igl +{ + // compute the rotation-invariant energy of a mapping (represented in Jacobians and areas) + // Input: + // Ji: #F by 4 (9 if 3D) entries of jacobians + // areas: #F by 1 face areas + // slim_energy: energy type as in igl::MappingEnergyType + // exp_factor: see igl::MappingEnergyType + // + // Output: + // energy value + IGL_INLINE double mapping_energy_with_jacobians(const Eigen::MatrixXd &Ji, + const Eigen::VectorXd &areas, + igl::MappingEnergyType slim_energy, + double exp_factor); + +} +#ifndef IGL_STATIC_LIBRARY +# include "mapping_energy_with_jacobians.cpp" +#endif + +#endif \ No newline at end of file diff --git a/src/external/libigl-2.3.0/include/igl/march_cube.cpp b/src/external/libigl-2.3.0/include/igl/march_cube.cpp new file mode 100644 index 000000000..86736ab7d --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/march_cube.cpp @@ -0,0 +1,136 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2021 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "march_cube.h" + +// Something bad is happening when I made this a function. Maybe +// something is not inlining? It ends up 1.25× slower than if the code is pasted +// into the respective functions in igl::marching_cubes +// +// Even if I make it a lambda with no arguments (all capture by reference [&]) +// and call it immediately I get a 1.25× slow-down. +// +// Maybe keeping it out of a function allows the compiler to optimize with the +// loop? But then I guess that measn this function is not getting inlined? Or +// that it's not getting optimized after inlining? +// +template < + typename DerivedGV, + typename Scalar, + typename Index, + typename DerivedV, + typename DerivedF> +IGL_INLINE void igl::march_cube( + const DerivedGV & GV, + const Eigen::Matrix & cS, + const Eigen::Matrix & cI, + const Scalar & isovalue, + Eigen::PlainObjectBase &V, + Index & n, + Eigen::PlainObjectBase &F, + Index & m, + std::unordered_map & E2V) +{ + +// These consts get stored reasonably +#include "marching_cubes_tables.h" + + // Seems this is also successfully inlined + const auto ij2vertex = + [&E2V,&V,&n,&GV] + (const Index & i, const Index & j, const Scalar & t)->Index + { + // Seems this is successfully inlined. + const auto ij2key = [](int32_t i,int32_t j) + { + if(i>j){ std::swap(i,j); } + std::int64_t ret = 0; + ret |= i; + ret |= static_cast(j) << 32; + return ret; + }; + const auto key = ij2key(i,j); + const auto it = E2V.find(key); + int v = -1; + if(it == E2V.end()) + { + // new vertex + if(n==V.rows()){ V.conservativeResize(V.rows()*2+1,V.cols()); } + V.row(n) = GV.row(i) + t*(GV.row(j) - GV.row(i)); + v = n; + E2V[key] = v; + n++; + }else + { + v = it->second; + } + return v; + }; + + int c_flags = 0; + for(int c = 0; c < 8; c++) + { + if(cS(c) > isovalue){ c_flags |= 1< edge_vertices; + for(int e = 0; e < 12; e++) + { +#ifndef NDEBUG + edge_vertices[e] = -1; +#endif + //if there is an intersection on this edge + if(e_flags & (1<= 0); + assert(edge_vertices[e] < n); + } + } + // Insert the triangles that were found. There can be up to five per cube + for(int f = 0; f < 5; f++) + { + if(a2fConnectionTable[c_flags][3*f] < 0) break; + if(m==F.rows()){ F.conservativeResize(F.rows()*2+1,F.cols()); } + assert(edge_vertices[a2fConnectionTable[c_flags][3*f+0]]>=0); + assert(edge_vertices[a2fConnectionTable[c_flags][3*f+1]]>=0); + assert(edge_vertices[a2fConnectionTable[c_flags][3*f+2]]>=0); + F.row(m) << + edge_vertices[a2fConnectionTable[c_flags][3*f+0]], + edge_vertices[a2fConnectionTable[c_flags][3*f+1]], + edge_vertices[a2fConnectionTable[c_flags][3*f+2]]; + m++; + } +} + + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +template void igl::march_cube >, float, unsigned int, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::Matrix const&, Eigen::Matrix const&, float const&, Eigen::PlainObjectBase >&, unsigned int&, Eigen::PlainObjectBase >&, unsigned int&, std::unordered_map, std::equal_to, std::allocator > >&); +template void igl::march_cube >, double, unsigned int, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::Matrix const&, Eigen::Matrix const&, double const&, Eigen::PlainObjectBase >&, unsigned int&, Eigen::PlainObjectBase >&, unsigned int&, std::unordered_map, std::equal_to, std::allocator > >&); +template void igl::march_cube >, double, long, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::Matrix const&, Eigen::Matrix const&, double const&, Eigen::PlainObjectBase >&, long&, Eigen::PlainObjectBase >&, long&, std::unordered_map, std::equal_to, std::allocator > >&); +template void igl::march_cube >, double, unsigned int, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::Matrix const&, Eigen::Matrix const&, double const&, Eigen::PlainObjectBase >&, unsigned int&, Eigen::PlainObjectBase >&, unsigned int&, std::unordered_map, std::equal_to, std::allocator > >&); +#ifdef WIN32 +template void __cdecl igl::march_cube >,double,__int64,class Eigen::Matrix,class Eigen::Matrix >(class Eigen::MatrixBase > const &,class Eigen::Matrix const &,class Eigen::Matrix<__int64,8,1,0,8,1> const &,double const &,class Eigen::PlainObjectBase > &,__int64 &,class Eigen::PlainObjectBase > &,__int64 &,class std::unordered_map<__int64,int,struct std::hash<__int64>,struct std::equal_to<__int64>,class std::allocator > > &); +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/march_cube.h b/src/external/libigl-2.3.0/include/igl/march_cube.h new file mode 100644 index 000000000..75f0e0e07 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/march_cube.h @@ -0,0 +1,52 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2021 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_MARCH_CUBE_H +#define IGL_MARCH_CUBE_H +#include "igl_inline.h" +#include +#include +namespace igl +{ + // Process a single cube of a marching cubes grid. + // + // Inputs: + // GV #GV by 3 list of grid vertex positions + // cS list of 8 scalar field values at grid corners + // cI list of 8 indices of corners into rows of GV + // isovalue level-set value being extracted (often 0) + // V #V by 3 current list of output mesh vertex positions + // n current number of mesh vertices (i.e., occupied rows in V) + // F #F by 3 current list of output mesh triangle indices into rows of V + // m current number of mesh triangles (i.e., occupied rows in F) + // E2V current edge (GV_i,GV_j) to vertex (V_k) map + // Side-effects: V,n,F,m,E2V are updated to contain new vertices and faces of + // any constructed mesh elements + // + template < + typename DerivedGV, + typename Scalar, + typename Index, + typename DerivedV, + typename DerivedF> + IGL_INLINE void march_cube( + const DerivedGV & GV, + const Eigen::Matrix & cS, + const Eigen::Matrix & cI, + const Scalar & isovalue, + Eigen::PlainObjectBase &V, + Index & n, + Eigen::PlainObjectBase &F, + Index & m, + std::unordered_map & E2V); +} + +#ifndef IGL_STATIC_LIBRARY +# include "march_cube.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/marching_cubes.cpp b/src/external/libigl-2.3.0/include/igl/marching_cubes.cpp new file mode 100644 index 000000000..c335f46b7 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/marching_cubes.cpp @@ -0,0 +1,138 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2021 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "marching_cubes.h" +#include "march_cube.h" + +// Adapted from public domain code at +// http://paulbourke.net/geometry/polygonise/marchingsource.cpp + +#include +#include + +template +IGL_INLINE void igl::marching_cubes( + const Eigen::MatrixBase &S, + const Eigen::MatrixBase &GV, + const unsigned nx, + const unsigned ny, + const unsigned nz, + const typename DerivedS::Scalar isovalue, + Eigen::PlainObjectBase &V, + Eigen::PlainObjectBase &F) +{ + typedef typename DerivedS::Scalar Scalar; + typedef unsigned Index; + // use same order as a2fVertexOffset + const unsigned ioffset[8] = {0,1,1+nx,nx,nx*ny,1+nx*ny,1+nx+nx*ny,nx+nx*ny}; + + + std::unordered_map E2V; + V.resize(std::pow(nx*ny*nz,2./3.),3); + F.resize(std::pow(nx*ny*nz,2./3.),3); + Index n = 0; + Index m = 0; + + const auto xyz2i = [&nx,&ny,&nz] + (const int & x, const int & y, const int & z)->unsigned + { + return x+nx*(y+ny*(z)); + }; + const auto cube = + [ + &GV,&S,&V,&n,&F,&m,&isovalue, + &E2V,&xyz2i,&ioffset + ] + (const int x, const int y, const int z) + { + const unsigned i = xyz2i(x,y,z); + + //Make a local copy of the values at the cube's corners + static Eigen::Matrix cS; + static Eigen::Matrix cI; + //Find which vertices are inside of the surface and which are outside + for(int c = 0; c < 8; c++) + { + const unsigned ic = i + ioffset[c]; + cI(c) = ic; + cS(c) = S(ic); + } + + march_cube(GV,cS,cI,isovalue,V,n,F,m,E2V); + + }; + + // march over all cubes (loop order chosen to match memory) + // + // Should be possible to parallelize safely if threads are "well separated". + // Like red-black Gauss Seidel. Probably each thread need's their own E2V,V,F, + // and then merge at the end. Annoying part are the edges lying on the + // interface between chunks. + for(int z=0;z +IGL_INLINE void igl::marching_cubes( + const Eigen::MatrixBase & S, + const Eigen::MatrixBase & GV, + const Eigen::MatrixBase & GI, + const typename DerivedS::Scalar isovalue, + Eigen::PlainObjectBase &V, + Eigen::PlainObjectBase &F) +{ + typedef Eigen::Index Index; + typedef typename DerivedV::Scalar Scalar; + + std::unordered_map E2V; + V.resize(4*GV.rows(),3); + F.resize(4*GV.rows(),3); + Index n = 0; + Index m = 0; + + // march over cubes + for(Index c = 0;c cS; + static Eigen::Matrix cI; + for(int v = 0; v < 8; v++) + { + cI(v) = GI(c,v); + cS(v) = S(GI(c,v)); + } + march_cube(GV,cS,cI,isovalue,V,n,F,m,E2V); + } + V.conservativeResize(n,3); + F.conservativeResize(m,3); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::marching_cubes, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, unsigned int, unsigned int, unsigned int, Eigen::Matrix::Scalar, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::marching_cubes, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, unsigned int, unsigned int, unsigned int, Eigen::Matrix::Scalar, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::marching_cubes, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, unsigned int, unsigned int, unsigned int, Eigen::Matrix::Scalar, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::marching_cubes, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::Matrix::Scalar, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/marching_cubes.h b/src/external/libigl-2.3.0/include/igl/marching_cubes.h new file mode 100644 index 000000000..e56d3bb87 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/marching_cubes.h @@ -0,0 +1,65 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2020 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_MARCHING_CUBES_H +#define IGL_MARCHING_CUBES_H +#include "igl_inline.h" + +#include +namespace igl +{ + // marching_cubes( values, points, x_res, y_res, z_res, isovalue, vertices, faces ) + // + // performs marching cubes reconstruction on a grid defined by values, and + // points, and generates a mesh defined by vertices and faces + // + // Input: + // S nx*ny*nz list of values at each grid corner + // i.e. S(x + y*xres + z*xres*yres) for corner (x,y,z) + // GV nx*ny*nz by 3 array of corresponding grid corner vertex locations + // nx resolutions of the grid in x dimension + // ny resolutions of the grid in y dimension + // nz resolutions of the grid in z dimension + // isovalue the isovalue of the surface to reconstruct + // Output: + // V #V by 3 list of mesh vertex positions + // F #F by 3 list of mesh triangle indices into rows of V + // + template < + typename DerivedS, + typename DerivedGV, + typename DerivedV, + typename DerivedF> + IGL_INLINE void marching_cubes( + const Eigen::MatrixBase & S, + const Eigen::MatrixBase & GV, + const unsigned nx, + const unsigned ny, + const unsigned nz, + const typename DerivedS::Scalar isovalue, + Eigen::PlainObjectBase &V, + Eigen::PlainObjectBase &F); + template < + typename DerivedS, + typename DerivedGV, + typename DerivedGI, + typename DerivedV, + typename DerivedF> + IGL_INLINE void marching_cubes( + const Eigen::MatrixBase & S, + const Eigen::MatrixBase & GV, + const Eigen::MatrixBase & GI, + const typename DerivedS::Scalar isovalue, + Eigen::PlainObjectBase &V, + Eigen::PlainObjectBase &F); +} + +#ifndef IGL_STATIC_LIBRARY +# include "marching_cubes.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/marching_cubes_tables.h b/src/external/libigl-2.3.0/include/igl/marching_cubes_tables.h new file mode 100644 index 000000000..84fb909ac --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/marching_cubes_tables.h @@ -0,0 +1,293 @@ + const int aiCubeEdgeFlags[256]= + { + 0x000, 0x109, 0x203, 0x30a, 0x406, 0x50f, 0x605, 0x70c, 0x80c, 0x905, 0xa0f, 0xb06, 0xc0a, 0xd03, 0xe09, 0xf00, + 0x190, 0x099, 0x393, 0x29a, 0x596, 0x49f, 0x795, 0x69c, 0x99c, 0x895, 0xb9f, 0xa96, 0xd9a, 0xc93, 0xf99, 0xe90, + 0x230, 0x339, 0x033, 0x13a, 0x636, 0x73f, 0x435, 0x53c, 0xa3c, 0xb35, 0x83f, 0x936, 0xe3a, 0xf33, 0xc39, 0xd30, + 0x3a0, 0x2a9, 0x1a3, 0x0aa, 0x7a6, 0x6af, 0x5a5, 0x4ac, 0xbac, 0xaa5, 0x9af, 0x8a6, 0xfaa, 0xea3, 0xda9, 0xca0, + 0x460, 0x569, 0x663, 0x76a, 0x066, 0x16f, 0x265, 0x36c, 0xc6c, 0xd65, 0xe6f, 0xf66, 0x86a, 0x963, 0xa69, 0xb60, + 0x5f0, 0x4f9, 0x7f3, 0x6fa, 0x1f6, 0x0ff, 0x3f5, 0x2fc, 0xdfc, 0xcf5, 0xfff, 0xef6, 0x9fa, 0x8f3, 0xbf9, 0xaf0, + 0x650, 0x759, 0x453, 0x55a, 0x256, 0x35f, 0x055, 0x15c, 0xe5c, 0xf55, 0xc5f, 0xd56, 0xa5a, 0xb53, 0x859, 0x950, + 0x7c0, 0x6c9, 0x5c3, 0x4ca, 0x3c6, 0x2cf, 0x1c5, 0x0cc, 0xfcc, 0xec5, 0xdcf, 0xcc6, 0xbca, 0xac3, 0x9c9, 0x8c0, + 0x8c0, 0x9c9, 0xac3, 0xbca, 0xcc6, 0xdcf, 0xec5, 0xfcc, 0x0cc, 0x1c5, 0x2cf, 0x3c6, 0x4ca, 0x5c3, 0x6c9, 0x7c0, + 0x950, 0x859, 0xb53, 0xa5a, 0xd56, 0xc5f, 0xf55, 0xe5c, 0x15c, 0x055, 0x35f, 0x256, 0x55a, 0x453, 0x759, 0x650, + 0xaf0, 0xbf9, 0x8f3, 0x9fa, 0xef6, 0xfff, 0xcf5, 0xdfc, 0x2fc, 0x3f5, 0x0ff, 0x1f6, 0x6fa, 0x7f3, 0x4f9, 0x5f0, + 0xb60, 0xa69, 0x963, 0x86a, 0xf66, 0xe6f, 0xd65, 0xc6c, 0x36c, 0x265, 0x16f, 0x066, 0x76a, 0x663, 0x569, 0x460, + 0xca0, 0xda9, 0xea3, 0xfaa, 0x8a6, 0x9af, 0xaa5, 0xbac, 0x4ac, 0x5a5, 0x6af, 0x7a6, 0x0aa, 0x1a3, 0x2a9, 0x3a0, + 0xd30, 0xc39, 0xf33, 0xe3a, 0x936, 0x83f, 0xb35, 0xa3c, 0x53c, 0x435, 0x73f, 0x636, 0x13a, 0x033, 0x339, 0x230, + 0xe90, 0xf99, 0xc93, 0xd9a, 0xa96, 0xb9f, 0x895, 0x99c, 0x69c, 0x795, 0x49f, 0x596, 0x29a, 0x393, 0x099, 0x190, + 0xf00, 0xe09, 0xd03, 0xc0a, 0xb06, 0xa0f, 0x905, 0x80c, 0x70c, 0x605, 0x50f, 0x406, 0x30a, 0x203, 0x109, 0x000 + }; + //a2eConnection lists the index of the endpoint vertices for each of the 12 edges of the cube + const int a2eConnection[12][2] = + { + {0,1}, {1,2}, {2,3}, {3,0}, + {4,5}, {5,6}, {6,7}, {7,4}, + {0,4}, {1,5}, {2,6}, {3,7} + }; + // For each of the possible vertex states listed in aiCubeEdgeFlags there is a specific triangulation + // of the edge intersection points. a2fConnectionTable lists all of them in the form of + // 0-5 edge triples with the list terminated by the invalid value -1. + // For example: a2fConnectionTable[3] list the 2 triangles formed when corner[0] + // and corner[1] are inside of the surface, but the rest of the cube is not. + // + // I found this table in an example program someone wrote long ago. It was probably generated by hand + const int a2fConnectionTable[256][16] = + { + {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {0, 1, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 8, 3, 9, 8, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {0, 8, 3, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {9, 2, 10, 0, 2, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {2, 8, 3, 2, 10, 8, 10, 9, 8, -1, -1, -1, -1, -1, -1, -1}, + {3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {0, 11, 2, 8, 11, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 9, 0, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 11, 2, 1, 9, 11, 9, 8, 11, -1, -1, -1, -1, -1, -1, -1}, + {3, 10, 1, 11, 10, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {0, 10, 1, 0, 8, 10, 8, 11, 10, -1, -1, -1, -1, -1, -1, -1}, + {3, 9, 0, 3, 11, 9, 11, 10, 9, -1, -1, -1, -1, -1, -1, -1}, + {9, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {4, 3, 0, 7, 3, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {0, 1, 9, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {4, 1, 9, 4, 7, 1, 7, 3, 1, -1, -1, -1, -1, -1, -1, -1}, + {1, 2, 10, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {3, 4, 7, 3, 0, 4, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1}, + {9, 2, 10, 9, 0, 2, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1}, + {2, 10, 9, 2, 9, 7, 2, 7, 3, 7, 9, 4, -1, -1, -1, -1}, + {8, 4, 7, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {11, 4, 7, 11, 2, 4, 2, 0, 4, -1, -1, -1, -1, -1, -1, -1}, + {9, 0, 1, 8, 4, 7, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1}, + {4, 7, 11, 9, 4, 11, 9, 11, 2, 9, 2, 1, -1, -1, -1, -1}, + {3, 10, 1, 3, 11, 10, 7, 8, 4, -1, -1, -1, -1, -1, -1, -1}, + {1, 11, 10, 1, 4, 11, 1, 0, 4, 7, 11, 4, -1, -1, -1, -1}, + {4, 7, 8, 9, 0, 11, 9, 11, 10, 11, 0, 3, -1, -1, -1, -1}, + {4, 7, 11, 4, 11, 9, 9, 11, 10, -1, -1, -1, -1, -1, -1, -1}, + {9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {9, 5, 4, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {0, 5, 4, 1, 5, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {8, 5, 4, 8, 3, 5, 3, 1, 5, -1, -1, -1, -1, -1, -1, -1}, + {1, 2, 10, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {3, 0, 8, 1, 2, 10, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1}, + {5, 2, 10, 5, 4, 2, 4, 0, 2, -1, -1, -1, -1, -1, -1, -1}, + {2, 10, 5, 3, 2, 5, 3, 5, 4, 3, 4, 8, -1, -1, -1, -1}, + {9, 5, 4, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {0, 11, 2, 0, 8, 11, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1}, + {0, 5, 4, 0, 1, 5, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1}, + {2, 1, 5, 2, 5, 8, 2, 8, 11, 4, 8, 5, -1, -1, -1, -1}, + {10, 3, 11, 10, 1, 3, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1}, + {4, 9, 5, 0, 8, 1, 8, 10, 1, 8, 11, 10, -1, -1, -1, -1}, + {5, 4, 0, 5, 0, 11, 5, 11, 10, 11, 0, 3, -1, -1, -1, -1}, + {5, 4, 8, 5, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1}, + {9, 7, 8, 5, 7, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {9, 3, 0, 9, 5, 3, 5, 7, 3, -1, -1, -1, -1, -1, -1, -1}, + {0, 7, 8, 0, 1, 7, 1, 5, 7, -1, -1, -1, -1, -1, -1, -1}, + {1, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {9, 7, 8, 9, 5, 7, 10, 1, 2, -1, -1, -1, -1, -1, -1, -1}, + {10, 1, 2, 9, 5, 0, 5, 3, 0, 5, 7, 3, -1, -1, -1, -1}, + {8, 0, 2, 8, 2, 5, 8, 5, 7, 10, 5, 2, -1, -1, -1, -1}, + {2, 10, 5, 2, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1}, + {7, 9, 5, 7, 8, 9, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1}, + {9, 5, 7, 9, 7, 2, 9, 2, 0, 2, 7, 11, -1, -1, -1, -1}, + {2, 3, 11, 0, 1, 8, 1, 7, 8, 1, 5, 7, -1, -1, -1, -1}, + {11, 2, 1, 11, 1, 7, 7, 1, 5, -1, -1, -1, -1, -1, -1, -1}, + {9, 5, 8, 8, 5, 7, 10, 1, 3, 10, 3, 11, -1, -1, -1, -1}, + {5, 7, 0, 5, 0, 9, 7, 11, 0, 1, 0, 10, 11, 10, 0, -1}, + {11, 10, 0, 11, 0, 3, 10, 5, 0, 8, 0, 7, 5, 7, 0, -1}, + {11, 10, 5, 7, 11, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {0, 8, 3, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {9, 0, 1, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 8, 3, 1, 9, 8, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1}, + {1, 6, 5, 2, 6, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 6, 5, 1, 2, 6, 3, 0, 8, -1, -1, -1, -1, -1, -1, -1}, + {9, 6, 5, 9, 0, 6, 0, 2, 6, -1, -1, -1, -1, -1, -1, -1}, + {5, 9, 8, 5, 8, 2, 5, 2, 6, 3, 2, 8, -1, -1, -1, -1}, + {2, 3, 11, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {11, 0, 8, 11, 2, 0, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1}, + {0, 1, 9, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1}, + {5, 10, 6, 1, 9, 2, 9, 11, 2, 9, 8, 11, -1, -1, -1, -1}, + {6, 3, 11, 6, 5, 3, 5, 1, 3, -1, -1, -1, -1, -1, -1, -1}, + {0, 8, 11, 0, 11, 5, 0, 5, 1, 5, 11, 6, -1, -1, -1, -1}, + {3, 11, 6, 0, 3, 6, 0, 6, 5, 0, 5, 9, -1, -1, -1, -1}, + {6, 5, 9, 6, 9, 11, 11, 9, 8, -1, -1, -1, -1, -1, -1, -1}, + {5, 10, 6, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {4, 3, 0, 4, 7, 3, 6, 5, 10, -1, -1, -1, -1, -1, -1, -1}, + {1, 9, 0, 5, 10, 6, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1}, + {10, 6, 5, 1, 9, 7, 1, 7, 3, 7, 9, 4, -1, -1, -1, -1}, + {6, 1, 2, 6, 5, 1, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1}, + {1, 2, 5, 5, 2, 6, 3, 0, 4, 3, 4, 7, -1, -1, -1, -1}, + {8, 4, 7, 9, 0, 5, 0, 6, 5, 0, 2, 6, -1, -1, -1, -1}, + {7, 3, 9, 7, 9, 4, 3, 2, 9, 5, 9, 6, 2, 6, 9, -1}, + {3, 11, 2, 7, 8, 4, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1}, + {5, 10, 6, 4, 7, 2, 4, 2, 0, 2, 7, 11, -1, -1, -1, -1}, + {0, 1, 9, 4, 7, 8, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1}, + {9, 2, 1, 9, 11, 2, 9, 4, 11, 7, 11, 4, 5, 10, 6, -1}, + {8, 4, 7, 3, 11, 5, 3, 5, 1, 5, 11, 6, -1, -1, -1, -1}, + {5, 1, 11, 5, 11, 6, 1, 0, 11, 7, 11, 4, 0, 4, 11, -1}, + {0, 5, 9, 0, 6, 5, 0, 3, 6, 11, 6, 3, 8, 4, 7, -1}, + {6, 5, 9, 6, 9, 11, 4, 7, 9, 7, 11, 9, -1, -1, -1, -1}, + {10, 4, 9, 6, 4, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {4, 10, 6, 4, 9, 10, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1}, + {10, 0, 1, 10, 6, 0, 6, 4, 0, -1, -1, -1, -1, -1, -1, -1}, + {8, 3, 1, 8, 1, 6, 8, 6, 4, 6, 1, 10, -1, -1, -1, -1}, + {1, 4, 9, 1, 2, 4, 2, 6, 4, -1, -1, -1, -1, -1, -1, -1}, + {3, 0, 8, 1, 2, 9, 2, 4, 9, 2, 6, 4, -1, -1, -1, -1}, + {0, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {8, 3, 2, 8, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1}, + {10, 4, 9, 10, 6, 4, 11, 2, 3, -1, -1, -1, -1, -1, -1, -1}, + {0, 8, 2, 2, 8, 11, 4, 9, 10, 4, 10, 6, -1, -1, -1, -1}, + {3, 11, 2, 0, 1, 6, 0, 6, 4, 6, 1, 10, -1, -1, -1, -1}, + {6, 4, 1, 6, 1, 10, 4, 8, 1, 2, 1, 11, 8, 11, 1, -1}, + {9, 6, 4, 9, 3, 6, 9, 1, 3, 11, 6, 3, -1, -1, -1, -1}, + {8, 11, 1, 8, 1, 0, 11, 6, 1, 9, 1, 4, 6, 4, 1, -1}, + {3, 11, 6, 3, 6, 0, 0, 6, 4, -1, -1, -1, -1, -1, -1, -1}, + {6, 4, 8, 11, 6, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {7, 10, 6, 7, 8, 10, 8, 9, 10, -1, -1, -1, -1, -1, -1, -1}, + {0, 7, 3, 0, 10, 7, 0, 9, 10, 6, 7, 10, -1, -1, -1, -1}, + {10, 6, 7, 1, 10, 7, 1, 7, 8, 1, 8, 0, -1, -1, -1, -1}, + {10, 6, 7, 10, 7, 1, 1, 7, 3, -1, -1, -1, -1, -1, -1, -1}, + {1, 2, 6, 1, 6, 8, 1, 8, 9, 8, 6, 7, -1, -1, -1, -1}, + {2, 6, 9, 2, 9, 1, 6, 7, 9, 0, 9, 3, 7, 3, 9, -1}, + {7, 8, 0, 7, 0, 6, 6, 0, 2, -1, -1, -1, -1, -1, -1, -1}, + {7, 3, 2, 6, 7, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {2, 3, 11, 10, 6, 8, 10, 8, 9, 8, 6, 7, -1, -1, -1, -1}, + {2, 0, 7, 2, 7, 11, 0, 9, 7, 6, 7, 10, 9, 10, 7, -1}, + {1, 8, 0, 1, 7, 8, 1, 10, 7, 6, 7, 10, 2, 3, 11, -1}, + {11, 2, 1, 11, 1, 7, 10, 6, 1, 6, 7, 1, -1, -1, -1, -1}, + {8, 9, 6, 8, 6, 7, 9, 1, 6, 11, 6, 3, 1, 3, 6, -1}, + {0, 9, 1, 11, 6, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {7, 8, 0, 7, 0, 6, 3, 11, 0, 11, 6, 0, -1, -1, -1, -1}, + {7, 11, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {3, 0, 8, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {0, 1, 9, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {8, 1, 9, 8, 3, 1, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1}, + {10, 1, 2, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 2, 10, 3, 0, 8, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1}, + {2, 9, 0, 2, 10, 9, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1}, + {6, 11, 7, 2, 10, 3, 10, 8, 3, 10, 9, 8, -1, -1, -1, -1}, + {7, 2, 3, 6, 2, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {7, 0, 8, 7, 6, 0, 6, 2, 0, -1, -1, -1, -1, -1, -1, -1}, + {2, 7, 6, 2, 3, 7, 0, 1, 9, -1, -1, -1, -1, -1, -1, -1}, + {1, 6, 2, 1, 8, 6, 1, 9, 8, 8, 7, 6, -1, -1, -1, -1}, + {10, 7, 6, 10, 1, 7, 1, 3, 7, -1, -1, -1, -1, -1, -1, -1}, + {10, 7, 6, 1, 7, 10, 1, 8, 7, 1, 0, 8, -1, -1, -1, -1}, + {0, 3, 7, 0, 7, 10, 0, 10, 9, 6, 10, 7, -1, -1, -1, -1}, + {7, 6, 10, 7, 10, 8, 8, 10, 9, -1, -1, -1, -1, -1, -1, -1}, + {6, 8, 4, 11, 8, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {3, 6, 11, 3, 0, 6, 0, 4, 6, -1, -1, -1, -1, -1, -1, -1}, + {8, 6, 11, 8, 4, 6, 9, 0, 1, -1, -1, -1, -1, -1, -1, -1}, + {9, 4, 6, 9, 6, 3, 9, 3, 1, 11, 3, 6, -1, -1, -1, -1}, + {6, 8, 4, 6, 11, 8, 2, 10, 1, -1, -1, -1, -1, -1, -1, -1}, + {1, 2, 10, 3, 0, 11, 0, 6, 11, 0, 4, 6, -1, -1, -1, -1}, + {4, 11, 8, 4, 6, 11, 0, 2, 9, 2, 10, 9, -1, -1, -1, -1}, + {10, 9, 3, 10, 3, 2, 9, 4, 3, 11, 3, 6, 4, 6, 3, -1}, + {8, 2, 3, 8, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1}, + {0, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 9, 0, 2, 3, 4, 2, 4, 6, 4, 3, 8, -1, -1, -1, -1}, + {1, 9, 4, 1, 4, 2, 2, 4, 6, -1, -1, -1, -1, -1, -1, -1}, + {8, 1, 3, 8, 6, 1, 8, 4, 6, 6, 10, 1, -1, -1, -1, -1}, + {10, 1, 0, 10, 0, 6, 6, 0, 4, -1, -1, -1, -1, -1, -1, -1}, + {4, 6, 3, 4, 3, 8, 6, 10, 3, 0, 3, 9, 10, 9, 3, -1}, + {10, 9, 4, 6, 10, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {4, 9, 5, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {0, 8, 3, 4, 9, 5, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1}, + {5, 0, 1, 5, 4, 0, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1}, + {11, 7, 6, 8, 3, 4, 3, 5, 4, 3, 1, 5, -1, -1, -1, -1}, + {9, 5, 4, 10, 1, 2, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1}, + {6, 11, 7, 1, 2, 10, 0, 8, 3, 4, 9, 5, -1, -1, -1, -1}, + {7, 6, 11, 5, 4, 10, 4, 2, 10, 4, 0, 2, -1, -1, -1, -1}, + {3, 4, 8, 3, 5, 4, 3, 2, 5, 10, 5, 2, 11, 7, 6, -1}, + {7, 2, 3, 7, 6, 2, 5, 4, 9, -1, -1, -1, -1, -1, -1, -1}, + {9, 5, 4, 0, 8, 6, 0, 6, 2, 6, 8, 7, -1, -1, -1, -1}, + {3, 6, 2, 3, 7, 6, 1, 5, 0, 5, 4, 0, -1, -1, -1, -1}, + {6, 2, 8, 6, 8, 7, 2, 1, 8, 4, 8, 5, 1, 5, 8, -1}, + {9, 5, 4, 10, 1, 6, 1, 7, 6, 1, 3, 7, -1, -1, -1, -1}, + {1, 6, 10, 1, 7, 6, 1, 0, 7, 8, 7, 0, 9, 5, 4, -1}, + {4, 0, 10, 4, 10, 5, 0, 3, 10, 6, 10, 7, 3, 7, 10, -1}, + {7, 6, 10, 7, 10, 8, 5, 4, 10, 4, 8, 10, -1, -1, -1, -1}, + {6, 9, 5, 6, 11, 9, 11, 8, 9, -1, -1, -1, -1, -1, -1, -1}, + {3, 6, 11, 0, 6, 3, 0, 5, 6, 0, 9, 5, -1, -1, -1, -1}, + {0, 11, 8, 0, 5, 11, 0, 1, 5, 5, 6, 11, -1, -1, -1, -1}, + {6, 11, 3, 6, 3, 5, 5, 3, 1, -1, -1, -1, -1, -1, -1, -1}, + {1, 2, 10, 9, 5, 11, 9, 11, 8, 11, 5, 6, -1, -1, -1, -1}, + {0, 11, 3, 0, 6, 11, 0, 9, 6, 5, 6, 9, 1, 2, 10, -1}, + {11, 8, 5, 11, 5, 6, 8, 0, 5, 10, 5, 2, 0, 2, 5, -1}, + {6, 11, 3, 6, 3, 5, 2, 10, 3, 10, 5, 3, -1, -1, -1, -1}, + {5, 8, 9, 5, 2, 8, 5, 6, 2, 3, 8, 2, -1, -1, -1, -1}, + {9, 5, 6, 9, 6, 0, 0, 6, 2, -1, -1, -1, -1, -1, -1, -1}, + {1, 5, 8, 1, 8, 0, 5, 6, 8, 3, 8, 2, 6, 2, 8, -1}, + {1, 5, 6, 2, 1, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 3, 6, 1, 6, 10, 3, 8, 6, 5, 6, 9, 8, 9, 6, -1}, + {10, 1, 0, 10, 0, 6, 9, 5, 0, 5, 6, 0, -1, -1, -1, -1}, + {0, 3, 8, 5, 6, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {10, 5, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {11, 5, 10, 7, 5, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {11, 5, 10, 11, 7, 5, 8, 3, 0, -1, -1, -1, -1, -1, -1, -1}, + {5, 11, 7, 5, 10, 11, 1, 9, 0, -1, -1, -1, -1, -1, -1, -1}, + {10, 7, 5, 10, 11, 7, 9, 8, 1, 8, 3, 1, -1, -1, -1, -1}, + {11, 1, 2, 11, 7, 1, 7, 5, 1, -1, -1, -1, -1, -1, -1, -1}, + {0, 8, 3, 1, 2, 7, 1, 7, 5, 7, 2, 11, -1, -1, -1, -1}, + {9, 7, 5, 9, 2, 7, 9, 0, 2, 2, 11, 7, -1, -1, -1, -1}, + {7, 5, 2, 7, 2, 11, 5, 9, 2, 3, 2, 8, 9, 8, 2, -1}, + {2, 5, 10, 2, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1}, + {8, 2, 0, 8, 5, 2, 8, 7, 5, 10, 2, 5, -1, -1, -1, -1}, + {9, 0, 1, 5, 10, 3, 5, 3, 7, 3, 10, 2, -1, -1, -1, -1}, + {9, 8, 2, 9, 2, 1, 8, 7, 2, 10, 2, 5, 7, 5, 2, -1}, + {1, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {0, 8, 7, 0, 7, 1, 1, 7, 5, -1, -1, -1, -1, -1, -1, -1}, + {9, 0, 3, 9, 3, 5, 5, 3, 7, -1, -1, -1, -1, -1, -1, -1}, + {9, 8, 7, 5, 9, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {5, 8, 4, 5, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1}, + {5, 0, 4, 5, 11, 0, 5, 10, 11, 11, 3, 0, -1, -1, -1, -1}, + {0, 1, 9, 8, 4, 10, 8, 10, 11, 10, 4, 5, -1, -1, -1, -1}, + {10, 11, 4, 10, 4, 5, 11, 3, 4, 9, 4, 1, 3, 1, 4, -1}, + {2, 5, 1, 2, 8, 5, 2, 11, 8, 4, 5, 8, -1, -1, -1, -1}, + {0, 4, 11, 0, 11, 3, 4, 5, 11, 2, 11, 1, 5, 1, 11, -1}, + {0, 2, 5, 0, 5, 9, 2, 11, 5, 4, 5, 8, 11, 8, 5, -1}, + {9, 4, 5, 2, 11, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {2, 5, 10, 3, 5, 2, 3, 4, 5, 3, 8, 4, -1, -1, -1, -1}, + {5, 10, 2, 5, 2, 4, 4, 2, 0, -1, -1, -1, -1, -1, -1, -1}, + {3, 10, 2, 3, 5, 10, 3, 8, 5, 4, 5, 8, 0, 1, 9, -1}, + {5, 10, 2, 5, 2, 4, 1, 9, 2, 9, 4, 2, -1, -1, -1, -1}, + {8, 4, 5, 8, 5, 3, 3, 5, 1, -1, -1, -1, -1, -1, -1, -1}, + {0, 4, 5, 1, 0, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {8, 4, 5, 8, 5, 3, 9, 0, 5, 0, 3, 5, -1, -1, -1, -1}, + {9, 4, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {4, 11, 7, 4, 9, 11, 9, 10, 11, -1, -1, -1, -1, -1, -1, -1}, + {0, 8, 3, 4, 9, 7, 9, 11, 7, 9, 10, 11, -1, -1, -1, -1}, + {1, 10, 11, 1, 11, 4, 1, 4, 0, 7, 4, 11, -1, -1, -1, -1}, + {3, 1, 4, 3, 4, 8, 1, 10, 4, 7, 4, 11, 10, 11, 4, -1}, + {4, 11, 7, 9, 11, 4, 9, 2, 11, 9, 1, 2, -1, -1, -1, -1}, + {9, 7, 4, 9, 11, 7, 9, 1, 11, 2, 11, 1, 0, 8, 3, -1}, + {11, 7, 4, 11, 4, 2, 2, 4, 0, -1, -1, -1, -1, -1, -1, -1}, + {11, 7, 4, 11, 4, 2, 8, 3, 4, 3, 2, 4, -1, -1, -1, -1}, + {2, 9, 10, 2, 7, 9, 2, 3, 7, 7, 4, 9, -1, -1, -1, -1}, + {9, 10, 7, 9, 7, 4, 10, 2, 7, 8, 7, 0, 2, 0, 7, -1}, + {3, 7, 10, 3, 10, 2, 7, 4, 10, 1, 10, 0, 4, 0, 10, -1}, + {1, 10, 2, 8, 7, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {4, 9, 1, 4, 1, 7, 7, 1, 3, -1, -1, -1, -1, -1, -1, -1}, + {4, 9, 1, 4, 1, 7, 0, 8, 1, 8, 7, 1, -1, -1, -1, -1}, + {4, 0, 3, 7, 4, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {4, 8, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {9, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {3, 0, 9, 3, 9, 11, 11, 9, 10, -1, -1, -1, -1, -1, -1, -1}, + {0, 1, 10, 0, 10, 8, 8, 10, 11, -1, -1, -1, -1, -1, -1, -1}, + {3, 1, 10, 11, 3, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 2, 11, 1, 11, 9, 9, 11, 8, -1, -1, -1, -1, -1, -1, -1}, + {3, 0, 9, 3, 9, 11, 1, 2, 9, 2, 11, 9, -1, -1, -1, -1}, + {0, 2, 11, 8, 0, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {3, 2, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {2, 3, 8, 2, 8, 10, 10, 8, 9, -1, -1, -1, -1, -1, -1, -1}, + {9, 10, 2, 0, 9, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {2, 3, 8, 2, 8, 10, 0, 1, 8, 1, 10, 8, -1, -1, -1, -1}, + {1, 10, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 3, 8, 9, 1, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {0, 9, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {0, 3, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1} + }; + diff --git a/src/external/libigl-2.3.0/include/igl/marching_tets.cpp b/src/external/libigl-2.3.0/include/igl/marching_tets.cpp new file mode 100644 index 000000000..08b22711b --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/marching_tets.cpp @@ -0,0 +1,195 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2018 Francis Williams +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +#include "marching_tets.h" + +#include +#include +#include +#include +#include + +template +void igl::marching_tets( + const Eigen::MatrixBase& TV, + const Eigen::MatrixBase& TT, + const Eigen::MatrixBase& isovals, + double isovalue, + Eigen::PlainObjectBase& outV, + Eigen::PlainObjectBase& outF, + Eigen::PlainObjectBase& J, + Eigen::SparseMatrix& BC) +{ + using namespace std; + + // We're hashing edges to deduplicate using 64 bit ints. The upper and lower + // 32 bits of a key are the indices of vertices in the mesh. The implication is + // that you can only have 2^32 vertices which I have deemed sufficient for + // anything reasonable. + const auto make_edge_key = [](const pair& p) -> int64_t + { + std::int64_t ret = 0; + ret |= p.first; + ret |= static_cast(p.second) << 32; + return ret; + }; + + const int mt_cell_lookup[16][4] = + { + { -1, -1, -1, -1 }, + { 0, 2, 1, -1 }, + { 0, 3, 4, -1 }, + { 2, 1, 3, 4 }, + { 5, 3, 1, -1 }, + { 0, 2, 5, 3 }, + { 0, 1, 5, 4 }, + { 2, 5, 4, -1 }, + { 4, 5, 2, -1 }, + { 0, 4, 5, 1 }, + { 0, 3, 5, 2 }, + { 1, 3, 5, -1 }, + { 4, 3, 1, 2 }, + { 0, 4, 3, -1 }, + { 0, 1, 2, -1 }, + { -1, -1, -1, -1 }, + }; + + const int mt_edge_lookup[6][2] = + { + {0, 1}, + {0, 2}, + {0, 3}, + {1, 2}, + {1, 3}, + {2, 3}, + }; + + // Store the faces and the tet they are in + vector> faces; + + // Store the edges in the tet mesh which we add vertices on + // so we can deduplicate + vector> edge_table; + + + assert(TT.cols() == 4 && TT.rows() >= 1); + assert(TV.cols() == 3 && TV.rows() >= 4); + assert(isovals.cols() == 1); + + // For each tet + for (int i = 0; i < TT.rows(); i++) + { + uint8_t key = 0; + for (int v = 0; v < 4; v++) + { + const int vid = TT(i, v); + const uint8_t flag = isovals(vid, 0) > isovalue; + key |= flag << v; + } + + // This will contain the index in TV of each vertex in the tet + int v_ids[4] = {-1, -1, -1, -1}; + + // Insert any vertices if the tet intersects the level surface + for (int e = 0; e < 4 && mt_cell_lookup[key][e] != -1; e++) + { + const int tv1_idx = TT(i, mt_edge_lookup[mt_cell_lookup[key][e]][0]); + const int tv2_idx = TT(i, mt_edge_lookup[mt_cell_lookup[key][e]][1]); + const int vertex_id = edge_table.size(); + edge_table.push_back(make_pair(min(tv1_idx, tv2_idx), max(tv1_idx, tv2_idx))); + v_ids[e] = vertex_id; + } + + // Insert the corresponding faces + if (v_ids[0] != -1) + { + bool is_quad = mt_cell_lookup[key][3] != -1; + if (is_quad) + { + const Eigen::RowVector3i f1(v_ids[0], v_ids[1], v_ids[3]); + const Eigen::RowVector3i f2(v_ids[1], v_ids[2], v_ids[3]); + faces.push_back(make_pair(f1, i)); + faces.push_back(make_pair(f2, i)); + } + else + { + const Eigen::RowVector3i f(v_ids[0], v_ids[1], v_ids[2]); + faces.push_back(make_pair(f, i)); + } + + } + } + + int num_unique = 0; + outV.resize(edge_table.size(), 3); + outF.resize(faces.size(), 3); + J.resize(faces.size()); + + // Sparse matrix triplets for BC + vector> bc_triplets; + bc_triplets.reserve(edge_table.size()); + + // Deduplicate vertices + unordered_map emap; + emap.max_load_factor(0.5); + emap.reserve(edge_table.size()); + + for (int f = 0; f < faces.size(); f++) + { + const int ti = faces[f].second; + assert(ti>=0); + assert(ti edge = edge_table[vi]; + const int64_t key = make_edge_key(edge); + auto it = emap.find(key); + if (it == emap.end()) // New unique vertex, insert it + { + // Typedef to make sure we handle floats properly + typedef Eigen::Matrix RowVector; + const RowVector v1 = TV.row(edge.first); + const RowVector v2 = TV.row(edge.second); + const double a = fabs(isovals(edge.first, 0) - isovalue); + const double b = fabs(isovals(edge.second, 0) - isovalue); + const double w = a / (a+b); + + // Create a casted copy in case BCType is a float and we need to downcast + const BCType bc_w = static_cast(w); + bc_triplets.push_back(Eigen::Triplet(num_unique, edge.first, 1-bc_w)); + bc_triplets.push_back(Eigen::Triplet(num_unique, edge.second, bc_w)); + + // Create a casted copy in case DerivedTV::Scalar is a float and we need to downcast + const typename DerivedTV::Scalar v_w = static_cast(w); + outV.row(num_unique) = (1-v_w)*v1 + v_w*v2; + outF(f, v) = num_unique; + + emap.emplace(key, num_unique); + num_unique += 1; + } else { + outF(f, v) = it->second; + } + } + } + outV.conservativeResize(num_unique, 3); + BC.resize(num_unique, TV.rows()); + BC.setFromTriplets(bc_triplets.begin(), bc_triplets.end()); +} + + +#ifdef IGL_STATIC_LIBRARY +template void igl::marching_tets, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, double>(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, double, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::SparseMatrix&); +#endif // IGL_STATIC_LIBRARY diff --git a/src/external/libigl-2.3.0/include/igl/marching_tets.h b/src/external/libigl-2.3.0/include/igl/marching_tets.h new file mode 100644 index 000000000..19df54482 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/marching_tets.h @@ -0,0 +1,196 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2018 Francis Williams +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef IGL_MARCHING_TETS_H +#define IGL_MARCHING_TETS_H + +#include "igl_inline.h" +#include +#include + +namespace igl { + // marching_tets( TV, TT, S, isovalue, SV, SF, J, BC) + // + // performs the marching tetrahedra algorithm on a tet mesh defined by TV and + // TT with scalar values defined at each vertex in TV. The output is a + // triangle mesh approximating the isosurface coresponding to the value + // isovalue. + // + // Input: + // TV #tet_vertices x 3 array -- The vertices of the tetrahedral mesh + // TT #tets x 4 array -- The indexes of each tet in the tetrahedral mesh + // S #tet_vertices x 1 array -- The values defined on each tet vertex + // isovalue scalar -- The isovalue of the level set we want to compute + // + // Output: + // SV #SV x 3 array -- The vertices of the output level surface mesh + // SF #SF x 3 array -- The face indexes of the output level surface mesh + // J #SF list of indices into TT revealing which tet each face comes from + // BC #SV x #TV list of barycentric coordinates so that SV = BC*TV + template + IGL_INLINE void marching_tets( + const Eigen::MatrixBase& TV, + const Eigen::MatrixBase& TT, + const Eigen::MatrixBase& S, + double isovalue, + Eigen::PlainObjectBase& SV, + Eigen::PlainObjectBase& SF, + Eigen::PlainObjectBase& J, + Eigen::SparseMatrix& BC); + + // marching_tets( TV, TT, S, SV, SF, J, BC) + // + // Performs the marching tetrahedra algorithm on a tet mesh defined by TV and + // TT with scalar values defined at each vertex in TV. The output is a + // triangle mesh approximating the isosurface coresponding to an isovalue of 0. + // + // Input: + // TV #tet_vertices x 3 array -- The vertices of the tetrahedral mesh + // TT #tets x 4 array -- The indexes of each tet in the tetrahedral mesh + // S #tet_vertices x 1 array -- The values defined on each tet vertex + // isovalue scalar -- The isovalue of the level set we want to compute + // + // Output: + // SV #SV x 3 array -- The vertices of the output level surface mesh + // SF #SF x 3 array -- The face indexes of the output level surface mesh + // J #SF list of indices into TT revealing which tet each face comes from + // BC #SV x #TV list of barycentric coordinates so that SV = BC*TV + template + IGL_INLINE void marching_tets( + const Eigen::MatrixBase& TV, + const Eigen::MatrixBase& TT, + const Eigen::MatrixBase& S, + Eigen::PlainObjectBase& SV, + Eigen::PlainObjectBase& SF, + Eigen::PlainObjectBase& J, + Eigen::SparseMatrix& BC) { + return igl::marching_tets(TV, TT, S, 0.0, SV, SF, J, BC); + } + + // marching_tets( TV, TT, S, isovalue, SV, SF, J) + // + // performs the marching tetrahedra algorithm on a tet mesh defined by TV and + // TT with scalar values defined at each vertex in TV. The output is a + // triangle mesh approximating the isosurface coresponding to the value + // isovalue. + // + // Input: + // TV #tet_vertices x 3 array -- The vertices of the tetrahedral mesh + // TT #tets x 4 array -- The indexes of each tet in the tetrahedral mesh + // S #tet_vertices x 1 array -- The values defined on each tet vertex + // isovalue scalar -- The isovalue of the level set we want to compute + // + // Output: + // SV #SV x 3 array -- The vertices of the output level surface mesh + // SF #SF x 3 array -- The face indexes of the output level surface mesh + // J #SF list of indices into TT revealing which tet each face comes from + template + IGL_INLINE void marching_tets( + const Eigen::MatrixBase& TV, + const Eigen::MatrixBase& TT, + const Eigen::MatrixBase& S, + double isovalue, + Eigen::PlainObjectBase& SV, + Eigen::PlainObjectBase& SF, + Eigen::PlainObjectBase& J) { + Eigen::SparseMatrix _BC; + return igl::marching_tets(TV, TT, S, isovalue, SV, SF, J, _BC); + } + + // marching_tets( TV, TT, S, isovalue, SV, SF, BC) + // + // performs the marching tetrahedra algorithm on a tet mesh defined by TV and + // TT with scalar values defined at each vertex in TV. The output is a + // triangle mesh approximating the isosurface coresponding to the value + // isovalue. + // + // Input: + // TV #tet_vertices x 3 array -- The vertices of the tetrahedral mesh + // TT #tets x 4 array -- The indexes of each tet in the tetrahedral mesh + // S #tet_vertices x 1 array -- The values defined on each tet vertex + // isovalue scalar -- The isovalue of the level set we want to compute + // + // Output: + // SV #SV x 3 array -- The vertices of the output level surface mesh + // SF #SF x 3 array -- The face indexes of the output level surface mesh + // BC #SV x #TV list of barycentric coordinates so that SV = BC*TV + template + IGL_INLINE void marching_tets( + const Eigen::MatrixBase& TV, + const Eigen::MatrixBase& TT, + const Eigen::MatrixBase& S, + double isovalue, + Eigen::PlainObjectBase& SV, + Eigen::PlainObjectBase& SF, + Eigen::SparseMatrix& BC) { + Eigen::VectorXi _J; + return igl::marching_tets(TV, TT, S, isovalue, SV, SF, _J, BC); + } + + // marching_tets( TV, TT, S, isovalue, SV, SF) + // + // performs the marching tetrahedra algorithm on a tet mesh defined by TV and + // TT with scalar values defined at each vertex in TV. The output is a + // triangle mesh approximating the isosurface coresponding to the value + // isovalue. + // + // Input: + // TV #tet_vertices x 3 array -- The vertices of the tetrahedral mesh + // TT #tets x 4 array -- The indexes of each tet in the tetrahedral mesh + // S #tet_vertices x 1 array -- The values defined on each tet vertex + // isovalue scalar -- The isovalue of the level set we want to compute + // + // Output: + // SV #SV x 3 array -- The vertices of the output level surface mesh + // SF #SF x 3 array -- The face indexes of the output level surface mesh + template + IGL_INLINE void marching_tets( + const Eigen::MatrixBase& TV, + const Eigen::MatrixBase& TT, + const Eigen::MatrixBase& S, + double isovalue, + Eigen::PlainObjectBase& SV, + Eigen::PlainObjectBase& SF) { + Eigen::VectorXi _J; + Eigen::SparseMatrix _BC; + return igl::marching_tets(TV, TT, S, isovalue, SV, SF, _J, _BC); + } + +} + +#ifndef IGL_STATIC_LIBRARY +# include "marching_tets.cpp" +#endif + +#endif // IGL_MARCHING_TETS_H diff --git a/src/external/libigl-2.3.0/include/igl/massmatrix.cpp b/src/external/libigl-2.3.0/include/igl/massmatrix.cpp new file mode 100644 index 000000000..e89c00f5a --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/massmatrix.cpp @@ -0,0 +1,96 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "massmatrix.h" +#include "massmatrix_intrinsic.h" +#include "edge_lengths.h" +#include "normalize_row_sums.h" +#include "sparse.h" +#include "doublearea.h" +#include "repmat.h" +#include +#include + +template +IGL_INLINE void igl::massmatrix( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const MassMatrixType type, + Eigen::SparseMatrix& M) +{ + using namespace Eigen; + using namespace std; + + const int n = V.rows(); + const int m = F.rows(); + const int simplex_size = F.cols(); + + MassMatrixType eff_type = type; + // Use voronoi of for triangles by default, otherwise barycentric + if(type == MASSMATRIX_TYPE_DEFAULT) + { + eff_type = (simplex_size == 3?MASSMATRIX_TYPE_VORONOI:MASSMATRIX_TYPE_BARYCENTRIC); + } + + // Not yet supported + assert(type!=MASSMATRIX_TYPE_FULL); + + if(simplex_size == 3) + { + // Triangles + // edge lengths numbered same as opposite vertices + Matrix l; + igl::edge_lengths(V,F,l); + return massmatrix_intrinsic(l,F,type,M); + }else if(simplex_size == 4) + { + Matrix MI; + Matrix MJ; + Matrix MV; + assert(V.cols() == 3); + assert(eff_type == MASSMATRIX_TYPE_BARYCENTRIC); + MI.resize(m*4,1); MJ.resize(m*4,1); MV.resize(m*4,1); + MI.block(0*m,0,m,1) = F.col(0); + MI.block(1*m,0,m,1) = F.col(1); + MI.block(2*m,0,m,1) = F.col(2); + MI.block(3*m,0,m,1) = F.col(3); + MJ = MI; + // loop over tets + for(int i = 0;i v0m3,v1m3,v2m3; + v0m3.head(V.cols()) = V.row(F(i,0)) - V.row(F(i,3)); + v1m3.head(V.cols()) = V.row(F(i,1)) - V.row(F(i,3)); + v2m3.head(V.cols()) = V.row(F(i,2)) - V.row(F(i,3)); + Scalar v = fabs(v0m3.dot(v1m3.cross(v2m3)))/6.0; + MV(i+0*m) = v/4.0; + MV(i+1*m) = v/4.0; + MV(i+2*m) = v/4.0; + MV(i+3*m) = v/4.0; + } + sparse(MI,MJ,MV,n,n,M); + }else + { + // Unsupported simplex size + assert(false && "Unsupported simplex size"); + } +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::massmatrix, Eigen::Matrix, double>(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, igl::MassMatrixType, Eigen::SparseMatrix&); +// generated by autoexplicit.sh +template void igl::massmatrix, Eigen::Matrix, double>(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, igl::MassMatrixType, Eigen::SparseMatrix&); +// generated by autoexplicit.sh +template void igl::massmatrix, Eigen::Matrix, double>(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, igl::MassMatrixType, Eigen::SparseMatrix&); +// generated by autoexplicit.sh +template void igl::massmatrix, Eigen::Matrix, double>(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, igl::MassMatrixType, Eigen::SparseMatrix&); +template void igl::massmatrix, Eigen::Matrix, double>(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, igl::MassMatrixType, Eigen::SparseMatrix&); +template void igl::massmatrix, Eigen::Matrix, double>(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, igl::MassMatrixType, Eigen::SparseMatrix&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/massmatrix.h b/src/external/libigl-2.3.0/include/igl/massmatrix.h new file mode 100644 index 000000000..b8a6fe486 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/massmatrix.h @@ -0,0 +1,60 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_MASSMATRIX_H +#define IGL_MASSMATRIX_H +#include "igl_inline.h" + +#include +#include + +namespace igl +{ + + enum MassMatrixType + { + MASSMATRIX_TYPE_BARYCENTRIC = 0, + MASSMATRIX_TYPE_VORONOI = 1, + MASSMATRIX_TYPE_FULL = 2, + MASSMATRIX_TYPE_DEFAULT = 3, + NUM_MASSMATRIX_TYPE = 4 + }; + + // Constructs the mass (area) matrix for a given mesh (V,F). + // + // Templates: + // DerivedV derived type of eigen matrix for V (e.g. derived from + // MatrixXd) + // DerivedF derived type of eigen matrix for F (e.g. derived from + // MatrixXi) + // Scalar scalar type for eigen sparse matrix (e.g. double) + // Inputs: + // V #V by dim list of mesh vertex positions + // F #F by simplex_size list of mesh elements (triangles or tetrahedra) + // type one of the following ints: + // MASSMATRIX_TYPE_BARYCENTRIC barycentric + // MASSMATRIX_TYPE_VORONOI voronoi-hybrid {default} + // MASSMATRIX_TYPE_FULL full {not implemented} + // Outputs: + // M #V by #V mass matrix + // + // See also: adjacency_matrix + // + template + IGL_INLINE void massmatrix( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const MassMatrixType type, + Eigen::SparseMatrix& M); +} + +#ifndef IGL_STATIC_LIBRARY +# include "massmatrix.cpp" +#endif + +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/massmatrix_intrinsic.cpp b/src/external/libigl-2.3.0/include/igl/massmatrix_intrinsic.cpp new file mode 100644 index 000000000..fe34873ab --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/massmatrix_intrinsic.cpp @@ -0,0 +1,128 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "massmatrix_intrinsic.h" +#include "edge_lengths.h" +#include "normalize_row_sums.h" +#include "sparse.h" +#include "doublearea.h" +#include "repmat.h" +#include +#include +#include + +template +IGL_INLINE void igl::massmatrix_intrinsic( + const Eigen::MatrixBase & l, + const Eigen::MatrixBase & F, + const MassMatrixType type, + Eigen::SparseMatrix& M) +{ + const int n = F.maxCoeff()+1; + return massmatrix_intrinsic(l,F,type,n,M); +} + +template +IGL_INLINE void igl::massmatrix_intrinsic( + const Eigen::MatrixBase & l, + const Eigen::MatrixBase & F, + const MassMatrixType type, + const int n, + Eigen::SparseMatrix& M) +{ + using namespace Eigen; + using namespace std; + MassMatrixType eff_type = type; + const int m = F.rows(); + const int simplex_size = F.cols(); + // Use voronoi of for triangles by default, otherwise barycentric + if(type == MASSMATRIX_TYPE_DEFAULT) + { + eff_type = (simplex_size == 3?MASSMATRIX_TYPE_VORONOI:MASSMATRIX_TYPE_BARYCENTRIC); + } + assert(F.cols() == 3 && "only triangles supported"); + Matrix dblA; + doublearea(l,0.,dblA); + Matrix MI; + Matrix MJ; + Matrix MV; + + switch(eff_type) + { + case MASSMATRIX_TYPE_BARYCENTRIC: + // diagonal entries for each face corner + MI.resize(m*3,1); MJ.resize(m*3,1); MV.resize(m*3,1); + MI.block(0*m,0,m,1) = F.col(0); + MI.block(1*m,0,m,1) = F.col(1); + MI.block(2*m,0,m,1) = F.col(2); + MJ = MI; + repmat(dblA,3,1,MV); + MV.array() /= 6.0; + break; + case MASSMATRIX_TYPE_VORONOI: + { + // diagonal entries for each face corner + // http://www.alecjacobson.com/weblog/?p=874 + MI.resize(m*3,1); MJ.resize(m*3,1); MV.resize(m*3,1); + MI.block(0*m,0,m,1) = F.col(0); + MI.block(1*m,0,m,1) = F.col(1); + MI.block(2*m,0,m,1) = F.col(2); + MJ = MI; + + // Holy shit this needs to be cleaned up and optimized + Matrix cosines(m,3); + cosines.col(0) = + (l.col(2).array().pow(2)+l.col(1).array().pow(2)-l.col(0).array().pow(2))/(l.col(1).array()*l.col(2).array()*2.0); + cosines.col(1) = + (l.col(0).array().pow(2)+l.col(2).array().pow(2)-l.col(1).array().pow(2))/(l.col(2).array()*l.col(0).array()*2.0); + cosines.col(2) = + (l.col(1).array().pow(2)+l.col(0).array().pow(2)-l.col(2).array().pow(2))/(l.col(0).array()*l.col(1).array()*2.0); + Matrix barycentric = cosines.array() * l.array(); + normalize_row_sums(barycentric,barycentric); + Matrix partial = barycentric; + partial.col(0).array() *= dblA.array() * 0.5; + partial.col(1).array() *= dblA.array() * 0.5; + partial.col(2).array() *= dblA.array() * 0.5; + Matrix quads(partial.rows(),partial.cols()); + quads.col(0) = (partial.col(1)+partial.col(2))*0.5; + quads.col(1) = (partial.col(2)+partial.col(0))*0.5; + quads.col(2) = (partial.col(0)+partial.col(1))*0.5; + + quads.col(0) = (cosines.col(0).array()<0).select( 0.25*dblA,quads.col(0)); + quads.col(1) = (cosines.col(0).array()<0).select(0.125*dblA,quads.col(1)); + quads.col(2) = (cosines.col(0).array()<0).select(0.125*dblA,quads.col(2)); + + quads.col(0) = (cosines.col(1).array()<0).select(0.125*dblA,quads.col(0)); + quads.col(1) = (cosines.col(1).array()<0).select(0.25*dblA,quads.col(1)); + quads.col(2) = (cosines.col(1).array()<0).select(0.125*dblA,quads.col(2)); + + quads.col(0) = (cosines.col(2).array()<0).select(0.125*dblA,quads.col(0)); + quads.col(1) = (cosines.col(2).array()<0).select(0.125*dblA,quads.col(1)); + quads.col(2) = (cosines.col(2).array()<0).select( 0.25*dblA,quads.col(2)); + + MV.block(0*m,0,m,1) = quads.col(0); + MV.block(1*m,0,m,1) = quads.col(1); + MV.block(2*m,0,m,1) = quads.col(2); + + break; + } + case MASSMATRIX_TYPE_FULL: + assert(false && "Implementation incomplete"); + break; + default: + assert(false && "Unknown Mass matrix eff_type"); + } + sparse(MI,MJ,MV,n,n,M); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +template void igl::massmatrix_intrinsic, Eigen::Matrix, double>(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, igl::MassMatrixType, Eigen::SparseMatrix&); +template void igl::massmatrix_intrinsic, Eigen::Matrix, double>(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, igl::MassMatrixType, Eigen::SparseMatrix&); +template void igl::massmatrix_intrinsic, Eigen::Matrix, double>(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, igl::MassMatrixType, Eigen::SparseMatrix&); +template void igl::massmatrix_intrinsic, Eigen::Matrix, double>(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, igl::MassMatrixType, Eigen::SparseMatrix&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/massmatrix_intrinsic.h b/src/external/libigl-2.3.0/include/igl/massmatrix_intrinsic.h new file mode 100644 index 000000000..cc491666d --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/massmatrix_intrinsic.h @@ -0,0 +1,56 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_MASSMATRIX_INTRINSIC_H +#define IGL_MASSMATRIX_INTRINSIC_H +#include "igl_inline.h" +#include "massmatrix.h" + +#include +#include + +namespace igl +{ + + // Constructs the mass (area) matrix for a given mesh (V,F). + // + // Inputs: + // l #l by simplex_size list of mesh edge lengths + // F #F by simplex_size list of mesh elements (triangles or tetrahedra) + // type one of the following ints: + // MASSMATRIX_TYPE_BARYCENTRIC barycentric + // MASSMATRIX_TYPE_VORONOI voronoi-hybrid {default} + // MASSMATRIX_TYPE_FULL full {not implemented} + // Outputs: + // M #V by #V mass matrix + // + // See also: adjacency_matrix + // + template + IGL_INLINE void massmatrix_intrinsic( + const Eigen::MatrixBase & l, + const Eigen::MatrixBase & F, + const MassMatrixType type, + Eigen::SparseMatrix& M); + // Inputs: + // n number of vertices (>= F.maxCoeff()+1) + template + IGL_INLINE void massmatrix_intrinsic( + const Eigen::MatrixBase & l, + const Eigen::MatrixBase & F, + const MassMatrixType type, + const int n, + Eigen::SparseMatrix& M); +} + +#ifndef IGL_STATIC_LIBRARY +# include "massmatrix_intrinsic.cpp" +#endif + +#endif + + diff --git a/src/external/libigl-2.3.0/include/igl/mat_max.cpp b/src/external/libigl-2.3.0/include/igl/mat_max.cpp new file mode 100644 index 000000000..c5da97569 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/mat_max.cpp @@ -0,0 +1,46 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "mat_max.h" + +template +IGL_INLINE void igl::mat_max( + const Eigen::DenseBase & X, + const int dim, + Eigen::PlainObjectBase & Y, + Eigen::PlainObjectBase & I) +{ + assert(dim==1||dim==2); + + // output size + int n = (dim==1?X.cols():X.rows()); + // resize output + Y.resize(n); + I.resize(n); + + // loop over dimension opposite of dim + for(int j = 0;j, Eigen::Matrix, Eigen::Matrix >(Eigen::DenseBase > const&, int, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/mat_max.h b/src/external/libigl-2.3.0/include/igl/mat_max.h new file mode 100644 index 000000000..ad3ec6e61 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/mat_max.h @@ -0,0 +1,44 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_MAT_MAX_H +#define IGL_MAT_MAX_H +#include "igl_inline.h" +#include + +namespace igl +{ + // Ideally this becomes a super overloaded function supporting everything + // that matlab's max supports + + // Max function for matrices to act like matlab's max function. Specifically + // like [Y,I] = max(X,[],dim); + // + // Templates: + // T should be a eigen matrix primitive type like int or double + // Inputs: + // X m by n matrix + // dim dimension along which to take max + // Outputs: + // Y n-long vector (if dim == 1) + // or + // Y m-long vector (if dim == 2) + // I vector the same size as Y containing the indices along dim of maximum + // entries + template + IGL_INLINE void mat_max( + const Eigen::DenseBase & X, + const int dim, + Eigen::PlainObjectBase & Y, + Eigen::PlainObjectBase & I); +} + +#ifndef IGL_STATIC_LIBRARY +# include "mat_max.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/mat_min.cpp b/src/external/libigl-2.3.0/include/igl/mat_min.cpp new file mode 100644 index 000000000..c34e993fe --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/mat_min.cpp @@ -0,0 +1,59 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "mat_min.h" + +template +IGL_INLINE void igl::mat_min( + const Eigen::DenseBase & X, + const int dim, + Eigen::PlainObjectBase & Y, + Eigen::PlainObjectBase & I) +{ + assert(dim==1||dim==2); + + // output size + int n = (dim==1?X.cols():X.rows()); + // resize output + Y.resize(n,1); + I.resize(n,1); + + // loop over dimension opposite of dim + for(int j = 0;j +//IGL_INLINE Eigen::Matrix igl::mat_min( +// const Eigen::Matrix & X, +// const int dim) +//{ +// Eigen::Matrix Y; +// Eigen::Matrix I; +// mat_min(X,dim,Y,I); +// return Y; +//} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::mat_min, Eigen::Array, Eigen::Matrix >(Eigen::DenseBase > const&, int, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::mat_min, Eigen::Matrix, Eigen::Matrix >(Eigen::DenseBase > const&, int, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/mat_min.h b/src/external/libigl-2.3.0/include/igl/mat_min.h new file mode 100644 index 000000000..3673aeded --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/mat_min.h @@ -0,0 +1,52 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_MAT_MIN_H +#define IGL_MAT_MIN_H +#include "igl_inline.h" +#include + +namespace igl +{ + // Ideally this becomes a super overloaded function supporting everything + // that matlab's min supports + + // Min function for matrices to act like matlab's min function. Specifically + // like [Y,I] = min(X,[],dim); + // + // Templates: + // T should be a eigen matrix primitive type like int or double + // Inputs: + // X m by n matrix + // dim dimension along which to take min + // Outputs: + // Y n-long sparse vector (if dim == 1) + // or + // Y m-long sparse vector (if dim == 2) + // I vector the same size as Y containing the indices along dim of minimum + // entries + // + // See also: mat_max + template + IGL_INLINE void mat_min( + const Eigen::DenseBase & X, + const int dim, + Eigen::PlainObjectBase & Y, + Eigen::PlainObjectBase & I); + // Use Y = X.colwise().minCoeff() instead + //// In-line wrapper + //template + //IGL_INLINE Eigen::Matrix mat_min( + // const Eigen::Matrix & X, + // const int dim); +} + +#ifndef IGL_STATIC_LIBRARY +# include "mat_min.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/mat_to_quat.cpp b/src/external/libigl-2.3.0/include/igl/mat_to_quat.cpp new file mode 100644 index 000000000..5c8e04b1f --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/mat_to_quat.cpp @@ -0,0 +1,141 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "mat_to_quat.h" +#include + +// This could be replaced by something fast +template +static inline Q_type ReciprocalSqrt( const Q_type x ) +{ + return 1.0/sqrt(x); +} + +//// Converts row major order matrix to quat +//// http://software.intel.com/sites/default/files/m/d/4/1/d/8/293748.pdf +//template +//IGL_INLINE void igl::mat4_to_quat(const Q_type * m, Q_type * q) +//{ +// Q_type t = + m[0 * 4 + 0] + m[1 * 4 + 1] + m[2 * 4 + 2] + 1.0f; +// Q_type s = ReciprocalSqrt( t ) * 0.5f; +// q[3] = s * t; +// q[2] = ( m[0 * 4 + 1] - m[1 * 4 + 0] ) * s; +// q[1] = ( m[2 * 4 + 0] - m[0 * 4 + 2] ) * s; +// q[0] = ( m[1 * 4 + 2] - m[2 * 4 + 1] ) * s; +//} + +// https://bmgame.googlecode.com/svn/idlib/math/Simd_AltiVec.cpp +template +IGL_INLINE void igl::mat4_to_quat(const Q_type * mat, Q_type * q) +{ + Q_type trace; + Q_type s; + Q_type t; + int i; + int j; + int k; + + static int next[3] = { 1, 2, 0 }; + + trace = mat[0 * 4 + 0] + mat[1 * 4 + 1] + mat[2 * 4 + 2]; + + if ( trace > 0.0f ) { + + t = trace + 1.0f; + s = ReciprocalSqrt( t ) * 0.5f; + + q[3] = s * t; + q[0] = ( mat[1 * 4 + 2] - mat[2 * 4 + 1] ) * s; + q[1] = ( mat[2 * 4 + 0] - mat[0 * 4 + 2] ) * s; + q[2] = ( mat[0 * 4 + 1] - mat[1 * 4 + 0] ) * s; + + } else { + + i = 0; + if ( mat[1 * 4 + 1] > mat[0 * 4 + 0] ) { + i = 1; + } + if ( mat[2 * 4 + 2] > mat[i * 4 + i] ) { + i = 2; + } + j = next[i]; + k = next[j]; + + t = ( mat[i * 4 + i] - ( mat[j * 4 + j] + mat[k * 4 + k] ) ) + 1.0f; + s = ReciprocalSqrt( t ) * 0.5f; + + q[i] = s * t; + q[3] = ( mat[j * 4 + k] - mat[k * 4 + j] ) * s; + q[j] = ( mat[i * 4 + j] + mat[j * 4 + i] ) * s; + q[k] = ( mat[i * 4 + k] + mat[k * 4 + i] ) * s; + } + + //// Unused translation + //jq.t[0] = mat[0 * 4 + 3]; + //jq.t[1] = mat[1 * 4 + 3]; + //jq.t[2] = mat[2 * 4 + 3]; +} + +template +IGL_INLINE void igl::mat3_to_quat(const Q_type * mat, Q_type * q) +{ + Q_type trace; + Q_type s; + Q_type t; + int i; + int j; + int k; + + static int next[3] = { 1, 2, 0 }; + + trace = mat[0 * 3 + 0] + mat[1 * 3 + 1] + mat[2 * 3 + 2]; + + if ( trace > 0.0f ) { + + t = trace + 1.0f; + s = ReciprocalSqrt( t ) * 0.5f; + + q[3] = s * t; + q[0] = ( mat[1 * 3 + 2] - mat[2 * 3 + 1] ) * s; + q[1] = ( mat[2 * 3 + 0] - mat[0 * 3 + 2] ) * s; + q[2] = ( mat[0 * 3 + 1] - mat[1 * 3 + 0] ) * s; + + } else { + + i = 0; + if ( mat[1 * 3 + 1] > mat[0 * 3 + 0] ) { + i = 1; + } + if ( mat[2 * 3 + 2] > mat[i * 3 + i] ) { + i = 2; + } + j = next[i]; + k = next[j]; + + t = ( mat[i * 3 + i] - ( mat[j * 3 + j] + mat[k * 3 + k] ) ) + 1.0f; + s = ReciprocalSqrt( t ) * 0.5f; + + q[i] = s * t; + q[3] = ( mat[j * 3 + k] - mat[k * 3 + j] ) * s; + q[j] = ( mat[i * 3 + j] + mat[j * 3 + i] ) * s; + q[k] = ( mat[i * 3 + k] + mat[k * 3 + i] ) * s; + } + + //// Unused translation + //jq.t[0] = mat[0 * 4 + 3]; + //jq.t[1] = mat[1 * 4 + 3]; + //jq.t[2] = mat[2 * 4 + 3]; +} + + + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +template void igl::mat4_to_quat(double const*, double*); +template void igl::mat4_to_quat(float const*, float*); +template void igl::mat3_to_quat(double const*, double*); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/mat_to_quat.h b/src/external/libigl-2.3.0/include/igl/mat_to_quat.h new file mode 100644 index 000000000..acea683f7 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/mat_to_quat.h @@ -0,0 +1,32 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_MAT_TO_QUAT_H +#define IGL_MAT_TO_QUAT_H +#include "igl_inline.h" +namespace igl +{ + // Convert a OpenGL (rotation) matrix to a quaternion + // + // Input: + // m 16-element opengl rotation matrix + // Output: + // q 4-element quaternion (not normalized) + template + IGL_INLINE void mat4_to_quat(const Q_type * m, Q_type * q); + // Input: + // m 9-element opengl rotation matrix + template + IGL_INLINE void mat3_to_quat(const Q_type * m, Q_type * q); +} + +#ifndef IGL_STATIC_LIBRARY +# include "mat_to_quat.cpp" +#endif + +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/material_colors.h b/src/external/libigl-2.3.0/include/igl/material_colors.h new file mode 100644 index 000000000..1927fa42d --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/material_colors.h @@ -0,0 +1,57 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_MATERIAL_COLORS_H +#define IGL_MATERIAL_COLORS_H +#include +// Define constant material colors for use with opengl glMaterialfv +// Most of these colors come from IGL publications +namespace igl +{ + // Gold/Silver used in BBW/MONO/STBS/FAST + const float GOLD_AMBIENT[4] = { 51.0/255.0, 43.0/255.0,33.3/255.0,1.0f }; + const float GOLD_DIFFUSE[4] = { 255.0/255.0,228.0/255.0,58.0/255.0,1.0f }; + const float GOLD_SPECULAR[4] = { 255.0/255.0,235.0/255.0,80.0/255.0,1.0f }; + const float SILVER_AMBIENT[4] = { 0.2f, 0.2f, 0.2f, 1.0f }; + const float SILVER_DIFFUSE[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; + const float SILVER_SPECULAR[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; + // Blue/Cyan more similar to Jovan Popovic's blue than to Mario Botsch's blue + const float CYAN_AMBIENT[4] = { 59.0/255.0, 68.0/255.0,255.0/255.0,1.0f }; + const float CYAN_DIFFUSE[4] = { 94.0/255.0,185.0/255.0,238.0/255.0,1.0f }; + const float CYAN_SPECULAR[4] = { 163.0/255.0,221.0/255.0,255.0/255.0,1.0f }; + const float DENIS_PURPLE_DIFFUSE[4] = { 80.0/255.0,64.0/255.0,255.0/255.0,1.0f }; + const float LADISLAV_ORANGE_DIFFUSE[4] = {1.0f, 125.0f / 255.0f, 19.0f / 255.0f, 0.0f}; + // FAST armadillos colors + const float FAST_GREEN_DIFFUSE[4] = { 113.0f/255.0f, 239.0f/255.0f, 46.0f/255.0f, 1.0f}; + const float FAST_RED_DIFFUSE[4] = { 255.0f/255.0f, 65.0f/255.0f, 46.0f/255.0f, 1.0f}; + const float FAST_BLUE_DIFFUSE[4] = { 106.0f/255.0f, 106.0f/255.0f, 255.0f/255.0f, 1.0f}; + const float FAST_GRAY_DIFFUSE[4] = { 150.0f/255.0f, 150.0f/255.0f, 150.0f/255.0f, 1.0f}; + // Basic colors + const float WHITE[4] = { 255.0/255.0,255.0/255.0,255.0/255.0,1.0f }; + const float BLACK[4] = { 0.0/255.0,0.0/255.0,0.0/255.0,1.0f }; + const float WHITE_AMBIENT[4] = { 255.0/255.0,255.0/255.0,255.0/255.0,1.0f }; + const float WHITE_DIFFUSE[4] = { 255.0/255.0,255.0/255.0,255.0/255.0,1.0f }; + const float WHITE_SPECULAR[4] = { 255.0/255.0,255.0/255.0,255.0/255.0,1.0f }; + const float BBW_POINT_COLOR[4] = {239./255.,213./255.,46./255.,255.0/255.0}; + const float BBW_LINE_COLOR[4] = {106./255.,106./255.,255./255.,255./255.}; + const float MIDNIGHT_BLUE_DIFFUSE[4] = { 21.0f/255.0f, 27.0f/255.0f, 84.0f/255.0f, 1.0f}; + // Winding number colors + const float EASTER_RED_DIFFUSE[4] = {0.603922,0.494118f,0.603922f,1.0f}; + const float WN_OPEN_BOUNDARY_COLOR[4] = {154./255.,0./255.,0./255.,1.0f}; + const float WN_NON_MANIFOLD_EDGE_COLOR[4] = {201./255., 51./255.,255./255.,1.0f}; + const Eigen::Vector4f + MAYA_GREEN(128./255.,242./255.,0./255.,1.), + MAYA_YELLOW(255./255.,247./255.,50./255.,1.), + MAYA_RED(234./255.,63./255.,52./255.,1.), + MAYA_BLUE(0./255.,73./255.,252./255.,1.), + MAYA_PURPLE(180./255.,73./255.,200./255.,1.), + MAYA_VIOLET(31./255.,15./255.,66./255.,1.), + MAYA_GREY(0.5,0.5,0.5,1.0), + MAYA_CYAN(131./255.,219./255.,252./255.,1.), + MAYA_SEA_GREEN(70./255.,252./255.,167./255.,1.); +} +#endif diff --git a/src/external/libigl-2.3.0/include/igl/matlab/MatlabWorkspace.h b/src/external/libigl-2.3.0/include/igl/matlab/MatlabWorkspace.h new file mode 100644 index 000000000..c8dcaf9ed --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/matlab/MatlabWorkspace.h @@ -0,0 +1,579 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_MATLAB_MATLAB_WORKSPACE_H +#define IGL_MATLAB_MATLAB_WORKSPACE_H + +#include +#include + +#include + +#include +#include + +namespace igl +{ + namespace matlab + { + // It would be really great to replicate this for a simple XML-based + // workspace. + // + // Class which contains data of a matlab workspace which can be written to a + // .mat file and loaded from matlab + // + // This depends on matlab at compile time (though it shouldn't necessarily + // have to) but it does not depend on running the matlab engine at run-time. + // + // Known bugs: Treats all matrices as doubles (this may actually be desired + // for some "index" matrices since matlab's sparse command takes doubles + // rather than int class matrices). It is of course not desired when dealing + // with logicals or uint's for images. + class MatlabWorkspace + { + private: + // KNOWN BUG: Why not use a map? Any reason to allow duplicate names? + // + // List of names + std::vector names; + // List of data pointers + std::vector data; + public: + MatlabWorkspace(); + ~MatlabWorkspace(); + // Clear names and data of variables in workspace + inline void clear(); + // Save current list of variables + // + // Inputs: + // path path to .mat file + // Returns true on success, false on failure + inline bool write(const std::string & path) const; + // Load list of variables from .mat file + // + // Inputs: + // path path to .mat file + // Returns true on success, false on failure + inline bool read(const std::string & path); + // Assign data to a variable name in the workspace + // + // Template: + // DerivedM eigen matrix (e.g. MatrixXd) + // Inputs: + // M data (usually a matrix) + // name variable name to save into work space + // Returns true on success, false on failure + // + // Known Bugs: Assumes Eigen is using column major ordering + template + inline MatlabWorkspace& save( + const Eigen::PlainObjectBase& M, + const std::string & name); + // Template: + // MT sparse matrix type (e.g. double) + template + inline MatlabWorkspace& save( + const Eigen::SparseMatrix& M, + const std::string & name); + // Templates: + // ScalarM scalar type, e.g. double + template + inline MatlabWorkspace& save( + const std::vector > & vM, + const std::string & name); + // Templates: + // ScalarV scalar type, e.g. double + template + inline MatlabWorkspace& save( + const std::vector & vV, + const std::string & name); + // NOTE: Eigen stores quaternions coefficients as (i,j,k,1), but most of + // our matlab code stores them as (1,i,j,k) This takes a quaternion and + // saves it as a (1,i,j,k) row vector + // + // Templates: + // Q quaternion type + template + inline MatlabWorkspace& save( + const Eigen::Quaternion & q, + const std::string & name); + inline MatlabWorkspace& save( + const double d, + const std::string & name); + // Same as save() but adds 1 to each element, useful for saving "index" + // matrices like lists of faces or elements + template + inline MatlabWorkspace& save_index( + const Eigen::DenseBase& M, + const std::string & name); + template + inline MatlabWorkspace& save_index( + const std::vector > & vM, + const std::string & name); + template + inline MatlabWorkspace& save_index( + const std::vector & vV, + const std::string & name); + // Find a certain matrix by name. + // + // KNOWN BUG: Outputs the first found (not necessarily unique lists). + // + // Template: + // DerivedM eigen matrix (e.g. MatrixXd) + // Inputs: + // name exact name of matrix as string + // Outputs: + // M matrix + // Returns true only if found. + template + inline bool find( + const std::string & name, + Eigen::PlainObjectBase& M); + template + inline bool find( + const std::string & name, + Eigen::SparseMatrix& M); + inline bool find( + const std::string & name, + double & d); + inline bool find( + const std::string & name, + int & v); + // Subtracts 1 from all entries + template + inline bool find_index( + const std::string & name, + Eigen::PlainObjectBase& M); + }; + } +} + +// Implementation + +// Be sure that this is not compiled into libigl.a +// http://stackoverflow.com/a/3318993/148668 + +// IGL +#include "igl/list_to_matrix.h" + +// MATLAB +#include "mat.h" + +// STL +#include +#include +#include + +inline igl::matlab::MatlabWorkspace::MatlabWorkspace(): + names(), + data() +{ +} + +inline igl::matlab::MatlabWorkspace::~MatlabWorkspace() +{ + // clean up data + clear(); +} + +inline void igl::matlab::MatlabWorkspace::clear() +{ + for_each(data.begin(),data.end(),&mxDestroyArray); + data.clear(); + names.clear(); +} + +inline bool igl::matlab::MatlabWorkspace::write(const std::string & path) const +{ + using namespace std; + MATFile * mat_file = matOpen(path.c_str(), "w"); + if(mat_file == NULL) + { + fprintf(stderr,"Error opening file %s\n",path.c_str()); + return false; + } + assert(names.size() == data.size()); + // loop over names and data + for(int i = 0;i < (int)names.size(); i++) + { + // Put variable as LOCAL variable + int status = matPutVariable(mat_file,names[i].c_str(), data[i]); + if(status != 0) + { + cerr<<"^MatlabWorkspace::save Error: matPutVariable ("< +inline igl::matlab::MatlabWorkspace& igl::matlab::MatlabWorkspace::save( + const Eigen::PlainObjectBase& M, + const std::string & name) +{ + using namespace std; + const int m = M.rows(); + const int n = M.cols(); + mxArray * mx_data = mxCreateDoubleMatrix(m,n,mxREAL); + data.push_back(mx_data); + names.push_back(name); + // Copy data immediately + // Use Eigen's map and cast to copy + Eigen::Map< Eigen::Matrix > + map(mxGetPr(mx_data),m,n); + map = M.template cast(); + return *this; +} + +// Treat everything as a double +template +inline igl::matlab::MatlabWorkspace& igl::matlab::MatlabWorkspace::save( + const Eigen::SparseMatrix& M, + const std::string & name) +{ + using namespace std; + const int m = M.rows(); + const int n = M.cols(); + // THIS WILL NOT WORK FOR ROW-MAJOR + assert(n==M.outerSize()); + const int nzmax = M.nonZeros(); + mxArray * mx_data = mxCreateSparse(m, n, nzmax, mxREAL); + data.push_back(mx_data); + names.push_back(name); + // Copy data immediately + double * pr = mxGetPr(mx_data); + mwIndex * ir = mxGetIr(mx_data); + mwIndex * jc = mxGetJc(mx_data); + + // Iterate over outside + int k = 0; + for(int j=0; j::InnerIterator it (M,j); it; ++it) + { + pr[k] = it.value(); + ir[k] = it.row(); + k++; + } + } + jc[M.outerSize()] = k; + + return *this; +} + +template +inline igl::matlab::MatlabWorkspace& igl::matlab::MatlabWorkspace::save( + const std::vector > & vM, + const std::string & name) +{ + Eigen::MatrixXd M; + list_to_matrix(vM,M); + return this->save(M,name); +} + +template +inline igl::matlab::MatlabWorkspace& igl::matlab::MatlabWorkspace::save( + const std::vector & vV, + const std::string & name) +{ + Eigen::MatrixXd V; + list_to_matrix(vV,V); + return this->save(V,name); +} + +template +inline igl::matlab::MatlabWorkspace& igl::matlab::MatlabWorkspace::save( + const Eigen::Quaternion & q, + const std::string & name) +{ + Eigen::Matrix qm; + qm(0,0) = q.w(); + qm(0,1) = q.x(); + qm(0,2) = q.y(); + qm(0,3) = q.z(); + return save(qm,name); +} + +inline igl::matlab::MatlabWorkspace& igl::matlab::MatlabWorkspace::save( + const double d, + const std::string & name) +{ + Eigen::VectorXd v(1); + v(0) = d; + return save(v,name); +} + +template +inline igl::matlab::MatlabWorkspace& + igl::matlab::MatlabWorkspace::save_index( + const Eigen::DenseBase& M, + const std::string & name) +{ + DerivedM Mp1 = M; + Mp1.array() += 1; + return this->save(Mp1,name); +} + +template +inline igl::matlab::MatlabWorkspace& igl::matlab::MatlabWorkspace::save_index( + const std::vector > & vM, + const std::string & name) +{ + Eigen::MatrixXd M; + list_to_matrix(vM,M); + return this->save_index(M,name); +} + +template +inline igl::matlab::MatlabWorkspace& igl::matlab::MatlabWorkspace::save_index( + const std::vector & vV, + const std::string & name) +{ + Eigen::MatrixXd V; + list_to_matrix(vV,V); + return this->save_index(V,name); +} + +template +inline bool igl::matlab::MatlabWorkspace::find( + const std::string & name, + Eigen::PlainObjectBase& M) +{ + using namespace std; + const int i = std::find(names.begin(), names.end(), name)-names.begin(); + if(i>=(int)names.size()) + { + return false; + } + assert(i<=(int)data.size()); + mxArray * mx_data = data[i]; + assert(!mxIsSparse(mx_data)); + assert(mxGetNumberOfDimensions(mx_data) == 2); + //cout< > + (mxGetPr(mx_data),M.rows(),M.cols()).cast(); + return true; +} + +template +inline bool igl::matlab::MatlabWorkspace::find( + const std::string & name, + Eigen::SparseMatrix& M) +{ + using namespace std; + using namespace Eigen; + const int i = std::find(names.begin(), names.end(), name)-names.begin(); + if(i>=(int)names.size()) + { + return false; + } + assert(i<=(int)data.size()); + mxArray * mx_data = data[i]; + // Handle boring case where matrix is actually an empty dense matrix + if(mxGetNumberOfElements(mx_data) == 0) + { + M.resize(0,0); + return true; + } + assert(mxIsSparse(mx_data)); + assert(mxGetNumberOfDimensions(mx_data) == 2); + //cout< > MIJV; + const int nnz = mxGetNzmax(mx_data); + MIJV.reserve(nnz); + // Iterate over outside + int k = 0; + for(int j=0; j(ir[k],j,pr[k])); + k++; + } + } + M.resize(m,n); + M.setFromTriplets(MIJV.begin(),MIJV.end()); + + return true; +} + +inline bool igl::matlab::MatlabWorkspace::find( + const std::string & name, + int & v) +{ + using namespace std; + const int i = std::find(names.begin(), names.end(), name)-names.begin(); + if(i>=(int)names.size()) + { + return false; + } + assert(i<=(int)data.size()); + mxArray * mx_data = data[i]; + assert(!mxIsSparse(mx_data)); + assert(mxGetNumberOfDimensions(mx_data) == 2); + //cout<=(int)names.size()) + { + return false; + } + assert(i<=(int)data.size()); + mxArray * mx_data = data[i]; + assert(!mxIsSparse(mx_data)); + assert(mxGetNumberOfDimensions(mx_data) == 2); + //cout< +inline bool igl::matlab::MatlabWorkspace::find_index( + const std::string & name, + Eigen::PlainObjectBase& M) +{ + if(!find(name,M)) + { + return false; + } + M.array() -= 1; + return true; +} + + +//template +//bool igl::matlab::MatlabWorkspace::save(const Data & M, const std::string & name) +//{ +// using namespace std; +// // If I don't know the type then I can't save it +// cerr<<"^MatlabWorkspace::save Error: Unknown data type. "<< +// name<<" not saved."< +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_MATLAB_MEX_STREAM_H +#define IGL_MATLAB_MEX_STREAM_H +#include +namespace igl +{ + namespace matlab + { + // http://stackoverflow.com/a/249008/148668 + + // Class to implement "cout" for mex files to print to the matlab terminal + // window. + // + // Insert at the beginning of mexFunction(): + // MexStream mout; + // std::streambuf *outbuf = std::cout.rdbuf(&mout); + // ... + // ALWAYS restore original buffer to avoid memory leak problems in matlab + // std::cout.rdbuf(outbuf); + // + class MexStream : public std::streambuf + { + public: + protected: + inline virtual std::streamsize xsputn(const char *s, std::streamsize n); + inline virtual int overflow(int c = EOF); + }; + } +} + +// Implementation +#include +inline std::streamsize igl::matlab::MexStream::xsputn( + const char *s, + std::streamsize n) +{ + mexPrintf("%.*s",n,s); + mexEvalString("drawnow;"); // to dump string. + return n; +} + +inline int igl::matlab::MexStream::overflow(int c) +{ + if (c != EOF) { + mexPrintf("%.1s",&c); + mexEvalString("drawnow;"); // to dump string. + } + return 1; +} +#endif diff --git a/src/external/libigl-2.3.0/include/igl/matlab/matlabinterface.cpp b/src/external/libigl-2.3.0/include/igl/matlab/matlabinterface.cpp new file mode 100644 index 000000000..6c03485de --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/matlab/matlabinterface.cpp @@ -0,0 +1,330 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include + +// Implementation + +// Init the MATLAB engine +// (no need to call it directly since it is automatically invoked by any other command) +IGL_INLINE void igl::matlab::mlinit(Engine** mlengine) +{ + *mlengine = engOpen("\0"); +} + +// Closes the MATLAB engine +IGL_INLINE void igl::matlab::mlclose(Engine** mlengine) +{ + engClose(*mlengine); + *mlengine = 0; +} + +// Send a matrix to MATLAB +IGL_INLINE void igl::matlab::mlsetmatrix(Engine** mlengine, std::string name, const Eigen::MatrixXd& M) +{ + if (*mlengine == 0) + mlinit(mlengine); + + mxArray *A = mxCreateDoubleMatrix(M.rows(), M.cols(), mxREAL); + double *pM = mxGetPr(A); + + int c = 0; + for(int j=0; j& M) +{ + if (*mlengine == 0) + mlinit(mlengine); + + mxArray *A = mxCreateDoubleMatrix(M.rows(), M.cols(), mxREAL); + double *pM = mxGetPr(A); + + int c = 0; + for(int j=0; j t; + + mxArray *ary = engGetVariable(*mlengine, name.c_str()); + if (ary == NULL) + { + m = 0; + n = 0; + M = Eigen::MatrixXd(0,0); + } + else + { + m = mxGetM(ary); + n = mxGetN(ary); + M = Eigen::MatrixXd(m,n); + + double *pM = mxGetPr(ary); + + int c = 0; + for(int j=0; j t; + + mxArray *ary = engGetVariable(*mlengine, name.c_str()); + if (ary == NULL) + { + m = 0; + n = 0; + M = Eigen::MatrixXf(0,0); + } + else + { + m = mxGetM(ary); + n = mxGetN(ary); + M = Eigen::MatrixXf(m,n); + + double *pM = mxGetPr(ary); + + int c = 0; + for(int j=0; j t; + + mxArray *ary = engGetVariable(*mlengine, name.c_str()); + if (ary == NULL) + { + m = 0; + n = 0; + M = Eigen::MatrixXi(0,0); + } + else + { + m = mxGetM(ary); + n = mxGetN(ary); + M = Eigen::MatrixXi(m,n); + + double *pM = mxGetPr(ary); + + int c = 0; + for(int j=0; j& M) +{ + if (*mlengine == 0) + mlinit(mlengine); + + unsigned long m = 0; + unsigned long n = 0; + std::vector t; + + mxArray *ary = engGetVariable(*mlengine, name.c_str()); + if (ary == NULL) + { + m = 0; + n = 0; + M = Eigen::Matrix(0,0); + } + else + { + m = mxGetM(ary); + n = mxGetN(ary); + M = Eigen::Matrix(m,n); + + double *pM = mxGetPr(ary); + + int c = 0; + for(int j=0; j' && buf[1] == '>' && buf[2] == ' ') + buf += 3; + if (buf[0] == '\n') ++buf; + + return std::string(buf); +} + +// Send a sparse matrix +IGL_INLINE void igl::matlab::mlsetmatrix(Engine** mlengine, std::string name, const Eigen::SparseMatrix& M) +{ + int count = 0; +// // Count non-zero +// for (unsigned k=0; k::InnerIterator it(M,k); it; ++it) +// if (it.value() != 0) +// ++count; + + Eigen::MatrixXd T(M.nonZeros(),3); + for (unsigned k=0; k<(unsigned)M.outerSize(); ++k) + { + for (Eigen::SparseMatrix::InnerIterator it(M,k); it; ++it) + { + T(count,0) = it.row(); + T(count,1) = it.col(); + T(count,2) = it.value(); + ++count; + } + } + + T.col(0) = T.col(0).array()+1; + T.col(1) = T.col(1).array()+1; + + mlsetmatrix(mlengine,"temp93765",T); + + std::string temp = name + " = sparse(temp93765(:,1),temp93765(:,2),temp93765(:,3)," + + std::to_string(M.rows()) + "," + + std::to_string(M.cols()) + ");"; + + mleval(mlengine,temp); + mleval(mlengine,"clear temp93765"); +} diff --git a/src/external/libigl-2.3.0/include/igl/matlab/matlabinterface.h b/src/external/libigl-2.3.0/include/igl/matlab/matlabinterface.h new file mode 100644 index 000000000..63d72c74e --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/matlab/matlabinterface.h @@ -0,0 +1,90 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Daniele Panozzo +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_MATLAB_MATLAB_INTERFACE_H +#define IGL_MATLAB_MATLAB_INTERFACE_H +#include "../igl_inline.h" +// WARNING: These functions require matlab installed +// Additional header folder required: +// /Applications/MATLAB_R2011a.app/extern/include +// Additional binary lib to be linked with: +// /Applications/MATLAB_R2011a.app/bin/maci64/libeng.dylib +// /Applications/MATLAB_R2011a.app/bin/maci64/libmx.dylib + +// MAC ONLY: +// Add to the environment variables: +// DYLD_LIBRARY_PATH = /Applications/MATLAB_R2011a.app/bin/maci64/ +// PATH = /opt/local/bin:/opt/local/sbin:/Applications/MATLAB_R2011a.app/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/usr/texbin:/usr/X11/bin + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include // Matlab engine header + +namespace igl +{ + namespace matlab + { + // Init the MATLAB engine + // (no need to call it directly since it is automatically invoked by any other command) + IGL_INLINE void mlinit(Engine** engine); + + // Closes the MATLAB engine + IGL_INLINE void mlclose(Engine** engine); + + // Send a matrix to MATLAB + IGL_INLINE void mlsetmatrix(Engine** engine, std::string name, const Eigen::MatrixXd& M); + + // Send a matrix to MATLAB + IGL_INLINE void mlsetmatrix(Engine** engine, std::string name, const Eigen::MatrixXf& M); + + // Send a matrix to MATLAB + IGL_INLINE void mlsetmatrix(Engine** engine, std::string name, const Eigen::MatrixXi& M); + + // Send a matrix to MATLAB + IGL_INLINE void mlsetmatrix(Engine** mlengine, std::string name, const Eigen::Matrix& M); + + // Receive a matrix from MATLAB + IGL_INLINE void mlgetmatrix(Engine** engine, std::string name, Eigen::MatrixXd& M); + + // Receive a matrix from MATLAB + IGL_INLINE void mlgetmatrix(Engine** engine, std::string name, Eigen::MatrixXf& M); + + // Receive a matrix from MATLAB + IGL_INLINE void mlgetmatrix(Engine** engine, std::string name, Eigen::MatrixXi& M); + + // Receive a matrix from MATLAB + IGL_INLINE void mlgetmatrix(Engine** mlengine, std::string name, Eigen::Matrix& M); + + // Send a single scalar to MATLAB + IGL_INLINE void mlsetscalar(Engine** engine, std::string name, double s); + + // Receive a single scalar from MATLAB + IGL_INLINE double mlgetscalar(Engine** engine, std::string name); + + // Execute arbitrary MATLAB code and return the MATLAB output + IGL_INLINE std::string mleval(Engine** engine, std::string code); + + // Send a sparse matrix to MATLAB + IGL_INLINE void mlsetmatrix(Engine** mlengine, std::string name, const Eigen::SparseMatrix& M); + + } +} + +// Be sure that this is not compiled into libigl.a +#ifndef IGL_STATIC_LIBRARY +# include "matlabinterface.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/matlab/mexErrMsgTxt.cpp b/src/external/libigl-2.3.0/include/igl/matlab/mexErrMsgTxt.cpp new file mode 100644 index 000000000..89dda1fa3 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/matlab/mexErrMsgTxt.cpp @@ -0,0 +1,17 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "mexErrMsgTxt.h" + +IGL_INLINE void igl::matlab::mexErrMsgTxt(bool assertion, const char * text) +{ + if(!assertion) + { + ::mexErrMsgTxt(text); + } +} + diff --git a/src/external/libigl-2.3.0/include/igl/matlab/mexErrMsgTxt.h b/src/external/libigl-2.3.0/include/igl/matlab/mexErrMsgTxt.h new file mode 100644 index 000000000..61b838e6e --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/matlab/mexErrMsgTxt.h @@ -0,0 +1,25 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_MATLAB_MEXERRMSGTXT_H +#define IGL_MATLAB_MEXERRMSGTXT_H +#include "../igl_inline.h" +// Overload mexErrMsgTxt to check an assertion then print text only if +// assertion fails +#include "mex.h" +namespace igl +{ + namespace matlab + { + // Wrapper for mexErrMsgTxt that only calls error if test fails + IGL_INLINE void mexErrMsgTxt(bool test, const char * message); + } +} +#ifndef IGL_STATIC_LIBRARY +# include "mexErrMsgTxt.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/matlab/parse_rhs.cpp b/src/external/libigl-2.3.0/include/igl/matlab/parse_rhs.cpp new file mode 100644 index 000000000..ac8d6b377 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/matlab/parse_rhs.cpp @@ -0,0 +1,85 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "parse_rhs.h" +#include + +template +IGL_INLINE void igl::matlab::parse_rhs_double( + const mxArray *prhs[], + Eigen::PlainObjectBase & V) +{ + using namespace Eigen; + // Use Eigen's map and cast to copy + V = Map< Matrix > + (mxGetPr(prhs[0]),mxGetM(prhs[0]),mxGetN(prhs[0])) + .cast(); +} + +template +IGL_INLINE void igl::matlab::parse_rhs_index( + const mxArray *prhs[], + Eigen::PlainObjectBase & V) +{ + parse_rhs_double(prhs,V); + V.array() -= 1; +} + +template +IGL_INLINE void igl::matlab::parse_rhs( + const mxArray *prhs[], + Eigen::SparseMatrix & M) +{ + using namespace Eigen; + using namespace std; + const mxArray * mx_data = prhs[0]; + // Handle boring case where matrix is actually an empty dense matrix + if(mxGetNumberOfElements(mx_data) == 0) + { + M.resize(0,0); + return; + } + assert(mxIsSparse(mx_data)); + assert(mxGetNumberOfDimensions(mx_data) == 2); + //cout< > MIJV; + MIJV.reserve(mxGetNumberOfElements(mx_data)); + // Iterate over outside + int k = 0; + for(int j=0; j(ir[k],j,pr[k])); + k++; + } + } + M.resize(m,n); + M.setFromTriplets(MIJV.begin(),MIJV.end()); +} + +#ifdef IGL_STATIC_LIBRARY +template void igl::matlab::parse_rhs_index >(mxArray_tag const**, Eigen::PlainObjectBase >&); +template void igl::matlab::parse_rhs_index >(mxArray_tag const**, Eigen::PlainObjectBase >&); +template void igl::matlab::parse_rhs_double >(mxArray_tag const**, Eigen::PlainObjectBase >&); +template void igl::matlab::parse_rhs_index >(mxArray_tag const**, Eigen::PlainObjectBase >&); +template void igl::matlab::parse_rhs_double >(mxArray_tag const**, Eigen::PlainObjectBase >&); +template void igl::matlab::parse_rhs_double >(mxArray_tag const**, Eigen::PlainObjectBase >&); +template void igl::matlab::parse_rhs_double >(mxArray_tag const**, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/matlab/parse_rhs.h b/src/external/libigl-2.3.0/include/igl/matlab/parse_rhs.h new file mode 100644 index 000000000..3cabec734 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/matlab/parse_rhs.h @@ -0,0 +1,42 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_MATLAB_PARSE_RHS_H +#define IGL_MATLAB_PARSE_RHS_H +#include +#include +#include +#include +namespace igl +{ + namespace matlab + { + // Reads in a matrix as a double + // + // Inputs: + // prhs points to rhs argument + // Outputs: + // V M by N matrix + template + IGL_INLINE void parse_rhs_double( + const mxArray *prhs[], + Eigen::PlainObjectBase & V); + // Reads in a matrix and subtracts 1 + template + IGL_INLINE void parse_rhs_index( + const mxArray *prhs[], + Eigen::PlainObjectBase & V); + template + IGL_INLINE void parse_rhs( + const mxArray *prhs[], + Eigen::SparseMatrix & M); + } +}; +#ifndef IGL_STATIC_LIBRARY +# include "parse_rhs.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/matlab/prepare_lhs.cpp b/src/external/libigl-2.3.0/include/igl/matlab/prepare_lhs.cpp new file mode 100644 index 000000000..d01697be7 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/matlab/prepare_lhs.cpp @@ -0,0 +1,126 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "prepare_lhs.h" +#include +template +IGL_INLINE void igl::matlab::prepare_lhs_double( + const Eigen::PlainObjectBase & V, + mxArray *plhs[]) +{ + using namespace std; + using namespace Eigen; + const auto m = V.rows(); + const auto n = V.cols(); + plhs[0] = mxCreateDoubleMatrix(m,n, mxREAL); + Eigen::Map< Eigen::Matrix > + map(mxGetPr(plhs[0]),m,n); + map = V.template cast(); +} + +template +IGL_INLINE void igl::matlab::prepare_lhs_logical( + const Eigen::PlainObjectBase & V, + mxArray *plhs[]) +{ + using namespace std; + using namespace Eigen; + const auto m = V.rows(); + const auto n = V.cols(); + plhs[0] = mxCreateLogicalMatrix(m,n); + mxLogical * Vp = static_cast(mxGetData(plhs[0])); + Eigen::Map< Eigen::Matrix > + map(static_cast(mxGetData(plhs[0])),m,n); + map = V.template cast(); +} + +template +IGL_INLINE void igl::matlab::prepare_lhs_index( + const Eigen::PlainObjectBase & V, + mxArray *plhs[]) +{ + // Treat indices as reals + const auto Vd = (V.template cast().array()+1).eval(); + return prepare_lhs_double(Vd,plhs); +} + +template +IGL_INLINE void igl::matlab::prepare_lhs_double( + const Eigen::SparseMatrix & M, + mxArray *plhs[]) +{ + using namespace std; + const auto m = M.rows(); + const auto n = M.cols(); + // THIS WILL NOT WORK FOR ROW-MAJOR + assert(n==M.outerSize()); + const int nzmax = M.nonZeros(); + plhs[0] = mxCreateSparse(m, n, nzmax, mxREAL); + mxArray * mx_data = plhs[0]; + // Copy data immediately + double * pr = mxGetPr(mx_data); + mwIndex * ir = mxGetIr(mx_data); + mwIndex * jc = mxGetJc(mx_data); + + // Iterate over outside + int k = 0; + for(int j=0; j::InnerIterator it (M,j); it; ++it) + { + // copy (cast to double) + pr[k] = it.value(); + ir[k] = it.row(); + k++; + } + } + jc[M.outerSize()] = k; + +} + + +template +IGL_INLINE void igl::matlab::prepare_lhs_double( + const std::vector & V, + mxArray *plhs[]) +{ + plhs[0] = mxCreateCellMatrix(V.size(), 1); + for(int i=0; i > + map(mxGetPr(ai),m,n); + map = V[i].template cast(); + mxSetCell(plhs[0],i,ai); + } +} + + + +#ifdef IGL_STATIC_LIBRARY +template void igl::matlab::prepare_lhs_double >(Eigen::PlainObjectBase > const&, mxArray_tag**); +template void igl::matlab::prepare_lhs_double >(Eigen::PlainObjectBase > const&, mxArray_tag**); +template void igl::matlab::prepare_lhs_index >(Eigen::PlainObjectBase > const&, mxArray_tag**); +template void igl::matlab::prepare_lhs_index >(Eigen::PlainObjectBase > const&, mxArray_tag**); +template void igl::matlab::prepare_lhs_double >(Eigen::PlainObjectBase > const&, mxArray_tag**); +template void igl::matlab::prepare_lhs_index >(Eigen::PlainObjectBase > const&, mxArray_tag**); +template void igl::matlab::prepare_lhs_logical >(Eigen::PlainObjectBase > const&, mxArray_tag**); +template void igl::matlab::prepare_lhs_double >(Eigen::PlainObjectBase > const&, mxArray_tag**); +template void igl::matlab::prepare_lhs_logical >(Eigen::PlainObjectBase > const&, mxArray_tag**); +template void igl::matlab::prepare_lhs_index >(Eigen::PlainObjectBase > const&, mxArray_tag**); +template void igl::matlab::prepare_lhs_double >(Eigen::PlainObjectBase > const&, mxArray_tag**); +template void igl::matlab::prepare_lhs_double >(Eigen::PlainObjectBase > const&, mxArray_tag**); +template void igl::matlab::prepare_lhs_double >(Eigen::PlainObjectBase > const&, mxArray_tag**); +template void igl::matlab::prepare_lhs_double >(Eigen::PlainObjectBase > const&, mxArray_tag**); +template void igl::matlab::prepare_lhs_double >(Eigen::PlainObjectBase > const&, mxArray_tag**); +template void igl::matlab::prepare_lhs_double(Eigen::SparseMatrix const&, mxArray_tag**); +template void igl::matlab::prepare_lhs_double >(std::vector, std::allocator > > const&, mxArray_tag**); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/matlab/prepare_lhs.h b/src/external/libigl-2.3.0/include/igl/matlab/prepare_lhs.h new file mode 100644 index 000000000..e3596db1f --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/matlab/prepare_lhs.h @@ -0,0 +1,54 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_MATLAB_PREPARE_LHS_H +#define IGL_MATLAB_PREPARE_LHS_H +#include +#include +#include +#include +namespace igl +{ + namespace matlab + { + // Writes out a matrix as a double + // + // Inputs: + // prhs points to rhs argument + // Outputs: + // V M by N matrix + template + IGL_INLINE void prepare_lhs_double( + const Eigen::PlainObjectBase & V, + mxArray *plhs[]); + // Casts to logical + template + IGL_INLINE void prepare_lhs_logical( + const Eigen::PlainObjectBase & V, + mxArray *plhs[]); + // Writes out a matrix and adds 1 + template + IGL_INLINE void prepare_lhs_index( + const Eigen::PlainObjectBase & V, + mxArray *plhs[]); + // SparseMatrix + template + IGL_INLINE void prepare_lhs_double( + const Eigen::SparseMatrix & V, + mxArray *plhs[]); + // Vector of matrices -> cell array of matrices + template + IGL_INLINE void prepare_lhs_double( + const std::vector & V, + mxArray *plhs[]); + }; +} +#ifndef IGL_STATIC_LIBRARY +# include "prepare_lhs.cpp" +#endif +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/matlab/requires_arg.cpp b/src/external/libigl-2.3.0/include/igl/matlab/requires_arg.cpp new file mode 100644 index 000000000..a03469183 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/matlab/requires_arg.cpp @@ -0,0 +1,16 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "requires_arg.h" +#include "mexErrMsgTxt.h" +#include "../C_STR.h" + +IGL_INLINE void igl::matlab::requires_arg(const int i, const int nrhs, const char *name) +{ + mexErrMsgTxt((i+1) +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_REQUIRES_ARG_H +#define IGL_REQUIRES_ARG_H +#include "../igl_inline.h" +#include +namespace igl +{ + namespace matlab + { + // Simply throw an error if (i+1) +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "validate_arg.h" +#include "requires_arg.h" +#include "mexErrMsgTxt.h" +#include "../C_STR.h" + +IGL_INLINE void igl::matlab::validate_arg_scalar( + const int i, const int nrhs, const mxArray * prhs[], const char * name) +{ + requires_arg(i,nrhs,name); + mexErrMsgTxt(mxGetN(prhs[i+1])==1 && mxGetM(prhs[i+1])==1, + C_STR("Parameter '"< +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_VALIDATE_ARG_H +#define IGL_VALIDATE_ARG_H +#include "../igl_inline.h" +#include +namespace igl +{ + namespace matlab + { + // Throw an error if arg i+1 is not a scalar + // + // Inputs: + // i index of current argument + // nrhs total number of arguments + // prhs pointer to arguments array + // name name of current argument + IGL_INLINE void validate_arg_scalar( + const int i, const int nrhs, const mxArray * prhs[], const char * name); + IGL_INLINE void validate_arg_logical( + const int i, const int nrhs, const mxArray * prhs[], const char * name); + IGL_INLINE void validate_arg_char( + const int i, const int nrhs, const mxArray * prhs[], const char * name); + IGL_INLINE void validate_arg_double( + const int i, const int nrhs, const mxArray * prhs[], const char * name); + IGL_INLINE void validate_arg_function_handle( + const int i, const int nrhs, const mxArray * prhs[], const char * name); + } +} +#ifndef IGL_STATIC_LIBRARY +# include "validate_arg.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/matlab_format.cpp b/src/external/libigl-2.3.0/include/igl/matlab_format.cpp new file mode 100644 index 000000000..b763d285c --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/matlab_format.cpp @@ -0,0 +1,297 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "matlab_format.h" +#include "STR.h" +#include "find.h" + +template +IGL_INLINE const Eigen::WithFormat< DerivedM > igl::matlab_format( + const Eigen::DenseBase & M, + const std::string name) +{ + using namespace std; + string prefix = ""; + if(!name.empty()) + { + prefix = name + " = "; + } + + return M.format(Eigen::IOFormat( + Eigen::FullPrecision, + 0, + " ", + "\n", + "", + "", + // This seems like a bit of a hack since I would expect the rows to align + // with out this extra spacing on the first line + prefix + "[\n ", + "\n];")); +} + +template +IGL_INLINE std::string igl::matlab_format_index( + const Eigen::MatrixBase & M, + const std::string name) +{ + // can't return WithFormat since that uses a pointer to matrix + return STR(igl::matlab_format((M.array()+1).eval(),name)); +} + +template +IGL_INLINE const std::string +igl::matlab_format( + const Eigen::SparseMatrix & S, + const std::string name) +{ + using namespace Eigen; + using namespace std; + Matrix::Scalar,Dynamic,1> I,J,V; + Matrix SIJV; + find(S,I,J,V); + I.array() += 1; + J.array() += 1; + SIJV.resize(V.rows(),3); + SIJV << I,J,V; + string prefix = ""; + string suffix = ""; + if(!name.empty()) + { + prefix = name + "IJV = "; + suffix = "\n"+name + " = sparse("+name+"IJV(:,1),"+name+"IJV(:,2),"+name+"IJV(:,3),"+std::to_string(S.rows())+","+std::to_string(S.cols())+" );"; + } + return STR(""<< + SIJV.format(Eigen::IOFormat( + Eigen::FullPrecision, + 0, + " ", + "\n", + "", + "", + // This seems like a bit of a hack since I would expect the rows to align + // with out this extra spacing on the first line + prefix + "[\n ", + "\n];"))< > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +// generated by autoexplicit.sh +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +// generated by autoexplicit.sh +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +// generated by autoexplicit.sh +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +// generated by autoexplicit.sh +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +// generated by autoexplicit.sh +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +// generated by autoexplicit.sh +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +// generated by autoexplicit.sh +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +// generated by autoexplicit.sh +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +// generated by autoexplicit.sh +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +// generated by autoexplicit.sh +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +// generated by autoexplicit.sh +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +// generated by autoexplicit.sh +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +// generated by autoexplicit.sh +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +// generated by autoexplicit.sh +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +// generated by autoexplicit.sh +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +// generated by autoexplicit.sh +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +// generated by autoexplicit.sh +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +// generated by autoexplicit.sh +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +// generated by autoexplicit.sh +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +// generated by autoexplicit.sh +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +// generated by autoexplicit.sh +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +// generated by autoexplicit.sh +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +// generated by autoexplicit.sh +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +// generated by autoexplicit.sh +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +// generated by autoexplicit.sh +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +// generated by autoexplicit.sh +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +// generated by autoexplicit.sh +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +// generated by autoexplicit.sh +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +// generated by autoexplicit.sh +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +// generated by autoexplicit.sh +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +// generated by autoexplicit.sh +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +// generated by autoexplicit.sh +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +// generated by autoexplicit.sh +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +// generated by autoexplicit.sh +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +// generated by autoexplicit.sh +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +// generated by autoexplicit.sh +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +// generated by autoexplicit.sh +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +// generated by autoexplicit.sh +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +// generated by autoexplicit.sh +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +// generated by autoexplicit.sh +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +// generated by autoexplicit.sh +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +// generated by autoexplicit.sh +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +// generated by autoexplicit.sh +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +// generated by autoexplicit.sh +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +// generated by autoexplicit.sh +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +// generated by autoexplicit.sh +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +// generated by autoexplicit.sh +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +// generated by autoexplicit.sh +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +// generated by autoexplicit.sh +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +// generated by autoexplicit.sh +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +// generated by autoexplicit.sh +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +// generated by autoexplicit.sh +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +// generated by autoexplicit.sh +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +// generated by autoexplicit.sh +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +// generated by autoexplicit.sh +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +// generated by autoexplicit.sh +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +// generated by autoexplicit.sh +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +template std::basic_string, std::allocator > igl::matlab_format_index >(Eigen::MatrixBase > const&, std::basic_string, std::allocator >); +template std::basic_string, std::allocator > igl::matlab_format_index >(Eigen::MatrixBase > const&, std::basic_string, std::allocator >); +/////////////////////////////////////////////////// +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +#if EIGEN_VERSION_AT_LEAST(3,3,0) +#else +template Eigen::WithFormat, Eigen::Matrix const> > const igl::matlab_format, Eigen::Matrix const> >(Eigen::DenseBase, Eigen::Matrix const> > const&, std::basic_string, std::allocator >); +template Eigen::WithFormat, Eigen::ArrayWrapper const> const> > const igl::matlab_format, Eigen::ArrayWrapper const> const> >(Eigen::DenseBase, Eigen::ArrayWrapper const> const> > const&, std::basic_string, std::allocator >); +template Eigen::WithFormat, Eigen::ArrayWrapper > const> > const igl::matlab_format, Eigen::ArrayWrapper > const> >(Eigen::DenseBase, Eigen::ArrayWrapper > const> > const&, std::basic_string, std::allocator >); +template Eigen::WithFormat, Eigen::ArrayWrapper > const> > const igl::matlab_format, Eigen::ArrayWrapper > const> >(Eigen::DenseBase, Eigen::ArrayWrapper > const> > const&, std::basic_string, std::allocator >); +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +template Eigen::WithFormat, -1, -1, false> > > const igl::matlab_format, -1, -1, false> > >(Eigen::DenseBase, -1, -1, false> > > const&, std::basic_string, std::allocator >); +template Eigen::WithFormat > > const igl::matlab_format > >(Eigen::DenseBase > > const&, std::basic_string, std::allocator >); +#endif +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +template std::basic_string, std::allocator > const igl::matlab_format(Eigen::SparseMatrix const&, std::basic_string, std::allocator >); +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::string); +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +template Eigen::WithFormat > const igl::matlab_format >(Eigen::DenseBase > const&, std::basic_string, std::allocator >); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/matlab_format.h b/src/external/libigl-2.3.0/include/igl/matlab_format.h new file mode 100644 index 000000000..c5c6a2690 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/matlab_format.h @@ -0,0 +1,93 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_MATLAB_FORMAT_H +#define IGL_MATLAB_FORMAT_H + +#include "igl_inline.h" + +#include +#include +#include + +namespace igl +{ + // This is a routine to print a matrix using format suitable for pasting into + // the matlab IDE + // + // Templates: + // DerivedM e.g. derived from MatrixXd + // Input: + // input some matrix to be formatted + // name name of matrix + // Returns Formatted matrix + // + // Example: + // // M := [1 2 3;4 5 6]; + // cout< + IGL_INLINE const Eigen::WithFormat< DerivedM > matlab_format( + const Eigen::DenseBase & M, + const std::string name = ""); + template + IGL_INLINE std::string matlab_format_index( + const Eigen::MatrixBase & M, + const std::string name = ""); + // Same but for sparse matrices. Print IJV format into an auxiliary variable + // and then print a call to sparse which will construct the sparse matrix + // Example: + // // S := [0 2 3;4 5 0]; + // cout< + IGL_INLINE const std::string matlab_format( + const Eigen::SparseMatrix & S, + const std::string name = ""); + IGL_INLINE const std::string matlab_format( + const double v, + const std::string name = ""); + IGL_INLINE const std::string matlab_format( + const float v, + const std::string name = ""); + // Return just IOFormat + // + // Example: + // // M := [1 2 3;4 5 6]; + // cout< +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "matrix_to_list.h" + +#include + +template +IGL_INLINE void igl::matrix_to_list( + const Eigen::MatrixBase & M, + std::vector > & V) +{ + using namespace std; + V.resize(M.rows(),vector(M.cols())); + // loop over rows + for(int i = 0;i +IGL_INLINE void igl::matrix_to_list( + const Eigen::MatrixBase & M, + std::vector & V) +{ + using namespace std; + V.resize(M.size()); + // loop over cols then rows + for(int j = 0;j +IGL_INLINE std::vector igl::matrix_to_list( + const Eigen::MatrixBase & M) +{ + std::vector V; + matrix_to_list(M,V); + return V; +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::matrix_to_list, -1, 1, true> >(Eigen::MatrixBase, -1, 1, true> > const&, std::vector, -1, 1, true>::Scalar, std::allocator, -1, 1, true>::Scalar> >&); +// generated by autoexplicit.sh +template void igl::matrix_to_list, -1, 1, true> >(Eigen::MatrixBase, -1, 1, true> > const&, std::vector, -1, 1, true>::Scalar, std::allocator, -1, 1, true>::Scalar> >&); +// generated by autoexplicit.sh +template void igl::matrix_to_list >(Eigen::MatrixBase > const&, std::vector::Scalar, std::allocator::Scalar> >&); +// generated by autoexplicit.sh +template std::vector::Scalar, std::allocator::Scalar> > igl::matrix_to_list >(Eigen::MatrixBase > const&); +// generated by autoexplicit.sh +template std::vector::Scalar, std::allocator::Scalar> > igl::matrix_to_list >(Eigen::MatrixBase > const&); +//template void igl::matrix_to_list >, double>(Eigen::PlainObjectBase > const&, std::vector >, std::allocator > > >&); +//template void igl::matrix_to_list >, int>(Eigen::PlainObjectBase > const&, std::vector >, std::allocator > > >&); +template void igl::matrix_to_list >(Eigen::MatrixBase > const&, std::vector::Scalar, std::allocator::Scalar> >, std::allocator::Scalar, std::allocator::Scalar> > > >&); +template void igl::matrix_to_list >(Eigen::MatrixBase > const&, std::vector::Scalar, std::allocator::Scalar> >, std::allocator::Scalar, std::allocator::Scalar> > > >&); +template void igl::matrix_to_list >(Eigen::MatrixBase > const&, std::vector::Scalar, std::allocator::Scalar> >&); +template void igl::matrix_to_list >(Eigen::MatrixBase > const&, std::vector::Scalar, std::allocator::Scalar> >&); +template void igl::matrix_to_list >(Eigen::MatrixBase > const&, std::vector::Scalar, std::allocator::Scalar> >&); +template void igl::matrix_to_list >(Eigen::MatrixBase > const&, std::vector::Scalar, std::allocator::Scalar> >, std::allocator::Scalar, std::allocator::Scalar> > > >&); +template void igl::matrix_to_list >(Eigen::MatrixBase > const&, std::vector::Scalar, std::allocator::Scalar> >&); +template void igl::matrix_to_list >(Eigen::MatrixBase > const&, std::vector::Scalar, std::allocator::Scalar> >&); +template std::vector::Scalar, std::allocator::Scalar> > igl::matrix_to_list >(Eigen::MatrixBase > const&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/matrix_to_list.h b/src/external/libigl-2.3.0/include/igl/matrix_to_list.h new file mode 100644 index 000000000..92ebf6b49 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/matrix_to_list.h @@ -0,0 +1,55 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_MATRIX_TO_LIST_H +#define IGL_MATRIX_TO_LIST_H +#include "igl_inline.h" +#include +#include + +namespace igl +{ + // Convert a matrix to a list (std::vector) of row vectors of the same size + // + // Template: + // Mat Matrix type, must implement: + // .resize(m,n) + // .row(i) = Row + // T type that can be safely cast to type in Mat via '=' + // Inputs: + // M an m by n matrix + // Outputs: + // V a m-long list of vectors of size n + // + // See also: list_to_matrix + template + IGL_INLINE void matrix_to_list( + const Eigen::MatrixBase & M, + std::vector > & V); + // Convert a matrix to a list (std::vector) of elements in column-major + // ordering. + // + // Inputs: + // M an m by n matrix + // Outputs: + // V an m*n list of elements + template + IGL_INLINE void matrix_to_list( + const Eigen::MatrixBase & M, + std::vector & V); + // Return wrapper + template + IGL_INLINE std::vector matrix_to_list( + const Eigen::MatrixBase & M); +} + +#ifndef IGL_STATIC_LIBRARY +# include "matrix_to_list.cpp" +#endif + +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/max.cpp b/src/external/libigl-2.3.0/include/igl/max.cpp new file mode 100644 index 000000000..e451c3b15 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/max.cpp @@ -0,0 +1,46 @@ +#include "max.h" +#include "for_each.h" +#include "find_zero.h" + +template +IGL_INLINE void igl::max( + const Eigen::SparseMatrix & A, + const int dim, + Eigen::PlainObjectBase & B, + Eigen::PlainObjectBase & I) +{ + const int n = A.cols(); + const int m = A.rows(); + B.resize(dim==1?n:m); + B.setConstant(std::numeric_limits::lowest()); + I.resize(dim==1?n:m); + for_each(A,[&B,&I,&dim](int i, int j,const typename DerivedB::Scalar v) + { + if(dim == 2) + { + std::swap(i,j); + } + // Coded as if dim == 1, assuming swap for dim == 2 + if(v > B(j)) + { + B(j) = v; + I(j) = i; + } + }); + Eigen::VectorXi Z; + find_zero(A,dim,Z); + for(int j = 0;j B(j)) + { + B(j) = 0; + I(j) = Z(j); + } + } +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::max, Eigen::Matrix >(Eigen::SparseMatrix const&, int, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/max.h b/src/external/libigl-2.3.0/include/igl/max.h new file mode 100644 index 000000000..554a19b13 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/max.h @@ -0,0 +1,27 @@ +#ifndef IGL_MAX_H +#define IGL_MAX_H +#include "igl_inline.h" +#include +#include +namespace igl +{ + // Inputs: + // X m by n matrix + // dim dimension along which to take max + // Outputs: + // Y n-long vector (if dim == 1) + // or + // Y m-long vector (if dim == 2) + // I vector the same size as Y containing the indices along dim of maximum + // entries + template + IGL_INLINE void max( + const Eigen::SparseMatrix & A, + const int dim, + Eigen::PlainObjectBase & B, + Eigen::PlainObjectBase & I); +} +#ifndef IGL_STATIC_LIBRARY +# include "max.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/max_faces_stopping_condition.cpp b/src/external/libigl-2.3.0/include/igl/max_faces_stopping_condition.cpp new file mode 100644 index 000000000..6d95022d2 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/max_faces_stopping_condition.cpp @@ -0,0 +1,49 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "max_faces_stopping_condition.h" + +IGL_INLINE void igl::max_faces_stopping_condition( + int & m, + const int orig_m, + const int max_m, + decimate_stopping_condition_callback & stopping_condition) +{ + stopping_condition = + [orig_m,max_m,&m]( + const Eigen::MatrixXd &, + const Eigen::MatrixXi &, + const Eigen::MatrixXi &, + const Eigen::VectorXi &, + const Eigen::MatrixXi &, + const Eigen::MatrixXi &, + const igl::min_heap< std::tuple > & , + const Eigen::VectorXi & , + const Eigen::MatrixXd &, + const int, + const int, + const int, + const int f1, + const int f2)->bool + { + // Only subtract if we're collapsing a real face + if(f1 < orig_m) m-=1; + if(f2 < orig_m) m-=1; + return m<=(int)max_m; + }; +} + +IGL_INLINE igl::decimate_stopping_condition_callback +igl::max_faces_stopping_condition( + int & m, + const int orig_m, + const int max_m) +{ + decimate_stopping_condition_callback stopping_condition; + max_faces_stopping_condition(m,orig_m,max_m,stopping_condition); + return stopping_condition; +} diff --git a/src/external/libigl-2.3.0/include/igl/max_faces_stopping_condition.h b/src/external/libigl-2.3.0/include/igl/max_faces_stopping_condition.h new file mode 100644 index 000000000..419a427bb --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/max_faces_stopping_condition.h @@ -0,0 +1,47 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_MAX_FACES_STOPPING_CONDITION_H +#define IGL_MAX_FACES_STOPPING_CONDITION_H +#include "igl_inline.h" +#include "decimate_callback_types.h" +#include +#include +#include +#include +namespace igl +{ + // Stopping condition function compatible with igl::decimate. The outpute + // function handle will return true if number of faces is less than max_m + // + // Inputs: + // m reference to working variable initially should be set to current + // number of faces. + // orig_m number (size) of original face list _**not**_ including any + // faces added to handle phony boundary faces connecting to point at + // infinity. For closed meshes it's safe to set this to F.rows() + // max_m maximum number of faces + // Outputs: + // stopping_condition + // + IGL_INLINE void max_faces_stopping_condition( + int & m, + const int orig_m, + const int max_m, + decimate_stopping_condition_callback & stopping_condition); + IGL_INLINE decimate_stopping_condition_callback + max_faces_stopping_condition( + int & m, + const int orign_m, + const int max_m); +} + +#ifndef IGL_STATIC_LIBRARY +# include "max_faces_stopping_condition.cpp" +#endif +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/max_size.cpp b/src/external/libigl-2.3.0/include/igl/max_size.cpp new file mode 100644 index 000000000..f3b9a07f2 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/max_size.cpp @@ -0,0 +1,39 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "max_size.h" + + +template +IGL_INLINE int igl::max_size(const std::vector & V) +{ + int max_size = -1; + for( + typename std::vector::const_iterator iter = V.begin(); + iter != V.end(); + iter++) + { + int size = (int)iter->size(); + max_size = (max_size > size ? max_size : size); + } + return max_size; +} + + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template int igl::max_size > >(std::vector >, std::allocator > > > const&); +// generated by autoexplicit.sh +template int igl::max_size > >(std::vector >, std::allocator > > > const&); +// generated by autoexplicit.sh +template int igl::max_size > >(std::vector >, std::allocator > > > const&); +// generated by autoexplicit.sh +template int igl::max_size > >(std::vector >, std::allocator > > > const&); +template int igl::max_size > >(std::vector >, std::allocator > > > const&); +template int igl::max_size > >(std::vector >, std::allocator > > > const&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/max_size.h b/src/external/libigl-2.3.0/include/igl/max_size.h new file mode 100644 index 000000000..58035d4ce --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/max_size.h @@ -0,0 +1,29 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_MAX_SIZE_H +#define IGL_MAX_SIZE_H +#include "igl_inline.h" +#include + +namespace igl +{ + // Determine max size of lists in a vector + // Template: + // T some list type object that implements .size() + // Inputs: + // V vector of list types T + // Returns max .size() found in V, returns -1 if V is empty + template + IGL_INLINE int max_size(const std::vector & V); +} + +#ifndef IGL_STATIC_LIBRARY +# include "max_size.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/median.cpp b/src/external/libigl-2.3.0/include/igl/median.cpp new file mode 100644 index 000000000..cf6424db3 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/median.cpp @@ -0,0 +1,46 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "median.h" +#include "matrix_to_list.h" + +#include +#include + +template +IGL_INLINE bool igl::median( + const Eigen::MatrixBase & V, mType & m) +{ + using namespace std; + if(V.size() == 0) + { + return false; + } + vector vV; + matrix_to_list(V,vV); + // http://stackoverflow.com/a/1719155/148668 + size_t n = vV.size()/2; + nth_element(vV.begin(),vV.begin()+n,vV.end()); + if(vV.size()%2==0) + { + nth_element(vV.begin(),vV.begin()+n-1,vV.end()); + m = 0.5*(vV[n]+vV[n-1]); + }else + { + m = vV[n]; + } + return true; +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template bool igl::median, -1, 1, true>, float>(Eigen::MatrixBase, -1, 1, true> > const&, float&); +// generated by autoexplicit.sh +template bool igl::median, -1, 1, true>, double>(Eigen::MatrixBase, -1, 1, true> > const&, double&); +template bool igl::median, double>(Eigen::MatrixBase > const&, double&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/median.h b/src/external/libigl-2.3.0/include/igl/median.h new file mode 100644 index 000000000..7986dfda4 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/median.h @@ -0,0 +1,30 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_MEDIAN_H +#define IGL_MEDIAN_H +#include "igl_inline.h" +#include +namespace igl +{ + // Compute the median of an eigen vector + // + // Inputs: + // V #V list of unsorted values + // Outputs: + // m median of those values + // Returns true on success, false on failure + template + IGL_INLINE bool median( + const Eigen::MatrixBase & V, mType & m); +} + +#ifndef IGL_STATIC_LIBRARY +# include "median.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/min.cpp b/src/external/libigl-2.3.0/include/igl/min.cpp new file mode 100644 index 000000000..ce8ba328e --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/min.cpp @@ -0,0 +1,41 @@ +#include "min.h" +#include "for_each.h" +#include "find_zero.h" + +template +IGL_INLINE void igl::min( + const Eigen::SparseMatrix & A, + const int dim, + Eigen::PlainObjectBase & B, + Eigen::PlainObjectBase & I) +{ + const int n = A.cols(); + const int m = A.rows(); + B.resize(dim==1?n:m); + B.setConstant(std::numeric_limits::max()); + I.resize(dim==1?n:m); + for_each(A,[&B,&I,&dim](int i, int j,const typename DerivedB::Scalar v) + { + if(dim == 2) + { + std::swap(i,j); + } + // Coded as if dim == 1, assuming swap for dim == 2 + if(v < B(j)) + { + B(j) = v; + I(j) = i; + } + }); + Eigen::VectorXi Z; + find_zero(A,dim,Z); + for(int j = 0;j +#include +namespace igl +{ + // Inputs: + // X m by n matrix + // dim dimension along which to take min + // Outputs: + // Y n-long vector (if dim == 1) + // or + // Y m-long vector (if dim == 2) + // I vector the same size as Y containing the indices along dim of minimum + // entries + template + IGL_INLINE void min( + const Eigen::SparseMatrix & A, + const int dim, + Eigen::PlainObjectBase & B, + Eigen::PlainObjectBase & I); +} +#ifndef IGL_STATIC_LIBRARY +# include "min.cpp" +#endif +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/min_heap.h b/src/external/libigl-2.3.0/include/igl/min_heap.h new file mode 100644 index 000000000..b5503ca29 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/min_heap.h @@ -0,0 +1,20 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2020 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_MIN_HEAP_H +#define IGL_MIN_HEAP_H +#include +#include +#include +namespace igl +{ + // Templated min heap (reverses sort order of std::priority_queue) + template using min_heap = + std::priority_queue< T, std::vector, std::greater >; +} +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/min_quad_with_fixed.cpp b/src/external/libigl-2.3.0/include/igl/min_quad_with_fixed.cpp new file mode 100644 index 000000000..1b1b04c54 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/min_quad_with_fixed.cpp @@ -0,0 +1,915 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "min_quad_with_fixed.h" + +#include "slice.h" +#include "is_symmetric.h" +#include "find.h" +#include "sparse.h" +#include "repmat.h" +#include "EPS.h" +#include "cat.h" + +//#include +// Bug in unsupported/Eigen/SparseExtra needs iostream first +#include +#include +#include +#include +#include +#include + +template +IGL_INLINE bool igl::min_quad_with_fixed_precompute( + const Eigen::SparseMatrix& A2, + const Eigen::MatrixBase & known, + const Eigen::SparseMatrix& Aeq, + const bool pd, + min_quad_with_fixed_data & data + ) +{ +//#define MIN_QUAD_WITH_FIXED_CPP_DEBUG + using namespace Eigen; + using namespace std; + const Eigen::SparseMatrix A = 0.5*A2; +#ifdef MIN_QUAD_WITH_FIXED_CPP_DEBUG + cout<<" pre"<= 0)&& "known indices should be in [0,n)"); + assert((kr == 0 || known.maxCoeff() < n) && "known indices should be in [0,n)"); + assert(neq <= n && "Number of equality constraints should be less than DOFs"); + + + // cache known + // FIXME: This is *NOT* generic and introduces a copy. + data.known = known.template cast(); + + // get list of unknown indices + data.unknown.resize(n-kr); + std::vector unknown_mask; + unknown_mask.resize(n,true); + for(int i = 0;i 0) + { + data.unknown_lagrange.head(data.unknown.size()) = data.unknown; + } + if(data.lagrange.size() > 0) + { + data.unknown_lagrange.tail(data.lagrange.size()) = data.lagrange; + } + + SparseMatrix Auu; + slice(A,data.unknown,data.unknown,Auu); + assert(Auu.size() != 0 && Auu.rows() > 0 && "There should be at least one unknown."); + + // Positive definiteness is *not* determined, rather it is given as a + // parameter + data.Auu_pd = pd; + if(data.Auu_pd) + { + // PD implies symmetric + data.Auu_sym = true; + // This is an annoying assertion unless EPS can be chosen in a nicer way. + //assert(is_symmetric(Auu,EPS())); + assert(is_symmetric(Auu,1.0) && + "Auu should be symmetric if positive definite"); + }else + { + // determine if A(unknown,unknown) is symmetric and/or positive definite + VectorXi AuuI,AuuJ; + MatrixXd AuuV; + find(Auu,AuuI,AuuJ,AuuV); + data.Auu_sym = is_symmetric(Auu,EPS()*AuuV.maxCoeff()); + } + + // Determine number of linearly independent constraints + int nc = 0; + if(neq>0) + { +#ifdef MIN_QUAD_WITH_FIXED_CPP_DEBUG + cout<<" qr"<(data.Aequ.transpose().eval()),"AeqT")< new_A; + SparseMatrix AeqT = Aeq.transpose(); + SparseMatrix Z(neq,neq); + // This is a bit slower. But why isn't cat fast? + new_A = cat(1, cat(2, A, AeqT ), + cat(2, Aeq, Z )); + + // precompute RHS builders + if(kr > 0) + { + SparseMatrix Aulk,Akul; + // Slow + slice(new_A,data.unknown_lagrange,data.known,Aulk); + //// This doesn't work!!! + //data.preY = Aulk + Akul.transpose(); + // Slow + if(data.Auu_sym) + { + data.preY = Aulk*2; + }else + { + slice(new_A,data.known,data.unknown_lagrange,Akul); + SparseMatrix AkulT = Akul.transpose(); + data.preY = Aulk + AkulT; + } + }else + { + data.preY.resize(data.unknown_lagrange.size(),0); + } + + // Positive definite and no equality constraints (Positive definiteness + // implies symmetric) +#ifdef MIN_QUAD_WITH_FIXED_CPP_DEBUG + cout<<" factorize"<::LLT; + }else + { +#ifdef MIN_QUAD_WITH_FIXED_CPP_DEBUG + cout<<" ldlt"< NA; + slice(new_A,data.unknown_lagrange,data.unknown_lagrange,NA); + data.NA = NA; + // Ideally we'd use LDLT but Eigen doesn't support positive semi-definite + // matrices: + // http://forum.kde.org/viewtopic.php?f=74&t=106962&p=291990#p291990 + if(data.Auu_sym && false) + { + data.ldlt.compute(NA); + switch(data.ldlt.info()) + { + case Eigen::Success: + break; + case Eigen::NumericalIssue: + cerr<<"Error: Numerical issue."<::LDLT; + }else + { +#ifdef MIN_QUAD_WITH_FIXED_CPP_DEBUG + cout<<" lu"<1/2 + data.lu.compute(NA); + //std::cout<<"NA=["<::LU; + } + } + }else + { +#ifdef MIN_QUAD_WITH_FIXED_CPP_DEBUG + cout<<" Aeq_li=false"< AeqTR,AeqTQ; + AeqTR = data.AeqTQR.matrixR(); + // This shouldn't be necessary + AeqTR.prune(static_cast(0.0)); +#ifdef MIN_QUAD_WITH_FIXED_CPP_DEBUG + cout<<" matrixQ"<(0.0)); + //cout<<"AeqTQ: "< I(neq,neq); + I.setIdentity(); + data.AeqTE = data.AeqTQR.colsPermutation() * I; + data.AeqTET = data.AeqTQR.colsPermutation().transpose() * I; + assert(AeqTR.rows() == nu && "#rows in AeqTR should match #unknowns"); + assert(AeqTR.cols() == neq && "#cols in AeqTR should match #constraints"); + assert(AeqTQ.rows() == nu && "#rows in AeqTQ should match #unknowns"); + assert(AeqTQ.cols() == nu && "#cols in AeqTQ should match #unknowns"); + //cout<<" slice"< QRAuu = data.AeqTQ2T * Auu * data.AeqTQ2; + { +#ifdef MIN_QUAD_WITH_FIXED_CPP_DEBUG + cout<<" factorize"<::QR_LLT; + } +#ifdef MIN_QUAD_WITH_FIXED_CPP_DEBUG + cout<<" smash"< Auk; + slice(A,data.unknown,data.known,Auk); + SparseMatrix Aku; + slice(A,data.known,data.unknown,Aku); + SparseMatrix AkuT = Aku.transpose(); + data.preY = Auk + AkuT; + // Needed during solve + data.Auu = Auu; + slice(Aeq,data.known,2,data.Aeqk); + assert(data.Aeqk.rows() == neq); + assert(data.Aeqk.cols() == data.known.size()); + } + return true; +} + + +template < + typename T, + typename DerivedB, + typename DerivedY, + typename DerivedBeq, + typename DerivedZ, + typename Derivedsol> +IGL_INLINE bool igl::min_quad_with_fixed_solve( + const min_quad_with_fixed_data & data, + const Eigen::MatrixBase & B, + const Eigen::MatrixBase & Y, + const Eigen::MatrixBase & Beq, + Eigen::PlainObjectBase & Z, + Eigen::PlainObjectBase & sol) +{ + using namespace std; + using namespace Eigen; + typedef Matrix VectorXT; + typedef Matrix MatrixXT; + // number of known rows + int kr = data.known.size(); + if(kr!=0) + { + assert(kr == Y.rows()); + } + // number of columns to solve + int cols = Y.cols(); + assert(B.cols() == 1 || B.cols() == cols); + assert(Beq.size() == 0 || Beq.cols() == 1 || Beq.cols() == cols); + + // resize output + Z.resize(data.n,cols); + // Set known values + for(int i = 0;i < kr;i++) + { + for(int j = 0;j < cols;j++) + { + Z(data.known(i),j) = Y(i,j); + } + } + + if(data.Aeq_li) + { + // number of lagrange multipliers aka linear equality constraints + int neq = data.lagrange.size(); + // append lagrange multiplier rhs's + MatrixXT BBeq(B.rows() + Beq.rows(),cols); + if(B.size() > 0) + { + BBeq.topLeftCorner(B.rows(),cols) = B.replicate(1,B.cols()==cols?1:cols); + } + if(Beq.size() > 0) + { + BBeq.bottomLeftCorner(Beq.rows(),cols) = -2.0*Beq.replicate(1,Beq.cols()==cols?1:cols); + } + + // Build right hand side + MatrixXT BBequlcols; + igl::slice(BBeq,data.unknown_lagrange,1,BBequlcols); + MatrixXT NB; + if(kr == 0) + { + NB = BBequlcols; + }else + { + NB = data.preY * Y + BBequlcols; + } + + //std::cout<<"NB=["<::LLT: + sol = data.llt.solve(NB); + break; + case igl::min_quad_with_fixed_data::LDLT: + sol = data.ldlt.solve(NB); + break; + case igl::min_quad_with_fixed_data::LU: + // Not a bottleneck + sol = data.lu.solve(NB); + break; + default: + cerr<<"Error: invalid solver type"<::QR_LLT); + MatrixXT eff_Beq; + // Adjust Aeq rhs to include known parts + eff_Beq = + //data.AeqTQR.colsPermutation().transpose() * (-data.Aeqk * Y + Beq); + data.AeqTET * (-data.Aeqk * Y + Beq.replicate(1,Beq.cols()==cols?1:cols)); + // Where did this -0.5 come from? Probably the same place as above. + MatrixXT Bu; + slice(B,data.unknown,1,Bu); + MatrixXT NB; + NB = -0.5*(Bu.replicate(1,B.cols()==cols?1:cols) + data.preY * Y); + // Trim eff_Beq + const int nc = data.AeqTQR.rank(); + const int neq = Beq.rows(); + eff_Beq = eff_Beq.topLeftCorner(nc,cols).eval(); + data.AeqTR1T.template triangularView().solveInPlace(eff_Beq); + // Now eff_Beq = (data.AeqTR1T \ (data.AeqTET * (-data.Aeqk * Y + Beq))) + MatrixXT lambda_0; + lambda_0 = data.AeqTQ1 * eff_Beq; + //cout<().solveInPlace(temp1); + //cout< +IGL_INLINE bool igl::min_quad_with_fixed_solve( + const min_quad_with_fixed_data & data, + const Eigen::MatrixBase & B, + const Eigen::MatrixBase & Y, + const Eigen::MatrixBase & Beq, + Eigen::PlainObjectBase & Z) +{ + Eigen::Matrix sol; + return min_quad_with_fixed_solve(data,B,Y,Beq,Z,sol); +} + +template < + typename T, + typename Derivedknown, + typename DerivedB, + typename DerivedY, + typename DerivedBeq, + typename DerivedZ> +IGL_INLINE bool igl::min_quad_with_fixed( + const Eigen::SparseMatrix& A, + const Eigen::MatrixBase & B, + const Eigen::MatrixBase & known, + const Eigen::MatrixBase & Y, + const Eigen::SparseMatrix& Aeq, + const Eigen::MatrixBase & Beq, + const bool pd, + Eigen::PlainObjectBase & Z) +{ + min_quad_with_fixed_data data; + if(!min_quad_with_fixed_precompute(A,known,Aeq,pd,data)) + { + return false; + } + return min_quad_with_fixed_solve(data,B,Y,Beq,Z); +} + + +template +IGL_INLINE Eigen::Matrix igl::min_quad_with_fixed( + const Eigen::Matrix & H, + const Eigen::Matrix & f, + const Eigen::Array & k, + const Eigen::Matrix & bc, + const Eigen::Matrix & A, + const Eigen::Matrix & b) +{ + const auto dyn_n = n == Eigen::Dynamic ? H.rows() : n; + const auto dyn_m = m == Eigen::Dynamic ? A.rows() : m; + constexpr const int nn = n == Eigen::Dynamic ? Eigen::Dynamic : n+m; + const auto dyn_nn = nn == Eigen::Dynamic ? dyn_n+dyn_m : nn; + if(dyn_m == 0) + { + return igl::min_quad_with_fixed(H,f,k,bc); + } + // min_x ½ xᵀ H x + xᵀ f subject to A x = b and x(k) = bc(k) + // let zᵀ = [xᵀ λᵀ] + // min_z ½ zᵀ [H Aᵀ;A 0] z + zᵀ [f;-b] z(k) = bc(k) + const auto make_HH = [&]() + { + // Windows can't remember that nn is const. + constexpr const int nn = n == Eigen::Dynamic ? Eigen::Dynamic : n+m; + Eigen::Matrix HH = + Eigen::Matrix::Zero(dyn_nn,dyn_nn); + HH.topLeftCorner(dyn_n,dyn_n) = H; + HH.bottomLeftCorner(dyn_m,dyn_n) = A; + HH.topRightCorner(dyn_n,dyn_m) = A.transpose(); + return HH; + }; + const Eigen::Matrix HH = make_HH(); + const auto make_ff = [&]() + { + // Windows can't remember that nn is const. + constexpr const int nn = n == Eigen::Dynamic ? Eigen::Dynamic : n+m; + Eigen::Matrix ff(dyn_nn); + ff.head(dyn_n) = f; + ff.tail(dyn_m) = -b; + return ff; + }; + const Eigen::Matrix ff = make_ff(); + const auto make_kk = [&]() + { + // Windows can't remember that nn is const. + constexpr const int nn = n == Eigen::Dynamic ? Eigen::Dynamic : n+m; + Eigen::Array kk = + Eigen::Array::Constant(dyn_nn,1,false); + kk.head(dyn_n) = k; + return kk; + }; + const Eigen::Array kk = make_kk(); + const auto make_bcbc= [&]() + { + // Windows can't remember that nn is const. + constexpr const int nn = n == Eigen::Dynamic ? Eigen::Dynamic : n+m; + Eigen::Matrix bcbc(dyn_nn); + bcbc.head(dyn_n) = bc; + return bcbc; + }; + const Eigen::Matrix bcbc = make_bcbc(); + const Eigen::Matrix xx = + min_quad_with_fixed(HH,ff,kk,bcbc); + return xx.head(dyn_n); +} + +template +IGL_INLINE Eigen::Matrix igl::min_quad_with_fixed( + const Eigen::Matrix & H, + const Eigen::Matrix & f, + const Eigen::Array & k, + const Eigen::Matrix & bc) +{ + assert(H.isApprox(H.transpose(),1e-7)); + assert(H.rows() == H.cols()); + assert(H.rows() == f.size()); + assert(H.rows() == k.size()); + assert(H.rows() == bc.size()); + const auto kcount = k.count(); + // Everything fixed + if(kcount == (Eigen::Dynamic?H.rows():n)) + { + return bc; + } + // Nothing fixed + if(kcount == 0) + { + // avoid function call + typedef Eigen::Matrix MatrixSn; + typedef typename + std::conditional,Eigen::CompleteOrthogonalDecomposition>::type + Solver; + return Solver(H).solve(-f); + } + // All-but-one fixed + if( (Eigen::Dynamic?H.rows():n)-kcount == 1) + { + // which one is not fixed? + int u = -1; + for(int i=0;i=0); + // min ½ x(u) Huu x(u) + x(u)(fu + H(u,k)bc(k)) + // Huu x(u) = -(fu + H(u,k) bc(k)) + // x(u) = (-fu + ∑ -Huj bcj)/Huu + Eigen::Matrix x = bc; + x(u) = -f(u); + for(int i=0;i(); + // % Matlibberish for generating these case statements: + // maxi=16;for i=1:maxi;fprintf(' case %d:\n {\n const bool D = (n-%d<=0)||(%d>=n)||(n>%d);\n return min_quad_with_fixed(H,f,k,bc);\n }\n',[i i i maxi i]);end + case 1: + { + const bool D = (n-1<=0)||(1>=n)||(n>16); + return min_quad_with_fixed(H,f,k,bc); + } + case 2: + { + const bool D = (n-2<=0)||(2>=n)||(n>16); + return min_quad_with_fixed(H,f,k,bc); + } + case 3: + { + const bool D = (n-3<=0)||(3>=n)||(n>16); + return min_quad_with_fixed(H,f,k,bc); + } + case 4: + { + const bool D = (n-4<=0)||(4>=n)||(n>16); + return min_quad_with_fixed(H,f,k,bc); + } + case 5: + { + const bool D = (n-5<=0)||(5>=n)||(n>16); + return min_quad_with_fixed(H,f,k,bc); + } + case 6: + { + const bool D = (n-6<=0)||(6>=n)||(n>16); + return min_quad_with_fixed(H,f,k,bc); + } + case 7: + { + const bool D = (n-7<=0)||(7>=n)||(n>16); + return min_quad_with_fixed(H,f,k,bc); + } + case 8: + { + const bool D = (n-8<=0)||(8>=n)||(n>16); + return min_quad_with_fixed(H,f,k,bc); + } + case 9: + { + const bool D = (n-9<=0)||(9>=n)||(n>16); + return min_quad_with_fixed(H,f,k,bc); + } + case 10: + { + const bool D = (n-10<=0)||(10>=n)||(n>16); + return min_quad_with_fixed(H,f,k,bc); + } + case 11: + { + const bool D = (n-11<=0)||(11>=n)||(n>16); + return min_quad_with_fixed(H,f,k,bc); + } + case 12: + { + const bool D = (n-12<=0)||(12>=n)||(n>16); + return min_quad_with_fixed(H,f,k,bc); + } + case 13: + { + const bool D = (n-13<=0)||(13>=n)||(n>16); + return min_quad_with_fixed(H,f,k,bc); + } + case 14: + { + const bool D = (n-14<=0)||(14>=n)||(n>16); + return min_quad_with_fixed(H,f,k,bc); + } + case 15: + { + const bool D = (n-15<=0)||(15>=n)||(n>16); + return min_quad_with_fixed(H,f,k,bc); + } + case 16: + { + const bool D = (n-16<=0)||(16>=n)||(n>16); + return min_quad_with_fixed(H,f,k,bc); + } + default: + return min_quad_with_fixed(H,f,k,bc); + } +} + +template +IGL_INLINE Eigen::Matrix igl::min_quad_with_fixed( + const Eigen::Matrix & H, + const Eigen::Matrix & f, + const Eigen::Array & k, + const Eigen::Matrix & bc) +{ + // 0 and n should be handle outside this function + static_assert(kcount==Eigen::Dynamic || kcount>0 ,""); + static_assert(kcount==Eigen::Dynamic || kcount MatrixSuu; + typedef Eigen::Matrix MatrixSuk; + typedef Eigen::Matrix VectorSn; + typedef Eigen::Matrix VectorSu; + typedef Eigen::Matrix VectorSk; + const auto dyn_n = n==Eigen::Dynamic ? H.rows() : n; + const auto dyn_kcount = kcount==Eigen::Dynamic ? k.count() : kcount; + const auto dyn_ucount = ucount==Eigen::Dynamic ? dyn_n- dyn_kcount : ucount; + // For ucount==2 or kcount==2 this calls the coefficient initiliazer rather + // than the size initilizer, but I guess that's ok. + MatrixSuu Huu(dyn_ucount,dyn_ucount); + MatrixSuk Huk(dyn_ucount,dyn_kcount); + VectorSu mrhs(dyn_ucount); + VectorSk bck(dyn_kcount); + { + int ui = 0; + int ki = 0; + for(int i = 0;i, + // LDLT should be faster for indefinite problems but already found some + // cases where it was too inaccurate when called via quadprog_primal. + // Ideally this function takes LLT,LDLT, or + // CompleteOrthogonalDecomposition as a template parameter. "template + // template" parameters did work because LLT,LDLT have different number of + // template parameters from CompleteOrthogonalDecomposition. Perhaps + // there's a way to take advantage of LLT and LDLT's default template + // parameters (I couldn't figure out how). + Eigen::CompleteOrthogonalDecomposition>::type + Solver; + VectorSu xu = Solver(Huu).solve(-mrhs); + VectorSn x(dyn_n); + { + int ui = 0; + int ki = 0; + for(int i = 0;i igl::min_quad_with_fixed(Eigen::Matrix const&, Eigen::Matrix const&, Eigen::Array const&, Eigen::Matrix const&, Eigen::Matrix const&, Eigen::Matrix const&); +// generated by autoexplicit.sh +template Eigen::Matrix igl::min_quad_with_fixed(Eigen::Matrix const&, Eigen::Matrix const&, Eigen::Array const&, Eigen::Matrix const&, Eigen::Matrix const&, Eigen::Matrix const&); +// generated by autoexplicit.sh +template Eigen::Matrix igl::min_quad_with_fixed(Eigen::Matrix const&, Eigen::Matrix const&, Eigen::Array const&, Eigen::Matrix const&, Eigen::Matrix const&, Eigen::Matrix const&); +template Eigen::Matrix igl::min_quad_with_fixed(Eigen::Matrix const&, Eigen::Matrix const&, Eigen::Array const&, Eigen::Matrix const&, Eigen::Matrix const&, Eigen::Matrix const&); +template Eigen::Matrix igl::min_quad_with_fixed(Eigen::Matrix const&, Eigen::Matrix const&, Eigen::Array const&, Eigen::Matrix const&, Eigen::Matrix const&, Eigen::Matrix const&); +template bool igl::min_quad_with_fixed, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::SparseMatrix const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::SparseMatrix const&, Eigen::MatrixBase > const&, bool, Eigen::PlainObjectBase >&); +#if EIGEN_VERSION_AT_LEAST(3,3,0) +#else +template bool igl::min_quad_with_fixed_solve, Eigen::Matrix const>, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(igl::min_quad_with_fixed_data const&, Eigen::MatrixBase, Eigen::Matrix const> > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template bool igl::min_quad_with_fixed_solve, Eigen::CwiseNullaryOp, Eigen::Matrix >, Eigen::Matrix, Eigen::Matrix >(igl::min_quad_with_fixed_data const&, Eigen::MatrixBase > const&, Eigen::MatrixBase, Eigen::Matrix > > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +#endif +template bool igl::min_quad_with_fixed, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::SparseMatrix const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::SparseMatrix const&, Eigen::MatrixBase > const&, bool, Eigen::PlainObjectBase >&); +template bool igl::min_quad_with_fixed_solve, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(igl::min_quad_with_fixed_data const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template bool igl::min_quad_with_fixed_precompute >(Eigen::SparseMatrix const&, Eigen::MatrixBase > const&, Eigen::SparseMatrix const&, bool, igl::min_quad_with_fixed_data&); +template bool igl::min_quad_with_fixed_solve, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(igl::min_quad_with_fixed_data const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template bool igl::min_quad_with_fixed_solve, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(igl::min_quad_with_fixed_data const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template bool igl::min_quad_with_fixed_precompute >(Eigen::SparseMatrix const&, Eigen::MatrixBase > const&, Eigen::SparseMatrix const&, bool, igl::min_quad_with_fixed_data&); +template bool igl::min_quad_with_fixed_solve, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(igl::min_quad_with_fixed_data const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template bool igl::min_quad_with_fixed_solve, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(igl::min_quad_with_fixed_data const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template bool igl::min_quad_with_fixed_solve, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(igl::min_quad_with_fixed_data const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template bool igl::min_quad_with_fixed_solve, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(igl::min_quad_with_fixed_data const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template bool igl::min_quad_with_fixed, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::SparseMatrix const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::SparseMatrix const&, Eigen::MatrixBase > const&, bool, Eigen::PlainObjectBase >&); +template bool igl::min_quad_with_fixed, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::SparseMatrix const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::SparseMatrix const&, Eigen::MatrixBase > const&, bool, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/min_quad_with_fixed.h b/src/external/libigl-2.3.0/include/igl/min_quad_with_fixed.h new file mode 100644 index 000000000..eed956db1 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/min_quad_with_fixed.h @@ -0,0 +1,225 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_MIN_QUAD_WITH_FIXED_H +#define IGL_MIN_QUAD_WITH_FIXED_H +#include "igl_inline.h" + +#define EIGEN_YES_I_KNOW_SPARSE_MODULE_IS_NOT_STABLE_YET +#include +#include +#include +// Bug in unsupported/Eigen/SparseExtra needs iostream first +#include +#include + +namespace igl +{ + template + struct min_quad_with_fixed_data; + // Known Bugs: rows of Aeq **should probably** be linearly independent. + // During precomputation, the rows of a Aeq are checked via QR. But in case + // they're not then resulting probably will no longer be sparse: it will be + // slow. + // + // MIN_QUAD_WITH_FIXED Minimize a quadratic energy of the form + // + // trace( 0.5*Z'*A*Z + Z'*B + constant ) + // + // subject to + // + // Z(known,:) = Y, and + // Aeq*Z = Beq + // + // Templates: + // T should be a eigen matrix primitive type like int or double + // Inputs: + // A n by n matrix of quadratic coefficients + // known list of indices to known rows in Z + // Y list of fixed values corresponding to known rows in Z + // Aeq m by n list of linear equality constraint coefficients + // pd flag specifying whether A(unknown,unknown) is positive definite + // Outputs: + // data factorization struct with all necessary information to solve + // using min_quad_with_fixed_solve + // Returns true on success, false on error + // + // Benchmark: For a harmonic solve on a mesh with 325K facets, matlab 2.2 + // secs, igl/min_quad_with_fixed.h 7.1 secs + // + template + IGL_INLINE bool min_quad_with_fixed_precompute( + const Eigen::SparseMatrix& A, + const Eigen::MatrixBase & known, + const Eigen::SparseMatrix& Aeq, + const bool pd, + min_quad_with_fixed_data & data + ); + // Solves a system previously factored using min_quad_with_fixed_precompute + // + // Template: + // T type of sparse matrix (e.g. double) + // DerivedY type of Y (e.g. derived from VectorXd or MatrixXd) + // DerivedZ type of Z (e.g. derived from VectorXd or MatrixXd) + // Inputs: + // data factorization struct with all necessary precomputation to solve + // B n by k column of linear coefficients + // Y b by k list of constant fixed values + // Beq m by k list of linear equality constraint constant values + // Outputs: + // Z n by k solution + // sol #unknowns+#lagrange by k solution to linear system + // Returns true on success, false on error + template < + typename T, + typename DerivedB, + typename DerivedY, + typename DerivedBeq, + typename DerivedZ, + typename Derivedsol> + IGL_INLINE bool min_quad_with_fixed_solve( + const min_quad_with_fixed_data & data, + const Eigen::MatrixBase & B, + const Eigen::MatrixBase & Y, + const Eigen::MatrixBase & Beq, + Eigen::PlainObjectBase & Z, + Eigen::PlainObjectBase & sol); + // Wrapper without sol + template < + typename T, + typename DerivedB, + typename DerivedY, + typename DerivedBeq, + typename DerivedZ> + IGL_INLINE bool min_quad_with_fixed_solve( + const min_quad_with_fixed_data & data, + const Eigen::MatrixBase & B, + const Eigen::MatrixBase & Y, + const Eigen::MatrixBase & Beq, + Eigen::PlainObjectBase & Z); + template < + typename T, + typename Derivedknown, + typename DerivedB, + typename DerivedY, + typename DerivedBeq, + typename DerivedZ> + IGL_INLINE bool min_quad_with_fixed( + const Eigen::SparseMatrix& A, + const Eigen::MatrixBase & B, + const Eigen::MatrixBase & known, + const Eigen::MatrixBase & Y, + const Eigen::SparseMatrix& Aeq, + const Eigen::MatrixBase & Beq, + const bool pd, + Eigen::PlainObjectBase & Z); + + // Dense version optimized for very small, known at compile time sizes. Still + // works for Eigen::Dynamic (and then everything needs to be Dynamic). + // + // min_x ½ xᵀ H x + xᵀ f + // subject to + // A x = b + // x(i) = bc(i) iff k(i)==true + // + // Templates: + // Scalar (e.g., double) + // n #H or Eigen::Dynamic if not known at compile time + // m #A or Eigen::Dynamic if not known at compile time + // Hpd whether H is positive definite (LLT used) or not (QR used) + // Inputs: + // H #H by #H quadratic coefficients (only lower triangle used) + // f #H linear coefficients + // k #H list of flags whether to fix value + // bc #H value to fix to (if !k(i) then bc(i) is ignored) + // A #A by #H list of linear equality constraint coefficients, must be + // linearly independent (with self and fixed value constraints) + // b #A list of linear equality right-hand sides + // Returns #H-long solution x + template + IGL_INLINE Eigen::Matrix min_quad_with_fixed( + const Eigen::Matrix & H, + const Eigen::Matrix & f, + const Eigen::Array & k, + const Eigen::Matrix & bc, + const Eigen::Matrix & A, + const Eigen::Matrix & b); + template + IGL_INLINE Eigen::Matrix min_quad_with_fixed( + const Eigen::Matrix & H, + const Eigen::Matrix & f, + const Eigen::Array & k, + const Eigen::Matrix & bc); + // Special wrapper where the number of constrained values (i.e., true values + // in k) is exposed as a template parameter. Not intended to be called + // directly. The overhead of calling the overloads above is already minimal. + template + IGL_INLINE Eigen::Matrix min_quad_with_fixed( + const Eigen::Matrix & H, + const Eigen::Matrix & f, + const Eigen::Array & k, + const Eigen::Matrix & bc); +} + +template +struct igl::min_quad_with_fixed_data +{ + // Size of original system: number of unknowns + number of knowns + int n; + // Whether A(unknown,unknown) is positive definite + bool Auu_pd; + // Whether A(unknown,unknown) is symmetric + bool Auu_sym; + // Indices of known variables + Eigen::VectorXi known; + // Indices of unknown variables + Eigen::VectorXi unknown; + // Indices of lagrange variables + Eigen::VectorXi lagrange; + // Indices of unknown variable followed by Indices of lagrange variables + Eigen::VectorXi unknown_lagrange; + // Matrix multiplied against Y when constructing right hand side + Eigen::SparseMatrix preY; + enum SolverType + { + LLT = 0, + LDLT = 1, + LU = 2, + QR_LLT = 3, + NUM_SOLVER_TYPES = 4 + } solver_type; + // Solvers + Eigen::SimplicialLLT > llt; + Eigen::SimplicialLDLT > ldlt; + Eigen::SparseLU, Eigen::COLAMDOrdering > lu; + // QR factorization + // Are rows of Aeq linearly independent? + bool Aeq_li; + // Columns of Aeq corresponding to unknowns + int neq; + Eigen::SparseQR, Eigen::COLAMDOrdering > AeqTQR; + Eigen::SparseMatrix Aeqk; + Eigen::SparseMatrix Aequ; + Eigen::SparseMatrix Auu; + Eigen::SparseMatrix AeqTQ1; + Eigen::SparseMatrix AeqTQ1T; + Eigen::SparseMatrix AeqTQ2; + Eigen::SparseMatrix AeqTQ2T; + Eigen::SparseMatrix AeqTR1; + Eigen::SparseMatrix AeqTR1T; + Eigen::SparseMatrix AeqTE; + Eigen::SparseMatrix AeqTET; + // Debug + Eigen::SparseMatrix NA; + Eigen::Matrix NB; +}; + +#ifndef IGL_STATIC_LIBRARY +# include "min_quad_with_fixed.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/min_size.cpp b/src/external/libigl-2.3.0/include/igl/min_size.cpp new file mode 100644 index 000000000..0b0cfa9e2 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/min_size.cpp @@ -0,0 +1,45 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "min_size.h" + +template +IGL_INLINE int igl::min_size(const std::vector & V) +{ + int min_size = -1; + for( + typename std::vector::const_iterator iter = V.begin(); + iter != V.end(); + iter++) + { + int size = (int)iter->size(); + // have to handle base case + if(min_size == -1) + { + min_size = size; + }else{ + min_size = (min_size < size ? min_size : size); + } + } + return min_size; +} + + + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template int igl::min_size > >(std::vector >, std::allocator > > > const&); +// generated by autoexplicit.sh +template int igl::min_size > >(std::vector >, std::allocator > > > const&); +// generated by autoexplicit.sh +template int igl::min_size > >(std::vector >, std::allocator > > > const&); +// generated by autoexplicit.sh +template int igl::min_size > >(std::vector >, std::allocator > > > const&); +template int igl::min_size > >(std::vector >, std::allocator > > > const&); +template int igl::min_size > >(std::vector >, std::allocator > > > const&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/min_size.h b/src/external/libigl-2.3.0/include/igl/min_size.h new file mode 100644 index 000000000..e44036279 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/min_size.h @@ -0,0 +1,30 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_MIN_SIZE_H +#define IGL_MIN_SIZE_H +#include "igl_inline.h" +#include + +namespace igl +{ + // Determine min size of lists in a vector + // Template: + // T some list type object that implements .size() + // Inputs: + // V vector of list types T + // Returns min .size() found in V, returns -1 if V is empty + template + IGL_INLINE int min_size(const std::vector & V); +} + + +#ifndef IGL_STATIC_LIBRARY +# include "min_size.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/mod.cpp b/src/external/libigl-2.3.0/include/igl/mod.cpp new file mode 100644 index 000000000..2064fe6a4 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/mod.cpp @@ -0,0 +1,34 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "mod.h" + +template +IGL_INLINE void igl::mod( + const Eigen::PlainObjectBase & A, + const int base, + Eigen::PlainObjectBase & B) +{ + B.resizeLike(A); + for(int i = 0;i +IGL_INLINE DerivedA igl::mod( + const Eigen::PlainObjectBase & A, const int base) +{ + DerivedA B; + mod(A,base,B); + return B; +} +#ifdef IGL_STATIC_LIBRARY +#endif diff --git a/src/external/libigl-2.3.0/include/igl/mod.h b/src/external/libigl-2.3.0/include/igl/mod.h new file mode 100644 index 000000000..3ff58a231 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/mod.h @@ -0,0 +1,33 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_MOD_H +#define IGL_MOD_H +#include "igl_inline.h" +#include +namespace igl +{ + // Compute elementwise mod: B = A % base + // + // Inputs: + // A m by n matrix + // base number to mod against + // Outputs: + // B m by n matrix + template + IGL_INLINE void mod( + const Eigen::PlainObjectBase & A, + const int base, + Eigen::PlainObjectBase & B); + template + IGL_INLINE DerivedA mod( + const Eigen::PlainObjectBase & A, const int base); +} +#ifndef IGL_STATIC_LIBRARY +#include "mod.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/mode.cpp b/src/external/libigl-2.3.0/include/igl/mode.cpp new file mode 100644 index 000000000..89df6be66 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/mode.cpp @@ -0,0 +1,62 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "mode.h" + +// Implementation +#include + +template +IGL_INLINE void igl::mode( + const Eigen::Matrix & X, + const int d, + Eigen::Matrix & M) +{ + assert(d==1 || d==2); + using namespace std; + int m = X.rows(); + int n = X.cols(); + M.resize((d==1)?n:m,1); + for(int i = 0;i<((d==2)?m:n);i++) + { + vector counts(((d==2)?n:m),0); + for(int j = 0;j<((d==2)?n:m);j++) + { + T v = (d==2)?X(i,j):X(j,i); + for(int k = 0;k<((d==2)?n:m);k++) + { + T u = (d==2)?X(i,k):X(k,i); + if(v == u) + { + counts[k]++; + } + } + } + assert(counts.size() > 0); + int max_count = -1; + int max_count_j = -1; + int j =0; + for(vector::iterator it = counts.begin();it(Eigen::Matrix const&, int, Eigen::Matrix&); +// generated by autoexplicit.sh +template void igl::mode(Eigen::Matrix const&, int, Eigen::Matrix&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/mode.h b/src/external/libigl-2.3.0/include/igl/mode.h new file mode 100644 index 000000000..4d0943881 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/mode.h @@ -0,0 +1,35 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_MODE_H +#define IGL_MODE_H +#include "igl_inline.h" +#include +namespace igl +{ + // Takes mode of coefficients in a matrix along a given dension + // + // Templates: + // T should be a eigen matrix primitive type like int or double + // Inputs: + // X m by n original matrix + // d dension along which to take mode, m or n + // Outputs: + // M vector containing mode along dension d, if d==1 then this will be a + // n-long vector if d==2 then this will be a m-long vector + template + IGL_INLINE void mode( + const Eigen::Matrix & X, + const int d, + Eigen::Matrix & M); +} + +#ifndef IGL_STATIC_LIBRARY +# include "mode.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/mosek/bbw.cpp b/src/external/libigl-2.3.0/include/igl/mosek/bbw.cpp new file mode 100644 index 000000000..99d28ab15 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/mosek/bbw.cpp @@ -0,0 +1,88 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "bbw.h" +#include "mosek_quadprog.h" +#include "../harmonic.h" +#include "../slice_into.h" +#include +#include +#include + + +template < + typename DerivedV, + typename DerivedEle, + typename Derivedb, + typename Derivedbc, + typename DerivedW> +IGL_INLINE bool igl::mosek::bbw( + const Eigen::PlainObjectBase & V, + const Eigen::PlainObjectBase & Ele, + const Eigen::PlainObjectBase & b, + const Eigen::PlainObjectBase & bc, + igl::BBWData & data, + igl::mosek::MosekData & mosek_data, + Eigen::PlainObjectBase & W + ) +{ + using namespace std; + using namespace Eigen; + assert(!data.partition_unity && "partition_unity not implemented yet"); + // number of domain vertices + int n = V.rows(); + // number of handles + int m = bc.cols(); + // Build biharmonic operator + Eigen::SparseMatrix Q; + harmonic(V,Ele,2,Q); + W.derived().resize(n,m); + // No linear terms + VectorXd c = VectorXd::Zero(n); + // No linear constraints + SparseMatrix A(0,n); + VectorXd uc(0,1),lc(0,1); + // Upper and lower box constraints (Constant bounds) + VectorXd ux = VectorXd::Ones(n); + VectorXd lx = VectorXd::Zero(n); + // Loop over handles + for(int i = 0;i= 1) + { + cout<<"BBW: Computing weight for handle "<, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, igl::BBWData&, igl::mosek::MosekData&, Eigen::PlainObjectBase >&); +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/mosek/bbw.h b/src/external/libigl-2.3.0/include/igl/mosek/bbw.h new file mode 100644 index 000000000..5dcae0fed --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/mosek/bbw.h @@ -0,0 +1,60 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_MOSEK_BBW_H +#define IGL_MOSEK_BBW_H +#include "../igl_inline.h" +#include "mosek_quadprog.h" +#include "../bbw.h" +#include + +namespace igl +{ + namespace mosek + { + // Compute Bounded Biharmonic Weights on a given domain (V,Ele) with a given + // set of boundary conditions + // + // Templates + // DerivedV derived type of eigen matrix for V (e.g. MatrixXd) + // DerivedF derived type of eigen matrix for F (e.g. MatrixXi) + // Derivedb derived type of eigen matrix for b (e.g. VectorXi) + // Derivedbc derived type of eigen matrix for bc (e.g. MatrixXd) + // DerivedW derived type of eigen matrix for W (e.g. MatrixXd) + // Inputs: + // V #V by dim vertex positions + // Ele #Elements by simplex-size list of element indices + // b #b boundary indices into V + // bc #b by #W list of boundary values + // data object containing options, initial guess --> solution and results + // mosek_data object containing mosek options + // Outputs: + // W #V by #W list of *unnormalized* weights to normalize use + // igl::normalize_row_sums(W,W); + // Returns true on success, false on failure + template < + typename DerivedV, + typename DerivedEle, + typename Derivedb, + typename Derivedbc, + typename DerivedW> + IGL_INLINE bool bbw( + const Eigen::PlainObjectBase & V, + const Eigen::PlainObjectBase & Ele, + const Eigen::PlainObjectBase & b, + const Eigen::PlainObjectBase & bc, + igl::BBWData & data, + igl::mosek::MosekData & mosek_data, + Eigen::PlainObjectBase & W); + } +} + +#ifndef IGL_STATIC_LIBRARY +# include "bbw.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/mosek/mosek_guarded.cpp b/src/external/libigl-2.3.0/include/igl/mosek/mosek_guarded.cpp new file mode 100644 index 000000000..242d928f6 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/mosek/mosek_guarded.cpp @@ -0,0 +1,24 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "mosek_guarded.h" +#include + +IGL_INLINE MSKrescodee igl::mosek::mosek_guarded(const MSKrescodee r) +{ + using namespace std; + if(r != MSK_RES_OK) + { + /* In case of an error print error code and description. */ + char symname[MSK_MAX_STR_LEN]; + char desc[MSK_MAX_STR_LEN]; + MSK_getcodedesc(r,symname,desc); + cerr<<"MOSEK ERROR ("< +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_MOSEK_MOSEK_GUARDED_H +#define IGL_MOSEK_MOSEK_GUARDED_H +#include "../igl_inline.h" + +#include +namespace igl +{ + namespace mosek + { + // Little function to wrap around mosek call to handle errors + // + // Inputs: + // r mosek error code returned from mosek call + // Returns r untouched + IGL_INLINE MSKrescodee mosek_guarded(const MSKrescodee r); + } +} + +#ifndef IGL_STATIC_LIBRARY +# include "mosek_guarded.cpp" +#endif + +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/mosek/mosek_linprog.cpp b/src/external/libigl-2.3.0/include/igl/mosek/mosek_linprog.cpp new file mode 100644 index 000000000..38ea88141 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/mosek/mosek_linprog.cpp @@ -0,0 +1,168 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "mosek_linprog.h" +#include "../mosek/mosek_guarded.h" +#include "../harwell_boeing.h" +#include +#include +#include + +IGL_INLINE bool igl::mosek::mosek_linprog( + const Eigen::VectorXd & c, + const Eigen::SparseMatrix & A, + const Eigen::VectorXd & lc, + const Eigen::VectorXd & uc, + const Eigen::VectorXd & lx, + const Eigen::VectorXd & ux, + Eigen::VectorXd & x) +{ + // variables for mosek task, env and result code + MSKenv_t env; + // Create the MOSEK environment + mosek_guarded(MSK_makeenv(&env,NULL)); + // initialize mosek environment +#if MSK_VERSION_MAJOR <= 7 + mosek_guarded(MSK_initenv(env)); +#endif + const bool ret = mosek_linprog(c,A,lc,uc,lx,ux,env,x); + MSK_deleteenv(&env); + return ret; +} + +IGL_INLINE bool igl::mosek::mosek_linprog( + const Eigen::VectorXd & c, + const Eigen::SparseMatrix & A, + const Eigen::VectorXd & lc, + const Eigen::VectorXd & uc, + const Eigen::VectorXd & lx, + const Eigen::VectorXd & ux, + const MSKenv_t & env, + Eigen::VectorXd & x) +{ + // following http://docs.mosek.com/7.1/capi/Linear_optimization.html + using namespace std; + // number of constraints + const int m = A.rows(); + // number of variables + const int n = A.cols(); + + + vector vAv; + vector vAri,vAcp; + int nr; + harwell_boeing(A,nr,vAv,vAri,vAcp); + + MSKtask_t task; + // Create the optimization task + mosek_guarded(MSK_maketask(env,m,n,&task)); + // no threads + mosek_guarded(MSK_putintparam(task,MSK_IPAR_NUM_THREADS,1)); + if(m>0) + { + // Append 'm' empty constraints, the constrainst will initially have no + // bounds + mosek_guarded(MSK_appendcons(task,m)); + } + mosek_guarded(MSK_appendvars(task,n)); + + + const auto & key = [](const double lxj, const double uxj) -> + MSKboundkeye + { + MSKboundkeye k = MSK_BK_FR; + if(isfinite(lxj) && isfinite(uxj)) + { + if(lxj == uxj) + { + k = MSK_BK_FX; + }else{ + k = MSK_BK_RA; + } + }else if(isfinite(lxj)) + { + k = MSK_BK_LO; + }else if(isfinite(uxj)) + { + k = MSK_BK_UP; + } + return k; + }; + + // loop over variables + for(int j = 0;j 0) + { + // Set linear term c_j in the objective + mosek_guarded(MSK_putcj(task,j,c(j))); + } + + // Set constant bounds on variable j + const double lxj = lx.size()>0?lx[j]:-numeric_limits::infinity(); + const double uxj = ux.size()>0?ux[j]: numeric_limits::infinity(); + mosek_guarded(MSK_putvarbound(task,j,key(lxj,uxj),lxj,uxj)); + + if(m>0) + { + // Input column j of A + mosek_guarded( + MSK_putacol( + task, + j, + vAcp[j+1]-vAcp[j], + &vAri[vAcp[j]], + &vAv[vAcp[j]]) + ); + } + } + // loop over constraints + for(int i = 0;i0?lc[i]:-numeric_limits::infinity(); + const double uci = uc.size()>0?uc[i]: numeric_limits::infinity(); + mosek_guarded(MSK_putconbound(task,i,key(lci,uci),lci,uci)); + } + + // Now the optimizer has been prepared + MSKrescodee trmcode; + // run the optimizer + mosek_guarded(MSK_optimizetrm(task,&trmcode)); + // Get status + MSKsolstae solsta; + MSK_getsolsta (task,MSK_SOL_ITR,&solsta); + bool success = false; + switch(solsta) + { + case MSK_SOL_STA_OPTIMAL: +#if MSK_VERSION_MAJOR <= 8 + case MSK_SOL_STA_NEAR_OPTIMAL: +#endif + x.resize(n); + /* Request the basic solution. */ + MSK_getxx(task,MSK_SOL_BAS,x.data()); + success = true; + break; + case MSK_SOL_STA_DUAL_INFEAS_CER: + case MSK_SOL_STA_PRIM_INFEAS_CER: +#if MSK_VERSION_MAJOR <= 8 + case MSK_SOL_STA_NEAR_DUAL_INFEAS_CER: + case MSK_SOL_STA_NEAR_PRIM_INFEAS_CER: +#endif + //printf("Primal or dual infeasibility certificate found.\n"); + break; + case MSK_SOL_STA_UNKNOWN: + //printf("The status of the solution could not be determined.\n"); + break; + default: + //printf("Other solution status."); + break; + } + MSK_deletetask(&task); + return success; +} diff --git a/src/external/libigl-2.3.0/include/igl/mosek/mosek_linprog.h b/src/external/libigl-2.3.0/include/igl/mosek/mosek_linprog.h new file mode 100644 index 000000000..57791cd60 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/mosek/mosek_linprog.h @@ -0,0 +1,59 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_MOSEK_MOSEK_LINPROG_H +#define IGL_MOSEK_MOSEK_LINPROG_H +#include "../igl_inline.h" +#include +#include +#include +namespace igl +{ + namespace mosek + { + // Solve a linear program using mosek: + // + // min c'x + // s.t. lc <= A x <= uc + // lx <= x <= ux + // + // Inputs: + // c #x list of linear objective coefficients + // A #A by #x matrix of linear inequality constraint coefficients + // lc #A list of lower constraint bounds + // uc #A list of upper constraint bounds + // lx #x list of lower variable bounds + // ux #x list of upper variable bounds + // Outputs: + // x #x list of solution values + // Returns true iff success. + IGL_INLINE bool mosek_linprog( + const Eigen::VectorXd & c, + const Eigen::SparseMatrix & A, + const Eigen::VectorXd & lc, + const Eigen::VectorXd & uc, + const Eigen::VectorXd & lx, + const Eigen::VectorXd & ux, + Eigen::VectorXd & x); + // Wrapper that keeps mosek environment alive (if licence checking is + // becoming a bottleneck) + IGL_INLINE bool mosek_linprog( + const Eigen::VectorXd & c, + const Eigen::SparseMatrix & A, + const Eigen::VectorXd & lc, + const Eigen::VectorXd & uc, + const Eigen::VectorXd & lx, + const Eigen::VectorXd & ux, + const MSKenv_t & env, + Eigen::VectorXd & x); + } +} + +#ifndef IGL_STATIC_LIBRARY +# include "mosek_linprog.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/mosek/mosek_quadprog.cpp b/src/external/libigl-2.3.0/include/igl/mosek/mosek_quadprog.cpp new file mode 100644 index 000000000..382c29284 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/mosek/mosek_quadprog.cpp @@ -0,0 +1,344 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "mosek_quadprog.h" +#include "mosek_guarded.h" +#include +#include "../find.h" +#include "../verbose.h" +#include "../speye.h" +#include "../matrix_to_list.h" +#include "../list_to_matrix.h" +#include "../harwell_boeing.h" +#include "../EPS.h" + + +igl::mosek::MosekData::MosekData() +{ + // These are the default settings that worked well for BBW. Your miles may + // very well be kilometers. + + // >1e0 NONSOLUTION + // 1e-1 artifacts in deformation + // 1e-3 artifacts in isolines + // 1e-4 seems safe + // 1e-8 MOSEK DEFAULT SOLUTION + douparam[MSK_DPAR_INTPNT_TOL_REL_GAP]=1e-8; +#if MSK_VERSION_MAJOR >= 8 + douparam[MSK_DPAR_INTPNT_QO_TOL_REL_GAP]=1e-12; +#endif + // Force using multiple threads, not sure if MOSEK is properly destroying + //extra threads... +#if MSK_VERSION_MAJOR >= 7 + intparam[MSK_IPAR_NUM_THREADS] = 6; +#elif MSK_VERSION_MAJOR == 6 + intparam[MSK_IPAR_INTPNT_NUM_THREADS] = 6; +#endif +#if MSK_VERSION_MAJOR == 6 + // Force turn off data check + intparam[MSK_IPAR_DATA_CHECK]=MSK_OFF; +#endif + // Turn off presolving + // intparam[MSK_IPAR_PRESOLVE_USE] = MSK_PRESOLVE_MODE_OFF; + // Force particular matrix reordering method + // MSK_ORDER_METHOD_NONE cuts time in half roughly, since half the time is + // usually spent reordering the matrix + // !! WARNING Setting this parameter to anything but MSK_ORDER_METHOD_FREE + // seems to have the effect of setting it to MSK_ORDER_METHOD_NONE + // *Or maybe Mosek is spending a bunch of time analyzing the matrix to + // choose the right ordering method when really any of them are + // instantaneous + intparam[MSK_IPAR_INTPNT_ORDER_METHOD] = MSK_ORDER_METHOD_NONE; + // 1.0 means optimizer is very lenient about declaring model infeasible + douparam[MSK_DPAR_INTPNT_TOL_INFEAS] = 1e-8; + // Hard to say if this is doing anything, probably nothing dramatic + douparam[MSK_DPAR_INTPNT_TOL_PSAFE]= 1e2; + // Turn off convexity check + intparam[MSK_IPAR_CHECK_CONVEXITY] = MSK_CHECK_CONVEXITY_NONE; +} + +template +IGL_INLINE bool igl::mosek::mosek_quadprog( + const Index n, + std::vector & Qi, + std::vector & Qj, + std::vector & Qv, + const std::vector & c, + const Scalar cf, + const Index m, + std::vector & Av, + std::vector & Ari, + const std::vector & Acp, + const std::vector & lc, + const std::vector & uc, + const std::vector & lx, + const std::vector & ux, + MosekData & mosek_data, + std::vector & x) +{ + // I J V vectors of Q should all be same length + assert(Qv.size() == Qi.size()); + assert(Qv.size() == Qj.size()); + // number of columns in linear constraint matrix must be ≤ number of + // variables + assert( (int)Acp.size() == (n+1)); + // linear bound vectors must be size of number of constraints or empty + assert( ((int)lc.size() == m) || ((int)lc.size() == 0)); + assert( ((int)uc.size() == m) || ((int)uc.size() == 0)); + // constant bound vectors must be size of number of variables or empty + assert( ((int)lx.size() == n) || ((int)lx.size() == 0)); + assert( ((int)ux.size() == n) || ((int)ux.size() == 0)); + + // allocate space for solution in x + x.resize(n); + + // variables for mosek task, env and result code + MSKenv_t env; + MSKtask_t task; + + // Create the MOSEK environment +#if MSK_VERSION_MAJOR >= 7 + mosek_guarded(MSK_makeenv(&env,NULL)); +#elif MSK_VERSION_MAJOR == 6 + mosek_guarded(MSK_makeenv(&env,NULL,NULL,NULL,NULL)); +#endif + ///* Directs the log stream to the 'printstr' function. */ + //// Little function mosek needs in order to know how to print to std out + //const auto & printstr = [](void *handle, char str[]) + //{ + // printf("%s",str); + //} + //mosek_guarded(MSK_linkfunctoenvstream(env,MSK_STREAM_LOG,NULL,printstr)); + // initialize mosek environment +#if MSK_VERSION_MAJOR <= 7 + mosek_guarded(MSK_initenv(env)); +#endif + // Create the optimization task + mosek_guarded(MSK_maketask(env,m,n,&task)); + verbose("Creating task with %ld linear constraints and %ld variables...\n",m,n); + //// Tell mosek how to print to std out + //mosek_guarded(MSK_linkfunctotaskstream(task,MSK_STREAM_LOG,NULL,printstr)); + // Give estimate of number of variables + mosek_guarded(MSK_putmaxnumvar(task,n)); + if(m>0) + { + // Give estimate of number of constraints + mosek_guarded(MSK_putmaxnumcon(task,m)); + // Give estimate of number of non zeros in A + mosek_guarded(MSK_putmaxnumanz(task,Av.size())); + } + // Give estimate of number of non zeros in Q + mosek_guarded(MSK_putmaxnumqnz(task,Qv.size())); + if(m>0) + { + // Append 'm' empty constraints, the constrainst will initially have no + // bounds +#if MSK_VERSION_MAJOR >= 7 + mosek_guarded(MSK_appendcons(task,m)); +#elif MSK_VERSION_MAJOR == 6 + mosek_guarded(MSK_append(task,MSK_ACC_CON,m)); +#endif + } + // Append 'n' variables +#if MSK_VERSION_MAJOR >= 7 + mosek_guarded(MSK_appendvars(task,n)); +#elif MSK_VERSION_MAJOR == 6 + mosek_guarded(MSK_append(task,MSK_ACC_VAR,n)); +#endif + // add a contant term to the objective + mosek_guarded(MSK_putcfix(task,cf)); + + // loop over variables + for(int j = 0;j 0) + { + // Set linear term c_j in the objective + mosek_guarded(MSK_putcj(task,j,c[j])); + } + + // Set constant bounds on variable j + if(lx[j] == ux[j]) + { +#if MSK_VERSION_MAJOR <=8 + mosek_guarded(MSK_putbound(task,MSK_ACC_VAR,j,MSK_BK_FX,lx[j],ux[j])); +#else + mosek_guarded(MSK_putvarbound(task,j,MSK_BK_FX,lx[j],ux[j])); +#endif + }else + { +#if MSK_VERSION_MAJOR <=8 + mosek_guarded(MSK_putbound(task,MSK_ACC_VAR,j,MSK_BK_RA,lx[j],ux[j])); +#else + mosek_guarded(MSK_putvarbound(task,j,MSK_BK_RA,lx[j],ux[j])); +#endif + } + + if(m>0) + { + // Input column j of A +#if MSK_VERSION_MAJOR >= 7 + mosek_guarded( MSK_putacol( task, j, Acp[j+1]-Acp[j], &Ari[Acp[j]], &Av[Acp[j]])); +#elif MSK_VERSION_MAJOR == 6 + mosek_guarded( MSK_putavec( task, MSK_ACC_VAR, j, Acp[j+1]-Acp[j], &Ari[Acp[j]], &Av[Acp[j]])); +#endif + } + } + + // loop over constraints + for(int i = 0;i::iterator pit = mosek_data.intparam.begin(); + pit != mosek_data.intparam.end(); + pit++) + { + mosek_guarded(MSK_putintparam(task,pit->first,pit->second)); + } + for( + std::map::iterator pit = mosek_data.douparam.begin(); + pit != mosek_data.douparam.end(); + pit++) + { + mosek_guarded(MSK_putdouparam(task,pit->first,pit->second)); + } + + // Now the optimizer has been prepared + MSKrescodee trmcode; + // run the optimizer + mosek_guarded(MSK_optimizetrm(task,&trmcode)); + + //// Print a summary containing information about the solution for debugging + //// purposes + //MSK_solutionsummary(task,MSK_STREAM_LOG); + + // Get status of solution + MSKsolstae solsta; +#if MSK_VERSION_MAJOR >= 7 + MSK_getsolsta (task,MSK_SOL_ITR,&solsta); +#elif MSK_VERSION_MAJOR == 6 + MSK_getsolutionstatus(task,MSK_SOL_ITR,NULL,&solsta); +#endif + + bool success = false; + switch(solsta) + { + case MSK_SOL_STA_OPTIMAL: +#if MSK_VERSION_MAJOR <= 8 + case MSK_SOL_STA_NEAR_OPTIMAL: +#endif + MSK_getsolutionslice(task,MSK_SOL_ITR,MSK_SOL_ITEM_XX,0,n,&x[0]); + //printf("Optimal primal solution\n"); + //for(size_t j=0; j & Q, + const Eigen::VectorXd & c, + const double cf, + const Eigen::SparseMatrix & A, + const Eigen::VectorXd & lc, + const Eigen::VectorXd & uc, + const Eigen::VectorXd & lx, + const Eigen::VectorXd & ux, + MosekData & mosek_data, + Eigen::VectorXd & x) +{ + using namespace Eigen; + using namespace std; + + typedef int Index; + typedef double Scalar; + // Q should be square + assert(Q.rows() == Q.cols()); + // Q should be symmetric +#ifdef EIGEN_HAS_A_BUG_AND_FAILS_TO_LET_ME_COMPUTE_Q_MINUS_Q_TRANSPOSE + assert( (Q-Q.transpose()).sum() < FLOAT_EPS); +#endif + // Only keep lower triangular part of Q + SparseMatrix QL; + //QL = Q.template triangularView(); + QL = Q.triangularView(); + VectorXi Qi,Qj; + VectorXd Qv; + find(QL,Qi,Qj,Qv); + vector vQi = matrix_to_list(Qi); + vector vQj = matrix_to_list(Qj); + vector vQv = matrix_to_list(Qv); + + // Convert linear term + vector vc = matrix_to_list(c); + + assert(lc.size() == A.rows()); + assert(uc.size() == A.rows()); + // Convert A to harwell boeing format + vector vAv; + vector vAr,vAc; + Index nr; + harwell_boeing(A,nr,vAv,vAr,vAc); + + assert(lx.size() == Q.rows()); + assert(ux.size() == Q.rows()); + vector vlc = matrix_to_list(lc); + vector vuc = matrix_to_list(uc); + vector vlx = matrix_to_list(lx); + vector vux = matrix_to_list(ux); + + vector vx; + bool ret = mosek_quadprog( + Q.rows(),vQi,vQj,vQv, + vc, + cf, + nr, + vAv, vAr, vAc, + vlc,vuc, + vlx,vux, + mosek_data, + vx); + list_to_matrix(vx,x); + return ret; +} +#ifdef IGL_STATIC_LIBRARY +// Explicit template declarations +#endif diff --git a/src/external/libigl-2.3.0/include/igl/mosek/mosek_quadprog.h b/src/external/libigl-2.3.0/include/igl/mosek/mosek_quadprog.h new file mode 100644 index 000000000..38343318a --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/mosek/mosek_quadprog.h @@ -0,0 +1,145 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_MOSEK_MOSEK_QUADPROG_H +#define IGL_MOSEK_MOSEK_QUADPROG_H +#include "../igl_inline.h" +#include +#include +#include + + +#define EIGEN_YES_I_KNOW_SPARSE_MODULE_IS_NOT_STABLE_YET +#include +#include + +namespace igl +{ + namespace mosek + { + struct MosekData + { + // Integer parameters + std::map intparam; + // Double parameters + std::map douparam; + // Default values + IGL_INLINE MosekData(); + }; + // Solve a convex quadratic optimization problem with linear and constant + // bounds, that is: + // + // Minimize: ½ * xT * Q⁰ * x + cT * x + cf + // + // Subject to: lc ≤ Ax ≤ uc + // lx ≤ x ≤ ux + // + // where we are trying to find the optimal vector of values x. + // + // Note: Q⁰ must be symmetric and the ½ is a convention of MOSEK + // + // Note: Because of how MOSEK accepts different parts of the system, Q + // should be stored in IJV (aka Coordinate) format and should only include + // entries in the lower triangle. A should be stored in Column compressed + // (aka Harwell Boeing) format. As described: + // http://netlib.org/linalg/html_templates/node92.html + // or + // http://en.wikipedia.org/wiki/Sparse_matrix + // #Compressed_sparse_column_.28CSC_or_CCS.29 + // + // + // Templates: + // Index type for index variables + // Scalar type for floating point variables (gets cast to double?) + // Input: + // n number of variables, i.e. size of x + // Qi vector of qnnz row indices of non-zeros in LOWER TRIANGLE ONLY of + // Q⁰ + // Qj vector of qnnz column indices of non-zeros in LOWER TRIANGLE ONLY + // of Q⁰ + // Qv vector of qnnz values of non-zeros in LOWER TRIANGLE ONLY of Q⁰, + // such that: + // + // Q⁰(Qi[k],Qj[k]) = Qv[k] for k ∈ [0,Qnnz-1], where Qnnz is the + // + // number of non-zeros in Q⁰ + // c (optional) vector of n values of c, transpose of coefficient row + // vector of linear terms, EMPTY means c == 0 + // cf (ignored) value of constant term in objective, 0 means cf == 0, so + // optional only in the sense that it is mandatory + // m number of constraints, therefore also number of rows in linear + // constraint coefficient matrix A, and in linear constraint bound + // vectors lc and uc + // Av vector of non-zero values of A, in column compressed order + // Ari vector of row indices corresponding to non-zero values of A, + // Acp vector of indices into Ari and Av of the first entry for each + // column of A, size(Acp) = (# columns of A) + 1 = n + 1 + // lc vector of m linear constraint lower bounds + // uc vector of m linear constraint upper bounds + // lx vector of n constant lower bounds + // ux vector of n constant upper bounds + // Output: + // x vector of size n to hold output of optimization + // Return: + // true only if optimization was successful with no errors + // + // Note: All indices are 0-based + // + template + IGL_INLINE bool mosek_quadprog( + const Index n, + /* mosek won't allow this to be const*/ std::vector & Qi, + /* mosek won't allow this to be const*/ std::vector & Qj, + /* mosek won't allow this to be const*/ std::vector & Qv, + const std::vector & c, + const Scalar cf, + const Index m, + /* mosek won't allow this to be const*/ std::vector & Av, + /* mosek won't allow this to be const*/ std::vector & Ari, + const std::vector & Acp, + const std::vector & lc, + const std::vector & uc, + const std::vector & lx, + const std::vector & ux, + MosekData & mosek_data, + std::vector & x); + // Wrapper with Eigen elements + // + // Inputs: + // Q n by n square quadratic coefficients matrix **only lower triangle + // is used**. + // c n-long vector of linear coefficients + // cf constant coefficient + // A m by n square linear coefficienst matrix of inequality constraints + // lc m-long vector of lower bounds for linear inequality constraints + // uc m-long vector of upper bounds for linear inequality constraints + // lx n-long vector of lower bounds + // ux n-long vector of upper bounds + // mosek_data parameters struct + // Outputs: + // x n-long solution vector + // Returns true only if optimization finishes without error + // + IGL_INLINE bool mosek_quadprog( + const Eigen::SparseMatrix & Q, + const Eigen::VectorXd & c, + const double cf, + const Eigen::SparseMatrix & A, + const Eigen::VectorXd & lc, + const Eigen::VectorXd & uc, + const Eigen::VectorXd & lx, + const Eigen::VectorXd & ux, + MosekData & mosek_data, + Eigen::VectorXd & x); + } +} + +#ifndef IGL_STATIC_LIBRARY +# include "mosek_quadprog.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/mvc.cpp b/src/external/libigl-2.3.0/include/igl/mvc.cpp new file mode 100644 index 000000000..a6fed49d8 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/mvc.cpp @@ -0,0 +1,196 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "mvc.h" +#include +#include +#include + +// Broken Implementation +IGL_INLINE void igl::mvc(const Eigen::MatrixXd &V, const Eigen::MatrixXd &C, Eigen::MatrixXd &W) +{ + + // at least three control points + assert(C.rows()>2); + + // dimension of points + assert(C.cols() == 3 || C.cols() == 2); + assert(V.cols() == 3 || V.cols() == 2); + + // number of polygon points + int num = C.rows(); + + Eigen::MatrixXd V1,C1; + int i_prev, i_next; + + // check if either are 3D but really all z's are 0 + bool V_flat = (V.cols() == 3) && (std::sqrt( (V.col(3)).dot(V.col(3)) ) < 1e-10); + bool C_flat = (C.cols() == 3) && (std::sqrt( (C.col(3)).dot(C.col(3)) ) < 1e-10); + + // if both are essentially 2D then ignore z-coords + if((C.cols() == 2 || C_flat) && (V.cols() == 2 || V_flat)) + { + // ignore z coordinate + V1 = V.block(0,0,V.rows(),2); + C1 = C.block(0,0,C.rows(),2); + } + else + { + // give dummy z coordinate to either mesh or poly + if(V.rows() == 2) + { + V1 = Eigen::MatrixXd(V.rows(),3); + V1.block(0,0,V.rows(),2) = V; + } + else + V1 = V; + + if(C.rows() == 2) + { + C1 = Eigen::MatrixXd(C.rows(),3); + C1.block(0,0,C.rows(),2) = C; + } + else + C1 = C; + + // check that C is planar + // average normal around poly corners + + Eigen::Vector3d n = Eigen::Vector3d::Zero(); + // take centroid as point on plane + Eigen::Vector3d p = Eigen::Vector3d::Zero(); + for (int i = 0; i0)?(i-1):(num-1); + i_next = (i1e-10) + std::cerr<<"Distance from V to plane of C is large..."< solver = basis.colPivHouseholderQr(); + // Throw away coordinates in normal direction + V1 = solver.solve(V1.transpose()).transpose().block(0,0,V1.rows(),2); + C1 = solver.solve(C1.transpose()).transpose().block(0,0,C1.rows(),2); + + } + + // vectors from V to every C, where CmV(i,j,:) is the vector from domain + // vertex j to handle i + double EPS = 1e-10; + Eigen::MatrixXd WW = Eigen::MatrixXd(C1.rows(), V1.rows()); + Eigen::MatrixXd dist_C_V (C1.rows(), V1.rows()); + std::vector< std::pair > on_corner(0); + std::vector< std::pair > on_segment(0); + for (int i = 0; i0)?(i-1):(num-1); + i_next = (i +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_MVC_H +#define IGL_MVC_H + +#include "igl_inline.h" +#include + +namespace igl +{ + // MVC - MEAN VALUE COORDINATES + // + // mvc(V,C,W) + // + // Inputs: + // V #V x dim list of vertex positions (dim = 2 or dim = 3) + // C #C x dim list of polygon vertex positions in counter-clockwise order + // (dim = 2 or dim = 3) + // + // Outputs: + // W weights, #V by #C matrix of weights + // + // Known Bugs: implementation is listed as "Broken" + IGL_INLINE void mvc( + const Eigen::MatrixXd &V, + const Eigen::MatrixXd &C, + Eigen::MatrixXd &W); + +} + +#ifndef IGL_STATIC_LIBRARY +# include "mvc.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/nchoosek.cpp b/src/external/libigl-2.3.0/include/igl/nchoosek.cpp new file mode 100644 index 000000000..88ab5449d --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/nchoosek.cpp @@ -0,0 +1,77 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Olga Diamanti, Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "nchoosek.h" +#include +#include + +IGL_INLINE double igl::nchoosek(const int n, const int k) +{ + if(k>n/2) + { + return nchoosek(n,n-k); + }else if(k==1) + { + return n; + }else + { + double c = 1; + for(int i = 1;i<=k;i++) + { + c *= (((double)n-k+i)/((double)i)); + } + return std::round(c); + } +} + +template < typename DerivedV, typename DerivedU> +IGL_INLINE void igl::nchoosek( + const Eigen::MatrixBase & V, + const int k, + Eigen::PlainObjectBase & U) +{ + using namespace Eigen; + if(V.size() == 0) + { + U.resize(0,k); + return; + } + assert((V.cols() == 1 || V.rows() == 1) && "V must be a vector"); + U.resize(nchoosek(V.size(),k),k); + int running_i = 0; + int running_j = 0; + Matrix running(1,k); + int N = V.size(); + const std::function doCombs = + [&running,&N,&doCombs,&running_i,&running_j,&U,&V](int offset, int k) + { + if(k==0) + { + U.row(running_i) = running; + running_i++; + return; + } + for (int i = offset; i <= N - k; ++i) + { + running(running_j) = V(i); + running_j++; + doCombs(i+1,k-1); + running_j--; + } + }; + doCombs(0,k); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +template void igl::nchoosek, Eigen::Matrix >(Eigen::MatrixBase > const&, int, Eigen::PlainObjectBase >&); +#if EIGEN_VERSION_AT_LEAST(3,3,0) +#else +template void igl::nchoosek, Eigen::Matrix >, Eigen::Matrix >(Eigen::MatrixBase, Eigen::Matrix > > const&, int, Eigen::PlainObjectBase >&); +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/nchoosek.h b/src/external/libigl-2.3.0/include/igl/nchoosek.h new file mode 100644 index 000000000..88ee63642 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/nchoosek.h @@ -0,0 +1,45 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Olga Diamanti, Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef IGL_NCHOOSEK +#define IGL_NCHOOSEK +#include "igl_inline.h" +#include + +#include + +namespace igl +{ + // NCHOOSEK Like matlab's nchoosek. + // + // Inputs: + // n total number elements + // k size of sub-set to consider + // Returns number of k-size combinations out of the set [1,...,n] + IGL_INLINE double nchoosek(const int n, const int k); + // + // Inputs: + // V n-long vector of elements + // k size of sub-set to consider + // Outputs: + // U nchoosek by k long matrix where each row is a unique k-size + // combination + template < typename DerivedV, typename DerivedU> + IGL_INLINE void nchoosek( + const Eigen::MatrixBase & V, + const int k, + Eigen::PlainObjectBase & U); +} + + +#ifndef IGL_STATIC_LIBRARY +#include "nchoosek.cpp" +#endif + + +#endif /* defined(IGL_NCHOOSEK) */ diff --git a/src/external/libigl-2.3.0/include/igl/next_filename.cpp b/src/external/libigl-2.3.0/include/igl/next_filename.cpp new file mode 100644 index 000000000..b453a149a --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/next_filename.cpp @@ -0,0 +1,38 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "next_filename.h" +#include "STR.h" +#include "file_exists.h" +#include +#include + +bool igl::next_filename( + const std::string & prefix, + const int zeros, + const std::string & suffix, + std::string & next) +{ + using namespace std; + // O(n), for huge lists could at least find bounds with exponential search + // and then narrow with binary search O(log(n)) + int i = 0; + while(true) + { + next = STR(prefix << setfill('0') << setw(zeros)< 0 && i >= pow(10,zeros)) + { + return false; + } + } +} + diff --git a/src/external/libigl-2.3.0/include/igl/next_filename.h b/src/external/libigl-2.3.0/include/igl/next_filename.h new file mode 100644 index 000000000..c56ad0857 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/next_filename.h @@ -0,0 +1,36 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_NEXT_FILENAME_H +#define IGL_NEXT_FILENAME_H +#include "igl_inline.h" +#include +namespace igl +{ + // Find the file with the first filename of the form + // "prefix%0[zeros]dsuffix" + // + // Inputs: + // prefix path to containing dir and filename prefix + // zeros number of leading zeros as if digit printed with printf + // suffix suffix of filename and extension (should include dot) + // Outputs: + // next path to next file + // Returns true if found, false if exceeding range in zeros + IGL_INLINE bool next_filename( + const std::string & prefix, + const int zeros, + const std::string & suffix, + std::string & next); +} + +#ifndef IGL_STATIC_LIBRARY +# include "next_filename.cpp" +#endif + +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/normal_derivative.cpp b/src/external/libigl-2.3.0/include/igl/normal_derivative.cpp new file mode 100644 index 000000000..49a332d05 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/normal_derivative.cpp @@ -0,0 +1,118 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "LinSpaced.h" +#include "normal_derivative.h" +#include "cotmatrix_entries.h" +#include "slice.h" +#include + +template < + typename DerivedV, + typename DerivedEle, + typename Scalar> +IGL_INLINE void igl::normal_derivative( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & Ele, + Eigen::SparseMatrix& DD) +{ + using namespace Eigen; + using namespace std; + // Element simplex-size + const size_t ss = Ele.cols(); + assert( ((ss==3) || (ss==4)) && "Only triangles or tets"); + // cotangents + Matrix C; + cotmatrix_entries(V,Ele,C); + vector > IJV; + // Number of elements + const size_t m = Ele.rows(); + // Number of vertices + const size_t n = V.rows(); + switch(ss) + { + default: + assert(false); + return; + case 4: + { + const MatrixXi DDJ = + slice( + Ele, + (VectorXi(24)<< + 1,0,2,0,3,0,2,1,3,1,0,1,3,2,0,2,1,2,0,3,1,3,2,3).finished(), + 2); + MatrixXi DDI(m,24); + for(size_t f = 0;f<4;f++) + { + const auto & I = (igl::LinSpaced(m,0,m-1).array()+f*m).eval(); + for(size_t r = 0;r<6;r++) + { + DDI.col(f*6+r) = I; + } + } + const DiagonalMatrix S = + (Matrix(1,-1).template replicate<12,1>()).asDiagonal(); + Matrix DDV = + slice( + C, + (VectorXi(24)<< + 2,2,1,1,3,3,0,0,4,4,2,2,5,5,1,1,0,0,3,3,4,4,5,5).finished(), + 2); + DDV *= S; + + IJV.reserve(DDV.size()); + for(size_t f = 0;f<6*4;f++) + { + for(size_t e = 0;e(DDI(e,f),DDJ(e,f),DDV(e,f))); + } + } + DD.resize(m*4,n); + DD.setFromTriplets(IJV.begin(),IJV.end()); + break; + } + case 3: + { + const MatrixXi DDJ = + slice(Ele,(VectorXi(12)<<2,0,1,0,0,1,2,1,1,2,0,2).finished(),2); + MatrixXi DDI(m,12); + for(size_t f = 0;f<3;f++) + { + const auto & I = (igl::LinSpaced(m,0,m-1).array()+f*m).eval(); + for(size_t r = 0;r<4;r++) + { + DDI.col(f*4+r) = I; + } + } + const DiagonalMatrix S = + (Matrix(1,-1).template replicate<6,1>()).asDiagonal(); + Matrix DDV = + slice(C,(VectorXi(12)<<1,1,2,2,2,2,0,0,0,0,1,1).finished(),2); + DDV *= S; + + IJV.reserve(DDV.size()); + for(size_t f = 0;f<12;f++) + { + for(size_t e = 0;e(DDI(e,f),DDJ(e,f),DDV(e,f))); + } + } + DD.resize(m*3,n); + DD.setFromTriplets(IJV.begin(),IJV.end()); + break; + } + } + +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +template void igl::normal_derivative, Eigen::Matrix, double>(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::SparseMatrix&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/normal_derivative.h b/src/external/libigl-2.3.0/include/igl/normal_derivative.h new file mode 100644 index 000000000..4718d321f --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/normal_derivative.h @@ -0,0 +1,44 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_NORMAL_DERIVATIVE_H +#define IGL_NORMAL_DERIVATIVE_H +#include "igl_inline.h" + +#include +#include +namespace igl +{ + // NORMAL_DERIVATIVE Computes the directional derivative **normal** to + // **all** (half-)edges of a triangle mesh (not just boundary edges). These + // are integrated along the edge: they're the per-face constant gradient dot + // the rotated edge vector (unit rotated edge vector for direction then + // magnitude for integration). + // + // Inputs: + // V #V by dim list of mesh vertex positions + // F #F by 3|4 list of triangle|tetrahedron indices into V + // Outputs: + // DD #F*3|4 by #V sparse matrix representing operator to compute + // directional derivative with respect to each facet of each element. + // + template < + typename DerivedV, + typename DerivedEle, + typename Scalar> + IGL_INLINE void normal_derivative( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & Ele, + Eigen::SparseMatrix& DD); +} + +#ifndef IGL_STATIC_LIBRARY +# include "normal_derivative.cpp" +#endif + +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/normalize_quat.cpp b/src/external/libigl-2.3.0/include/igl/normalize_quat.cpp new file mode 100644 index 000000000..f110d6b75 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/normalize_quat.cpp @@ -0,0 +1,41 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "normalize_quat.h" + +#include "EPS.h" +#include + +template +IGL_INLINE bool igl::normalize_quat( + const Q_type *q, + Q_type *out) +{ + // Get length + Q_type len = sqrt( + q[0]*q[0]+ + q[1]*q[1]+ + q[2]*q[2]+ + q[3]*q[3]); + + // Noramlize each coordinate + out[0] = q[0]/len; + out[1] = q[1]/len; + out[2] = q[2]/len; + out[3] = q[3]/len; + + // Test whether length was below Epsilon + return (len > igl::EPS()); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template bool igl::normalize_quat(double const*, double*); +// generated by autoexplicit.sh +template bool igl::normalize_quat(float const*, float*); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/normalize_quat.h b/src/external/libigl-2.3.0/include/igl/normalize_quat.h new file mode 100644 index 000000000..e97759b17 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/normalize_quat.h @@ -0,0 +1,32 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_NORMALIZE_QUAT_H +#define IGL_NORMALIZE_QUAT_H +#include "igl_inline.h" + +namespace igl +{ + // Normalize a quaternion + // A Quaternion, q, is defined here as an arrays of four scalars (x,y,z,w), + // such that q = x*i + y*j + z*k + w + // Inputs: + // q input quaternion + // Outputs: + // out result of normalization, allowed to be same as q + // Returns true on success, false if len(q) < EPS + template + IGL_INLINE bool normalize_quat( + const Q_type *q, + Q_type *out); +}; + +#ifndef IGL_STATIC_LIBRARY +# include "normalize_quat.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/normalize_row_lengths.cpp b/src/external/libigl-2.3.0/include/igl/normalize_row_lengths.cpp new file mode 100644 index 000000000..3d7e566e8 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/normalize_row_lengths.cpp @@ -0,0 +1,33 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "normalize_row_lengths.h" + +template +IGL_INLINE void igl::normalize_row_lengths( + const Eigen::PlainObjectBase& A, + Eigen::PlainObjectBase & B) +{ + // Resize output + B.resizeLike(A); + + // loop over rows + for(int i = 0; i < A.rows();i++) + { + B.row(i) = A.row(i).normalized(); + } + //// Or just: + //B = A; + //B.rowwise().normalize(); +} +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::normalize_row_lengths >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&); +template void igl::normalize_row_lengths >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&); +template void igl::normalize_row_lengths >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/normalize_row_lengths.h b/src/external/libigl-2.3.0/include/igl/normalize_row_lengths.h new file mode 100644 index 000000000..c305c0f65 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/normalize_row_lengths.h @@ -0,0 +1,37 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_NORMALIZE_ROW_LENGTHS_H +#define IGL_NORMALIZE_ROW_LENGTHS_H +#include "igl_inline.h" +#include + +// History: +// March 24, 2012: Alec changed function name from normalize_rows to +// normalize_row_lengths to avoid confusion with normalize_row_sums + +namespace igl +{ + // Obsolete: just use A.rowwise().normalize() or B=A.rowwise().normalized(); + // + // Normalize the rows in A so that their lengths are each 1 and place the new + // entries in B + // Inputs: + // A #rows by k input matrix + // Outputs: + // B #rows by k input matrix, can be the same as A + template + IGL_INLINE void normalize_row_lengths( + const Eigen::PlainObjectBase& A, + Eigen::PlainObjectBase & B); +} + +#ifndef IGL_STATIC_LIBRARY +# include "normalize_row_lengths.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/normalize_row_sums.cpp b/src/external/libigl-2.3.0/include/igl/normalize_row_sums.cpp new file mode 100644 index 000000000..1204e073d --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/normalize_row_sums.cpp @@ -0,0 +1,29 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "normalize_row_sums.h" + +template +IGL_INLINE void igl::normalize_row_sums( + const Eigen::MatrixBase& A, + Eigen::MatrixBase & B) +{ +#ifndef NDEBUG + // loop over rows + for(int i = 0; i < A.rows();i++) + { + typename DerivedB::Scalar sum = A.row(i).sum(); + assert(sum != 0); + } +#endif + B = (A.array().colwise() / A.rowwise().sum().array()).eval(); +} +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +template void igl::normalize_row_sums, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase >&); +template void igl::normalize_row_sums, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/normalize_row_sums.h b/src/external/libigl-2.3.0/include/igl/normalize_row_sums.h new file mode 100644 index 000000000..b27c6c282 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/normalize_row_sums.h @@ -0,0 +1,36 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_NORMALIZE_ROW_SUMS_H +#define IGL_NORMALIZE_ROW_SUMS_H +#include "igl_inline.h" +#include + +namespace igl +{ + // Normalize the rows in A so that their sums are each 1 and place the new + // entries in B + // Inputs: + // A #rows by k input matrix + // Outputs: + // B #rows by k input matrix, can be the same as A + // + // Note: This is just calling an Eigen one-liner: + // + // B = A.array().colwise() / A.array().rowwise().sum(); + // + template + IGL_INLINE void normalize_row_sums( + const Eigen::MatrixBase& A, + Eigen::MatrixBase & B); +} + +#ifndef IGL_STATIC_LIBRARY +# include "normalize_row_sums.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/null.cpp b/src/external/libigl-2.3.0/include/igl/null.cpp new file mode 100644 index 000000000..971149266 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/null.cpp @@ -0,0 +1,25 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "null.h" +#include "EPS.h" + +template +IGL_INLINE void igl::null( + const Eigen::PlainObjectBase & A, + Eigen::PlainObjectBase & N) +{ + using namespace Eigen; + typedef typename DerivedA::Scalar Scalar; + JacobiSVD svd(A, ComputeFullV); + svd.setThreshold(A.cols() * svd.singularValues().maxCoeff() * EPS()); + N = svd.matrixV().rightCols(A.cols()-svd.rank()); +} + +#ifdef IGL_STATIC_LIBRARY +template void igl::null, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/null.h b/src/external/libigl-2.3.0/include/igl/null.h new file mode 100644 index 000000000..2349217fb --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/null.h @@ -0,0 +1,36 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_NULL_H +#define IGL_NULL_H +#include "igl_inline.h" + +#include + +namespace igl +{ + // Like MATLAB's null + // + // Compute a basis for the null space for the given matrix A: the columns of + // the output N form a basis for the space orthogonal to that spanned by the + // rows of A. + // + // Inputs: + // A m by n matrix + // Outputs: + // N n by r matrix, where r is the row rank of A + template + IGL_INLINE void null( + const Eigen::PlainObjectBase & A, + Eigen::PlainObjectBase & N); +} + +#ifndef IGL_STATIC_LIBRARY +# include "null.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/octree.cpp b/src/external/libigl-2.3.0/include/igl/octree.cpp new file mode 100644 index 000000000..3360732f6 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/octree.cpp @@ -0,0 +1,176 @@ +#include "octree.h" +#include +#include + +namespace igl { + template + IGL_INLINE void octree(const Eigen::MatrixBase& P, + std::vector > & point_indices, + Eigen::PlainObjectBase& CH, + Eigen::PlainObjectBase& CN, + Eigen::PlainObjectBase& W) + { + + + + const int MAX_DEPTH = 30000; + + typedef typename DerivedCH::Scalar ChildrenType; + typedef typename DerivedCN::Scalar CentersType; + typedef typename DerivedW::Scalar WidthsType; + typedef typename DerivedP::Scalar PointScalar; + typedef Eigen::Matrix Vector8i; + typedef Eigen::Matrix RowVector3PType; + typedef Eigen::Matrix RowVector3CentersType; + + std::vector, + Eigen::aligned_allocator > > children; + std::vector, + Eigen::aligned_allocator > > centers; + std::vector widths; + + auto get_octant = [](const RowVector3PType& location, + const RowVector3CentersType& center){ + // We use a binary numbering of children. Treating the parent cell's + // center as the origin, we number the octants in the following manner: + // The first bit is 1 iff the octant's x coordinate is positive + // The second bit is 1 iff the octant's y coordinate is positive + // The third bit is 1 iff the octant's z coordinate is positive + // + // For example, the octant with negative x, positive y, positive z is: + // 110 binary = 6 decimal + IndexType index = 0; + if( location(0) >= center(0)){ + index = index + 1; + } + if( location(1) >= center(1)){ + index = index + 2; + } + if( location(2) >= center(2)){ + index = index + 4; + } + return index; + }; + + + std::function< RowVector3CentersType(const RowVector3CentersType, + const CentersType, + const ChildrenType) > + translate_center = + [](const RowVector3CentersType & parent_center, + const CentersType h, + const ChildrenType child_index){ + RowVector3CentersType change_vector; + change_vector << -h,-h,-h; + + //positive x chilren are 1,3,4,7 + if(child_index % 2){ + change_vector(0) = h; + } + //positive y children are 2,3,6,7 + if(child_index == 2 || child_index == 3 || + child_index == 6 || child_index == 7){ + change_vector(1) = h; + } + //positive z children are 4,5,6,7 + if(child_index > 3){ + change_vector(2) = h; + } + RowVector3CentersType output = parent_center + change_vector; + return output; + }; + + // How many cells do we have so far? + IndexType m = 0; + + // Useful list of number 0..7 + const Vector8i zero_to_seven = (Vector8i()<<0,1,2,3,4,5,6,7).finished(); + const Vector8i neg_ones = Vector8i::Constant(-1); + + std::function< void(const ChildrenType, const int) > helper; + helper = [&helper,&translate_center,&get_octant,&m, + &zero_to_seven,&neg_ones,&P, + &point_indices,&children,¢ers,&widths,&MAX_DEPTH] + (const ChildrenType index, const int depth)-> void + { + if(point_indices.at(index).size() > 1 && depth < MAX_DEPTH){ + //give the parent access to the children + children.at(index) = zero_to_seven.array() + m; + //make the children's data in our arrays + + //Add the children to the lists, as default children + CentersType h = widths.at(index)/2; + RowVector3CentersType curr_center = centers.at(index); + + + for(ChildrenType i = 0; i < 8; i++){ + children.emplace_back(neg_ones); + point_indices.emplace_back(std::vector()); + centers.emplace_back(translate_center(curr_center,h/2,i)); + widths.emplace_back(h); + } + + + //Split up the points into the corresponding children + for(int j = 0; j < point_indices.at(index).size(); j++){ + IndexType curr_point_index = point_indices.at(index).at(j); + IndexType cell_of_curr_point = + get_octant(P.row(curr_point_index),curr_center)+m; + point_indices.at(cell_of_curr_point).emplace_back(curr_point_index); + } + + //Now increase m + m += 8; + + + // Look ma, I'm calling myself. + for(int i = 0; i < 8; i++){ + helper(children.at(index)(i),depth+1); + } + } + }; + + { + std::vector all(P.rows()); + for(IndexType i = 0;i, int, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, std::vector >, std::allocator > > >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::octree, int, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, std::vector >, std::allocator > > >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/octree.h b/src/external/libigl-2.3.0/include/igl/octree.h new file mode 100644 index 000000000..a4c8cfaa6 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/octree.h @@ -0,0 +1,62 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2018 Gavin Barill +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/ + +#ifndef IGL_OCTREE +#define IGL_OCTREE +#include "igl_inline.h" +#include +#include + + + + +namespace igl +{ + // Given a set of 3D points P, generate data structures for a pointerless + // octree. Each cell stores its points, children, center location and width. + // Our octree is not dense. We use the following rule: if the current cell + // has any number of points, it will have all 8 children. A leaf cell will + // have -1's as its list of child indices. + // + // We use a binary numbering of children. Treating the parent cell's center + // as the origin, we number the octants in the following manner: + // The first bit is 1 iff the octant's x coordinate is positive + // The second bit is 1 iff the octant's y coordinate is positive + // The third bit is 1 iff the octant's z coordinate is positive + // + // For example, the octant with negative x, positive y, positive z is: + // 110 binary = 6 decimal + // + // Inputs: + // P #P by 3 list of point locations + // + // Outputs: + // point_indices a vector of vectors, where the ith entry is a vector of + // the indices into P that are the ith octree cell's points + // CH #OctreeCells by 8, where the ith row is the indices of + // the ith octree cell's children + // CN #OctreeCells by 3, where the ith row is a 3d row vector + // representing the position of the ith cell's center + // W #OctreeCells, a vector where the ith entry is the width + // of the ith octree cell + // + template + IGL_INLINE void octree(const Eigen::MatrixBase& P, + std::vector > & point_indices, + Eigen::PlainObjectBase& CH, + Eigen::PlainObjectBase& CN, + Eigen::PlainObjectBase& W); +} + +#ifndef IGL_STATIC_LIBRARY +# include "octree.cpp" +#endif + +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/offset_surface.cpp b/src/external/libigl-2.3.0/include/igl/offset_surface.cpp new file mode 100644 index 000000000..04bdb273b --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/offset_surface.cpp @@ -0,0 +1,57 @@ +#include "offset_surface.h" +#include "marching_cubes.h" +#include "voxel_grid.h" +#include "signed_distance.h" +#include "flood_fill.h" +#include + +template < + typename DerivedV, + typename DerivedF, + typename isolevelType, + typename DerivedSV, + typename DerivedSF, + typename DerivedGV, + typename Derivedside, + typename DerivedS> +void igl::offset_surface( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const isolevelType isolevel, + const typename Derivedside::Scalar s, + const SignedDistanceType & signed_distance_type, + Eigen::PlainObjectBase & SV, + Eigen::PlainObjectBase & SF, + Eigen::PlainObjectBase & GV, + Eigen::PlainObjectBase & side, + Eigen::PlainObjectBase & S) +{ + typedef typename DerivedV::Scalar Scalar; + typedef typename DerivedF::Scalar Index; + igl::voxel_grid(V,isolevel,s,1,GV,side); + + const Scalar h = + (GV.col(0).maxCoeff()-GV.col(0).minCoeff())/((Scalar)(side(0)-1)); + const Scalar lower_bound = isolevel-sqrt(3.0)*h; + const Scalar upper_bound = isolevel+sqrt(3.0)*h; + { + Eigen::Matrix I; + Eigen::Matrix C,N; + igl::signed_distance( + GV,V,F,signed_distance_type,lower_bound,upper_bound,S,I,C,N); + } + igl::flood_fill(side,S); + + DerivedS SS = S.array()-isolevel; + igl::marching_cubes(SS,GV,side(0),side(1),side(2),0,SV,SF); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::offset_surface, Eigen::Matrix, int, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, int, Eigen::Matrix::Scalar, igl::SignedDistanceType const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::offset_surface, Eigen::Matrix, double, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, double, Eigen::Matrix::Scalar, igl::SignedDistanceType const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::offset_surface, Eigen::Matrix, float, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, float, Eigen::Matrix::Scalar, igl::SignedDistanceType const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::offset_surface, Eigen::Matrix, double, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, double, Eigen::Matrix::Scalar, igl::SignedDistanceType const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/offset_surface.h b/src/external/libigl-2.3.0/include/igl/offset_surface.h new file mode 100644 index 000000000..aac8e2375 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/offset_surface.h @@ -0,0 +1,52 @@ +#ifndef IGL_OFFSET_SURFACE_H +#define IGL_OFFSET_SURFACE_H +#include "igl_inline.h" +#include "signed_distance.h" +#include + +namespace igl +{ + // Compute a triangulated offset surface using matching cubes on a grid of + // signed distance values from the input triangle mesh. + // + // Inputs: + // V #V by 3 list of mesh vertex positions + // F #F by 3 list of mesh triangle indices into V + // isolevel iso level to extract (signed distance: negative inside) + // s number of grid cells along longest side (controls resolution) + // signed_distance_type type of signing to use (see + // ../signed_distance.h) + // Outputs: + // SV #SV by 3 list of output surface mesh vertex positions + // SF #SF by 3 list of output mesh triangle indices into SV + // GV #GV=side(0)*side(1)*side(2) by 3 list of grid cell centers + // side list of number of grid cells in x, y, and z directions + // S #GV by 3 list of signed distance values _near_ `isolevel` ("far" + // from `isolevel` these values are incorrect) + // + template < + typename DerivedV, + typename DerivedF, + typename isolevelType, + typename DerivedSV, + typename DerivedSF, + typename DerivedGV, + typename Derivedside, + typename DerivedS> + void offset_surface( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const isolevelType isolevel, + const typename Derivedside::Scalar s, + const SignedDistanceType & signed_distance_type, + Eigen::PlainObjectBase & SV, + Eigen::PlainObjectBase & SF, + Eigen::PlainObjectBase & GV, + Eigen::PlainObjectBase & side, + Eigen::PlainObjectBase & S); + +} +#ifndef IGL_STATIC_LIBRARY +# include "offset_surface.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/on_boundary.cpp b/src/external/libigl-2.3.0/include/igl/on_boundary.cpp new file mode 100644 index 000000000..3fb70ec59 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/on_boundary.cpp @@ -0,0 +1,141 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "on_boundary.h" + +// IGL includes +#include "sort.h" +#include "face_occurrences.h" + +// STL includes + +template +IGL_INLINE void igl::on_boundary( + const std::vector > & T, + std::vector & I, + std::vector > & C) +{ + using namespace std; + if(T.empty()) + { + I.clear(); + C.clear(); + return; + } + + switch(T[0].size()) + { + case 3: + { + // Get a list of all faces + vector > F(T.size()*3,vector(2)); + // Gather faces, loop over tets + for(int i = 0; i< (int)T.size();i++) + { + assert(T[i].size() == 3); + // get face in correct order + F[i*3+0][0] = T[i][1]; + F[i*3+0][1] = T[i][2]; + F[i*3+1][0] = T[i][2]; + F[i*3+1][1] = T[i][0]; + F[i*3+2][0] = T[i][0]; + F[i*3+2][1] = T[i][1]; + } + // Counts + vector FC; + face_occurrences(F,FC); + C.resize(T.size(),vector(3)); + I.resize(T.size(),false); + for(int i = 0; i< (int)T.size();i++) + { + for(int j = 0;j<3;j++) + { + assert(FC[i*3+j] == 2 || FC[i*3+j] == 1); + C[i][j] = FC[i*3+j]==1; + // if any are on boundary set to true + I[i] = I[i] || C[i][j]; + } + } + return; + } + case 4: + { + // Get a list of all faces + vector > F(T.size()*4,vector(3)); + // Gather faces, loop over tets + for(int i = 0; i< (int)T.size();i++) + { + assert(T[i].size() == 4); + // get face in correct order + F[i*4+0][0] = T[i][1]; + F[i*4+0][1] = T[i][3]; + F[i*4+0][2] = T[i][2]; + // get face in correct order + F[i*4+1][0] = T[i][0]; + F[i*4+1][1] = T[i][2]; + F[i*4+1][2] = T[i][3]; + // get face in correct order + F[i*4+2][0] = T[i][0]; + F[i*4+2][1] = T[i][3]; + F[i*4+2][2] = T[i][1]; + // get face in correct order + F[i*4+3][0] = T[i][0]; + F[i*4+3][1] = T[i][1]; + F[i*4+3][2] = T[i][2]; + } + // Counts + vector FC; + face_occurrences(F,FC); + C.resize(T.size(),vector(4)); + I.resize(T.size(),false); + for(int i = 0; i< (int)T.size();i++) + { + for(int j = 0;j<4;j++) + { + assert(FC[i*4+j] == 2 || FC[i*4+j] == 1); + C[i][j] = FC[i*4+j]==1; + // if any are on boundary set to true + I[i] = I[i] || C[i][j]; + } + } + return; + } + } + + +} + +#include "list_to_matrix.h" +#include "matrix_to_list.h" + +template +IGL_INLINE void igl::on_boundary( + const Eigen::MatrixBase& T, + Eigen::PlainObjectBase& I, + Eigen::PlainObjectBase& C) +{ + assert(T.cols() == 0 || T.cols() == 4 || T.cols() == 3); + using namespace std; + using namespace Eigen; + // Cop out: use vector of vectors version + vector > vT; + matrix_to_list(T,vT); + vector vI; + vector > vC; + on_boundary(vT,vI,vC); + list_to_matrix(vI,I); + list_to_matrix(vC,C); +} + + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::on_boundary, Eigen::Array, Eigen::Array >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::on_boundary, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::on_boundary, Eigen::Array, Eigen::Array >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/on_boundary.h b/src/external/libigl-2.3.0/include/igl/on_boundary.h new file mode 100644 index 000000000..c4dab1706 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/on_boundary.h @@ -0,0 +1,51 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_ON_BOUNDARY_H +#define IGL_ON_BOUNDARY_H +#include "igl_inline.h" +#include + +#include + +namespace igl +{ + // ON_BOUNDARY Determine boundary facets of mesh elements stored in T + // + // Templates: + // IntegerT integer-value: i.e. int + // IntegerF integer-value: i.e. int + // Input: + // T triangle|tetrahedron index list, m by 3|4, where m is the number of + // elements + // Output: + // I m long list of bools whether tet is on boundary + // C m by 3|4 list of bools whether opposite facet is on boundary + // + template + IGL_INLINE void on_boundary( + const std::vector > & T, + std::vector & I, + std::vector > & C); + // Templates: + // DerivedT integer-value: i.e. from MatrixXi + // DerivedI bool-value: i.e. from MatrixXi + // DerivedC bool-value: i.e. from MatrixXi + template + IGL_INLINE void on_boundary( + const Eigen::MatrixBase& T, + Eigen::PlainObjectBase& I, + Eigen::PlainObjectBase& C); +} + +#ifndef IGL_STATIC_LIBRARY +# include "on_boundary.cpp" +#endif + +#endif + + diff --git a/src/external/libigl-2.3.0/include/igl/opengl/MeshGL.cpp b/src/external/libigl-2.3.0/include/igl/opengl/MeshGL.cpp new file mode 100644 index 000000000..6122c5c0b --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/opengl/MeshGL.cpp @@ -0,0 +1,484 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Daniele Panozzo +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +#include "MeshGL.h" +#include "bind_vertex_attrib_array.h" +#include "create_shader_program.h" +#include "destroy_shader_program.h" +#include "verasansmono_compressed.h" +#include + +IGL_INLINE igl::opengl::MeshGL::MeshGL(): + tex_filter(GL_LINEAR), + tex_wrap(GL_REPEAT) +{ +} + +IGL_INLINE void igl::opengl::MeshGL::init_buffers() +{ + // Mesh: Vertex Array Object & Buffer objects + glGenVertexArrays(1, &vao_mesh); + glBindVertexArray(vao_mesh); + glGenBuffers(1, &vbo_V); + glGenBuffers(1, &vbo_V_normals); + glGenBuffers(1, &vbo_V_ambient); + glGenBuffers(1, &vbo_V_diffuse); + glGenBuffers(1, &vbo_V_specular); + glGenBuffers(1, &vbo_V_uv); + glGenBuffers(1, &vbo_F); + glGenTextures(1, &vbo_tex); + glGenTextures(1, &font_atlas); + + // Line overlay + glGenVertexArrays(1, &vao_overlay_lines); + glBindVertexArray(vao_overlay_lines); + glGenBuffers(1, &vbo_lines_F); + glGenBuffers(1, &vbo_lines_V); + glGenBuffers(1, &vbo_lines_V_colors); + + // Point overlay + glGenVertexArrays(1, &vao_overlay_points); + glBindVertexArray(vao_overlay_points); + glGenBuffers(1, &vbo_points_F); + glGenBuffers(1, &vbo_points_V); + glGenBuffers(1, &vbo_points_V_colors); + + // Text Labels + vertex_labels.init_buffers(); + face_labels.init_buffers(); + custom_labels.init_buffers(); + + dirty = MeshGL::DIRTY_ALL; +} + +IGL_INLINE void igl::opengl::MeshGL::free_buffers() +{ + if (is_initialized) + { + glDeleteVertexArrays(1, &vao_mesh); + glDeleteVertexArrays(1, &vao_overlay_lines); + glDeleteVertexArrays(1, &vao_overlay_points); + + glDeleteBuffers(1, &vbo_V); + glDeleteBuffers(1, &vbo_V_normals); + glDeleteBuffers(1, &vbo_V_ambient); + glDeleteBuffers(1, &vbo_V_diffuse); + glDeleteBuffers(1, &vbo_V_specular); + glDeleteBuffers(1, &vbo_V_uv); + glDeleteBuffers(1, &vbo_F); + glDeleteBuffers(1, &vbo_lines_F); + glDeleteBuffers(1, &vbo_lines_V); + glDeleteBuffers(1, &vbo_lines_V_colors); + glDeleteBuffers(1, &vbo_points_F); + glDeleteBuffers(1, &vbo_points_V); + glDeleteBuffers(1, &vbo_points_V_colors); + + // Text Labels + vertex_labels.free_buffers(); + face_labels.free_buffers(); + custom_labels.free_buffers(); + + glDeleteTextures(1, &vbo_tex); + glDeleteTextures(1, &font_atlas); + } +} + +IGL_INLINE void igl::opengl::MeshGL::TextGL::init_buffers() +{ + glGenVertexArrays(1, &vao_labels); + glBindVertexArray(vao_labels); + glGenBuffers(1, &vbo_labels_pos); + glGenBuffers(1, &vbo_labels_characters); + glGenBuffers(1, &vbo_labels_offset); + glGenBuffers(1, &vbo_labels_indices); +} + +IGL_INLINE void igl::opengl::MeshGL::TextGL::free_buffers() +{ + glDeleteBuffers(1, &vbo_labels_pos); + glDeleteBuffers(1, &vbo_labels_characters); + glDeleteBuffers(1, &vbo_labels_offset); + glDeleteBuffers(1, &vbo_labels_indices); +} + +IGL_INLINE void igl::opengl::MeshGL::bind_mesh() +{ + glBindVertexArray(vao_mesh); + glUseProgram(shader_mesh); + bind_vertex_attrib_array(shader_mesh,"position", vbo_V, V_vbo, dirty & MeshGL::DIRTY_POSITION); + bind_vertex_attrib_array(shader_mesh,"normal", vbo_V_normals, V_normals_vbo, dirty & MeshGL::DIRTY_NORMAL); + bind_vertex_attrib_array(shader_mesh,"Ka", vbo_V_ambient, V_ambient_vbo, dirty & MeshGL::DIRTY_AMBIENT); + bind_vertex_attrib_array(shader_mesh,"Kd", vbo_V_diffuse, V_diffuse_vbo, dirty & MeshGL::DIRTY_DIFFUSE); + bind_vertex_attrib_array(shader_mesh,"Ks", vbo_V_specular, V_specular_vbo, dirty & MeshGL::DIRTY_SPECULAR); + bind_vertex_attrib_array(shader_mesh,"texcoord", vbo_V_uv, V_uv_vbo, dirty & MeshGL::DIRTY_UV); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo_F); + if (dirty & MeshGL::DIRTY_FACE) + glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned)*F_vbo.size(), F_vbo.data(), GL_DYNAMIC_DRAW); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, vbo_tex); + if (dirty & MeshGL::DIRTY_TEXTURE) + { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, tex_wrap); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, tex_wrap); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, tex_filter); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, tex_filter); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex_u, tex_v, 0, GL_RGBA, GL_UNSIGNED_BYTE, tex.data()); + } + glUniform1i(glGetUniformLocation(shader_mesh,"tex"), 0); + dirty &= ~MeshGL::DIRTY_MESH; +} + +IGL_INLINE void igl::opengl::MeshGL::bind_overlay_lines() +{ + bool is_dirty = dirty & MeshGL::DIRTY_OVERLAY_LINES; + + glBindVertexArray(vao_overlay_lines); + glUseProgram(shader_overlay_lines); + bind_vertex_attrib_array(shader_overlay_lines,"position", vbo_lines_V, lines_V_vbo, is_dirty); + bind_vertex_attrib_array(shader_overlay_lines,"color", vbo_lines_V_colors, lines_V_colors_vbo, is_dirty); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo_lines_F); + if (is_dirty) + { + glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned)*lines_F_vbo.size(), lines_F_vbo.data(), GL_DYNAMIC_DRAW); + } + + dirty &= ~MeshGL::DIRTY_OVERLAY_LINES; +} + +IGL_INLINE void igl::opengl::MeshGL::bind_overlay_points() +{ + bool is_dirty = dirty & MeshGL::DIRTY_OVERLAY_POINTS; + + glBindVertexArray(vao_overlay_points); + glUseProgram(shader_overlay_points); + bind_vertex_attrib_array(shader_overlay_points,"position", vbo_points_V, points_V_vbo, is_dirty); + bind_vertex_attrib_array(shader_overlay_points,"color", vbo_points_V_colors, points_V_colors_vbo, is_dirty); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo_points_F); + if (is_dirty) + { + glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned)*points_F_vbo.size(), points_F_vbo.data(), GL_DYNAMIC_DRAW); + } + + dirty &= ~MeshGL::DIRTY_OVERLAY_POINTS; +} + +IGL_INLINE void igl::opengl::MeshGL::init_text_rendering() +{ + // Decompress the png of the font atlas + unsigned char verasansmono_font_atlas[256*256]; + decompress_verasansmono_atlas(verasansmono_font_atlas); + + // Bind atlas + glBindTexture(GL_TEXTURE_2D, font_atlas); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, 256, 256, 0, GL_RED, GL_UNSIGNED_BYTE, verasansmono_font_atlas); + + // TextGL initialization + vertex_labels.dirty_flag = MeshGL::DIRTY_VERTEX_LABELS; + face_labels.dirty_flag = MeshGL::DIRTY_FACE_LABELS; + custom_labels.dirty_flag = MeshGL::DIRTY_CUSTOM_LABELS; +} + +IGL_INLINE void igl::opengl::MeshGL::bind_labels(const TextGL& labels) +{ + bool is_dirty = dirty & labels.dirty_flag; + glBindTexture(GL_TEXTURE_2D, font_atlas); + glBindVertexArray(labels.vao_labels); + glUseProgram(shader_text); + bind_vertex_attrib_array(shader_text, "position" , labels.vbo_labels_pos , labels.label_pos_vbo , is_dirty); + bind_vertex_attrib_array(shader_text, "character", labels.vbo_labels_characters, labels.label_char_vbo , is_dirty); + bind_vertex_attrib_array(shader_text, "offset" , labels.vbo_labels_offset , labels.label_offset_vbo, is_dirty); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, labels.vbo_labels_indices); + if (is_dirty) + { + glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned)*labels.label_indices_vbo.size(), labels.label_indices_vbo.data(), GL_DYNAMIC_DRAW); + } + dirty &= ~labels.dirty_flag; +} + +IGL_INLINE void igl::opengl::MeshGL::draw_mesh(bool solid) +{ + glPolygonMode(GL_FRONT_AND_BACK, solid ? GL_FILL : GL_LINE); + + /* Avoid Z-buffer fighting between filled triangles & wireframe lines */ + if (solid) + { + glEnable(GL_POLYGON_OFFSET_FILL); + glPolygonOffset(1.0, 1.0); + } + glDrawElements(GL_TRIANGLES, 3*F_vbo.rows(), GL_UNSIGNED_INT, 0); + + glDisable(GL_POLYGON_OFFSET_FILL); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); +} + +IGL_INLINE void igl::opengl::MeshGL::draw_overlay_lines() +{ + glDrawElements(GL_LINES, lines_F_vbo.rows(), GL_UNSIGNED_INT, 0); +} + +IGL_INLINE void igl::opengl::MeshGL::draw_overlay_points() +{ + glDrawElements(GL_POINTS, points_F_vbo.rows(), GL_UNSIGNED_INT, 0); +} + +IGL_INLINE void igl::opengl::MeshGL::draw_labels(const TextGL& labels) +{ + glDrawElements(GL_POINTS, labels.label_indices_vbo.rows(), GL_UNSIGNED_INT, 0); +} + +IGL_INLINE void igl::opengl::MeshGL::init() +{ + if(is_initialized) + { + return; + } + is_initialized = true; + std::string mesh_vertex_shader_string = +R"(#version 150 + uniform mat4 view; + uniform mat4 proj; + uniform mat4 normal_matrix; + in vec3 position; + in vec3 normal; + out vec3 position_eye; + out vec3 normal_eye; + in vec4 Ka; + in vec4 Kd; + in vec4 Ks; + in vec2 texcoord; + out vec2 texcoordi; + out vec4 Kai; + out vec4 Kdi; + out vec4 Ksi; + + void main() + { + position_eye = vec3 (view * vec4 (position, 1.0)); + normal_eye = vec3 (normal_matrix * vec4 (normal, 0.0)); + normal_eye = normalize(normal_eye); + gl_Position = proj * vec4 (position_eye, 1.0); //proj * view * vec4(position, 1.0);" + Kai = Ka; + Kdi = Kd; + Ksi = Ks; + texcoordi = texcoord; + } +)"; + + std::string mesh_fragment_shader_string = +R"(#version 150 + uniform mat4 view; + uniform mat4 proj; + uniform vec4 fixed_color; + in vec3 position_eye; + in vec3 normal_eye; + uniform vec3 light_position_eye; + vec3 Ls = vec3 (1, 1, 1); + vec3 Ld = vec3 (1, 1, 1); + vec3 La = vec3 (1, 1, 1); + in vec4 Ksi; + in vec4 Kdi; + in vec4 Kai; + in vec2 texcoordi; + uniform sampler2D tex; + uniform float specular_exponent; + uniform float lighting_factor; + uniform float texture_factor; + uniform float matcap_factor; + uniform float double_sided; + out vec4 outColor; + void main() + { + if(matcap_factor == 1.0f) + { + vec2 uv = normalize(normal_eye).xy * 0.5 + 0.5; + outColor = texture(tex, uv); + }else + { + vec3 Ia = La * vec3(Kai); // ambient intensity + + vec3 vector_to_light_eye = light_position_eye - position_eye; + vec3 direction_to_light_eye = normalize (vector_to_light_eye); + float dot_prod = dot (direction_to_light_eye, normalize(normal_eye)); + float clamped_dot_prod = abs(max (dot_prod, -double_sided)); + vec3 Id = Ld * vec3(Kdi) * clamped_dot_prod; // Diffuse intensity + + vec3 reflection_eye = reflect (-direction_to_light_eye, normalize(normal_eye)); + vec3 surface_to_viewer_eye = normalize (-position_eye); + float dot_prod_specular = dot (reflection_eye, surface_to_viewer_eye); + dot_prod_specular = float(abs(dot_prod)==dot_prod) * abs(max (dot_prod_specular, -double_sided)); + float specular_factor = pow (dot_prod_specular, specular_exponent); + vec3 Is = Ls * vec3(Ksi) * specular_factor; // specular intensity + vec4 color = vec4(lighting_factor * (Is + Id) + Ia + (1.0-lighting_factor) * vec3(Kdi),(Kai.a+Ksi.a+Kdi.a)/3); + outColor = mix(vec4(1,1,1,1), texture(tex, texcoordi), texture_factor) * color; + if (fixed_color != vec4(0.0)) outColor = fixed_color; + } + } +)"; + + std::string overlay_vertex_shader_string = +R"(#version 150 + uniform mat4 view; + uniform mat4 proj; + in vec3 position; + in vec3 color; + out vec3 color_frag; + + void main() + { + gl_Position = proj * view * vec4 (position, 1.0); + color_frag = color; + } +)"; + + std::string overlay_fragment_shader_string = +R"(#version 150 + in vec3 color_frag; + out vec4 outColor; + void main() + { + outColor = vec4(color_frag, 1.0); + } +)"; + + std::string overlay_point_fragment_shader_string = +R"(#version 150 + in vec3 color_frag; + out vec4 outColor; + void main() + { + if (length(gl_PointCoord - vec2(0.5)) > 0.5) + discard; + outColor = vec4(color_frag, 1.0); + } +)"; + + std::string text_vert_shader = +R"(#version 330 + in vec3 position; + in float character; + in float offset; + uniform mat4 view; + uniform mat4 proj; + out int vCharacter; + out float vOffset; + void main() + { + vCharacter = int(character); + vOffset = offset; + gl_Position = proj * view * vec4(position, 1.0); + } +)"; + + std::string text_geom_shader = +R"(#version 150 core + layout(points) in; + layout(triangle_strip, max_vertices = 4) out; + out vec2 gTexCoord; + uniform mat4 view; + uniform mat4 proj; + uniform vec2 CellSize; + uniform vec2 CellOffset; + uniform vec2 RenderSize; + uniform vec2 RenderOrigin; + uniform float TextShiftFactor; + in int vCharacter[1]; + in float vOffset[1]; + void main() + { + // Code taken from https://prideout.net/strings-inside-vertex-buffers + // Determine the final quad's position and size: + vec4 P = gl_in[0].gl_Position + vec4( vOffset[0]*TextShiftFactor, 0.0, 0.0, 0.0 ); // 0.04 + vec4 U = vec4(1, 0, 0, 0) * RenderSize.x; // 1.0 + vec4 V = vec4(0, 1, 0, 0) * RenderSize.y; // 1.0 + + // Determine the texture coordinates: + int letter = vCharacter[0]; // used to be the character + letter = clamp(letter - 32, 0, 96); + int row = letter / 16 + 1; + int col = letter % 16; + float S0 = CellOffset.x + CellSize.x * col; + float T0 = CellOffset.y + 1 - CellSize.y * row; + float S1 = S0 + CellSize.x - CellOffset.x; + float T1 = T0 + CellSize.y; + + // Output the quad's vertices: + gTexCoord = vec2(S0, T1); gl_Position = P - U - V; EmitVertex(); + gTexCoord = vec2(S1, T1); gl_Position = P + U - V; EmitVertex(); + gTexCoord = vec2(S0, T0); gl_Position = P - U + V; EmitVertex(); + gTexCoord = vec2(S1, T0); gl_Position = P + U + V; EmitVertex(); + EndPrimitive(); + } +)"; + + std::string text_frag_shader = +R"(#version 330 + out vec4 outColor; + in vec2 gTexCoord; + uniform sampler2D font_atlas; + uniform vec3 TextColor; + void main() + { + float A = texture(font_atlas, gTexCoord).r; + outColor = vec4(TextColor, A); + } +)"; + + init_buffers(); + init_text_rendering(); + create_shader_program( + mesh_vertex_shader_string, + mesh_fragment_shader_string, + {}, + shader_mesh); + create_shader_program( + overlay_vertex_shader_string, + overlay_fragment_shader_string, + {}, + shader_overlay_lines); + create_shader_program( + overlay_vertex_shader_string, + overlay_point_fragment_shader_string, + {}, + shader_overlay_points); + create_shader_program( + text_geom_shader, + text_vert_shader, + text_frag_shader, + {}, + shader_text); +} + +IGL_INLINE void igl::opengl::MeshGL::free() +{ + const auto free = [](GLuint & id) + { + if(id) + { + destroy_shader_program(id); + id = 0; + } + }; + + if (is_initialized) + { + free(shader_mesh); + free(shader_overlay_lines); + free(shader_overlay_points); + free(shader_text); + free_buffers(); + } +} diff --git a/src/external/libigl-2.3.0/include/igl/opengl/MeshGL.h b/src/external/libigl-2.3.0/include/igl/opengl/MeshGL.h new file mode 100644 index 000000000..269b76c23 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/opengl/MeshGL.h @@ -0,0 +1,168 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Daniele Panozzo +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_OPENGL_MESHGL_H +#define IGL_OPENGL_MESHGL_H + +// Coverts mesh data inside a igl::ViewerData class in an OpenGL +// compatible format The class includes a shader and the opengl calls to plot +// the data + +#include +#include + +namespace igl +{ +namespace opengl +{ + +class MeshGL +{ +public: + typedef unsigned int GLuint; + typedef unsigned int GLint; + + enum DirtyFlags + { + DIRTY_NONE = 0x0000, + DIRTY_POSITION = 0x0001, + DIRTY_UV = 0x0002, + DIRTY_NORMAL = 0x0004, + DIRTY_AMBIENT = 0x0008, + DIRTY_DIFFUSE = 0x0010, + DIRTY_SPECULAR = 0x0020, + DIRTY_TEXTURE = 0x0040, + DIRTY_FACE = 0x0080, + DIRTY_MESH = 0x00FF, + DIRTY_OVERLAY_LINES = 0x0100, + DIRTY_OVERLAY_POINTS = 0x0200, + DIRTY_VERTEX_LABELS = 0x0400, + DIRTY_FACE_LABELS = 0x0800, + DIRTY_CUSTOM_LABELS = 0x1000, + DIRTY_ALL = 0xFFFF + }; + + bool is_initialized = false; + GLuint vao_mesh; + GLuint vao_overlay_lines; + GLuint vao_overlay_points; + GLuint shader_mesh; + GLuint shader_overlay_lines; + GLuint shader_overlay_points; + GLuint shader_text; + + GLuint vbo_V; // Vertices of the current mesh (#V x 3) + GLuint vbo_V_uv; // UV coordinates for the current mesh (#V x 2) + GLuint vbo_V_normals; // Vertices of the current mesh (#V x 3) + GLuint vbo_V_ambient; // Ambient material (#V x 3) + GLuint vbo_V_diffuse; // Diffuse material (#V x 3) + GLuint vbo_V_specular; // Specular material (#V x 3) + + GLuint vbo_F; // Faces of the mesh (#F x 3) + GLuint vbo_tex; // Texture + + GLuint vbo_lines_F; // Indices of the line overlay + GLuint vbo_lines_V; // Vertices of the line overlay + GLuint vbo_lines_V_colors; // Color values of the line overlay + GLuint vbo_points_F; // Indices of the point overlay + GLuint vbo_points_V; // Vertices of the point overlay + GLuint vbo_points_V_colors; // Color values of the point overlay + + // Temporary copy of the content of each VBO + typedef Eigen::Matrix RowMatrixXf; + RowMatrixXf V_vbo; + RowMatrixXf V_normals_vbo; + RowMatrixXf V_ambient_vbo; + RowMatrixXf V_diffuse_vbo; + RowMatrixXf V_specular_vbo; + RowMatrixXf V_uv_vbo; + RowMatrixXf lines_V_vbo; + RowMatrixXf lines_V_colors_vbo; + RowMatrixXf points_V_vbo; + RowMatrixXf points_V_colors_vbo; + + // Text Rendering + struct TextGL + { + uint32_t dirty_flag; + GLuint vao_labels; + GLuint vbo_labels_pos; + GLuint vbo_labels_characters; + GLuint vbo_labels_offset; + GLuint vbo_labels_indices; + RowMatrixXf label_pos_vbo; + RowMatrixXf label_char_vbo; + RowMatrixXf label_offset_vbo; + Eigen::Matrix label_indices_vbo; + void init_buffers(); + void free_buffers(); + }; + TextGL vertex_labels; + TextGL face_labels; + TextGL custom_labels; + GLuint font_atlas; + + int tex_u; + int tex_v; + GLint tex_filter; + GLint tex_wrap; + Eigen::Matrix tex; + + Eigen::Matrix F_vbo; + Eigen::Matrix lines_F_vbo; + Eigen::Matrix points_F_vbo; + + // Marks dirty buffers that need to be uploaded to OpenGL + uint32_t dirty; + + IGL_INLINE MeshGL(); + + // Initialize shaders and buffers + IGL_INLINE void init(); + + // Release all resources + IGL_INLINE void free(); + + // Create a new set of OpenGL buffer objects + IGL_INLINE void init_buffers(); + + // Bind the underlying OpenGL buffer objects for subsequent mesh draw calls + IGL_INLINE void bind_mesh(); + + /// Draw the currently buffered mesh (either solid or wireframe) + IGL_INLINE void draw_mesh(bool solid); + + // Bind the underlying OpenGL buffer objects for subsequent line overlay draw calls + IGL_INLINE void bind_overlay_lines(); + + /// Draw the currently buffered line overlay + IGL_INLINE void draw_overlay_lines(); + + // Bind the underlying OpenGL buffer objects for subsequent point overlay draw calls + IGL_INLINE void bind_overlay_points(); + + /// Draw the currently buffered point overlay + IGL_INLINE void draw_overlay_points(); + + // Text Binding and Draw functions + IGL_INLINE void init_text_rendering(); + IGL_INLINE void bind_labels(const TextGL& labels); + IGL_INLINE void draw_labels(const TextGL& labels); + + // Release the OpenGL buffer objects + IGL_INLINE void free_buffers(); + +}; + +} +} + +#ifndef IGL_STATIC_LIBRARY +# include "MeshGL.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/opengl/ViewerCore.cpp b/src/external/libigl-2.3.0/include/igl/opengl/ViewerCore.cpp new file mode 100644 index 000000000..50759ddeb --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/opengl/ViewerCore.cpp @@ -0,0 +1,457 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Daniele Panozzo +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +#include "ViewerCore.h" +#include "ViewerData.h" +#include "gl.h" +#include "../quat_to_mat.h" +#include "../snap_to_fixed_up.h" +#include "../look_at.h" +#include "../frustum.h" +#include "../ortho.h" +#include "../massmatrix.h" +#include "../barycenter.h" +#include "../PI.h" +#include +#include + +IGL_INLINE void igl::opengl::ViewerCore::align_camera_center( + const Eigen::MatrixXd& V, + const Eigen::MatrixXi& F) +{ + if(V.rows() == 0) + return; + + get_scale_and_shift_to_fit_mesh(V,F,camera_base_zoom,camera_base_translation); + // Rather than crash on empty mesh... + if(V.size() > 0) + { + object_scale = (V.colwise().maxCoeff() - V.colwise().minCoeff()).norm(); + } +} + +IGL_INLINE void igl::opengl::ViewerCore::get_scale_and_shift_to_fit_mesh( + const Eigen::MatrixXd& V, + const Eigen::MatrixXi& F, + float& zoom, + Eigen::Vector3f& shift) +{ + if (V.rows() == 0) + return; + + Eigen::MatrixXd BC; + if (F.rows() <= 1) + { + BC = V; + } else + { + igl::barycenter(V,F,BC); + } + return get_scale_and_shift_to_fit_mesh(BC,zoom,shift); +} + +IGL_INLINE void igl::opengl::ViewerCore::align_camera_center( + const Eigen::MatrixXd& V) +{ + if(V.rows() == 0) + return; + + get_scale_and_shift_to_fit_mesh(V,camera_base_zoom,camera_base_translation); + // Rather than crash on empty mesh... + if(V.size() > 0) + { + object_scale = (V.colwise().maxCoeff() - V.colwise().minCoeff()).norm(); + } +} + +IGL_INLINE void igl::opengl::ViewerCore::get_scale_and_shift_to_fit_mesh( + const Eigen::MatrixXd& V, + float& zoom, + Eigen::Vector3f& shift) +{ + if (V.rows() == 0) + return; + + auto min_point = V.colwise().minCoeff(); + auto max_point = V.colwise().maxCoeff(); + auto centroid = (0.5*(min_point + max_point)).eval(); + shift.setConstant(0); + shift.head(centroid.size()) = -centroid.cast(); + zoom = 2.0 / (max_point-min_point).array().abs().maxCoeff(); +} + + +IGL_INLINE void igl::opengl::ViewerCore::clear_framebuffers() +{ + // The glScissor call ensures we only clear this core's buffers, + // (in case the user wants different background colors in each viewport.) + glScissor(viewport(0), viewport(1), viewport(2), viewport(3)); + glEnable(GL_SCISSOR_TEST); + glClearColor(background_color[0], + background_color[1], + background_color[2], + background_color[3]); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glDisable(GL_SCISSOR_TEST); +} + +IGL_INLINE void igl::opengl::ViewerCore::draw( + ViewerData& data, + bool update_matrices) +{ + using namespace std; + using namespace Eigen; + + if (depth_test) + glEnable(GL_DEPTH_TEST); + else + glDisable(GL_DEPTH_TEST); + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + /* Bind and potentially refresh mesh/line/point data */ + if (data.dirty) + { + data.updateGL(data, data.invert_normals, data.meshgl); + data.dirty = MeshGL::DIRTY_NONE; + } + data.meshgl.bind_mesh(); + + // Initialize uniform + glViewport(viewport(0), viewport(1), viewport(2), viewport(3)); + + if(update_matrices) + { + view = Eigen::Matrix4f::Identity(); + proj = Eigen::Matrix4f::Identity(); + norm = Eigen::Matrix4f::Identity(); + + float width = viewport(2); + float height = viewport(3); + + // Set view + look_at( camera_eye, camera_center, camera_up, view); + view = view + * (trackball_angle * Eigen::Scaling(camera_zoom * camera_base_zoom) + * Eigen::Translation3f(camera_translation + camera_base_translation)).matrix(); + + norm = view.inverse().transpose(); + + // Set projection + if (orthographic) + { + float length = (camera_eye - camera_center).norm(); + float h = tan(camera_view_angle/360.0 * igl::PI) * (length); + ortho(-h*width/height, h*width/height, -h, h, camera_dnear, camera_dfar,proj); + } + else + { + float fH = tan(camera_view_angle / 360.0 * igl::PI) * camera_dnear; + float fW = fH * (double)width/(double)height; + frustum(-fW, fW, -fH, fH, camera_dnear, camera_dfar,proj); + } + } + + // Send transformations to the GPU + GLint viewi = glGetUniformLocation(data.meshgl.shader_mesh,"view"); + GLint proji = glGetUniformLocation(data.meshgl.shader_mesh,"proj"); + GLint normi = glGetUniformLocation(data.meshgl.shader_mesh,"normal_matrix"); + glUniformMatrix4fv(viewi, 1, GL_FALSE, view.data()); + glUniformMatrix4fv(proji, 1, GL_FALSE, proj.data()); + glUniformMatrix4fv(normi, 1, GL_FALSE, norm.data()); + + // Light parameters + GLint specular_exponenti = glGetUniformLocation(data.meshgl.shader_mesh,"specular_exponent"); + GLint light_position_eyei = glGetUniformLocation(data.meshgl.shader_mesh,"light_position_eye"); + GLint lighting_factori = glGetUniformLocation(data.meshgl.shader_mesh,"lighting_factor"); + GLint fixed_colori = glGetUniformLocation(data.meshgl.shader_mesh,"fixed_color"); + GLint texture_factori = glGetUniformLocation(data.meshgl.shader_mesh,"texture_factor"); + GLint matcap_factori = glGetUniformLocation(data.meshgl.shader_mesh,"matcap_factor"); + GLint double_sidedi = glGetUniformLocation(data.meshgl.shader_mesh,"double_sided"); + + glUniform1f(specular_exponenti, data.shininess); + glUniform3fv(light_position_eyei, 1, light_position.data()); + glUniform1f(lighting_factori, lighting_factor); // enables lighting + glUniform4f(fixed_colori, 0.0, 0.0, 0.0, 0.0); + + if (data.V.rows()>0) + { + // Render fill + if (is_set(data.show_faces)) + { + // Texture + glUniform1f(texture_factori, is_set(data.show_texture) ? 1.0f : 0.0f); + glUniform1f(matcap_factori, is_set(data.use_matcap) ? 1.0f : 0.0f); + glUniform1f(double_sidedi, data.double_sided ? 1.0f : 0.0f); + data.meshgl.draw_mesh(true); + glUniform1f(matcap_factori, 0.0f); + glUniform1f(texture_factori, 0.0f); + } + + // Render wireframe + if (is_set(data.show_lines)) + { + glLineWidth(data.line_width); + glUniform4f(fixed_colori, + data.line_color[0], + data.line_color[1], + data.line_color[2], 1.0f); + data.meshgl.draw_mesh(false); + glUniform4f(fixed_colori, 0.0f, 0.0f, 0.0f, 0.0f); + } + } + + if (is_set(data.show_overlay)) + { + if (is_set(data.show_overlay_depth)) + glEnable(GL_DEPTH_TEST); + else + glDisable(GL_DEPTH_TEST); + + if (data.lines.rows() > 0) + { + data.meshgl.bind_overlay_lines(); + viewi = glGetUniformLocation(data.meshgl.shader_overlay_lines,"view"); + proji = glGetUniformLocation(data.meshgl.shader_overlay_lines,"proj"); + + glUniformMatrix4fv(viewi, 1, GL_FALSE, view.data()); + glUniformMatrix4fv(proji, 1, GL_FALSE, proj.data()); + // This must be enabled, otherwise glLineWidth has no effect + glEnable(GL_LINE_SMOOTH); + glLineWidth(data.line_width); + + data.meshgl.draw_overlay_lines(); + } + + if (data.points.rows() > 0) + { + data.meshgl.bind_overlay_points(); + viewi = glGetUniformLocation(data.meshgl.shader_overlay_points,"view"); + proji = glGetUniformLocation(data.meshgl.shader_overlay_points,"proj"); + + glUniformMatrix4fv(viewi, 1, GL_FALSE, view.data()); + glUniformMatrix4fv(proji, 1, GL_FALSE, proj.data()); + glPointSize(data.point_size); + data.meshgl.draw_overlay_points(); + } + glEnable(GL_DEPTH_TEST); + } + + if(is_set(data.show_vertex_labels)&&data.vertex_labels_positions.rows()>0) + draw_labels(data, data.meshgl.vertex_labels); + if(is_set(data.show_face_labels)&&data.face_labels_positions.rows()>0) + draw_labels(data, data.meshgl.face_labels); + if(is_set(data.show_custom_labels)&&data.labels_positions.rows()>0) + draw_labels(data, data.meshgl.custom_labels); +} + +IGL_INLINE void igl::opengl::ViewerCore::draw_buffer(ViewerData& data, + bool update_matrices, + Eigen::Matrix& R, + Eigen::Matrix& G, + Eigen::Matrix& B, + Eigen::Matrix& A) +{ + assert(R.rows() == G.rows() && G.rows() == B.rows() && B.rows() == A.rows()); + assert(R.cols() == G.cols() && G.cols() == B.cols() && B.cols() == A.cols()); + + unsigned width = R.rows(); + unsigned height = R.cols(); + + // https://learnopengl.com/Advanced-OpenGL/Anti-Aliasing + unsigned int framebuffer; + glGenFramebuffers(1, &framebuffer); + glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); + // create a multisampled color attachment texture + unsigned int textureColorBufferMultiSampled; + glGenTextures(1, &textureColorBufferMultiSampled); + glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, textureColorBufferMultiSampled); + glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 4, GL_RGBA, width, height, GL_TRUE); + glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, textureColorBufferMultiSampled, 0); + // create a (also multisampled) renderbuffer object for depth and stencil attachments + unsigned int rbo; + glGenRenderbuffers(1, &rbo); + glBindRenderbuffer(GL_RENDERBUFFER, rbo); + glRenderbufferStorageMultisample(GL_RENDERBUFFER, 4, GL_DEPTH24_STENCIL8, width, height); + glBindRenderbuffer(GL_RENDERBUFFER, 0); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo); + assert(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + // configure second post-processing framebuffer + unsigned int intermediateFBO; + glGenFramebuffers(1, &intermediateFBO); + glBindFramebuffer(GL_FRAMEBUFFER, intermediateFBO); + // create a color attachment texture + unsigned int screenTexture; + glGenTextures(1, &screenTexture); + glBindTexture(GL_TEXTURE_2D, screenTexture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, screenTexture, 0); // we only need a color buffer + assert(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); + + // Clear the buffer + glClearColor(background_color(0), background_color(1), background_color(2), 0.f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + // Save old viewport + Eigen::Vector4f viewport_ori = viewport; + viewport << 0,0,width,height; + // Draw + draw(data,update_matrices); + // Restore viewport + viewport = viewport_ori; + + glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, intermediateFBO); + glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_NEAREST); + + glBindFramebuffer(GL_FRAMEBUFFER, intermediateFBO); + // Copy back in the given Eigen matrices + GLubyte* pixels = (GLubyte*)calloc(width*height*4,sizeof(GLubyte)); + glReadPixels(0, 0,width, height,GL_RGBA, GL_UNSIGNED_BYTE, pixels); + + // Clean up + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); + glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glDeleteTextures(1, &screenTexture); + glDeleteTextures(1, &textureColorBufferMultiSampled); + glDeleteFramebuffers(1, &framebuffer); + glDeleteFramebuffers(1, &intermediateFBO); + glDeleteRenderbuffers(1, &rbo); + + int count = 0; + for (unsigned j=0; j +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_OPENGL_VIEWERCORE_H +#define IGL_OPENGL_VIEWERCORE_H + +#include + +#include +#include +#include + +namespace igl +{ +namespace opengl +{ + +// Forward declaration +class ViewerData; + +// Basic class of the 3D mesh viewer +// TODO: write documentation +class ViewerCore +{ +public: + IGL_INLINE ViewerCore(); + + // Initialization + IGL_INLINE void init(); + + // Shutdown + IGL_INLINE void shut(); + + // Serialization code + IGL_INLINE void InitSerialization(); + + // ------------------- Camera control functions + + // Adjust the view to see the entire model + IGL_INLINE void align_camera_center( + const Eigen::MatrixXd& V, + const Eigen::MatrixXi& F); + + // Determines how much to zoom and shift such that the mesh fills the unit + // box (centered at the origin) + IGL_INLINE void get_scale_and_shift_to_fit_mesh( + const Eigen::MatrixXd& V, + const Eigen::MatrixXi& F, + float & zoom, + Eigen::Vector3f& shift); + + // Adjust the view to see the entire model + IGL_INLINE void align_camera_center( + const Eigen::MatrixXd& V); + + // Determines how much to zoom and shift such that the mesh fills the unit + // box (centered at the origin) + IGL_INLINE void get_scale_and_shift_to_fit_mesh( + const Eigen::MatrixXd& V, + float & zoom, + Eigen::Vector3f& shift); + + // ------------------- Drawing functions + + // Clear the frame buffers + IGL_INLINE void clear_framebuffers(); + + // Draw everything + // + // data cannot be const because it is being set to "clean" + IGL_INLINE void draw(ViewerData& data, bool update_matrices = true); + IGL_INLINE void draw_buffer( + ViewerData& data, + bool update_matrices, + Eigen::Matrix& R, + Eigen::Matrix& G, + Eigen::Matrix& B, + Eigen::Matrix& A); + IGL_INLINE void draw_labels( + ViewerData& data, + const igl::opengl::MeshGL::TextGL& labels + ); + + // Trackball angle (quaternion) + enum RotationType + { + ROTATION_TYPE_TRACKBALL = 0, + ROTATION_TYPE_TWO_AXIS_VALUATOR_FIXED_UP = 1, + ROTATION_TYPE_NO_ROTATION = 2, + NUM_ROTATION_TYPES = 3 + }; + IGL_INLINE void set_rotation_type(const RotationType & value); + + // ------------------- Option helpers + + // Set a ViewerData visualization option for this viewport + IGL_INLINE void set(unsigned int &property_mask, bool value = true) const; + + // Unset a ViewerData visualization option for this viewport + IGL_INLINE void unset(unsigned int &property_mask) const; + + // Toggle a ViewerData visualization option for this viewport + IGL_INLINE void toggle(unsigned int &property_mask) const; + + // Check whether a ViewerData visualization option is set for this viewport + IGL_INLINE bool is_set(unsigned int property_mask) const; + + // ------------------- Properties + + // Unique identifier + unsigned int id = 1u; + + // Colors + Eigen::Vector4f background_color; + + // Lighting + Eigen::Vector3f light_position; + float lighting_factor; + + RotationType rotation_type; + Eigen::Quaternionf trackball_angle; + + // Camera parameters + float camera_base_zoom; + float camera_zoom; + bool orthographic; + Eigen::Vector3f camera_base_translation; + Eigen::Vector3f camera_translation; + Eigen::Vector3f camera_eye; + Eigen::Vector3f camera_up; + Eigen::Vector3f camera_center; + float camera_view_angle; + float camera_dnear; + float camera_dfar; + + bool depth_test; + + // Animation + bool is_animating; + double animation_max_fps; + + // Caches the two-norm between the min/max point of the bounding box + float object_scale; + + // Viewport size + Eigen::Vector4f viewport; + + // Save the OpenGL transformation matrices used for the previous rendering pass + Eigen::Matrix4f view; + Eigen::Matrix4f proj; + Eigen::Matrix4f norm; + public: + EIGEN_MAKE_ALIGNED_OPERATOR_NEW +}; + +} +} + +#include +namespace igl { + namespace serialization { + + inline void serialization(bool s, igl::opengl::ViewerCore& obj, std::vector& buffer) + { + + SERIALIZE_MEMBER(background_color); + + SERIALIZE_MEMBER(light_position); + SERIALIZE_MEMBER(lighting_factor); + + SERIALIZE_MEMBER(trackball_angle); + SERIALIZE_MEMBER(rotation_type); + + SERIALIZE_MEMBER(camera_base_zoom); + SERIALIZE_MEMBER(camera_zoom); + SERIALIZE_MEMBER(orthographic); + SERIALIZE_MEMBER(camera_base_translation); + SERIALIZE_MEMBER(camera_translation); + SERIALIZE_MEMBER(camera_view_angle); + SERIALIZE_MEMBER(camera_dnear); + SERIALIZE_MEMBER(camera_dfar); + SERIALIZE_MEMBER(camera_eye); + SERIALIZE_MEMBER(camera_center); + SERIALIZE_MEMBER(camera_up); + + SERIALIZE_MEMBER(depth_test); + SERIALIZE_MEMBER(is_animating); + SERIALIZE_MEMBER(animation_max_fps); + + SERIALIZE_MEMBER(object_scale); + + SERIALIZE_MEMBER(viewport); + SERIALIZE_MEMBER(view); + SERIALIZE_MEMBER(proj); + SERIALIZE_MEMBER(norm); + } + + template<> + inline void serialize(const igl::opengl::ViewerCore& obj, std::vector& buffer) + { + serialization(true, const_cast(obj), buffer); + } + + template<> + inline void deserialize(igl::opengl::ViewerCore& obj, const std::vector& buffer) + { + serialization(false, obj, const_cast&>(buffer)); + } + } +} + +#ifndef IGL_STATIC_LIBRARY +# include "ViewerCore.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/opengl/ViewerData.cpp b/src/external/libigl-2.3.0/include/igl/opengl/ViewerData.cpp new file mode 100644 index 000000000..255bb7617 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/opengl/ViewerData.cpp @@ -0,0 +1,910 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Daniele Panozzo +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +#include "ViewerData.h" +#include "ViewerCore.h" + +#include "../per_face_normals.h" +#include "../material_colors.h" +#include "../per_vertex_normals.h" + +// Really? Just for GL_NEAREST? +#include "gl.h" + +#include + + +IGL_INLINE igl::opengl::ViewerData::ViewerData() +: dirty(MeshGL::DIRTY_ALL), + show_faces (~unsigned(0)), + show_lines (~unsigned(0)), + face_based (false), + double_sided (false), + invert_normals (false), + show_overlay (~unsigned(0)), + show_overlay_depth(~unsigned(0)), + show_vertex_labels(0), + show_face_labels (0), + show_custom_labels(0), + show_texture (false), + use_matcap (false), + point_size(30), + line_width(0.5f), + line_color(0,0,0,1), + label_color(0,0,0.04,1), + shininess(35.0f), + id(-1), + is_visible (~unsigned(0)) +{ + clear(); +}; + +IGL_INLINE void igl::opengl::ViewerData::set_face_based(bool newvalue) +{ + if (face_based != newvalue) + { + face_based = newvalue; + dirty = MeshGL::DIRTY_ALL; + } +} + +// Helpers that draws the most common meshes +IGL_INLINE void igl::opengl::ViewerData::set_mesh( + const Eigen::MatrixXd& _V, const Eigen::MatrixXi& _F) +{ + using namespace std; + + Eigen::MatrixXd V_temp; + + // If V only has two columns, pad with a column of zeros + if (_V.cols() == 2) + { + V_temp = Eigen::MatrixXd::Zero(_V.rows(),3); + V_temp.block(0,0,_V.rows(),2) = _V; + } + else + V_temp = _V; + + if (V.rows() == 0 && F.rows() == 0) + { + V = V_temp; + F = _F; + + compute_normals(); + uniform_colors( + Eigen::Vector3d(GOLD_AMBIENT[0], GOLD_AMBIENT[1], GOLD_AMBIENT[2]), + Eigen::Vector3d(GOLD_DIFFUSE[0], GOLD_DIFFUSE[1], GOLD_DIFFUSE[2]), + Eigen::Vector3d(GOLD_SPECULAR[0], GOLD_SPECULAR[1], GOLD_SPECULAR[2])); + + // Generates a checkerboard texture + grid_texture(); + } + else + { + if (_V.rows() == V.rows() && _F.rows() == F.rows()) + { + V = V_temp; + F = _F; + } + else + cerr << "ERROR (set_mesh): The new mesh has a different number of vertices/faces. Please clear the mesh before plotting."<0 && C.cols() == 1) + { + assert(false && "deprecated: call set_data directly instead"); + return set_data(C); + } + // Ambient color should be darker color + const auto ambient = [](const MatrixXd & C)->MatrixXd + { + MatrixXd T = 0.1*C; + T.col(3) = C.col(3); + return T; + }; + // Specular color should be a less saturated and darker color: dampened + // highlights + const auto specular = [](const MatrixXd & C)->MatrixXd + { + const double grey = 0.3; + MatrixXd T = grey+0.1*(C.array()-grey); + T.col(3) = C.col(3); + return T; + }; + if (C.rows() == 1) + { + for (unsigned i=0;i& R, + const Eigen::Matrix& G, + const Eigen::Matrix& B) +{ + texture_R = R; + texture_G = G; + texture_B = B; + texture_A = Eigen::Matrix::Constant(R.rows(),R.cols(),255); + dirty |= MeshGL::DIRTY_TEXTURE; +} + +IGL_INLINE void igl::opengl::ViewerData::set_texture( + const Eigen::Matrix& R, + const Eigen::Matrix& G, + const Eigen::Matrix& B, + const Eigen::Matrix& A) +{ + texture_R = R; + texture_G = G; + texture_B = B; + texture_A = A; + dirty |= MeshGL::DIRTY_TEXTURE; +} + +IGL_INLINE void igl::opengl::ViewerData::set_data( + const Eigen::VectorXd & D, + double caxis_min, + double caxis_max, + igl::ColorMapType cmap, + int num_steps) +{ + if(!show_texture) + { + Eigen::MatrixXd CM; + igl::colormap(cmap,Eigen::VectorXd::LinSpaced(num_steps,0,1).eval(),0,1,CM); + set_colormap(CM); + } + set_uv(((D.array()-caxis_min)/(caxis_max-caxis_min)).replicate(1,2)); +} + +IGL_INLINE void igl::opengl::ViewerData::set_data(const Eigen::VectorXd & D, igl::ColorMapType cmap, int num_steps) +{ + const double caxis_min = D.minCoeff(); + const double caxis_max = D.maxCoeff(); + return set_data(D,caxis_min,caxis_max,cmap,num_steps); +} + +IGL_INLINE void igl::opengl::ViewerData::set_colormap(const Eigen::MatrixXd & CM) +{ + assert(CM.cols() == 3 && "colormap CM should have 3 columns"); + // Convert to R,G,B textures + const Eigen::Matrix R = + (CM.col(0)*255.0).cast(); + const Eigen::Matrix G = + (CM.col(1)*255.0).cast(); + const Eigen::Matrix B = + (CM.col(2)*255.0).cast(); + set_colors(Eigen::RowVector3d(1,1,1)); + set_texture(R,G,B); + show_texture = ~unsigned(0); + meshgl.tex_filter = GL_NEAREST; + meshgl.tex_wrap = GL_CLAMP_TO_EDGE; +} + +IGL_INLINE void igl::opengl::ViewerData::set_points( + const Eigen::MatrixXd& P, + const Eigen::MatrixXd& C) +{ + // clear existing points + points.resize(0,0); + add_points(P,C); +} + +IGL_INLINE void igl::opengl::ViewerData::add_points(const Eigen::MatrixXd& P, const Eigen::MatrixXd& C) +{ + Eigen::MatrixXd P_temp; + + // If P only has two columns, pad with a column of zeros + if (P.cols() == 2) + { + P_temp = Eigen::MatrixXd::Zero(P.rows(),3); + P_temp.block(0,0,P.rows(),2) = P; + } + else + P_temp = P; + + int lastid = points.rows(); + points.conservativeResize(points.rows() + P_temp.rows(),6); + for (unsigned i=0; i(); + set_edges(PV,E, C.rows() == 1?C:C.replicate<2,1>()); +} + +IGL_INLINE void igl::opengl::ViewerData::add_edges(const Eigen::MatrixXd& P1, const Eigen::MatrixXd& P2, const Eigen::MatrixXd& C) +{ + Eigen::MatrixXd P1_temp,P2_temp; + + // If P1 only has two columns, pad with a column of zeros + if (P1.cols() == 2) + { + P1_temp = Eigen::MatrixXd::Zero(P1.rows(),3); + P1_temp.block(0,0,P1.rows(),2) = P1; + P2_temp = Eigen::MatrixXd::Zero(P2.rows(),3); + P2_temp.block(0,0,P2.rows(),2) = P2; + } + else + { + P1_temp = P1; + P2_temp = P2; + } + + int lastid = lines.rows(); + lines.conservativeResize(lines.rows() + P1_temp.rows(),9); + for (unsigned i=0; i& str) +{ + assert(P.rows() == str.size() && "position # and label # do not match!"); + assert(P.cols() == 3 && "dimension of label positions incorrect!"); + labels_positions = P; + labels_strings = str; +} + +IGL_INLINE void igl::opengl::ViewerData::clear_labels() +{ + labels_positions.resize(0,3); + labels_strings.clear(); +} + +IGL_INLINE void igl::opengl::ViewerData::clear() +{ + V = Eigen::MatrixXd (0,3); + F = Eigen::MatrixXi (0,3); + + F_material_ambient = Eigen::MatrixXd (0,4); + F_material_diffuse = Eigen::MatrixXd (0,4); + F_material_specular = Eigen::MatrixXd (0,4); + + V_material_ambient = Eigen::MatrixXd (0,4); + V_material_diffuse = Eigen::MatrixXd (0,4); + V_material_specular = Eigen::MatrixXd (0,4); + + F_normals = Eigen::MatrixXd (0,3); + V_normals = Eigen::MatrixXd (0,3); + + V_uv = Eigen::MatrixXd (0,2); + F_uv = Eigen::MatrixXi (0,3); + + lines = Eigen::MatrixXd (0,9); + points = Eigen::MatrixXd (0,6); + + vertex_labels_positions = Eigen::MatrixXd (0,3); + face_labels_positions = Eigen::MatrixXd (0,3); + labels_positions = Eigen::MatrixXd (0,3); + vertex_labels_strings.clear(); + face_labels_strings.clear(); + labels_strings.clear(); + + face_based = false; + double_sided = false; + invert_normals = false; + show_texture = false; + use_matcap = false; +} + +IGL_INLINE void igl::opengl::ViewerData::compute_normals() +{ + if(V.cols() == 2) + { + F_normals = Eigen::RowVector3d(0,0,1).replicate(F.rows(),1); + V_normals = Eigen::RowVector3d(0,0,1).replicate(V.rows(),1); + }else + { + assert(V.cols() == 3); + igl::per_face_normals(V, F, F_normals); + igl::per_vertex_normals(V, F, F_normals, V_normals); + } + dirty |= MeshGL::DIRTY_NORMAL; +} + +IGL_INLINE void igl::opengl::ViewerData::uniform_colors( + const Eigen::Vector3d& ambient, + const Eigen::Vector3d& diffuse, + const Eigen::Vector3d& specular) +{ + Eigen::Vector4d ambient4; + Eigen::Vector4d diffuse4; + Eigen::Vector4d specular4; + + ambient4 << ambient, 1; + diffuse4 << diffuse, 1; + specular4 << specular, 1; + + uniform_colors(ambient4,diffuse4,specular4); +} + +IGL_INLINE void igl::opengl::ViewerData::uniform_colors( + const Eigen::Vector4d& ambient, + const Eigen::Vector4d& diffuse, + const Eigen::Vector4d& specular) +{ + V_material_ambient.resize(V.rows(),4); + V_material_diffuse.resize(V.rows(),4); + V_material_specular.resize(V.rows(),4); + + for (unsigned i=0; i=size2 && j>=size2)) + texture_R(i,j) = 255; + } + } + + texture_G = texture_R; + texture_B = texture_R; + texture_A = Eigen::Matrix::Constant(texture_R.rows(),texture_R.cols(),255); + dirty |= MeshGL::DIRTY_TEXTURE; +} + +// Populate VBOs of a particular label stype (Vert, Face, Custom) +IGL_INLINE void igl::opengl::ViewerData::update_labels( + igl::opengl::MeshGL& meshgl, + igl::opengl::MeshGL::TextGL& GL_labels, + const Eigen::MatrixXd& positions, + const std::vector& strings +){ + if (positions.rows()>0) + { + int numCharsToRender = 0; + for(size_t p=0; p(); + GL_labels.label_char_vbo(idx) = (float)(label.at(c)); + GL_labels.label_offset_vbo(idx) = c; + GL_labels.label_indices_vbo(idx) = idx; + idx++; + } + } + } +} + +IGL_INLINE void igl::opengl::ViewerData::updateGL( + const igl::opengl::ViewerData& data, + const bool invert_normals, + igl::opengl::MeshGL& meshgl + ) +{ + if (!meshgl.is_initialized) + { + meshgl.init(); + } + + bool per_corner_uv = (data.F_uv.rows() == data.F.rows()); + bool per_corner_normals = (data.F_normals.rows() == 3 * data.F.rows()); + + meshgl.dirty |= data.dirty; + + // Input: + // X #F by dim quantity + // Output: + // X_vbo #F*3 by dim scattering per corner + const auto per_face = [&data]( + const Eigen::MatrixXd & X, + MeshGL::RowMatrixXf & X_vbo) + { + assert(X.cols() == 4); + X_vbo.resize(data.F.rows()*3,4); + for (unsigned i=0; i(); + }; + + // Input: + // X #V by dim quantity + // Output: + // X_vbo #F*3 by dim scattering per corner + const auto per_corner = [&data]( + const Eigen::MatrixXd & X, + MeshGL::RowMatrixXf & X_vbo) + { + X_vbo.resize(data.F.rows()*3,X.cols()); + for (unsigned i=0; i(); + }; + + if (!data.face_based) + { + if (!(per_corner_uv || per_corner_normals)) + { + // Vertex positions + if (meshgl.dirty & MeshGL::DIRTY_POSITION) + meshgl.V_vbo = data.V.cast(); + + // Vertex normals + if (meshgl.dirty & MeshGL::DIRTY_NORMAL) + { + meshgl.V_normals_vbo = data.V_normals.cast(); + if (invert_normals) + meshgl.V_normals_vbo = -meshgl.V_normals_vbo; + } + + // Per-vertex material settings + if (meshgl.dirty & MeshGL::DIRTY_AMBIENT) + meshgl.V_ambient_vbo = data.V_material_ambient.cast(); + if (meshgl.dirty & MeshGL::DIRTY_DIFFUSE) + meshgl.V_diffuse_vbo = data.V_material_diffuse.cast(); + if (meshgl.dirty & MeshGL::DIRTY_SPECULAR) + meshgl.V_specular_vbo = data.V_material_specular.cast(); + + // Face indices + if (meshgl.dirty & MeshGL::DIRTY_FACE) + meshgl.F_vbo = data.F.cast(); + + // Texture coordinates + if (meshgl.dirty & MeshGL::DIRTY_UV) + { + meshgl.V_uv_vbo = data.V_uv.cast(); + } + } + else + { + + // Per vertex properties with per corner UVs + if (meshgl.dirty & MeshGL::DIRTY_POSITION) + { + per_corner(data.V,meshgl.V_vbo); + } + + if (meshgl.dirty & MeshGL::DIRTY_AMBIENT) + { + meshgl.V_ambient_vbo.resize(data.F.rows()*3,4); + per_corner(data.V_material_ambient,meshgl.V_ambient_vbo); + } + if (meshgl.dirty & MeshGL::DIRTY_DIFFUSE) + { + meshgl.V_diffuse_vbo.resize(data.F.rows()*3,4); + per_corner(data.V_material_diffuse,meshgl.V_diffuse_vbo); + } + if (meshgl.dirty & MeshGL::DIRTY_SPECULAR) + { + meshgl.V_specular_vbo.resize(data.F.rows()*3,4); + per_corner(data.V_material_specular,meshgl.V_specular_vbo); + } + + if (meshgl.dirty & MeshGL::DIRTY_NORMAL) + { + meshgl.V_normals_vbo.resize(data.F.rows()*3,3); + per_corner(data.V_normals,meshgl.V_normals_vbo); + + if (invert_normals) + meshgl.V_normals_vbo = -meshgl.V_normals_vbo; + } + + if (meshgl.dirty & MeshGL::DIRTY_FACE) + { + meshgl.F_vbo.resize(data.F.rows(),3); + for (unsigned i=0; i0) + { + meshgl.V_uv_vbo.resize(data.F.rows()*3,2); + for (unsigned i=0; i(); + } + } + } else + { + if (meshgl.dirty & MeshGL::DIRTY_POSITION) + { + per_corner(data.V,meshgl.V_vbo); + } + if (meshgl.dirty & MeshGL::DIRTY_AMBIENT) + { + per_face(data.F_material_ambient,meshgl.V_ambient_vbo); + } + if (meshgl.dirty & MeshGL::DIRTY_DIFFUSE) + { + per_face(data.F_material_diffuse,meshgl.V_diffuse_vbo); + } + if (meshgl.dirty & MeshGL::DIRTY_SPECULAR) + { + per_face(data.F_material_specular,meshgl.V_specular_vbo); + } + + if (meshgl.dirty & MeshGL::DIRTY_NORMAL) + { + meshgl.V_normals_vbo.resize(data.F.rows()*3,3); + for (unsigned i=0; i() : + data.F_normals.row(i).cast(); + + if (invert_normals) + meshgl.V_normals_vbo = -meshgl.V_normals_vbo; + } + + if (meshgl.dirty & MeshGL::DIRTY_FACE) + { + meshgl.F_vbo.resize(data.F.rows(),3); + for (unsigned i=0; i0) + { + meshgl.V_uv_vbo.resize(data.F.rows()*3,2); + for (unsigned i=0; i(); + } + } + + if (meshgl.dirty & MeshGL::DIRTY_TEXTURE) + { + meshgl.tex_u = data.texture_R.rows(); + meshgl.tex_v = data.texture_R.cols(); + meshgl.tex.resize(data.texture_R.size()*4); + for (unsigned i=0;i(i, 0).cast(); + meshgl.lines_V_vbo.row(2*i+1) = data.lines.block<1, 3>(i, 3).cast(); + meshgl.lines_V_colors_vbo.row(2*i+0) = data.lines.block<1, 3>(i, 6).cast(); + meshgl.lines_V_colors_vbo.row(2*i+1) = data.lines.block<1, 3>(i, 6).cast(); + meshgl.lines_F_vbo(2*i+0) = 2*i+0; + meshgl.lines_F_vbo(2*i+1) = 2*i+1; + } + } + + if (meshgl.dirty & MeshGL::DIRTY_OVERLAY_POINTS) + { + meshgl.points_V_vbo.resize(data.points.rows(),3); + meshgl.points_V_colors_vbo.resize(data.points.rows(),3); + meshgl.points_F_vbo.resize(data.points.rows(),1); + for (unsigned i=0; i(i, 0).cast(); + meshgl.points_V_colors_vbo.row(i) = data.points.block<1, 3>(i, 3).cast(); + meshgl.points_F_vbo(i) = i; + } + } + + if (meshgl.dirty & MeshGL::DIRTY_FACE_LABELS) + { + if(face_labels_positions.rows()==0) + { + face_labels_positions.conservativeResize(F.rows(), 3); + Eigen::MatrixXd faceNormals = F_normals.normalized(); + for (int f=0; f +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_VIEWERDATA_H +#define IGL_VIEWERDATA_H + +#include "MeshGL.h" +#include +#include +#include +#include +#include +#include +#include + +// Alec: This is a mesh class containing a variety of data types (normals, +// overlays, material colors, etc.) +// +// WARNING: Eigen data members (such as Eigen::Vector4f) should explicitly +// disable alignment (e.g. use `Eigen::Matrix`), +// in order to avoid alignment issues further down the line (esp. if the +// structure are stored in a std::vector). +// +// See this thread for a more detailed discussion: +// https://github.com/libigl/libigl/pull/1029 +// +namespace igl +{ + +// TODO: write documentation +namespace opengl +{ + +// Forward declaration +class ViewerCore; + +class ViewerData +{ +public: + ViewerData(); + + // Empty all fields + IGL_INLINE void clear(); + + // Change the visualization mode, invalidating the cache if necessary + IGL_INLINE void set_face_based(bool newvalue); + + // Helpers that can draw the most common meshes + IGL_INLINE void set_mesh(const Eigen::MatrixXd& V, const Eigen::MatrixXi& F); + IGL_INLINE void set_vertices(const Eigen::MatrixXd& V); + IGL_INLINE void set_normals(const Eigen::MatrixXd& N); + + IGL_INLINE void set_visible(bool value, unsigned int core_id = 1); + + // Set the color of the mesh + // + // Inputs: + // C #V|#F|1 by 3 list of colors + IGL_INLINE void set_colors(const Eigen::MatrixXd &C); + + // Set per-vertex UV coordinates + // + // Inputs: + // UV #V by 2 list of UV coordinates (indexed by F) + IGL_INLINE void set_uv(const Eigen::MatrixXd& UV); + + // Set per-corner UV coordinates + // + // Inputs: + // UV_V #UV by 2 list of UV coordinates + // UV_F #F by 3 list of UV indices into UV_V + IGL_INLINE void set_uv(const Eigen::MatrixXd& UV_V, const Eigen::MatrixXi& UV_F); + + // Set the texture associated with the mesh. + // + // Inputs: + // R width by height image matrix of red channel + // G width by height image matrix of green channel + // B width by height image matrix of blue channel + // + IGL_INLINE void set_texture( + const Eigen::Matrix& R, + const Eigen::Matrix& G, + const Eigen::Matrix& B); + + // Set the texture associated with the mesh. + // + // Inputs: + // R width by height image matrix of red channel + // G width by height image matrix of green channel + // B width by height image matrix of blue channel + // A width by height image matrix of alpha channel + // + IGL_INLINE void set_texture( + const Eigen::Matrix& R, + const Eigen::Matrix& G, + const Eigen::Matrix& B, + const Eigen::Matrix& A); + + // Set pseudo-colorable scalar data associated with the mesh. + // + // Inputs: + // caxis_min caxis minimum bound + // caxis_max caxis maximum bound + // D #V by 1 list of scalar values + // cmap colormap type + // num_steps number of intervals to discretize the colormap + // + // To-do: support #F by 1 per-face data + IGL_INLINE void set_data( + const Eigen::VectorXd & D, + double caxis_min, + double caxis_max, + igl::ColorMapType cmap = igl::COLOR_MAP_TYPE_VIRIDIS, + int num_steps = 21); + + // Use min(D) and max(D) to set caxis. + IGL_INLINE void set_data(const Eigen::VectorXd & D, + igl::ColorMapType cmap = igl::COLOR_MAP_TYPE_VIRIDIS, + int num_steps = 21); + + // Not to be confused with set_colors, this creates a _texture_ that will be + // referenced to pseudocolor according to the scalar field passed to set_data. + // + // Inputs: + // CM #CM by 3 list of colors + IGL_INLINE void set_colormap(const Eigen::MatrixXd & CM); + + // Sets points given a list of point vertices. In constrast to `add_points` + // this will (purposefully) clober existing points. + // + // Inputs: + // P #P by 3 list of vertex positions + // C #P|1 by 3 color(s) + IGL_INLINE void set_points( + const Eigen::MatrixXd& P, + const Eigen::MatrixXd& C); + IGL_INLINE void add_points(const Eigen::MatrixXd& P, const Eigen::MatrixXd& C); + + // Clear the point data + IGL_INLINE void clear_points(); + + // Sets edges given a list of edge vertices and edge indices. In constrast + // to `add_edges` this will (purposefully) clober existing edges. + // + // Inputs: + // P #P by 3 list of vertex positions + // E #E by 2 list of edge indices into P + // C #E|1 by 3 color(s) + + IGL_INLINE void set_edges (const Eigen::MatrixXd& P, const Eigen::MatrixXi& E, const Eigen::MatrixXd& C); + // Alec: This is very confusing. Why does add_edges have a different API from + // set_edges? + IGL_INLINE void add_edges (const Eigen::MatrixXd& P1, const Eigen::MatrixXd& P2, const Eigen::MatrixXd& C); + // Sets edges given a list of points and eminating vectors + IGL_INLINE void set_edges_from_vector_field( + const Eigen::MatrixXd& P, + const Eigen::MatrixXd& V, + const Eigen::MatrixXd& C); + + // Clear the edge data + IGL_INLINE void clear_edges(); + + // Sets / Adds text labels at the given positions in 3D. + // Note: This requires the ImGui viewer plugin to display text labels. + IGL_INLINE void add_label (const Eigen::VectorXd& P, const std::string& str); + IGL_INLINE void set_labels (const Eigen::MatrixXd& P, const std::vector& str); + + // Clear the label data + IGL_INLINE void clear_labels (); + + // Computes the normals of the mesh + IGL_INLINE void compute_normals(); + + // Assigns uniform colors to all faces/vertices + IGL_INLINE void uniform_colors( + const Eigen::Vector3d& diffuse, + const Eigen::Vector3d& ambient, + const Eigen::Vector3d& specular); + + // Assigns uniform colors to all faces/vertices + IGL_INLINE void uniform_colors( + const Eigen::Vector4d& ambient, + const Eigen::Vector4d& diffuse, + const Eigen::Vector4d& specular); + + // Generate a normal image matcap + IGL_INLINE void normal_matcap(); + + // Generates a default grid texture (without uvs) + IGL_INLINE void grid_texture(); + + // Copy visualization options from one viewport to another + IGL_INLINE void copy_options(const ViewerCore &from, const ViewerCore &to); + + Eigen::MatrixXd V; // Vertices of the current mesh (#V x 3) + Eigen::MatrixXi F; // Faces of the mesh (#F x 3) + + // Per face attributes + Eigen::MatrixXd F_normals; // One normal per face + + Eigen::MatrixXd F_material_ambient; // Per face ambient color + Eigen::MatrixXd F_material_diffuse; // Per face diffuse color + Eigen::MatrixXd F_material_specular; // Per face specular color + + // Per vertex attributes + Eigen::MatrixXd V_normals; // One normal per vertex + + Eigen::MatrixXd V_material_ambient; // Per vertex ambient color + Eigen::MatrixXd V_material_diffuse; // Per vertex diffuse color + Eigen::MatrixXd V_material_specular; // Per vertex specular color + + // UV parametrization + Eigen::MatrixXd V_uv; // UV vertices + Eigen::MatrixXi F_uv; // optional faces for UVs + + // Texture + Eigen::Matrix texture_R; + Eigen::Matrix texture_G; + Eigen::Matrix texture_B; + Eigen::Matrix texture_A; + + // Overlays + + // Lines plotted over the scene + // (Every row contains 9 doubles in the following format S_x, S_y, S_z, T_x, T_y, T_z, C_r, C_g, C_b), + // with S and T the coordinates of the two vertices of the line in global coordinates, and C the color in floating point rgb format + Eigen::MatrixXd lines; + + // Points plotted over the scene + // (Every row contains 6 doubles in the following format P_x, P_y, P_z, C_r, C_g, C_b), + // with P the position in global coordinates of the center of the point, and C the color in floating point rgb format + Eigen::MatrixXd points; + + // Text labels plotted over the scene + // Textp contains, in the i-th row, the position in global coordinates where the i-th label should be anchored + // Texts contains in the i-th position the text of the i-th label + Eigen::MatrixXd vertex_labels_positions; + Eigen::MatrixXd face_labels_positions; + Eigen::MatrixXd labels_positions; + std::vector vertex_labels_strings; + std::vector face_labels_strings; + std::vector labels_strings; + + // Marks dirty buffers that need to be uploaded to OpenGL + uint32_t dirty; + + // Enable per-face or per-vertex properties + bool face_based; + + // Enable double-sided lighting on faces + bool double_sided; + + // Invert mesh normals + bool invert_normals; + + // Visualization options + // Each option is a binary mask specifying on which viewport each option is set. + // When using a single viewport, standard boolean can still be used for simplicity. + unsigned int is_visible; + unsigned int show_overlay; + unsigned int show_overlay_depth; + unsigned int show_texture; + unsigned int use_matcap; + unsigned int show_faces; + unsigned int show_lines; + unsigned int show_vertex_labels; + unsigned int show_face_labels; + unsigned int show_custom_labels; + + // Point size / line width + float point_size; + // line_width is NOT SUPPORTED on Mac OS and Windows + float line_width; + Eigen::Matrix line_color; + Eigen::Matrix label_color; + + // Shape material + float shininess; + + // Unique identifier + int id; + + // OpenGL representation of the mesh + igl::opengl::MeshGL meshgl; + + // Update contents from a 'Data' instance + IGL_INLINE void update_labels( + igl::opengl::MeshGL& meshgl, + igl::opengl::MeshGL::TextGL& GL_labels, + const Eigen::MatrixXd& positions, + const std::vector& strings + ); + IGL_INLINE void updateGL( + const igl::opengl::ViewerData& data, + const bool invert_normals, + igl::opengl::MeshGL& meshgl); + }; + +} // namespace opengl +} // namespace igl + +//////////////////////////////////////////////////////////////////////////////// + +#include +namespace igl +{ + namespace serialization + { + inline void serialization(bool s, igl::opengl::ViewerData& obj, std::vector& buffer) + { + SERIALIZE_MEMBER(V); + SERIALIZE_MEMBER(F); + SERIALIZE_MEMBER(F_normals); + SERIALIZE_MEMBER(F_material_ambient); + SERIALIZE_MEMBER(F_material_diffuse); + SERIALIZE_MEMBER(F_material_specular); + SERIALIZE_MEMBER(V_normals); + SERIALIZE_MEMBER(V_material_ambient); + SERIALIZE_MEMBER(V_material_diffuse); + SERIALIZE_MEMBER(V_material_specular); + SERIALIZE_MEMBER(V_uv); + SERIALIZE_MEMBER(F_uv); + SERIALIZE_MEMBER(texture_R); + SERIALIZE_MEMBER(texture_G); + SERIALIZE_MEMBER(texture_B); + SERIALIZE_MEMBER(texture_A); + SERIALIZE_MEMBER(lines); + SERIALIZE_MEMBER(points); + SERIALIZE_MEMBER(labels_positions); + SERIALIZE_MEMBER(labels_strings); + SERIALIZE_MEMBER(dirty); + SERIALIZE_MEMBER(face_based); + SERIALIZE_MEMBER(show_faces); + SERIALIZE_MEMBER(show_lines); + SERIALIZE_MEMBER(invert_normals); + SERIALIZE_MEMBER(show_overlay); + SERIALIZE_MEMBER(show_overlay_depth); + SERIALIZE_MEMBER(show_vertex_labels); + SERIALIZE_MEMBER(show_face_labels); + SERIALIZE_MEMBER(show_custom_labels); + SERIALIZE_MEMBER(show_texture); + SERIALIZE_MEMBER(double_sided); + SERIALIZE_MEMBER(point_size); + SERIALIZE_MEMBER(line_width); + SERIALIZE_MEMBER(line_color); + SERIALIZE_MEMBER(shininess); + SERIALIZE_MEMBER(id); + } + template<> + inline void serialize(const igl::opengl::ViewerData& obj, std::vector& buffer) + { + serialization(true, const_cast(obj), buffer); + } + template<> + inline void deserialize(igl::opengl::ViewerData& obj, const std::vector& buffer) + { + serialization(false, obj, const_cast&>(buffer)); + obj.dirty = igl::opengl::MeshGL::DIRTY_ALL; + } + } +} + +#ifndef IGL_STATIC_LIBRARY +# include "ViewerData.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/opengl/bind_vertex_attrib_array.cpp b/src/external/libigl-2.3.0/include/igl/opengl/bind_vertex_attrib_array.cpp new file mode 100644 index 000000000..4aa807c18 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/opengl/bind_vertex_attrib_array.cpp @@ -0,0 +1,24 @@ +#include "bind_vertex_attrib_array.h" + +IGL_INLINE GLint igl::opengl::bind_vertex_attrib_array( + const GLuint program_shader, + const std::string &name, + GLuint bufferID, + const Eigen::Matrix &M, + bool refresh) +{ + GLint id = glGetAttribLocation(program_shader, name.c_str()); + if (id < 0) + return id; + if (M.size() == 0) + { + glDisableVertexAttribArray(id); + return id; + } + glBindBuffer(GL_ARRAY_BUFFER, bufferID); + if (refresh) + glBufferData(GL_ARRAY_BUFFER, sizeof(float)*M.size(), M.data(), GL_DYNAMIC_DRAW); + glVertexAttribPointer(id, M.cols(), GL_FLOAT, GL_FALSE, 0, 0); + glEnableVertexAttribArray(id); + return id; +} diff --git a/src/external/libigl-2.3.0/include/igl/opengl/bind_vertex_attrib_array.h b/src/external/libigl-2.3.0/include/igl/opengl/bind_vertex_attrib_array.h new file mode 100644 index 000000000..4e9443136 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/opengl/bind_vertex_attrib_array.h @@ -0,0 +1,32 @@ +#ifndef IGL_OPENGL_BIND_VERTEX_ATTRIB_ARRAY_H +#define IGL_OPENGL_BIND_VERTEX_ATTRIB_ARRAY_H +#include "gl.h" +#include "../igl_inline.h" +#include +#include +namespace igl +{ + namespace opengl + { + // Bind a per-vertex array attribute and refresh its contents from an Eigen + // matrix + // + // Inputs: + // program_shader id of shader program + // name name of attribute in vertex shader + // bufferID id of buffer to bind to + // M #V by dim matrix of per-vertex data + // refresh whether to actually call glBufferData or just bind the buffer + // Returns id of named attribute in shader + IGL_INLINE GLint bind_vertex_attrib_array( + const GLuint program_shader, + const std::string &name, + GLuint bufferID, + const Eigen::Matrix &M, + bool refresh); + } +} +#ifndef IGL_STATIC_LIBRARY +#include "bind_vertex_attrib_array.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/opengl/create_index_vbo.cpp b/src/external/libigl-2.3.0/include/igl/opengl/create_index_vbo.cpp new file mode 100644 index 000000000..76f6248c0 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/opengl/create_index_vbo.cpp @@ -0,0 +1,46 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "create_index_vbo.h" + +// http://www.songho.ca/opengl/gl_vbo.html#create +IGL_INLINE void igl::opengl::create_index_vbo( + const Eigen::MatrixXi & F, + GLuint & F_vbo_id) +{ + // Generate Buffers + glGenBuffers(1,&F_vbo_id); + // Bind Buffers + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,F_vbo_id); + // Copy data to buffers + // We expect a matrix with each vertex position on a row, we then want to + // pass this data to OpenGL reading across rows (row-major) + if(F.Options & Eigen::RowMajor) + { + glBufferData( + GL_ELEMENT_ARRAY_BUFFER, + sizeof(int)*F.size(), + F.data(), + GL_STATIC_DRAW); + }else + { + // Create temporary copy of transpose + Eigen::MatrixXi FT = F.transpose(); + // If its column major then we need to temporarily store a transpose + glBufferData( + GL_ELEMENT_ARRAY_BUFFER, + sizeof(int)*F.size(), + FT.data(), + GL_STATIC_DRAW); + } + // bind with 0, so, switch back to normal pointer operation + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +#endif diff --git a/src/external/libigl-2.3.0/include/igl/opengl/create_index_vbo.h b/src/external/libigl-2.3.0/include/igl/opengl/create_index_vbo.h new file mode 100644 index 000000000..e48f3a489 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/opengl/create_index_vbo.h @@ -0,0 +1,35 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_OPENGL_CREATE_INDEX_VBO_H +#define IGL_OPENGL_CREATE_INDEX_VBO_H +#include "../igl_inline.h" +#include "gl.h" +#include + +// Create a VBO (Vertex Buffer Object) for a list of indices: +// GL_ELEMENT_ARRAY_BUFFER_ARB for the triangle indices (F) +namespace igl +{ + namespace opengl + { + // Inputs: + // F #F by 3 eigen Matrix of face (triangle) indices + // Outputs: + // F_vbo_id buffer id for face indices + // + IGL_INLINE void create_index_vbo( + const Eigen::MatrixXi & F, + GLuint & F_vbo_id); + } +} + +#ifndef IGL_STATIC_LIBRARY +# include "create_index_vbo.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/opengl/create_mesh_vbo.cpp b/src/external/libigl-2.3.0/include/igl/opengl/create_mesh_vbo.cpp new file mode 100644 index 000000000..3876e1dfa --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/opengl/create_mesh_vbo.cpp @@ -0,0 +1,43 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "create_mesh_vbo.h" + +#include "create_vector_vbo.h" +#include "create_index_vbo.h" + +// http://www.songho.ca/opengl/gl_vbo.html#create +IGL_INLINE void igl::opengl::create_mesh_vbo( + const Eigen::MatrixXd & V, + const Eigen::MatrixXi & F, + GLuint & V_vbo_id, + GLuint & F_vbo_id) +{ + // Create VBO for vertex position vectors + create_vector_vbo(V,V_vbo_id); + // Create VBO for face index lists + create_index_vbo(F,F_vbo_id); +} + +// http://www.songho.ca/opengl/gl_vbo.html#create +IGL_INLINE void igl::opengl::create_mesh_vbo( + const Eigen::MatrixXd & V, + const Eigen::MatrixXi & F, + const Eigen::MatrixXd & N, + GLuint & V_vbo_id, + GLuint & F_vbo_id, + GLuint & N_vbo_id) +{ + // Create VBOs for faces and vertices + create_mesh_vbo(V,F,V_vbo_id,F_vbo_id); + // Create VBO for normal vectors + create_vector_vbo(N,N_vbo_id); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +#endif diff --git a/src/external/libigl-2.3.0/include/igl/opengl/create_mesh_vbo.h b/src/external/libigl-2.3.0/include/igl/opengl/create_mesh_vbo.h new file mode 100644 index 000000000..ecb303b09 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/opengl/create_mesh_vbo.h @@ -0,0 +1,61 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_OPENGL_CREATE_MESH_VBO_H +#define IGL_OPENGL_CREATE_MESH_VBO_H +#include "../igl_inline.h" +#include "gl.h" +#include + +// Create a VBO (Vertex Buffer Object) for a mesh. Actually two VBOs: one +// GL_ARRAY_BUFFER for the vertex positions (V) and one +// GL_ELEMENT_ARRAY_BUFFER for the triangle indices (F) +namespace igl +{ + namespace opengl + { + + // Inputs: + // V #V by 3 eigen Matrix of mesh vertex 3D positions + // F #F by 3 eigen Matrix of face (triangle) indices + // Outputs: + // V_vbo_id buffer id for vertex positions + // F_vbo_id buffer id for face indices + // + // NOTE: when using glDrawElements VBOs for V and F using MatrixXd and + // MatrixXi will have types GL_DOUBLE and GL_UNSIGNED_INT respectively + // + IGL_INLINE void create_mesh_vbo( + const Eigen::MatrixXd & V, + const Eigen::MatrixXi & F, + GLuint & V_vbo_id, + GLuint & F_vbo_id); + + // Inputs: + // V #V by 3 eigen Matrix of mesh vertex 3D positions + // F #F by 3 eigen Matrix of face (triangle) indices + // N #V by 3 eigen Matrix of mesh vertex 3D normals + // Outputs: + // V_vbo_id buffer id for vertex positions + // F_vbo_id buffer id for face indices + // N_vbo_id buffer id for vertex positions + IGL_INLINE void create_mesh_vbo( + const Eigen::MatrixXd & V, + const Eigen::MatrixXi & F, + const Eigen::MatrixXd & N, + GLuint & V_vbo_id, + GLuint & F_vbo_id, + GLuint & N_vbo_id); + } + +} + +#ifndef IGL_STATIC_LIBRARY +# include "create_mesh_vbo.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/opengl/create_shader_program.cpp b/src/external/libigl-2.3.0/include/igl/opengl/create_shader_program.cpp new file mode 100644 index 000000000..6c4b31a2f --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/opengl/create_shader_program.cpp @@ -0,0 +1,141 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "create_shader_program.h" + +#include "load_shader.h" +#include "print_program_info_log.h" +#include +#include + +IGL_INLINE bool igl::opengl::create_shader_program( + const std::string & geom_source, + const std::string & vert_source, + const std::string & frag_source, + const std::map & attrib, + GLuint & id) +{ + using namespace std; + if(vert_source == "" && frag_source == "") + { + cerr<< + "create_shader_program() could not create shader program," + " both .vert and .frag source given were empty"<::const_iterator ait = attrib.begin(); + ait != attrib.end(); + ait++) + { + glBindAttribLocation( + id, + (*ait).second, + (*ait).first.c_str()); + } + // Link program + glLinkProgram(id); + const auto & detach = [&id](const GLuint shader) + { + if(shader) + { + glDetachShader(id,shader); + glDeleteShader(shader); + } + }; + detach(g); + detach(f); + detach(v); + + // print log if any + igl::opengl::print_program_info_log(id); + + return true; +} + +IGL_INLINE bool igl::opengl::create_shader_program( + const std::string & vert_source, + const std::string & frag_source, + const std::map & attrib, + GLuint & prog_id) +{ + return create_shader_program("",vert_source,frag_source,attrib,prog_id); +} + + +IGL_INLINE GLuint igl::opengl::create_shader_program( + const std::string & geom_source, + const std::string & vert_source, + const std::string & frag_source, + const std::map & attrib) +{ + GLuint prog_id = 0; + create_shader_program(geom_source,vert_source,frag_source,attrib,prog_id); + return prog_id; +} + +IGL_INLINE GLuint igl::opengl::create_shader_program( + const std::string & vert_source, + const std::string & frag_source, + const std::map & attrib) +{ + GLuint prog_id = 0; + create_shader_program(vert_source,frag_source,attrib,prog_id); + return prog_id; +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/opengl/create_shader_program.h b/src/external/libigl-2.3.0/include/igl/opengl/create_shader_program.h new file mode 100644 index 000000000..5dfdc701d --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/opengl/create_shader_program.h @@ -0,0 +1,64 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_OPENGL_CREATE_SHADER_PROGRAM_H +#define IGL_OPENGL_CREATE_SHADER_PROGRAM_H +#include "../igl_inline.h" +#include "gl.h" +#include +#include + +namespace igl +{ + namespace opengl + { + // Create a shader program with a vertex and fragments shader loading from + // source strings and vertex attributes assigned from a map before linking the + // shaders to the program, making it ready to use with glUseProgram(id) + // Inputs: + // geom_source string containing source code of geometry shader (can be + // "" to mean use default pass-through) + // vert_source string containing source code of vertex shader + // frag_source string containing source code of fragment shader + // attrib map containing table of vertex attribute strings add their + // correspondingly ids (generated previously using glBindAttribLocation) + // Outputs: + // id index id of created shader, set to 0 on error + // Returns true on success, false on error + // + // Note: Caller is responsible for making sure that current value of id is not + // leaking a shader (since it will be overwritten) + // + // See also: destroy_shader_program + IGL_INLINE bool create_shader_program( + const std::string &geom_source, + const std::string &vert_source, + const std::string &frag_source, + const std::map &attrib, + GLuint & id); + IGL_INLINE bool create_shader_program( + const std::string &vert_source, + const std::string &frag_source, + const std::map &attrib, + GLuint & id); + IGL_INLINE GLuint create_shader_program( + const std::string & geom_source, + const std::string & vert_source, + const std::string & frag_source, + const std::map &attrib); + IGL_INLINE GLuint create_shader_program( + const std::string & vert_source, + const std::string & frag_source, + const std::map &attrib); + } +} + +#ifndef IGL_STATIC_LIBRARY +# include "create_shader_program.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/opengl/create_vector_vbo.cpp b/src/external/libigl-2.3.0/include/igl/opengl/create_vector_vbo.cpp new file mode 100644 index 000000000..8690359b7 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/opengl/create_vector_vbo.cpp @@ -0,0 +1,57 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "create_vector_vbo.h" + +#include + +// http://www.songho.ca/opengl/gl_vbo.html#create +template +IGL_INLINE void igl::opengl::create_vector_vbo( + const Eigen::Matrix & V, + GLuint & V_vbo_id) +{ + //// Expects that input is list of 3D vectors along rows + //assert(V.cols() == 3); + + // Generate Buffers + glGenBuffers(1,&V_vbo_id); + // Bind Buffers + glBindBuffer(GL_ARRAY_BUFFER,V_vbo_id); + // Copy data to buffers + // We expect a matrix with each vertex position on a row, we then want to + // pass this data to OpenGL reading across rows (row-major) + if(V.Options & Eigen::RowMajor) + { + glBufferData( + GL_ARRAY_BUFFER, + sizeof(T)*V.size(), + V.data(), + GL_STATIC_DRAW); + }else + { + // Create temporary copy of transpose + Eigen::Matrix VT = V.transpose(); + // If its column major then we need to temporarily store a transpose + glBufferData( + GL_ARRAY_BUFFER, + sizeof(T)*V.size(), + VT.data(), + GL_STATIC_DRAW); + } + // bind with 0, so, switch back to normal pointer operation + glBindBuffer(GL_ARRAY_BUFFER, 0); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::opengl::create_vector_vbo(Eigen::Matrix const&, unsigned int&); +// generated by autoexplicit.sh +template void igl::opengl::create_vector_vbo(Eigen::Matrix const&, unsigned int&); +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/opengl/create_vector_vbo.h b/src/external/libigl-2.3.0/include/igl/opengl/create_vector_vbo.h new file mode 100644 index 000000000..757c1a199 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/opengl/create_vector_vbo.h @@ -0,0 +1,38 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_OPENGL_CREATE_VECTOR_VBO_H +#define IGL_OPENGL_CREATE_VECTOR_VBO_H +#include "../igl_inline.h" +#include "gl.h" +#include + +// Create a VBO (Vertex Buffer Object) for a list of vectors: +// GL_ARRAY_BUFFER for the vectors (V) +namespace igl +{ + namespace opengl + { + // Templates: + // T should be a eigen matrix primitive type like int or double + // Inputs: + // V m by n eigen Matrix of type T values + // Outputs: + // V_vbo_id buffer id for vectors + // + template + IGL_INLINE void create_vector_vbo( + const Eigen::Matrix & V, + GLuint & V_vbo_id); + } +} + +#ifndef IGL_STATIC_LIBRARY +# include "create_vector_vbo.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/opengl/destroy_shader_program.cpp b/src/external/libigl-2.3.0/include/igl/opengl/destroy_shader_program.cpp new file mode 100644 index 000000000..2ceace7c2 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/opengl/destroy_shader_program.cpp @@ -0,0 +1,50 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "destroy_shader_program.h" +#include "report_gl_error.h" +#include + +IGL_INLINE bool igl::opengl::destroy_shader_program(const GLuint id) +{ + // Don't try to destroy id == 0 (no shader program) + if(id == 0) + { + fprintf(stderr,"Error: destroy_shader_program() id = %d" + " but must should be positive\n",id); + return false; + } + // Get each attached shader one by one and detach and delete it + GLsizei count; + // shader id + GLuint s; + do + { + // Try to get at most *1* attached shader + glGetAttachedShaders(id,1,&count,&s); + GLenum err = igl::opengl::report_gl_error(); + if (GL_NO_ERROR != err) + { + return false; + } + // Check that we actually got *1* + if(count == 1) + { + // Detach and delete this shader + glDetachShader(id,s); + glDeleteShader(s); + } + }while(count > 0); + // Now that all of the shaders are gone we can just delete the program + glDeleteProgram(id); + return true; +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/opengl/destroy_shader_program.h b/src/external/libigl-2.3.0/include/igl/opengl/destroy_shader_program.h new file mode 100644 index 000000000..5d53d8c3e --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/opengl/destroy_shader_program.h @@ -0,0 +1,35 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_OPENGL_DESTROY_SHADER_PROGRAM_H +#define IGL_OPENGL_DESTROY_SHADER_PROGRAM_H +#include "../igl_inline.h" +#include "gl.h" + +namespace igl +{ + namespace opengl + { + // Properly destroy a shader program. Detach and delete each of its shaders + // and delete it + // Inputs: + // id index id of created shader, set to 0 on error + // Returns true on success, false on error + // + // Note: caller is responsible for making sure he doesn't foolishly continue + // to use id as if it still contains a program + // + // See also: create_shader_program + IGL_INLINE bool destroy_shader_program(const GLuint id); + } +} + +#ifndef IGL_STATIC_LIBRARY +# include "destroy_shader_program.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/opengl/gl.h b/src/external/libigl-2.3.0/include/igl/opengl/gl.h new file mode 100644 index 000000000..fc037c198 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/opengl/gl.h @@ -0,0 +1,25 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013, 2017 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_OPENGL_GL_H +#define IGL_OPENGL_GL_H + +#ifdef IGL_OPENGL2_GL_H +# error "igl/opengl2/gl.h already included" +#endif + +// Always use this: +// #include "gl.h" +// Instead of: +// #include +// or +// #include +// + +#include + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/opengl/gl_type_size.cpp b/src/external/libigl-2.3.0/include/igl/opengl/gl_type_size.cpp new file mode 100644 index 000000000..0fd02bf05 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/opengl/gl_type_size.cpp @@ -0,0 +1,30 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "gl_type_size.h" +#include + +IGL_INLINE int igl::opengl::gl_type_size(const GLenum type) +{ + switch(type) + { + case GL_DOUBLE: + return 8; + break; + case GL_FLOAT: + return 4; + break; + case GL_INT: + return 4; + break; + default: + // should handle all other GL_[types] + assert(false && "Implementation incomplete."); + break; + } + return -1; +} diff --git a/src/external/libigl-2.3.0/include/igl/opengl/gl_type_size.h b/src/external/libigl-2.3.0/include/igl/opengl/gl_type_size.h new file mode 100644 index 000000000..a74119549 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/opengl/gl_type_size.h @@ -0,0 +1,28 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_OPENGL_GL_TYPE_SIZE_H +#define IGL_OPENGL_GL_TYPE_SIZE_H +#include "../igl_inline.h" +#include "gl.h" + +namespace igl +{ + namespace opengl + { + // Return the number of bytes for a given OpenGL type // Inputs: + // type enum value of opengl type + // Returns size in bytes of type + IGL_INLINE int gl_type_size(const GLenum type); + } +} + +#ifndef IGL_STATIC_LIBRARY +# include "gl_type_size.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/opengl/glfw/Viewer.cpp b/src/external/libigl-2.3.0/include/igl/opengl/glfw/Viewer.cpp new file mode 100644 index 000000000..49752d7e1 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/opengl/glfw/Viewer.cpp @@ -0,0 +1,1140 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Daniele Panozzo +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +#include "Viewer.h" + +#include +#include + +#include + +#include "../gl.h" +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Internal global variables used for glfw event handling +static igl::opengl::glfw::Viewer * __viewer; +static double highdpi = 1; +static double scroll_x = 0; +static double scroll_y = 0; + +static void glfw_mouse_press(GLFWwindow* window, int button, int action, int modifier) +{ + + igl::opengl::glfw::Viewer::MouseButton mb; + + if (button == GLFW_MOUSE_BUTTON_1) + mb = igl::opengl::glfw::Viewer::MouseButton::Left; + else if (button == GLFW_MOUSE_BUTTON_2) + mb = igl::opengl::glfw::Viewer::MouseButton::Right; + else //if (button == GLFW_MOUSE_BUTTON_3) + mb = igl::opengl::glfw::Viewer::MouseButton::Middle; + + if (action == GLFW_PRESS) + __viewer->mouse_down(mb,modifier); + else + __viewer->mouse_up(mb,modifier); +} + +static void glfw_error_callback(int error, const char* description) +{ + fputs(description, stderr); +} + +static void glfw_char_mods_callback(GLFWwindow* window, unsigned int codepoint, int modifier) +{ + __viewer->key_pressed(codepoint, modifier); +} + +static void glfw_key_callback(GLFWwindow* window, int key, int scancode, int action, int modifier) +{ + if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) + glfwSetWindowShouldClose(window, GL_TRUE); + + if (action == GLFW_PRESS) + __viewer->key_down(key, modifier); + else if(action == GLFW_RELEASE) + __viewer->key_up(key, modifier); +} + +static void glfw_window_size(GLFWwindow* window, int width, int height) +{ + int w = width*highdpi; + int h = height*highdpi; + + __viewer->post_resize(w, h); + +} + +static void glfw_mouse_move(GLFWwindow* window, double x, double y) +{ + __viewer->mouse_move(x*highdpi, y*highdpi); +} + +static void glfw_mouse_scroll(GLFWwindow* window, double x, double y) +{ + using namespace std; + scroll_x += x; + scroll_y += y; + + __viewer->mouse_scroll(y); +} + +static void glfw_drop_callback(GLFWwindow *window,int count,const char **filenames) +{ +} + +namespace igl +{ +namespace opengl +{ +namespace glfw +{ + + IGL_INLINE int Viewer::launch(bool resizable /*= true*/, bool fullscreen /*= false*/, + const std::string &name, int windowWidth /*= 0*/, int windowHeight /*= 0*/) + { + // TODO return values are being ignored... + launch_init(resizable,fullscreen,name,windowWidth,windowHeight); + launch_rendering(true); + launch_shut(); + return EXIT_SUCCESS; + } + + IGL_INLINE int Viewer::launch_init(bool resizable, bool fullscreen, + const std::string &name, int windowWidth, int windowHeight) + { + glfwSetErrorCallback(glfw_error_callback); + if (!glfwInit()) + { + return EXIT_FAILURE; + } + glfwWindowHint(GLFW_SAMPLES, 8); + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); + #ifdef __APPLE__ + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); + #endif + if(fullscreen) + { + GLFWmonitor *monitor = glfwGetPrimaryMonitor(); + const GLFWvidmode *mode = glfwGetVideoMode(monitor); + window = glfwCreateWindow(mode->width,mode->height,name.c_str(),monitor,nullptr); + windowWidth = mode->width; + windowHeight = mode->height; + } + else + { + // Set default windows width + if (windowWidth <= 0 && core_list.size() == 1 && core().viewport[2] > 0) + windowWidth = core().viewport[2]; + else if (windowWidth <= 0) + windowWidth = 1280; + // Set default windows height + if (windowHeight <= 0 && core_list.size() == 1 && core().viewport[3] > 0) + windowHeight = core().viewport[3]; + else if (windowHeight <= 0) + windowHeight = 800; + window = glfwCreateWindow(windowWidth,windowHeight,name.c_str(),nullptr,nullptr); + } + if (!window) + { + glfwTerminate(); + return EXIT_FAILURE; + } + glfwMakeContextCurrent(window); + // Load OpenGL and its extensions + if (!gladLoadGLLoader((GLADloadproc) glfwGetProcAddress)) + { + printf("Failed to load OpenGL and its extensions\n"); + return(-1); + } + #if defined(DEBUG) || defined(_DEBUG) + printf("OpenGL Version %d.%d loaded\n", GLVersion.major, GLVersion.minor); + int major, minor, rev; + major = glfwGetWindowAttrib(window, GLFW_CONTEXT_VERSION_MAJOR); + minor = glfwGetWindowAttrib(window, GLFW_CONTEXT_VERSION_MINOR); + rev = glfwGetWindowAttrib(window, GLFW_CONTEXT_REVISION); + printf("OpenGL version received: %d.%d.%d\n", major, minor, rev); + printf("Supported OpenGL is %s\n", (const char*)glGetString(GL_VERSION)); + printf("Supported GLSL is %s\n", (const char*)glGetString(GL_SHADING_LANGUAGE_VERSION)); + #endif + glfwSetInputMode(window,GLFW_CURSOR,GLFW_CURSOR_NORMAL); + // Initialize FormScreen + __viewer = this; + // Register callbacks + glfwSetKeyCallback(window, glfw_key_callback); + glfwSetCursorPosCallback(window,glfw_mouse_move); + glfwSetWindowSizeCallback(window,glfw_window_size); + glfwSetMouseButtonCallback(window,glfw_mouse_press); + glfwSetScrollCallback(window,glfw_mouse_scroll); + glfwSetCharModsCallback(window,glfw_char_mods_callback); + glfwSetDropCallback(window,glfw_drop_callback); + // Handle retina displays (windows and mac) + int width, height; + glfwGetFramebufferSize(window, &width, &height); + int width_window, height_window; + glfwGetWindowSize(window, &width_window, &height_window); + highdpi = windowWidth/width_window; + glfw_window_size(window,width_window,height_window); + // Initialize IGL viewer + init(); + for(auto &core : this->core_list) + { + for(auto &data : this->data_list) + { + if(data.is_visible & core.id) + { + this->core(core.id).align_camera_center(data.V, data.F); + } + } + } + return EXIT_SUCCESS; + } + + IGL_INLINE bool Viewer::launch_rendering(bool loop) + { + // glfwMakeContextCurrent(window); + // Rendering loop + const int num_extra_frames = 5; + int frame_counter = 0; + while (!glfwWindowShouldClose(window)) + { + double tic = get_seconds(); + draw(); + glfwSwapBuffers(window); + if(core().is_animating || frame_counter++ < num_extra_frames) + { + glfwPollEvents(); + // In microseconds + double duration = 1000000.*(get_seconds()-tic); + const double min_duration = 1000000./core().animation_max_fps; + if(durationinit(this); + } + } + + IGL_INLINE void Viewer::shutdown_plugins() + { + for (unsigned int i = 0; ishutdown(); + } + } + + IGL_INLINE Viewer::Viewer(): + data_list(1), + selected_data_index(0), + next_data_id(1), + selected_core_index(0), + next_core_id(2) + { + window = nullptr; + data_list.front().id = 0; + + core_list.emplace_back(ViewerCore()); + core_list.front().id = 1; + + // Temporary variables initialization + down = false; + hack_never_moved = true; + scroll_position = 0.0f; + + // Per face + data().set_face_based(false); + + // C-style callbacks + callback_init = nullptr; + callback_pre_draw = nullptr; + callback_post_draw = nullptr; + callback_mouse_down = nullptr; + callback_mouse_up = nullptr; + callback_mouse_move = nullptr; + callback_mouse_scroll = nullptr; + callback_key_down = nullptr; + callback_key_up = nullptr; + + callback_init_data = nullptr; + callback_pre_draw_data = nullptr; + callback_post_draw_data = nullptr; + callback_mouse_down_data = nullptr; + callback_mouse_up_data = nullptr; + callback_mouse_move_data = nullptr; + callback_mouse_scroll_data = nullptr; + callback_key_down_data = nullptr; + callback_key_up_data = nullptr; + +#ifndef IGL_VIEWER_VIEWER_QUIET + const std::string usage(R"(igl::opengl::glfw::Viewer usage: + [drag] Rotate scene + A,a Toggle animation (tight draw loop) + D,d Toggle double sided lighting + F,f Toggle face based + I,i Toggle invert normals + L,l Toggle wireframe + O,o Toggle orthographic/perspective projection + T,t Toggle filled faces + Z Snap to canonical view + [,] Toggle between rotation control types (trackball, two-axis + valuator with fixed up, 2D mode with no rotation)) + <,> Toggle between models + ; Toggle vertex labels + : Toggle face labels)" +); + std::cout<load(mesh_file_name_string)) + { + return true; + } + } + + // Create new data slot and set to selected + if(!(data().F.rows() == 0 && data().V.rows() == 0)) + { + append_mesh(); + } + data().clear(); + + size_t last_dot = mesh_file_name_string.rfind('.'); + if (last_dot == std::string::npos) + { + std::cerr<<"Error: No file extension found in "<< + mesh_file_name_string<post_load()) + return true; + + return true; + } + + IGL_INLINE bool Viewer::save_mesh_to_file( + const std::string & mesh_file_name_string) + { + // first try to load it with a plugin + for (unsigned int i = 0; isave(mesh_file_name_string)) + return true; + + size_t last_dot = mesh_file_name_string.rfind('.'); + if (last_dot == std::string::npos) + { + // No file type determined + std::cerr<<"Error: No file extension found in "<< + mesh_file_name_string<key_pressed(unicode_key, modifiers)) + { + return true; + } + } + + if (callback_key_pressed) + if (callback_key_pressed(*this,unicode_key,modifiers)) + return true; + + switch(unicode_key) + { + case 'A': + case 'a': + { + core().is_animating = !core().is_animating; + return true; + } + case 'D': + case 'd': + { + data().double_sided = !data().double_sided; + return true; + } + case 'F': + case 'f': + { + data().set_face_based(!data().face_based); + return true; + } + case 'I': + case 'i': + { + data().dirty |= MeshGL::DIRTY_NORMAL; + data().invert_normals = !data().invert_normals; + return true; + } + case 'L': + case 'l': + { + core().toggle(data().show_lines); + return true; + } + case 'O': + case 'o': + { + core().orthographic = !core().orthographic; + return true; + } + case 'T': + case 't': + { + core().toggle(data().show_faces); + return true; + } + case 'Z': + { + snap_to_canonical_quaternion(); + return true; + } + case '[': + case ']': + { + if(core().rotation_type == ViewerCore::ROTATION_TYPE_TRACKBALL) + core().set_rotation_type(ViewerCore::ROTATION_TYPE_TWO_AXIS_VALUATOR_FIXED_UP); + else + core().set_rotation_type(ViewerCore::ROTATION_TYPE_TRACKBALL); + + return true; + } + case '<': + case '>': + { + selected_data_index = + (selected_data_index + data_list.size() + (unicode_key=='>'?1:-1))%data_list.size(); + return true; + } + case '{': + case '}': + { + selected_core_index = + (selected_core_index + core_list.size() + (unicode_key=='}'?1:-1))%core_list.size(); + return true; + } + case ';': + data().show_vertex_labels = !data().show_vertex_labels; + return true; + case ':': + data().show_face_labels = !data().show_face_labels; + return true; + default: break;//do nothing + } + return false; + } + + IGL_INLINE bool Viewer::key_down(int key,int modifiers) + { + for (unsigned int i = 0; ikey_down(key, modifiers)) + return true; + + if (callback_key_down) + if (callback_key_down(*this,key,modifiers)) + return true; + + return false; + } + + IGL_INLINE bool Viewer::key_up(int key,int modifiers) + { + for (unsigned int i = 0; ikey_up(key, modifiers)) + return true; + + if (callback_key_up) + if (callback_key_up(*this,key,modifiers)) + return true; + + return false; + } + + IGL_INLINE void Viewer::select_hovered_core() + { + int width_window, height_window; + glfwGetFramebufferSize(window, &width_window, &height_window); + for (int i = 0; i < core_list.size(); i++) + { + Eigen::Vector4f viewport = core_list[i].viewport; + + if ((current_mouse_x > viewport[0]) && + (current_mouse_x < viewport[0] + viewport[2]) && + ((height_window - current_mouse_y) > viewport[1]) && + ((height_window - current_mouse_y) < viewport[1] + viewport[3])) + { + selected_core_index = i; + break; + } + } + } + + IGL_INLINE bool Viewer::mouse_down(MouseButton button,int modifier) + { + // Remember mouse location at down even if used by callback/plugin + down_mouse_x = current_mouse_x; + down_mouse_y = current_mouse_y; + + for (unsigned int i = 0; imouse_down(static_cast(button),modifier)) + return true; + + if (callback_mouse_down) + if (callback_mouse_down(*this,static_cast(button),modifier)) + return true; + + down = true; + + // Select the core containing the click location. + select_hovered_core(); + + down_translation = core().camera_translation; + + + // Initialization code for the trackball + Eigen::RowVector3d center; + if (data().V.rows() == 0) + { + center << 0,0,0; + }else + { + center = data().V.colwise().sum()/data().V.rows(); + } + + Eigen::Vector3f coord = + igl::project( + Eigen::Vector3f(center(0),center(1),center(2)), + core().view, + core().proj, + core().viewport); + down_mouse_z = coord[2]; + down_rotation = core().trackball_angle; + + mouse_mode = MouseMode::Rotation; + + switch (button) + { + case MouseButton::Left: + if (core().rotation_type == ViewerCore::ROTATION_TYPE_NO_ROTATION) { + mouse_mode = MouseMode::Translation; + } else { + mouse_mode = MouseMode::Rotation; + } + break; + + case MouseButton::Right: + mouse_mode = MouseMode::Translation; + break; + + default: + mouse_mode = MouseMode::None; + break; + } + + return true; + } + + IGL_INLINE bool Viewer::mouse_up(MouseButton button,int modifier) + { + down = false; + + for (unsigned int i = 0; imouse_up(static_cast(button),modifier)) + return true; + + if (callback_mouse_up) + if (callback_mouse_up(*this,static_cast(button),modifier)) + return true; + + mouse_mode = MouseMode::None; + + return true; + } + + IGL_INLINE bool Viewer::mouse_move(int mouse_x,int mouse_y) + { + if(hack_never_moved) + { + down_mouse_x = mouse_x; + down_mouse_y = mouse_y; + hack_never_moved = false; + } + current_mouse_x = mouse_x; + current_mouse_y = mouse_y; + + for (unsigned int i = 0; imouse_move(mouse_x, mouse_y)) + return true; + + if (callback_mouse_move) + if (callback_mouse_move(*this, mouse_x, mouse_y)) + return true; + + + if (down) + { + // We need the window height to transform the mouse click coordinates into viewport-mouse-click coordinates + // for igl::trackball and igl::two_axis_valuator_fixed_up + int width_window, height_window; + glfwGetFramebufferSize(window, &width_window, &height_window); + switch (mouse_mode) + { + case MouseMode::Rotation: + { + switch(core().rotation_type) + { + default: + assert(false && "Unknown rotation type"); + case ViewerCore::ROTATION_TYPE_NO_ROTATION: + break; + case ViewerCore::ROTATION_TYPE_TRACKBALL: + igl::trackball( + core().viewport(2), + core().viewport(3), + 2.0f, + down_rotation, + down_mouse_x - core().viewport(0), + down_mouse_y - (height_window - core().viewport(1) - core().viewport(3)), + mouse_x - core().viewport(0), + mouse_y - (height_window - core().viewport(1) - core().viewport(3)), + core().trackball_angle); + break; + case ViewerCore::ROTATION_TYPE_TWO_AXIS_VALUATOR_FIXED_UP: + igl::two_axis_valuator_fixed_up( + core().viewport(2),core().viewport(3), + 2.0, + down_rotation, + down_mouse_x - core().viewport(0), + down_mouse_y - (height_window - core().viewport(1) - core().viewport(3)), + mouse_x - core().viewport(0), + mouse_y - (height_window - core().viewport(1) - core().viewport(3)), + core().trackball_angle); + break; + } + //Eigen::Vector4f snapq = core().trackball_angle; + + break; + } + + case MouseMode::Translation: + { + //translation + Eigen::Vector3f pos1 = igl::unproject(Eigen::Vector3f(mouse_x, core().viewport[3] - mouse_y, down_mouse_z), core().view, core().proj, core().viewport); + Eigen::Vector3f pos0 = igl::unproject(Eigen::Vector3f(down_mouse_x, core().viewport[3] - down_mouse_y, down_mouse_z), core().view, core().proj, core().viewport); + + Eigen::Vector3f diff = pos1 - pos0; + core().camera_translation = down_translation + Eigen::Vector3f(diff[0],diff[1],diff[2]); + + break; + } + case MouseMode::Zoom: + { + float delta = 0.001f * (mouse_x - down_mouse_x + mouse_y - down_mouse_y); + core().camera_zoom *= 1 + delta; + down_mouse_x = mouse_x; + down_mouse_y = mouse_y; + break; + } + + default: + break; + } + } + return true; + } + + IGL_INLINE bool Viewer::mouse_scroll(float delta_y) + { + // Direct the scrolling operation to the appropriate viewport + // (unless the core selection is locked by an ongoing mouse interaction). + if (!down) + select_hovered_core(); + scroll_position += delta_y; + + for (unsigned int i = 0; imouse_scroll(delta_y)) + return true; + + if (callback_mouse_scroll) + if (callback_mouse_scroll(*this,delta_y)) + return true; + + // Only zoom if there's actually a change + if(delta_y != 0) + { + float mult = (1.0+((delta_y>0)?1.:-1.)*0.05); + const float min_zoom = 0.1f; + core().camera_zoom = (core().camera_zoom * mult > min_zoom ? core().camera_zoom * mult : min_zoom); + } + return true; + } + + IGL_INLINE bool Viewer::load_scene() + { + std::string fname = igl::file_dialog_open(); + if(fname.length() == 0) + return false; + return load_scene(fname); + } + + IGL_INLINE bool Viewer::load_scene(std::string fname) + { + igl::deserialize(core(),"Core",fname.c_str()); + igl::deserialize(data(),"Data",fname.c_str()); + return true; + } + + IGL_INLINE bool Viewer::save_scene() + { + std::string fname = igl::file_dialog_save(); + if (fname.length() == 0) + return false; + return save_scene(fname); + } + + IGL_INLINE bool Viewer::save_scene(std::string fname) + { + igl::serialize(core(),"Core",fname.c_str(),true); + igl::serialize(data(),"Data",fname.c_str()); + + return true; + } + + IGL_INLINE void Viewer::draw() + { + using namespace std; + using namespace Eigen; + + int width, height; + glfwGetFramebufferSize(window, &width, &height); + + int width_window, height_window; + glfwGetWindowSize(window, &width_window, &height_window); + + auto highdpi_tmp = (width_window == 0 || width == 0) ? highdpi : (width/width_window); + + if(fabs(highdpi_tmp-highdpi)>1e-8) + { + post_resize(width, height); + highdpi=highdpi_tmp; + } + + for (auto& core : core_list) + { + core.clear_framebuffers(); + } + + for (unsigned int i = 0; ipre_draw()) + { + return; + } + } + if (callback_pre_draw) + { + if (callback_pre_draw(*this)) + { + return; + } + } + + for (auto& core : core_list) + { + for (auto& mesh : data_list) + { + if (mesh.is_visible & core.id) + { + core.draw(mesh); + } + } + } + for (unsigned int i = 0; ipost_draw()) + { + break; + } + } + if (callback_post_draw) + { + if (callback_post_draw(*this)) + { + return; + } + } + } + + IGL_INLINE void Viewer::resize(int w,int h) + { + if (window) { + glfwSetWindowSize(window, w/highdpi, h/highdpi); + } + post_resize(w, h); + } + + IGL_INLINE void Viewer::post_resize(int w,int h) + { + if (core_list.size() == 1) + { + core().viewport = Eigen::Vector4f(0,0,w,h); + } + else + { + // It is up to the user to define the behavior of the post_resize() function + // when there are multiple viewports (through the `callback_post_resize` callback) + } + for (unsigned int i = 0; ipost_resize(w, h); + } + if (callback_post_resize) + { + callback_post_resize(*this, w, h); + } + } + + IGL_INLINE void Viewer::snap_to_canonical_quaternion() + { + Eigen::Quaternionf snapq = this->core().trackball_angle; + igl::snap_to_canonical_view_quat(snapq,1.0f,this->core().trackball_angle); + } + + IGL_INLINE void Viewer::open_dialog_load_mesh() + { + std::string fname = igl::file_dialog_open(); + + if (fname.length() == 0) + return; + + this->load_mesh_from_file(fname.c_str()); + } + + IGL_INLINE void Viewer::open_dialog_save_mesh() + { + std::string fname = igl::file_dialog_save(); + + if(fname.length() == 0) + return; + + this->save_mesh_to_file(fname.c_str()); + } + + IGL_INLINE ViewerData& Viewer::data(int mesh_id /*= -1*/) + { + assert(!data_list.empty() && "data_list should never be empty"); + int index; + if (mesh_id == -1) + index = selected_data_index; + else + index = mesh_index(mesh_id); + + assert((index >= 0 && index < data_list.size()) && + "selected_data_index or mesh_id should be in bounds"); + return data_list[index]; + } + + IGL_INLINE const ViewerData& Viewer::data(int mesh_id /*= -1*/) const + { + assert(!data_list.empty() && "data_list should never be empty"); + int index; + if (mesh_id == -1) + index = selected_data_index; + else + index = mesh_index(mesh_id); + + assert((index >= 0 && index < data_list.size()) && + "selected_data_index or mesh_id should be in bounds"); + return data_list[index]; + } + + IGL_INLINE int Viewer::append_mesh(bool visible /*= true*/) + { + assert(data_list.size() >= 1); + + data_list.emplace_back(); + selected_data_index = data_list.size()-1; + data_list.back().id = next_data_id++; + if (visible) + for (int i = 0; i < core_list.size(); i++) + data_list.back().set_visible(true, core_list[i].id); + else + data_list.back().is_visible = 0; + return data_list.back().id; + } + + IGL_INLINE bool Viewer::erase_mesh(const size_t index) + { + assert((index >= 0 && index < data_list.size()) && "index should be in bounds"); + assert(data_list.size() >= 1); + if(data_list.size() == 1) + { + // Cannot remove last mesh + return false; + } + data_list[index].meshgl.free(); + data_list.erase(data_list.begin() + index); + if(selected_data_index >= index && selected_data_index > 0) + { + selected_data_index--; + } + + return true; + } + + IGL_INLINE size_t Viewer::mesh_index(const int id) const { + for (size_t i = 0; i < data_list.size(); ++i) + { + if (data_list[i].id == id) + return i; + } + return 0; + } + + IGL_INLINE ViewerCore& Viewer::core(unsigned core_id /*= 0*/) + { + assert(!core_list.empty() && "core_list should never be empty"); + int core_index; + if (core_id == 0) + core_index = selected_core_index; + else + core_index = this->core_index(core_id); + assert((core_index >= 0 && core_index < core_list.size()) && "selected_core_index should be in bounds"); + return core_list[core_index]; + } + + IGL_INLINE const ViewerCore& Viewer::core(unsigned core_id /*= 0*/) const + { + assert(!core_list.empty() && "core_list should never be empty"); + int core_index; + if (core_id == 0) + core_index = selected_core_index; + else + core_index = this->core_index(core_id); + assert((core_index >= 0 && core_index < core_list.size()) && "selected_core_index should be in bounds"); + return core_list[core_index]; + } + + IGL_INLINE bool Viewer::erase_core(const size_t index) + { + assert((index >= 0 && index < core_list.size()) && "index should be in bounds"); + assert(data_list.size() >= 1); + if (core_list.size() == 1) + { + // Cannot remove last viewport + return false; + } + core_list[index].shut(); // does nothing + core_list.erase(core_list.begin() + index); + if (selected_core_index >= index && selected_core_index > 0) + { + selected_core_index--; + } + return true; + } + + IGL_INLINE size_t Viewer::core_index(const int id) const { + for (size_t i = 0; i < core_list.size(); ++i) + { + if (core_list[i].id == id) + return i; + } + return 0; + } + + IGL_INLINE int Viewer::append_core(Eigen::Vector4f viewport, bool append_empty /*= false*/) + { + core_list.push_back(core()); // copies the previous active core and only changes the viewport + core_list.back().viewport = viewport; + core_list.back().id = next_core_id; + next_core_id <<= 1; + if (!append_empty) + { + for (auto &data : data_list) + { + data.set_visible(true, core_list.back().id); + data.copy_options(core(), core_list.back()); + } + } + selected_core_index = core_list.size()-1; + return core_list.back().id; + } + +} // end namespace +} // end namespace +} diff --git a/src/external/libigl-2.3.0/include/igl/opengl/glfw/Viewer.h b/src/external/libigl-2.3.0/include/igl/opengl/glfw/Viewer.h new file mode 100644 index 000000000..046684c5b --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/opengl/glfw/Viewer.h @@ -0,0 +1,237 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Daniele Panozzo +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_OPENGL_GLFW_VIEWER_H +#define IGL_OPENGL_GLFW_VIEWER_H + +#ifndef IGL_OPENGL_4 +#define IGL_OPENGL_4 +#endif + +#include "../../igl_inline.h" +#include "../MeshGL.h" +#include "../ViewerCore.h" +#include "../ViewerData.h" +#include "ViewerPlugin.h" + +#include +#include + +#include +#include +#include + +#define IGL_MOD_SHIFT 0x0001 +#define IGL_MOD_CONTROL 0x0002 +#define IGL_MOD_ALT 0x0004 +#define IGL_MOD_SUPER 0x0008 + +struct GLFWwindow; + +namespace igl +{ +namespace opengl +{ +namespace glfw +{ + // GLFW-based mesh viewer + class Viewer + { + public: + // UI Enumerations + enum class MouseButton {Left, Middle, Right}; + enum class MouseMode { None, Rotation, Zoom, Pan, Translation} mouse_mode; + IGL_INLINE int launch(bool resizable = true, bool fullscreen = false, const std::string &name = "libigl viewer", int width = 0, int height = 0); + IGL_INLINE int launch_init(bool resizable = true, bool fullscreen = false, const std::string &name = "libigl viewer", int width = 0, int height = 0); + IGL_INLINE bool launch_rendering(bool loop = true); + IGL_INLINE void launch_shut(); + IGL_INLINE void init(); + IGL_INLINE void init_plugins(); + IGL_INLINE void shutdown_plugins(); + Viewer(); + ~Viewer(); + // Mesh IO + IGL_INLINE bool load_mesh_from_file(const std::string & mesh_file_name); + IGL_INLINE bool save_mesh_to_file(const std::string & mesh_file_name); + // Callbacks + IGL_INLINE bool key_pressed(unsigned int unicode_key,int modifier); + IGL_INLINE bool key_down(int key,int modifier); + IGL_INLINE bool key_up(int key,int modifier); + IGL_INLINE bool mouse_down(MouseButton button,int modifier); + IGL_INLINE bool mouse_up(MouseButton button,int modifier); + IGL_INLINE bool mouse_move(int mouse_x,int mouse_y); + IGL_INLINE bool mouse_scroll(float delta_y); + // Scene IO + IGL_INLINE bool load_scene(); + IGL_INLINE bool load_scene(std::string fname); + IGL_INLINE bool save_scene(); + IGL_INLINE bool save_scene(std::string fname); + // Draw everything + IGL_INLINE void draw(); + // OpenGL context resize + IGL_INLINE void resize(int w,int h); // explicitly set window size + IGL_INLINE void post_resize(int w,int h); // external resize due to user interaction + // Helper functions + IGL_INLINE void snap_to_canonical_quaternion(); + IGL_INLINE void open_dialog_load_mesh(); + IGL_INLINE void open_dialog_save_mesh(); + + //////////////////////// + // Multi-mesh methods // + //////////////////////// + + // Return the current mesh, or the mesh corresponding to a given unique identifier + // + // Inputs: + // mesh_id unique identifier associated to the desired mesh (current mesh if -1) + IGL_INLINE ViewerData& data(int mesh_id = -1); + IGL_INLINE const ViewerData& data(int mesh_id = -1) const; + + // Append a new "slot" for a mesh (i.e., create empty entries at the end of + // the data_list and opengl_state_list. + // + // Inputs: + // visible If true, the new mesh is set to be visible on all existing viewports + // Returns the id of the last appended mesh + // + // Side Effects: + // selected_data_index is set this newly created, last entry (i.e., + // #meshes-1) + IGL_INLINE int append_mesh(bool visible = true); + + // Erase a mesh (i.e., its corresponding data and state entires in data_list + // and opengl_state_list) + // + // Inputs: + // index index of mesh to erase + // Returns whether erasure was successful <=> cannot erase last mesh + // + // Side Effects: + // If selected_data_index is greater than or equal to index then it is + // decremented + // Example: + // // Erase all mesh slots except first and clear remaining mesh + // viewer.selected_data_index = viewer.data_list.size()-1; + // while(viewer.erase_mesh(viewer.selected_data_index)){}; + // viewer.data().clear(); + // + IGL_INLINE bool erase_mesh(const size_t index); + + // Retrieve mesh index from its unique identifier + // Returns 0 if not found + IGL_INLINE size_t mesh_index(const int id) const; + + //////////////////////////// + // Multi-viewport methods // + //////////////////////////// + + // Return the current viewport, or the viewport corresponding to a given unique identifier + // + // Inputs: + // core_id unique identifier corresponding to the desired viewport (current viewport if 0) + IGL_INLINE ViewerCore& core(unsigned core_id = 0); + IGL_INLINE const ViewerCore& core(unsigned core_id = 0) const; + + // Append a new "slot" for a viewport (i.e., copy properties of the current viewport, only + // changing the viewport size/position) + // + // Inputs: + // viewport Vector specifying the viewport origin and size in screen coordinates. + // append_empty If true, existing meshes are hidden on the new viewport. + // + // Returns the unique id of the newly inserted viewport. There can be a maximum of 31 + // viewports created in the same viewport. Erasing a viewport does not change the id of + // other existing viewports + IGL_INLINE int append_core(Eigen::Vector4f viewport, bool append_empty = false); + + // Erase a viewport + // + // Inputs: + // index index of the viewport to erase + IGL_INLINE bool erase_core(const size_t index); + + // Retrieve viewport index from its unique identifier + // Returns 0 if not found + IGL_INLINE size_t core_index(const int id) const; + + // Change selected_core_index to the viewport containing the mouse + // (current_mouse_x, current_mouse_y) + IGL_INLINE void select_hovered_core(); + +public: + ////////////////////// + // Member variables // + ////////////////////// + + // Alec: I call this data_list instead of just data to avoid confusion with + // old "data" variable. + // Stores all the data that should be visualized + std::vector data_list; + + size_t selected_data_index; + int next_data_id; + GLFWwindow* window; + + // Stores all the viewing options + std::vector core_list; + size_t selected_core_index; + int next_core_id; + + // List of registered plugins + std::vector plugins; + // Temporary data stored when the mouse button is pressed + Eigen::Quaternionf down_rotation; + int current_mouse_x; + int current_mouse_y; + int down_mouse_x; + int down_mouse_y; + float down_mouse_z; + Eigen::Vector3f down_translation; + bool down; + bool hack_never_moved; + // Keep track of the global position of the scrollwheel + float scroll_position; + // C++-style functions + // + // Returns **true** if action should be cancelled. + std::function callback_init; + std::function callback_pre_draw; + std::function callback_post_draw; + std::function callback_mouse_down; + std::function callback_mouse_up; + std::function callback_mouse_move; + std::function callback_mouse_scroll; + std::function callback_key_pressed; + std::function callback_post_resize; + // THESE SHOULD BE DEPRECATED: + std::function callback_key_down; + std::function callback_key_up; + // Pointers to per-callback data + void* callback_init_data; + void* callback_pre_draw_data; + void* callback_post_draw_data; + void* callback_mouse_down_data; + void* callback_mouse_up_data; + void* callback_mouse_move_data; + void* callback_mouse_scroll_data; + void* callback_key_pressed_data; + void* callback_key_down_data; + void* callback_key_up_data; + + public: + EIGEN_MAKE_ALIGNED_OPERATOR_NEW + }; + +} // end namespace +} // end namespace +} // end namespace + +#ifndef IGL_STATIC_LIBRARY +# include "Viewer.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/opengl/glfw/ViewerPlugin.h b/src/external/libigl-2.3.0/include/igl/opengl/glfw/ViewerPlugin.h new file mode 100644 index 000000000..9ba7903a8 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/opengl/glfw/ViewerPlugin.h @@ -0,0 +1,182 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Daniele Panozzo +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_OPENGL_GLFW_VIEWERPLUGIN_H +#define IGL_OPENGL_GLFW_VIEWERPLUGIN_H + +// TODO: +// * create plugins/skeleton.h +// * pass time in draw function +// * remove Preview3D from comments +// * clean comments +#include +#include +#include + +namespace igl +{ +namespace opengl +{ +namespace glfw +{ + +// Abstract class for plugins +// All plugins MUST have this class as their parent and may implement any/all +// the callbacks marked `virtual` here. +// +// /////For an example of a basic plugins see plugins/skeleton.h +// +// Return value of callbacks: returning true to any of the callbacks tells +// Viewer that the event has been handled and that it should not be passed to +// other plugins or to other internal functions of Viewer + +// Forward declaration of the viewer +class Viewer; + +class ViewerPlugin +{ +public: + IGL_INLINE ViewerPlugin() + {plugin_name = "dummy";} + + virtual ~ViewerPlugin(){} + + // This function is called when the viewer is initialized (no mesh will be loaded at this stage) + IGL_INLINE virtual void init(Viewer *_viewer) + { + viewer = _viewer; + } + + // This function is called before shutdown + IGL_INLINE virtual void shutdown() + { + } + + // This function is called before a mesh is loaded + IGL_INLINE virtual bool load(std::string filename) + { + return false; + } + + // This function is called before a mesh is saved + IGL_INLINE virtual bool save(std::string filename) + { + return false; + } + + // This function is called when the scene is serialized + IGL_INLINE virtual bool serialize(std::vector& buffer) const + { + return false; + } + + // This function is called when the scene is deserialized + IGL_INLINE virtual bool deserialize(const std::vector& buffer) + { + return false; + } + + // Runs immediately after a new mesh has been loaded. + IGL_INLINE virtual bool post_load() + { + return false; + } + + // This function is called before the draw procedure of Preview3D + IGL_INLINE virtual bool pre_draw() + { + return false; + } + + // This function is called after the draw procedure of Preview3D + IGL_INLINE virtual bool post_draw() + { + return false; + } + + // This function is called after the window has been resized + IGL_INLINE virtual void post_resize(int w, int h) + { + } + + // This function is called when the mouse button is pressed + // - button can be GLUT_LEFT_BUTTON, GLUT_MIDDLE_BUTTON or GLUT_RIGHT_BUTTON + // - modifiers is a bitfield that might one or more of the following bits Preview3D::NO_KEY, Preview3D::SHIFT, Preview3D::CTRL, Preview3D::ALT; + IGL_INLINE virtual bool mouse_down(int button, int modifier) + { + return false; + } + + // This function is called when the mouse button is released + // - button can be GLUT_LEFT_BUTTON, GLUT_MIDDLE_BUTTON or GLUT_RIGHT_BUTTON + // - modifiers is a bitfield that might one or more of the following bits Preview3D::NO_KEY, Preview3D::SHIFT, Preview3D::CTRL, Preview3D::ALT; + IGL_INLINE virtual bool mouse_up(int button, int modifier) + { + return false; + } + + // This function is called every time the mouse is moved + // - mouse_x and mouse_y are the new coordinates of the mouse pointer in screen coordinates + IGL_INLINE virtual bool mouse_move(int mouse_x, int mouse_y) + { + return false; + } + + // This function is called every time the scroll wheel is moved + // Note: this callback is not working with every glut implementation + IGL_INLINE virtual bool mouse_scroll(float delta_y) + { + return false; + } + + // This function is called when a keyboard key is pressed. Unlike key_down + // this will reveal the actual character being sent (not just the physical + // key) + // - modifiers is a bitfield that might one or more of the following bits Preview3D::NO_KEY, Preview3D::SHIFT, Preview3D::CTRL, Preview3D::ALT; + IGL_INLINE virtual bool key_pressed(unsigned int key, int modifiers) + { + return false; + } + + // This function is called when a keyboard key is down + // - modifiers is a bitfield that might one or more of the following bits Preview3D::NO_KEY, Preview3D::SHIFT, Preview3D::CTRL, Preview3D::ALT; + IGL_INLINE virtual bool key_down(int key, int modifiers) + { + return false; + } + + // This function is called when a keyboard key is release + // - modifiers is a bitfield that might one or more of the following bits Preview3D::NO_KEY, Preview3D::SHIFT, Preview3D::CTRL, Preview3D::ALT; + IGL_INLINE virtual bool key_up(int key, int modifiers) + { + return false; + } + + std::string plugin_name; +protected: + // Pointer to the main Viewer class + Viewer *viewer; +}; + +namespace serialization +{ + inline void serialize(const ViewerPlugin& obj,std::vector& buffer) + { + obj.serialize(buffer); + } + + inline void deserialize(ViewerPlugin& obj,const std::vector& buffer) + { + obj.deserialize(buffer); + } +} + +} +} +} + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/opengl/glfw/background_window.cpp b/src/external/libigl-2.3.0/include/igl/opengl/glfw/background_window.cpp new file mode 100644 index 000000000..964202cc2 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/opengl/glfw/background_window.cpp @@ -0,0 +1,30 @@ +#include "background_window.h" + +#include + +IGL_INLINE bool igl::opengl::glfw::background_window(GLFWwindow* & window) +{ + if(!glfwInit()) return false; + glfwSetErrorCallback([](int id,const char* m){std::cerr< + +namespace igl +{ + namespace opengl + { + namespace glfw + { + // Create a background window with a valid core profile opengl context + // set to current. + // + // After you're finished with this window you may call + // `glfwDestroyWindow(window)` + // + // After you're finished with glfw you should call `glfwTerminate()` + // + // Outputs: + // window pointer to glfw window + // Returns true iff success + IGL_INLINE bool background_window(GLFWwindow* & window); + } + } +} + +#ifndef IGL_STATIC_LIBRARY +# include "background_window.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/opengl/glfw/imgui/ImGuiHelpers.h b/src/external/libigl-2.3.0/include/igl/opengl/glfw/imgui/ImGuiHelpers.h new file mode 100644 index 000000000..066339093 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/opengl/glfw/imgui/ImGuiHelpers.h @@ -0,0 +1,115 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2018 Jérémie Dumas +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_OPENGL_GLFW_IMGUI_IMGUIHELPERS_H +#define IGL_OPENGL_GLFW_IMGUI_IMGUIHELPERS_H + +//////////////////////////////////////////////////////////////////////////////// +#include "ImGuiTraits.h" +#include +#include +#include +#include +#include +#include +//////////////////////////////////////////////////////////////////////////////// + +// Extend ImGui by populating its namespace directly +// +// Code snippets taken from there: +// https://eliasdaler.github.io/using-imgui-with-sfml-pt2/ +namespace ImGui +{ + +static auto vector_getter = [](void* vec, int idx, const char** out_text) +{ + auto& vector = *static_cast*>(vec); + if (idx < 0 || idx >= static_cast(vector.size())) { return false; } + *out_text = vector.at(idx).c_str(); + return true; +}; + +inline bool Combo(const char* label, int* idx, std::vector& values) +{ + if (values.empty()) { return false; } + return Combo(label, idx, vector_getter, + static_cast(&values), values.size()); +} + +inline bool Combo(const char* label, int* idx, std::function getter, int items_count) +{ + auto func = [](void* data, int i, const char** out_text) { + auto &getter = *reinterpret_cast *>(data); + const char *s = getter(i); + if (s) { *out_text = s; return true; } + else { return false; } + }; + return Combo(label, idx, func, reinterpret_cast(&getter), items_count); +} + +inline bool ListBox(const char* label, int* idx, std::vector& values) +{ + if (values.empty()) { return false; } + return ListBox(label, idx, vector_getter, + static_cast(&values), values.size()); +} + +inline bool InputText(const char* label, std::string &str, ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = NULL, void* user_data = NULL) +{ + char buf[1024]; + std::fill_n(buf, 1024, 0); + std::copy_n(str.begin(), std::min(1024, (int) str.size()), buf); + if (ImGui::InputText(label, buf, 1024, flags, callback, user_data)) + { + str = std::string(buf); + return true; + } + return false; +} + +// template +// inline bool DragScalar(const char *label, T* value, void* v, float v_speed, const void* v_min = NULL, const void* v_max = NULL, const char* format = NULL, float power = 1.0f) +// { +// const char *fmt = format; +// if (format == nullptr) { +// fmt = ImGuiDataTypeTraits::format; +// } +// return DragScalar(label, ImGuiDataTypeTraits::value, value, &min, &max, fmt); +// } + +// template +// inline bool InputScalar(const char *label, T* value, T min = 0, T max = 0, const char* format = nulltptr) +// { +// const char *fmt = format; +// if (format == nullptr) { +// fmt = ImGuiDataTypeTraits::format; +// } +// return InputScalar(label, ImGuiDataTypeTraits::value, value, &min, &max, fmt); +// } + +template +inline bool SliderScalar(const char *label, T* value, T min = 0, T max = 0, const char* format = "") +{ + const char *fmt = format; + if (format == nullptr) { + fmt = ImGuiDataTypeTraits::format; + } + return SliderScalar(label, ImGuiDataTypeTraits::value, value, &min, &max, fmt); +} + +template +inline bool Checkbox(const char* label, Getter get, Setter set) +{ + bool value = get(); + bool ret = ImGui::Checkbox(label, &value); + set(value); + return ret; +} + +} // namespace ImGui + +#endif // IGL_OPENGL_GLFW_IMGUI_IMGUIHELPERS_H diff --git a/src/external/libigl-2.3.0/include/igl/opengl/glfw/imgui/ImGuiMenu.cpp b/src/external/libigl-2.3.0/include/igl/opengl/glfw/imgui/ImGuiMenu.cpp new file mode 100644 index 000000000..c91c1cc5b --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/opengl/glfw/imgui/ImGuiMenu.cpp @@ -0,0 +1,330 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2018 Jérémie Dumas +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +//////////////////////////////////////////////////////////////////////////////// +#include "ImGuiMenu.h" +#include "ImGuiHelpers.h" +#include +#include +#include +#include +#include +#include +#include +//////////////////////////////////////////////////////////////////////////////// + +namespace igl +{ +namespace opengl +{ +namespace glfw +{ +namespace imgui +{ + +IGL_INLINE void ImGuiMenu::init(igl::opengl::glfw::Viewer *_viewer) +{ + ViewerPlugin::init(_viewer); + // Setup ImGui binding + if (_viewer) + { + IMGUI_CHECKVERSION(); + if (!context_) + { + // Single global context by default, but can be overridden by the user + static ImGuiContext * __global_context = ImGui::CreateContext(); + context_ = __global_context; + } + const char* glsl_version = "#version 150"; + ImGui_ImplGlfw_InitForOpenGL(viewer->window, false); + ImGui_ImplOpenGL3_Init(glsl_version); + ImGui::GetIO().IniFilename = nullptr; + ImGui::StyleColorsDark(); + ImGuiStyle& style = ImGui::GetStyle(); + style.FrameRounding = 5.0f; + reload_font(); + } +} + +IGL_INLINE void ImGuiMenu::reload_font(int font_size) +{ + hidpi_scaling_ = hidpi_scaling(); + pixel_ratio_ = pixel_ratio(); + ImGuiIO& io = ImGui::GetIO(); + io.Fonts->Clear(); + io.Fonts->AddFontFromMemoryCompressedTTF(droid_sans_compressed_data, + droid_sans_compressed_size, font_size * hidpi_scaling_); + io.FontGlobalScale = 1.0 / pixel_ratio_; +} + +IGL_INLINE void ImGuiMenu::shutdown() +{ + // Cleanup + ImGui_ImplOpenGL3_Shutdown(); + ImGui_ImplGlfw_Shutdown(); + // User is responsible for destroying context if a custom context is given + // ImGui::DestroyContext(*context_); +} + +IGL_INLINE bool ImGuiMenu::pre_draw() +{ + glfwPollEvents(); + + // Check whether window dpi has changed + float scaling = hidpi_scaling(); + if (std::abs(scaling - hidpi_scaling_) > 1e-5) + { + reload_font(); + ImGui_ImplOpenGL3_DestroyDeviceObjects(); + } + + ImGui_ImplOpenGL3_NewFrame(); + ImGui_ImplGlfw_NewFrame(); + ImGui::NewFrame(); + return false; +} + +IGL_INLINE bool ImGuiMenu::post_draw() +{ + draw_menu(); + ImGui::Render(); + ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); + return false; +} + +IGL_INLINE void ImGuiMenu::post_resize(int width, int height) +{ + if (context_) + { + ImGui::GetIO().DisplaySize.x = float(width); + ImGui::GetIO().DisplaySize.y = float(height); + } +} + +// Mouse IO +IGL_INLINE bool ImGuiMenu::mouse_down(int button, int modifier) +{ + ImGui_ImplGlfw_MouseButtonCallback(viewer->window, button, GLFW_PRESS, modifier); + return ImGui::GetIO().WantCaptureMouse; +} + +IGL_INLINE bool ImGuiMenu::mouse_up(int button, int modifier) +{ + //return ImGui::GetIO().WantCaptureMouse; + // !! Should not steal mouse up + return false; +} + +IGL_INLINE bool ImGuiMenu::mouse_move(int mouse_x, int mouse_y) +{ + return ImGui::GetIO().WantCaptureMouse; +} + +IGL_INLINE bool ImGuiMenu::mouse_scroll(float delta_y) +{ + ImGui_ImplGlfw_ScrollCallback(viewer->window, 0.f, delta_y); + return ImGui::GetIO().WantCaptureMouse; +} + +// Keyboard IO +IGL_INLINE bool ImGuiMenu::key_pressed(unsigned int key, int modifiers) +{ + ImGui_ImplGlfw_CharCallback(nullptr, key); + return ImGui::GetIO().WantCaptureKeyboard; +} + +IGL_INLINE bool ImGuiMenu::key_down(int key, int modifiers) +{ + ImGui_ImplGlfw_KeyCallback(viewer->window, key, 0, GLFW_PRESS, modifiers); + return ImGui::GetIO().WantCaptureKeyboard; +} + +IGL_INLINE bool ImGuiMenu::key_up(int key, int modifiers) +{ + ImGui_ImplGlfw_KeyCallback(viewer->window, key, 0, GLFW_RELEASE, modifiers); + return ImGui::GetIO().WantCaptureKeyboard; +} + +// Draw menu +IGL_INLINE void ImGuiMenu::draw_menu() +{ + // Viewer settings + if (callback_draw_viewer_window) { callback_draw_viewer_window(); } + else { draw_viewer_window(); } + + // Other windows + if (callback_draw_custom_window) { callback_draw_custom_window(); } + else { draw_custom_window(); } +} + +IGL_INLINE void ImGuiMenu::draw_viewer_window() +{ + float menu_width = 180.f * menu_scaling(); + ImGui::SetNextWindowPos(ImVec2(0.0f, 0.0f), ImGuiCond_FirstUseEver); + ImGui::SetNextWindowSize(ImVec2(0.0f, 0.0f), ImGuiCond_FirstUseEver); + ImGui::SetNextWindowSizeConstraints(ImVec2(menu_width, -1.0f), ImVec2(menu_width, -1.0f)); + bool _viewer_menu_visible = true; + ImGui::Begin( + "Viewer", &_viewer_menu_visible, + ImGuiWindowFlags_NoSavedSettings + | ImGuiWindowFlags_AlwaysAutoResize + ); + ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.4f); + if (callback_draw_viewer_menu) { callback_draw_viewer_menu(); } + else { draw_viewer_menu(); } + ImGui::PopItemWidth(); + ImGui::End(); +} + +IGL_INLINE void ImGuiMenu::draw_viewer_menu() +{ + // Workspace + if (ImGui::CollapsingHeader("Workspace", ImGuiTreeNodeFlags_DefaultOpen)) + { + float w = ImGui::GetContentRegionAvailWidth(); + float p = ImGui::GetStyle().FramePadding.x; + if (ImGui::Button("Load##Workspace", ImVec2((w-p)/2.f, 0))) + { + viewer->load_scene(); + } + ImGui::SameLine(0, p); + if (ImGui::Button("Save##Workspace", ImVec2((w-p)/2.f, 0))) + { + viewer->save_scene(); + } + } + + // Mesh + if (ImGui::CollapsingHeader("Mesh", ImGuiTreeNodeFlags_DefaultOpen)) + { + float w = ImGui::GetContentRegionAvailWidth(); + float p = ImGui::GetStyle().FramePadding.x; + if (ImGui::Button("Load##Mesh", ImVec2((w-p)/2.f, 0))) + { + viewer->open_dialog_load_mesh(); + } + ImGui::SameLine(0, p); + if (ImGui::Button("Save##Mesh", ImVec2((w-p)/2.f, 0))) + { + viewer->open_dialog_save_mesh(); + } + } + + // Viewing options + if (ImGui::CollapsingHeader("Viewing Options", ImGuiTreeNodeFlags_DefaultOpen)) + { + if (ImGui::Button("Center object", ImVec2(-1, 0))) + { + viewer->core().align_camera_center(viewer->data().V, viewer->data().F); + } + if (ImGui::Button("Snap canonical view", ImVec2(-1, 0))) + { + viewer->snap_to_canonical_quaternion(); + } + + // Zoom + ImGui::PushItemWidth(80 * menu_scaling()); + ImGui::DragFloat("Zoom", &(viewer->core().camera_zoom), 0.05f, 0.1f, 20.0f); + + // Select rotation type + int rotation_type = static_cast(viewer->core().rotation_type); + static Eigen::Quaternionf trackball_angle = Eigen::Quaternionf::Identity(); + static bool orthographic = true; + if (ImGui::Combo("Camera Type", &rotation_type, "Trackball\0Two Axes\0002D Mode\0\0")) + { + using RT = igl::opengl::ViewerCore::RotationType; + auto new_type = static_cast(rotation_type); + if (new_type != viewer->core().rotation_type) + { + if (new_type == RT::ROTATION_TYPE_NO_ROTATION) + { + trackball_angle = viewer->core().trackball_angle; + orthographic = viewer->core().orthographic; + viewer->core().trackball_angle = Eigen::Quaternionf::Identity(); + viewer->core().orthographic = true; + } + else if (viewer->core().rotation_type == RT::ROTATION_TYPE_NO_ROTATION) + { + viewer->core().trackball_angle = trackball_angle; + viewer->core().orthographic = orthographic; + } + viewer->core().set_rotation_type(new_type); + } + } + + // Orthographic view + ImGui::Checkbox("Orthographic view", &(viewer->core().orthographic)); + ImGui::PopItemWidth(); + } + + // Helper for setting viewport specific mesh options + auto make_checkbox = [&](const char *label, unsigned int &option) + { + return ImGui::Checkbox(label, + [&]() { return viewer->core().is_set(option); }, + [&](bool value) { return viewer->core().set(option, value); } + ); + }; + + // Draw options + if (ImGui::CollapsingHeader("Draw Options", ImGuiTreeNodeFlags_DefaultOpen)) + { + if (ImGui::Checkbox("Face-based", &(viewer->data().face_based))) + { + viewer->data().dirty = MeshGL::DIRTY_ALL; + } + make_checkbox("Show texture", viewer->data().show_texture); + if (ImGui::Checkbox("Invert normals", &(viewer->data().invert_normals))) + { + viewer->data().dirty |= igl::opengl::MeshGL::DIRTY_NORMAL; + } + make_checkbox("Show overlay", viewer->data().show_overlay); + make_checkbox("Show overlay depth", viewer->data().show_overlay_depth); + ImGui::ColorEdit4("Background", viewer->core().background_color.data(), + ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_PickerHueWheel); + ImGui::ColorEdit4("Line color", viewer->data().line_color.data(), + ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_PickerHueWheel); + ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.3f); + ImGui::DragFloat("Shininess", &(viewer->data().shininess), 0.05f, 0.0f, 100.0f); + ImGui::PopItemWidth(); + } + + // Overlays + if (ImGui::CollapsingHeader("Overlays", ImGuiTreeNodeFlags_DefaultOpen)) + { + make_checkbox("Wireframe", viewer->data().show_lines); + make_checkbox("Fill", viewer->data().show_faces); + make_checkbox("Show vertex labels", viewer->data().show_vertex_labels); + make_checkbox("Show faces labels", viewer->data().show_face_labels); + make_checkbox("Show extra labels", viewer->data().show_custom_labels); + } +} + +IGL_INLINE float ImGuiMenu::pixel_ratio() +{ + // Computes pixel ratio for hidpi devices + int buf_size[2]; + int win_size[2]; + GLFWwindow* window = glfwGetCurrentContext(); + glfwGetFramebufferSize(window, &buf_size[0], &buf_size[1]); + glfwGetWindowSize(window, &win_size[0], &win_size[1]); + return (float) buf_size[0] / (float) win_size[0]; +} + +IGL_INLINE float ImGuiMenu::hidpi_scaling() +{ + // Computes scaling factor for hidpi devices + float xscale, yscale; + GLFWwindow* window = glfwGetCurrentContext(); + glfwGetWindowContentScale(window, &xscale, &yscale); + return 0.5 * (xscale + yscale); +} + +} // end namespace +} // end namespace +} // end namespace +} // end namespace diff --git a/src/external/libigl-2.3.0/include/igl/opengl/glfw/imgui/ImGuiMenu.h b/src/external/libigl-2.3.0/include/igl/opengl/glfw/imgui/ImGuiMenu.h new file mode 100644 index 000000000..b48188251 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/opengl/glfw/imgui/ImGuiMenu.h @@ -0,0 +1,111 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2018 Jérémie Dumas +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_OPENGL_GLFW_IMGUI_IMGUIMENU_H +#define IGL_OPENGL_GLFW_IMGUI_IMGUIMENU_H + +//////////////////////////////////////////////////////////////////////////////// +#include +#include +#include +#include +//////////////////////////////////////////////////////////////////////////////// + +// Forward declarations +struct ImGuiContext; + +namespace igl +{ +namespace opengl +{ +namespace glfw +{ +namespace imgui +{ + +class ImGuiMenu : public igl::opengl::glfw::ViewerPlugin +{ +protected: + // Hidpi scaling to be used for text rendering. + float hidpi_scaling_; + + // Ratio between the framebuffer size and the window size. + // May be different from the hipdi scaling! + float pixel_ratio_; + + // ImGui Context + ImGuiContext * context_ = nullptr; + +public: + IGL_INLINE virtual void init(igl::opengl::glfw::Viewer *_viewer) override; + + IGL_INLINE virtual void reload_font(int font_size = 13); + + IGL_INLINE virtual void shutdown() override; + + IGL_INLINE virtual bool pre_draw() override; + + IGL_INLINE virtual bool post_draw() override; + + IGL_INLINE virtual void post_resize(int width, int height) override; + + // Mouse IO + IGL_INLINE virtual bool mouse_down(int button, int modifier) override; + + IGL_INLINE virtual bool mouse_up(int button, int modifier) override; + + IGL_INLINE virtual bool mouse_move(int mouse_x, int mouse_y) override; + + IGL_INLINE virtual bool mouse_scroll(float delta_y) override; + + // Keyboard IO + IGL_INLINE virtual bool key_pressed(unsigned int key, int modifiers) override; + + IGL_INLINE virtual bool key_down(int key, int modifiers) override; + + IGL_INLINE virtual bool key_up(int key, int modifiers) override; + + // Draw menu + IGL_INLINE virtual void draw_menu(); + + // Can be overwritten by `callback_draw_viewer_window` + IGL_INLINE virtual void draw_viewer_window(); + + // Can be overwritten by `callback_draw_viewer_menu` + IGL_INLINE virtual void draw_viewer_menu(); + + // Can be overwritten by `callback_draw_custom_window` + IGL_INLINE virtual void draw_custom_window() { } + + // Easy-to-customize callbacks + std::function callback_draw_viewer_window; + std::function callback_draw_viewer_menu; + std::function callback_draw_custom_window; + + IGL_INLINE void draw_text( + Eigen::Vector3d pos, + Eigen::Vector3d normal, + const std::string &text, + const Eigen::Vector4f color = Eigen::Vector4f(0,0,0.04,1)); // old default color + + IGL_INLINE float pixel_ratio(); + + IGL_INLINE float hidpi_scaling(); + + float menu_scaling() { return hidpi_scaling_ / pixel_ratio_; } +}; + +} // end namespace +} // end namespace +} // end namespace +} // end namespace + +#ifndef IGL_STATIC_LIBRARY +# include "ImGuiMenu.cpp" +#endif + +#endif // IGL_OPENGL_GLFW_IMGUI_IMGUIMENU_H diff --git a/src/external/libigl-2.3.0/include/igl/opengl/glfw/imgui/ImGuiTraits.h b/src/external/libigl-2.3.0/include/igl/opengl/glfw/imgui/ImGuiTraits.h new file mode 100644 index 000000000..7dae22a78 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/opengl/glfw/imgui/ImGuiTraits.h @@ -0,0 +1,69 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2018 Jérémie Dumas +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_OPENGL_GLFW_IMGUI_IMGUITRAITS_H +#define IGL_OPENGL_GLFW_IMGUI_IMGUITRAITS_H + +#include + +// Extend ImGui by populating its namespace directly +namespace ImGui +{ + +// Infer ImGuiDataType enum based on actual type +template +class ImGuiDataTypeTraits +{ + static const ImGuiDataType value; // link error + static const char * format; +}; + +template<> +class ImGuiDataTypeTraits +{ + static constexpr ImGuiDataType value = ImGuiDataType_S32; + static constexpr const char *format = "%d"; +}; + +template<> +class ImGuiDataTypeTraits +{ + static constexpr ImGuiDataType value = ImGuiDataType_U32; + static constexpr const char *format = "%u"; +}; + +template<> +class ImGuiDataTypeTraits +{ + static constexpr ImGuiDataType value = ImGuiDataType_S64; + static constexpr const char *format = "%lld"; +}; + +template<> +class ImGuiDataTypeTraits +{ + static constexpr ImGuiDataType value = ImGuiDataType_U64; + static constexpr const char *format = "%llu"; +}; + +template<> +class ImGuiDataTypeTraits +{ + static constexpr ImGuiDataType value = ImGuiDataType_Float; + static constexpr const char *format = "%.3f"; +}; + +template<> +class ImGuiDataTypeTraits +{ + static constexpr ImGuiDataType value = ImGuiDataType_Double; + static constexpr const char *format = "%.6f"; +}; + +} // namespace ImGui + +#endif // IGL_OPENGL_GLFW_IMGUI_IMGUIHELPERS_H diff --git a/src/external/libigl-2.3.0/include/igl/opengl/glfw/imgui/ImGuizmoPlugin.cpp b/src/external/libigl-2.3.0/include/igl/opengl/glfw/imgui/ImGuizmoPlugin.cpp new file mode 100644 index 000000000..245540f8e --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/opengl/glfw/imgui/ImGuizmoPlugin.cpp @@ -0,0 +1,51 @@ +#include "ImGuizmoPlugin.h" +#include +#include +#include +#include +#include + +namespace igl{ namespace opengl{ namespace glfw{ namespace imgui{ + +IGL_INLINE void ImGuizmoPlugin::init(igl::opengl::glfw::Viewer *_viewer) +{ + ImGuiMenu::init(_viewer); +} +IGL_INLINE bool ImGuizmoPlugin::pre_draw() +{ + if(!visible){ return false; } + ImGuiMenu::pre_draw(); + ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0); + ImGuizmo::BeginFrame(); + ImGui::PopStyleVar(); + return false; +} +IGL_INLINE bool ImGuizmoPlugin::post_draw() +{ + if(!visible){ return false; } + // Don't draw the Viewer's default menu: draw just the ImGuizmo + Eigen::Matrix4f view = (viewer->core().view / viewer->core().camera_zoom); + Eigen::Matrix4f proj = viewer->core().proj; + if(viewer->core().orthographic){ view(2,3) -= 1000;/* Hack depth */ } + // ImGuizmo doesn't like a lot of scaling in view, shift it to T + const float z = viewer->core().camera_base_zoom; + const Eigen::Matrix4f S = + (Eigen::Matrix4f()<< z,0,0,0, 0,z,0,0, 0,0,z,0, 0,0,0,1).finished(); + view = (view * S.inverse()).eval(); + const Eigen::Matrix4f T0 = T; + T = (S * T).eval(); + ImGuiIO& io = ImGui::GetIO(); + ImGuizmo::SetRect(0, 0, io.DisplaySize.x, io.DisplaySize.y); + ImGuizmo::Manipulate( + view.data(),proj.data(),operation,ImGuizmo::LOCAL,T.data(),NULL,NULL); + // invert scaling that was shifted onto T + T = (S.inverse() * T).eval(); + const float diff = (T-T0).array().abs().maxCoeff(); + // Only call if actually changed; otherwise, triggers on all mouse events + if( diff > 1e-7) { callback(T); } + ImGui::Render(); + ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); + return false; +} + +}}}} diff --git a/src/external/libigl-2.3.0/include/igl/opengl/glfw/imgui/ImGuizmoPlugin.h b/src/external/libigl-2.3.0/include/igl/opengl/glfw/imgui/ImGuizmoPlugin.h new file mode 100644 index 000000000..6df008d1a --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/opengl/glfw/imgui/ImGuizmoPlugin.h @@ -0,0 +1,39 @@ +#ifndef IGL_OPENGL_GFLW_IMGUI_IMGUIZMOPLUGIN_H +#define IGL_OPENGL_GFLW_IMGUI_IMGUIZMOPLUGIN_H +#include "../../../igl_inline.h" +#include "ImGuiMenu.h" +#include +#include +#include +#include + +namespace igl{ namespace opengl{ namespace glfw{ namespace imgui{ + +class ImGuizmoPlugin : public igl::opengl::glfw::imgui::ImGuiMenu +{ +public: + // callback(T) called when the stored transform T changes + std::function callback; + // Whether to display + bool visible = true; + // whether rotating, translating or scaling + ImGuizmo::OPERATION operation; + // stored transformation + Eigen::Matrix4f T; + // Initilize with rotate operation on an identity transform (at origin) + ImGuizmoPlugin():operation(ImGuizmo::ROTATE),T(Eigen::Matrix4f::Identity()){}; + ///////////////////////////////////////////////////////////////////////////// + // Boilerplate + virtual void init(igl::opengl::glfw::Viewer *_viewer) override; + virtual bool pre_draw() override; + ///////////////////////////////////////////////////////////////////////////// + virtual bool post_draw() override; +}; + +}}}} + +#ifndef IGL_STATIC_LIBRARY +# include "ImGuizmoPlugin.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/opengl/glfw/imgui/SelectionPlugin.cpp b/src/external/libigl-2.3.0/include/igl/opengl/glfw/imgui/SelectionPlugin.cpp new file mode 100644 index 000000000..4355e3545 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/opengl/glfw/imgui/SelectionPlugin.cpp @@ -0,0 +1,208 @@ +#include "SelectionPlugin.h" + +#include +#include +#include +#include +#include +#include "../../../PI.h" + +namespace igl{ namespace opengl{ namespace glfw{ namespace imgui{ + +IGL_INLINE void SelectionPlugin::init(igl::opengl::glfw::Viewer *_viewer) +{ + ImGuiMenu::init(_viewer); + std::cout<window, &fwidth, &fheight); + int iwidth, iheight; + glfwGetWindowSize(viewer->window, &iwidth, &iheight); + highdpi = float(iwidth)/float(fwidth); + // highdpi + width = (float)iwidth; + height = (float)iheight; + } + + ImGui::SetNextWindowPos( ImVec2(0,0) ); + ImGui::SetNextWindowSize(ImVec2(width,height), ImGuiCond_Always); + + ImGui::Begin("testing", nullptr, + ImGuiWindowFlags_NoBackground + | ImGuiWindowFlags_NoTitleBar + | ImGuiWindowFlags_NoResize + | ImGuiWindowFlags_NoMove + | ImGuiWindowFlags_NoScrollbar + | ImGuiWindowFlags_NoSavedSettings + | ImGuiWindowFlags_NoInputs); + + ImDrawList* list = ImGui::GetWindowDrawList(); + for(int pass = 0;pass<2;pass++) + { + for(auto & p : L) + { + list->PathLineTo({ highdpi*p(0),height-highdpi*p(1) }); + } + const bool closed = !(mode==LASSO || mode==POLYGONAL_LASSO) || !(is_down || is_drawing); + if(pass == 0) + { + list->PathStroke(IM_COL32(255, 255, 255, 255), closed, 2); + }else + { + list->PathStroke(IM_COL32(0, 0, 0, 255), closed, 1); + } + } + + ImGui::End(); + + ImGui::Render(); + ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); + + + return false; +} + +IGL_INLINE bool SelectionPlugin::mouse_down(int button, int modifier) +{ + if(mode == OFF){ return false;} + is_down = true; + has_moved_since_down = false; + if(!is_drawing) + { + L.clear(); + is_drawing = true; + } + M.row(0) = xy(viewer); + M.row(1) = M.row(0); + L.emplace_back(M.row(0)); + return true; +} + +IGL_INLINE bool SelectionPlugin::mouse_up(int button, int modifier) +{ + is_down = false; + // are we done? Check first and last lasso point (need at least 3 (2 real + // points + 1 mouse-mouse point)) + if(is_drawing && + (mode!=POLYGONAL_LASSO ||(L.size()>=3&&(L[0]-L[L.size()-1]).norm()<=10.0))) + { + if(callback){ callback();} + is_drawing = false; + } + return false; +} + +IGL_INLINE bool SelectionPlugin::mouse_move(int mouse_x, int mouse_y) +{ + if(!is_drawing){ return false; } + if(!has_moved_since_down) + { + if(mode == POLYGONAL_LASSO) { L.emplace_back(L[L.size()-1]); } + has_moved_since_down = true; + } + M.row(1) = xy(viewer); + switch(mode) + { + case RECTANGULAR_MARQUEE: + rect(M,L); + break; + case ELLIPTICAL_MARQUEE: + circle(M,L); + break; + case POLYGONAL_LASSO: + // Over write last point + L[L.size()-1] = xy(viewer); + break; + case LASSO: + L.emplace_back(xy(viewer)); + break; + default: assert(false); + } + return true; +} + +IGL_INLINE bool SelectionPlugin::key_pressed(unsigned int key, int modifiers) +{ + const auto clear = [&]() { M.setZero(); L.clear(); is_drawing = false; is_down = false; }; + if(OFF_KEY.find(char(key)) != std::string::npos) + { + mode = OFF; + return true; + } + if(LASSO_KEY.find(char(key)) != std::string::npos) + { + if(mode == LASSO) + { + mode = POLYGONAL_LASSO; + }else/*if(mode == POLYGONAL_LASSO)*/ + { + mode = LASSO; + } + clear(); + return true; + } + if(MARQUEE_KEY.find(char(key)) != std::string::npos) + { + if(mode == RECTANGULAR_MARQUEE) + { + mode = ELLIPTICAL_MARQUEE; + }else/*if(mode == ELLIPTICAL_MARQUEE)*/ + { + mode = RECTANGULAR_MARQUEE; + } + clear(); + return true; + } + return false; +} + +IGL_INLINE void SelectionPlugin::circle(const Eigen::Matrix & M, std::vector & L) +{ + L.clear(); + L.reserve(64); + const float r = (M.row(1)-M.row(0)).norm(); + for(float th = 0;th<2.*igl::PI;th+=0.1) + { + L.emplace_back(M(0,0)+r*cos(th),M(0,1)+r*sin(th)); + } +} + +IGL_INLINE void SelectionPlugin::rect(const Eigen::Matrix & M, std::vector & L) +{ + L.resize(4); + L[0] = Eigen::RowVector2f(M(0,0),M(0,1)); + L[1] = Eigen::RowVector2f(M(1,0),M(0,1)); + L[2] = Eigen::RowVector2f(M(1,0),M(1,1)); + L[3] = Eigen::RowVector2f(M(0,0),M(1,1)); +} + +IGL_INLINE Eigen::RowVector2f SelectionPlugin::xy(const Viewer * vr) +{ + return Eigen::RowVector2f( + vr->current_mouse_x, + vr->core().viewport(3) - vr->current_mouse_y); +} + + + +}}}} diff --git a/src/external/libigl-2.3.0/include/igl/opengl/glfw/imgui/SelectionPlugin.h b/src/external/libigl-2.3.0/include/igl/opengl/glfw/imgui/SelectionPlugin.h new file mode 100644 index 000000000..f7ecd4f7e --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/opengl/glfw/imgui/SelectionPlugin.h @@ -0,0 +1,64 @@ +#ifndef IGL_OPENGL_GFLW_IMGUI_IMGUIDRAWLISTPLUGIN_H +#define IGL_OPENGL_GFLW_IMGUI_IMGUIDRAWLISTPLUGIN_H +#include +#include +#include +#include +#include +#include +#include + +namespace igl{ namespace opengl{ namespace glfw{ namespace imgui{ + +class SelectionPlugin: public igl::opengl::glfw::imgui::ImGuiMenu +{ +public: + // callback called when slection is completed (usually on mouse_up) + std::function callback; + // whether rotating, translating or scaling + ImGuizmo::OPERATION operation; + // stored transformation + Eigen::Matrix4f T; + // Initilize with rotate operation on an identity transform (at origin) + SelectionPlugin():operation(ImGuizmo::ROTATE),T(Eigen::Matrix4f::Identity()){}; + IGL_INLINE virtual void init(igl::opengl::glfw::Viewer *_viewer) override; + IGL_INLINE virtual bool pre_draw() override; + IGL_INLINE virtual bool post_draw() override; + IGL_INLINE virtual bool mouse_down(int button, int modifier) override; + IGL_INLINE virtual bool mouse_up(int button, int modifier) override; + IGL_INLINE virtual bool mouse_move(int mouse_x, int mouse_y) override; + IGL_INLINE virtual bool key_pressed(unsigned int key, int modifiers) override; + // helpers + IGL_INLINE static void circle(const Eigen::Matrix & M, std::vector & L); + IGL_INLINE static void rect(const Eigen::Matrix & M, std::vector & L); + IGL_INLINE static Eigen::RowVector2f xy(const Viewer * v); + // customizable hotkeys + std::string MARQUEE_KEY = "Mm"; + // leave 'L' for show_lines in viewer + std::string LASSO_KEY = "l"; + std::string OFF_KEY = "Vv"; + enum Mode + { + OFF = 0, + RECTANGULAR_MARQUEE = 1, + ELLIPTICAL_MARQUEE = 2, + POLYGONAL_LASSO = 3, + LASSO = 4, + NUM_MODES = 5 + } mode = RECTANGULAR_MARQUEE; + bool visible = true; + bool is_down = false; + bool has_moved_since_down = false; + bool is_drawing = false; + // min and max corners of 2D rectangular marquee + Eigen::Matrix M = Eigen::Matrix::Zero(); + // list of points of 2D lasso marquee + std::vector L; +}; + +}}}} + +#ifndef IGL_STATIC_LIBRARY +#include "SelectionPlugin.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/opengl/glfw/map_texture.cpp b/src/external/libigl-2.3.0/include/igl/opengl/glfw/map_texture.cpp new file mode 100644 index 000000000..7975d87d4 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/opengl/glfw/map_texture.cpp @@ -0,0 +1,211 @@ +#ifdef IGL_OPENGL_4 + +#include "map_texture.h" +#include "background_window.h" +#include "../create_shader_program.h" + +#include "../gl.h" +#include + +#include +#include + +template +IGL_INLINE bool igl::opengl::glfw::map_texture( + const Eigen::MatrixBase & _V, + const Eigen::MatrixBase & _F, + const Eigen::MatrixBase & _U, + const unsigned char * in_data, + const int w, + const int h, + const int nc, + std::vector & out_data) +{ + int out_w = w; + int out_h = h; + int out_nc = nc; + return map_texture(_V,_F,_U,in_data,w,h,nc,out_data,out_w,out_h,out_nc); +} + + +template +IGL_INLINE bool igl::opengl::glfw::map_texture( + const Eigen::MatrixBase & _V, + const Eigen::MatrixBase & _F, + const Eigen::MatrixBase & _U, + const unsigned char * in_data, + const int w, + const int h, + const int nc, + std::vector & out_data, + int & out_w, + int & out_h, + int & out_nc) +{ + const auto fail = [](const std::string msg) + { + std::cerr< V = _V.template cast(); + Eigen::Matrix< + double, + DerivedU::RowsAtCompileTime, + DerivedU::ColsAtCompileTime, + Eigen::RowMajor> U = _U.template cast(); + Eigen::Matrix< + int, + DerivedF::RowsAtCompileTime, + DerivedF::ColsAtCompileTime, + Eigen::RowMajor> F = _F.template cast(); + const int dim = U.cols(); + GLFWwindow * window; + if(!background_window(window)) + { + fail("Could not initialize glfw window"); + } + + // Compile each shader + std::string vertex_shader = dim == 2 ? + R"( +#version 330 core +layout(location = 0) in vec2 position; +layout(location = 1) in vec2 tex_coord_v; +out vec2 tex_coord_f; +void main() +{ + tex_coord_f = vec2(tex_coord_v.x,1.-tex_coord_v.y); + gl_Position = vec4( 2.*position.x-1., 2.*(1.-position.y)-1., 0.,1.); +} +)" + : + R"( +#version 330 core +layout(location = 0) in vec3 position; +layout(location = 1) in vec2 tex_coord_v; +out vec2 tex_coord_f; +void main() +{ + tex_coord_f = vec2(tex_coord_v.x,1.-tex_coord_v.y); + gl_Position = vec4( 2.*position.x-1., 2.*(1.-position.y)-1., position.z,1.); +} +)" + ; + std::string fragment_shader = R"( +#version 330 core +layout(location = 0) out vec3 color; +uniform sampler2D tex; +in vec2 tex_coord_f; +void main() +{ + color = texture(tex,tex_coord_f).rgb; +} +)"; + GLuint prog_id = + igl::opengl::create_shader_program(vertex_shader,fragment_shader,{}); + glUniform1i(glGetUniformLocation(prog_id, "tex"),0); + // Generate and attach buffers to vertex array + glDisable(GL_CULL_FACE); + GLuint VAO = 0; + glGenVertexArrays(1,&VAO); + glBindVertexArray(VAO); + GLuint ibo,vbo,tbo; + glGenBuffers(1,&ibo); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint)*F.size(), F.data(), GL_STATIC_DRAW); + glGenBuffers(1,&vbo); + glEnableVertexAttribArray(0); + glBindBuffer(GL_ARRAY_BUFFER,vbo); + glBufferData(GL_ARRAY_BUFFER, sizeof(double)*U.size(), U.data(), GL_STATIC_DRAW); + glVertexAttribLPointer(0, U.cols(), GL_DOUBLE, U.cols() * sizeof(GLdouble), (GLvoid*)0); + glGenBuffers(1,&tbo); + glEnableVertexAttribArray(1); + glBindBuffer(GL_ARRAY_BUFFER,tbo); + glBufferData(GL_ARRAY_BUFFER, sizeof(double)*V.size(), V.data(), GL_STATIC_DRAW); + glVertexAttribLPointer(1, V.cols(), GL_DOUBLE, V.cols() * sizeof(GLdouble), (GLvoid*)0); + glBindVertexArray(0); + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindVertexArray(0); + // Prepare texture + GLuint in_tex; + GLenum format; + { + format = nc==1 ? GL_RED : (nc==3 ? GL_RGB : (nc == 4 ? GL_RGBA : GL_FALSE)); + glGenTextures(1, &in_tex); + glBindTexture(GL_TEXTURE_2D, in_tex); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + glTexImage2D(GL_TEXTURE_2D, 0,GL_RGB, w, h, 0,format, GL_UNSIGNED_BYTE, in_data); + } + // Prepare framebuffer + GLuint fb = 0; + glGenFramebuffers(1, &fb); + glBindFramebuffer(GL_FRAMEBUFFER, fb); + GLuint out_tex; + glGenTextures(1, &out_tex); + glBindTexture(GL_TEXTURE_2D, out_tex); + // always use float for internal storage + assert(out_nc == 3); + glTexImage2D(GL_TEXTURE_2D, 0,GL_RGB, out_w, out_h, 0,GL_RGB, GL_FLOAT, 0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, out_tex, 0); + { + GLenum bufs[1] = {GL_COLOR_ATTACHMENT0}; + glDrawBuffers(1, bufs); + } + if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) + { + fail("framebuffer setup failed."); + } + glBindFramebuffer(GL_FRAMEBUFFER, fb); + // clear screen and set viewport + glClearColor(0.0,1.0,0.0,0.); + glClear(GL_COLOR_BUFFER_BIT); + glViewport(0,0,out_w,out_h); + // Attach shader program + glUseProgram(prog_id); + glActiveTexture(GL_TEXTURE0 + 0); + glBindTexture(GL_TEXTURE_2D, in_tex); + // Draw mesh as wireframe + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + glBindVertexArray(VAO); + glDrawElements(GL_TRIANGLES, F.size(), GL_UNSIGNED_INT, 0); + glBindVertexArray(0); + // Write into memory + assert(out_nc == 3); + out_data.resize(out_nc*out_w*out_h); + glBindTexture(GL_TEXTURE_2D, out_tex); + glGetTexImage(GL_TEXTURE_2D, 0, format, GL_UNSIGNED_BYTE, &out_data[0]); + // OpenGL cleanup + glDeleteBuffers(1,&fb); + glDeleteBuffers(1,&ibo); + glDeleteBuffers(1,&vbo); + glDeleteBuffers(1,&tbo); + glDeleteTextures(1,&in_tex); + glDeleteTextures(1,&out_tex); + glDeleteVertexArrays(1,&VAO); + glUseProgram(0); + glDeleteProgram(prog_id); + // GLFW cleanup + glfwDestroyWindow(window); + glfwTerminate(); + return true; +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template bool igl::opengl::glfw::map_texture, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, unsigned char const*, int, int, int, std::vector >&); +#endif + +#endif // IGL_OPENGL_4 diff --git a/src/external/libigl-2.3.0/include/igl/opengl/glfw/map_texture.h b/src/external/libigl-2.3.0/include/igl/opengl/glfw/map_texture.h new file mode 100644 index 000000000..ee3b30a45 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/opengl/glfw/map_texture.h @@ -0,0 +1,63 @@ +#ifndef IGL_OPENGL_GLFW_MAP_TEXTURE_H +#define IGL_OPENGL_GLFW_MAP_TEXTURE_H + +#ifdef IGL_OPENGL_4 + +#include "../../igl_inline.h" +#include +#include + +namespace igl +{ + namespace opengl + { + namespace glfw + { + // Given a mesh (V,F) in [0,1]² and new positions (U) and a texture image + // (in_data), _render_ a new image (out_data) of the same size. + // Inputs: + // V #V by 2 list of undeformed mesh vertex positions (matching texture) + // F #F by 3 list of mesh triangle indices into V + // U #U by 2 list of deformed vertex positions + // in_data w*h*nc array of color values, channels, then columns, then + // rows (e.g., what stbi_image returns and expects) + // w width + // h height + // nc number of channels + // Outputs: + // out_data h*w*nc list of output colors in same order as input + // + template + IGL_INLINE bool map_texture( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const Eigen::MatrixBase & U, + const unsigned char * in_data, + const int w, + const int h, + const int nc, + std::vector & out_data); + template + IGL_INLINE bool map_texture( + const Eigen::MatrixBase & _V, + const Eigen::MatrixBase & _F, + const Eigen::MatrixBase & _U, + const unsigned char * in_data, + const int w, + const int h, + const int nc, + std::vector & out_data, + int & out_w, + int & out_h, + int & out_nc); + } + } +} + +#ifndef IGL_STATIC_LIBRARY +# include "map_texture.cpp" +#endif + +#endif // IGL_OPENGL_4 + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/opengl/init_render_to_texture.cpp b/src/external/libigl-2.3.0/include/igl/opengl/init_render_to_texture.cpp new file mode 100644 index 000000000..7fbcfea10 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/opengl/init_render_to_texture.cpp @@ -0,0 +1,86 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "init_render_to_texture.h" +#include "gl.h" +#include + +IGL_INLINE void igl::opengl::init_render_to_texture( + const size_t width, + const size_t height, + const bool depth_texture, + GLuint & tex_id, + GLuint & fbo_id, + GLuint & d_id) +{ + using namespace std; + // http://www.opengl.org/wiki/Framebuffer_Object_Examples#Quick_example.2C_render_to_texture_.282D.29 + const auto & gen_tex = [](GLuint & tex_id) + { + glGenTextures(1, &tex_id); + glBindTexture(GL_TEXTURE_2D, tex_id); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + }; + gen_tex(tex_id); + //NULL means reserve texture memory, but texels are undefined + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, width, height, 0, GL_BGRA, GL_FLOAT, NULL); + glBindTexture(GL_TEXTURE_2D, 0); + + glGenFramebuffers(1, &fbo_id); + glBindFramebuffer(GL_FRAMEBUFFER, fbo_id); + //Attach 2D texture to this FBO + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex_id, 0); + if(depth_texture) + { + // Generate a depth texture + gen_tex(d_id); + glTexImage2D( + GL_TEXTURE_2D, + 0, + GL_DEPTH_COMPONENT32, + width, + height, + 0, + GL_DEPTH_COMPONENT, + GL_FLOAT, + NULL); + glFramebufferTexture2D( + GL_FRAMEBUFFER,GL_DEPTH_ATTACHMENT,GL_TEXTURE_2D,d_id,0); + }else + { + // Attach a depth buffer + glGenRenderbuffers(1, &d_id); + glBindRenderbuffer(GL_RENDERBUFFER, d_id); + glRenderbufferStorage(GL_RENDERBUFFER,GL_DEPTH_COMPONENT24,width,height); + glFramebufferRenderbuffer( + GL_FRAMEBUFFER,GL_DEPTH_ATTACHMENT,GL_RENDERBUFFER,d_id); + } + + //Does the GPU support current FBO configuration? + GLenum status; + status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + assert(status == GL_FRAMEBUFFER_COMPLETE); + // Unbind to clean up + if(!depth_texture) + { + glBindRenderbuffer(GL_RENDERBUFFER, 0); + } + glBindFramebuffer(GL_FRAMEBUFFER, 0); +} + +IGL_INLINE void igl::opengl::init_render_to_texture( + const size_t width, + const size_t height, + GLuint & tex_id, + GLuint & fbo_id, + GLuint & dfbo_id) +{ + return init_render_to_texture(width,height,false,tex_id,fbo_id,dfbo_id); +} diff --git a/src/external/libigl-2.3.0/include/igl/opengl/init_render_to_texture.h b/src/external/libigl-2.3.0/include/igl/opengl/init_render_to_texture.h new file mode 100644 index 000000000..ae854e770 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/opengl/init_render_to_texture.h @@ -0,0 +1,77 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_OPENGL_INIT_RENDER_TO_TEXTURE_H +#define IGL_OPENGL_INIT_RENDER_TO_TEXTURE_H +#include "../igl_inline.h" +#include "gl.h" +#include +namespace igl +{ + namespace opengl + { + // Create a frame buffer that renders color to a RGBA texture a depth to a + // "render buffer". + // + // After calling this, you can use with something like: + // + // glBindFramebuffer(GL_FRAMEBUFFER, fbo_id); + // if(!depth_texture) + // { + // glBindRenderbuffer(GL_RENDERBUFFER, d_id); + // } + // // + // // draw scene ... + // // + // // clean up + // glBindFramebuffer(GL_FRAMEBUFFER,0); + // if(!depth_texture) + // { + // glBindRenderbuffer(GL_RENDERBUFFER, 0); + // } + // // Later ... + // glActiveTexture(GL_TEXTURE0+0); + // glBindTexture(GL_TEXTURE_2D,tex_id); + // if(depth_texture) + // { + // glActiveTexture(GL_TEXTURE0+1); + // glBindTexture(GL_TEXTURE_2D,d_id); + // } + // // draw textures + // + // + // + // Inputs: + // width image width + // height image height + // depth_texture whether to create a texture for depth or to create a + // render buffer for depth + // Outputs: + // tex_id id of the texture + // fbo_id id of the frame buffer object + // d_id id of the depth texture or frame buffer object + // + IGL_INLINE void init_render_to_texture( + const size_t width, + const size_t height, + const bool depth_texture, + GLuint & tex_id, + GLuint & fbo_id, + GLuint & d_id); + // Wrapper with depth_texture = false for legacy reasons + IGL_INLINE void init_render_to_texture( + const size_t width, + const size_t height, + GLuint & tex_id, + GLuint & fbo_id, + GLuint & dfbo_id); + } +} +#ifndef IGL_STATIC_LIBRARY +# include "init_render_to_texture.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/opengl/load_shader.cpp b/src/external/libigl-2.3.0/include/igl/opengl/load_shader.cpp new file mode 100644 index 000000000..0ee0a978f --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/opengl/load_shader.cpp @@ -0,0 +1,34 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "load_shader.h" + +// Copyright Denis Kovacs 4/10/08 +#include "print_shader_info_log.h" +#include +IGL_INLINE GLuint igl::opengl::load_shader( + const std::string & src,const GLenum type) +{ + if(src.empty()) + { + return (GLuint) 0; + } + + GLuint s = glCreateShader(type); + if(s == 0) + { + fprintf(stderr,"Error: load_shader() failed to create shader.\n"); + return 0; + } + // Pass shader source string + const char *c = src.c_str(); + glShaderSource(s, 1, &c, NULL); + glCompileShader(s); + // Print info log (if any) + igl::opengl::print_shader_info_log(s); + return s; +} diff --git a/src/external/libigl-2.3.0/include/igl/opengl/load_shader.h b/src/external/libigl-2.3.0/include/igl/opengl/load_shader.h new file mode 100644 index 000000000..6c234d8fc --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/opengl/load_shader.h @@ -0,0 +1,38 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_OPENGL_LOAD_SHADER_H +#define IGL_OPENGL_LOAD_SHADER_H +#include "../igl_inline.h" +#include "gl.h" +#include + +namespace igl +{ + namespace opengl + { + // Creates and compiles a shader from a given string + // + // Inputs: + // src string containing GLSL shader code + // type GLSL type of shader, one of: + // GL_VERTEX_SHADER + // GL_FRAGMENT_SHADER + // GL_GEOMETRY_SHADER + // Returns index id of the newly created shader, 0 on error + // + // Will immediately return 0 if src is empty. + IGL_INLINE GLuint load_shader( + const std::string & src,const GLenum type); + } +} + +#ifndef IGL_STATIC_LIBRARY +# include "load_shader.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/opengl/print_program_info_log.cpp b/src/external/libigl-2.3.0/include/igl/opengl/print_program_info_log.cpp new file mode 100644 index 000000000..41b37b7fb --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/opengl/print_program_info_log.cpp @@ -0,0 +1,28 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "print_program_info_log.h" + +#include +#include +// Copyright Denis Kovacs 4/10/08 +IGL_INLINE void igl::opengl::print_program_info_log(const GLuint obj) +{ + GLint infologLength = 0; + GLint charsWritten = 0; + char *infoLog; + + glGetProgramiv(obj, GL_INFO_LOG_LENGTH,&infologLength); + + if (infologLength > 0) + { + infoLog = (char *)malloc(infologLength); + glGetProgramInfoLog(obj, infologLength, &charsWritten, infoLog); + printf("%s\n",infoLog); + free(infoLog); + } +} diff --git a/src/external/libigl-2.3.0/include/igl/opengl/print_program_info_log.h b/src/external/libigl-2.3.0/include/igl/opengl/print_program_info_log.h new file mode 100644 index 000000000..43bcc0974 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/opengl/print_program_info_log.h @@ -0,0 +1,27 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_OPENGL_PRINT_PROGRAM_INFO_LOG_H +#define IGL_OPENGL_PRINT_PROGRAM_INFO_LOG_H +#include "../igl_inline.h" +#include "gl.h" + +namespace igl +{ + namespace opengl + { + // Inputs: + // obj OpenGL index of program to print info log about + IGL_INLINE void print_program_info_log(const GLuint obj); + } +} + +#ifndef IGL_STATIC_LIBRARY +# include "print_program_info_log.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/opengl/print_shader_info_log.cpp b/src/external/libigl-2.3.0/include/igl/opengl/print_shader_info_log.cpp new file mode 100644 index 000000000..2d3554387 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/opengl/print_shader_info_log.cpp @@ -0,0 +1,29 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "print_shader_info_log.h" + +#include +#include +// Copyright Denis Kovacs 4/10/08 +IGL_INLINE void igl::opengl::print_shader_info_log(const GLuint obj) +{ + GLint infologLength = 0; + GLint charsWritten = 0; + char *infoLog; + + // Get shader info log from opengl + glGetShaderiv(obj, GL_INFO_LOG_LENGTH,&infologLength); + // Only print if there is something in the log + if (infologLength > 0) + { + infoLog = (char *)malloc(infologLength); + glGetShaderInfoLog(obj, infologLength, &charsWritten, infoLog); + printf("%s\n",infoLog); + free(infoLog); + } +} diff --git a/src/external/libigl-2.3.0/include/igl/opengl/print_shader_info_log.h b/src/external/libigl-2.3.0/include/igl/opengl/print_shader_info_log.h new file mode 100644 index 000000000..5a571fb11 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/opengl/print_shader_info_log.h @@ -0,0 +1,27 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_OPENGL_PRINT_SHADER_INFO_LOG_H +#define IGL_OPENGL_PRINT_SHADER_INFO_LOG_H +#include "../igl_inline.h" +#include "gl.h" + +namespace igl +{ + namespace opengl + { + // Inputs: + // obj OpenGL index of shader to print info log about + IGL_INLINE void print_shader_info_log(const GLuint obj); + } +} + +#ifndef IGL_STATIC_LIBRARY +# include "print_shader_info_log.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/opengl/report_gl_error.cpp b/src/external/libigl-2.3.0/include/igl/opengl/report_gl_error.cpp new file mode 100644 index 000000000..2dcc0b632 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/opengl/report_gl_error.cpp @@ -0,0 +1,61 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "report_gl_error.h" +#include "../verbose.h" +#include + +IGL_INLINE GLenum igl::opengl::report_gl_error(const std::string id) +{ + // http://stackoverflow.com/q/28485180/148668 + + // gluErrorString was deprecated + const auto gluErrorString = [](GLenum errorCode)->const char * + { + switch(errorCode) + { + default: + return "unknown error code"; + case GL_NO_ERROR: + return "no error"; + case GL_INVALID_ENUM: + return "invalid enumerant"; + case GL_INVALID_VALUE: + return "invalid value"; + case GL_INVALID_OPERATION: + return "invalid operation"; +#ifndef GL_VERSION_3_0 + case GL_STACK_OVERFLOW: + return "stack overflow"; + case GL_STACK_UNDERFLOW: + return "stack underflow"; + case GL_TABLE_TOO_LARGE: + return "table too large"; +#endif + case GL_OUT_OF_MEMORY: + return "out of memory"; +#ifdef GL_EXT_framebuffer_object + case GL_INVALID_FRAMEBUFFER_OPERATION_EXT: + return "invalid framebuffer operation"; +#endif + } + }; + + GLenum err = glGetError(); + if(GL_NO_ERROR != err) + { + verbose("GL_ERROR: "); + fprintf(stderr,"%s%s\n",id.c_str(),gluErrorString(err)); + } + return err; +} + +IGL_INLINE GLenum igl::opengl::report_gl_error() +{ + return igl::opengl::report_gl_error(std::string("")); +} + diff --git a/src/external/libigl-2.3.0/include/igl/opengl/report_gl_error.h b/src/external/libigl-2.3.0/include/igl/opengl/report_gl_error.h new file mode 100644 index 000000000..70e5c7d74 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/opengl/report_gl_error.h @@ -0,0 +1,36 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_OPENGL_REPORT_GL_ERROR_H +#define IGL_OPENGL_REPORT_GL_ERROR_H +#include "../igl_inline.h" + +// Hack to allow both opengl/ and opengl2 to use this (we shouldn't allow this) +#ifndef __gl_h_ +# include "gl.h" +#endif +#include + +namespace igl +{ + namespace opengl + { + // Print last OpenGL error to stderr prefixed by specified id string + // Inputs: + // id string to appear before any error msgs + // Returns result of glGetError() + IGL_INLINE GLenum report_gl_error(const std::string id); + // No prefix + IGL_INLINE GLenum report_gl_error(); + } +} + +#ifndef IGL_STATIC_LIBRARY +# include "report_gl_error.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/opengl/uniform_type_to_string.cpp b/src/external/libigl-2.3.0/include/igl/opengl/uniform_type_to_string.cpp new file mode 100644 index 000000000..b2f9a2fdb --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/opengl/uniform_type_to_string.cpp @@ -0,0 +1,71 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "uniform_type_to_string.h" + +IGL_INLINE std::string igl::opengl::uniform_type_to_string(const GLenum type) +{ + switch(type) + { + case GL_FLOAT: + return "GL_FLOAT"; + case GL_FLOAT_VEC2: + return "GL_FLOAT_VEC2"; + case GL_FLOAT_VEC3: + return "GL_FLOAT_VEC3"; + case GL_FLOAT_VEC4: + return "GL_FLOAT_VEC4"; + case GL_INT: + return "GL_INT"; + case GL_INT_VEC2: + return "GL_INT_VEC2"; + case GL_INT_VEC3: + return "GL_INT_VEC3"; + case GL_INT_VEC4: + return "GL_INT_VEC4"; + case GL_BOOL: + return "GL_BOOL"; + case GL_BOOL_VEC2: + return "GL_BOOL_VEC2"; + case GL_BOOL_VEC3: + return "GL_BOOL_VEC3"; + case GL_BOOL_VEC4: + return "GL_BOOL_VEC4"; + case GL_FLOAT_MAT2: + return "GL_FLOAT_MAT2"; + case GL_FLOAT_MAT3: + return "GL_FLOAT_MAT3"; + case GL_FLOAT_MAT4: + return "GL_FLOAT_MAT4"; + case GL_FLOAT_MAT2x3: + return "GL_FLOAT_MAT2x3"; + case GL_FLOAT_MAT2x4: + return "GL_FLOAT_MAT2x4"; + case GL_FLOAT_MAT3x2: + return "GL_FLOAT_MAT3x2"; + case GL_FLOAT_MAT3x4: + return "GL_FLOAT_MAT3x4"; + case GL_FLOAT_MAT4x2: + return "GL_FLOAT_MAT4x2"; + case GL_FLOAT_MAT4x3: + return "GL_FLOAT_MAT4x3"; + case GL_SAMPLER_1D: + return "GL_SAMPLER_1D"; + case GL_SAMPLER_2D: + return "GL_SAMPLER_2D"; + case GL_SAMPLER_3D: + return "GL_SAMPLER_3D"; + case GL_SAMPLER_CUBE: + return "GL_SAMPLER_CUBE"; + case GL_SAMPLER_1D_SHADOW: + return "GL_SAMPLER_1D_SHADOW"; + case GL_SAMPLER_2D_SHADOW: + return "GL_SAMPLER_2D_SHADOW"; + default: + return "UNKNOWN_TYPE"; + } +} diff --git a/src/external/libigl-2.3.0/include/igl/opengl/uniform_type_to_string.h b/src/external/libigl-2.3.0/include/igl/opengl/uniform_type_to_string.h new file mode 100644 index 000000000..ed0a93e90 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/opengl/uniform_type_to_string.h @@ -0,0 +1,31 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_OPENGL_UNIFORM_TYPE_TO_STRING_H +#define IGL_OPENGL_UNIFORM_TYPE_TO_STRING_H +#include "../igl_inline.h" +#include "gl.h" +#include + +namespace igl +{ + namespace opengl + { + // Convert a GL uniform variable type (say, returned from + // glGetActiveUniform) and output a string naming that type + // Inputs: + // type enum for given type + // Returns string name of that type + IGL_INLINE std::string uniform_type_to_string(const GLenum type); + } +} + +#ifndef IGL_STATIC_LIBRARY +# include "uniform_type_to_string.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/opengl/verasansmono_compressed.cpp b/src/external/libigl-2.3.0/include/igl/opengl/verasansmono_compressed.cpp new file mode 100644 index 000000000..65111157d --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/opengl/verasansmono_compressed.cpp @@ -0,0 +1,67 @@ +#include "verasansmono_compressed.h" + +#include +#include +#include + +namespace igl +{ +namespace opengl +{ + +// The string below is a compression of a 256x256x256 font atlas where each pixel's grayscale value is represented by a byte. +// Source font atlas: https://github.com/prideout/recipes/blob/master/verasansmono.png +// The compression below is a pair: hex_value_of_pixel-recurrence_in_hex. If recurrence_in_hex==1, +// it was not appended to the pair and only the pixel value constitutes the item in the list. +// The method below can be used to recover the original format. +// For example, 0-d1e compresses to 3358 neighbouring pixels with value 0x00. +static char verasansmono_compressed_atlas[] = "0-d1e,66-4,0-4,66-4,0-17,44-2,0-8,44-2,0-9,22,66,0-18,1b,46,66,22,0-7,11,5d,1a,0-2,1b,46,66,22,0-4,24,55,5c,30,0-92,72-2,81,a0,0-4,72-2,81,a0,0-17,4c-2,0-8,6b-2,0-3,33,9a,0-4,35,a0,0-18,8e,7d,a0,35,0-6,4,5a,6e,b,0-2,8e,7d,a0,35,0-2,1,31,97,83,75,86,0-94,35,a0,0-6,35,a0,0-21,6b-2,0-3,35,a0,0-4,35,a0,0-18,2d,11,a0,35,0-6,1e,89,2f,0-3,2d,11,a0,35,0-2,e,75,77,1a,5,1f,0-83,12,63,8b-2,5c,0-3,13,67,8e,86,4a,3,0-3,35,a0,0-6,35,a0,0-c,84,49,0-4,49,84,0,64,97-2,64,0-3,1,1f,7a,92,57,77,6b,0,32,97,9a,a0,97-2,64,0,35,a0,2d,7a,90,64,8,0-4,1d-2,0-f,a0,35,0-6,5c,78,1,0-5,a0,35,0-2,27,92,32,0-85,b,66,8b,53,48,71,0-2,b,66,7a,48,5d,92,2a,0-3,35,a0,0-6,35,a0,0-c,6d,6e,0-4,6e,6c,0,2b,41,80,6b,0-3,10,73,7f,49,64,95,6b,0,15,41,61,a0,41-2,2b,0,35,a0,6c,4b,5e,97,3a,0-4,6b-2,0-f,a0,35,0-5,10,8e,38,0-6,a0,35,0-2,31,9c,25,4e,53,24,0-82,28,93,2d,3,1,6,0-2,28,92,3a,29,2e,7e,5e,0-3,35,a0,0-6,35,a0,0-c,46,92,5,5d,5c,4,93,46,0-3,6b-2,0-3,2b,95,22,1,13,7c,6b,0-3,35,a0,0-4,35,a0,21,1,9,73,62,0-4,50-2,0-f,a0,35,0-4,3,56,70,c,0-6,a0,35,0-2,35,9f,69,79,85,93,1e,0-81,33,9e,6,0-5,33,9e,9f-2,a0-2,6a,0-3,35,a0,0-6,35,a0,0-c,2d,97,29,6e-2,29,97,2c,0-3,6b-2,0-3,33,9e,4,0,2,6d,6b,0-3,35,a0,0-4,35,a0,3,0-2,6b,6a,0-15,a0,35,0-4,1d,88,32,0-7,a0,35,0-2,32,9d,33,5,1d,81,57,0-81,30,9a,13,0-5,2f,98,17,10-3,a,0-3,35,9f,2,0-5,35,9f,2,0-b,19,84,68,59-2,67,83,18,0-3,6b-2,0-3,30,9b,e,0,7,72,6b,0-3,35,a0,1,0-3,35,a0,0-3,6b-2,0-15,a0,35,0-4,58,7a,3,0-7,a0,35,0-2,28,92,8,0,3,6e,66,0-81,1c,86,5c,11,6,2c,0-2,1a,85,4f,10,4,1b,2e,0-3,2d,98,26,1,0-4,2d,98,26,1,0-a,8,72,94,3d,3f,94,71,8,0-3,6b-2,0-3,1f,8a,4a,8,30,8d,6b,0-3,31,9c,1e,1,0-2,35,a0,0-3,6b-2,0-4,3c-2,0-f,a0,35,0-3,f,8d,3a,0-8,a0,35,0-2,14,7f,3d,6,23,84,52,0-81,2,3d,8c,8e,8b,84,0-2,2,38,89,8d-2,89,57,0-3,10,6c,91,8e,5e,0-3,10,6c,91,8e,5e,0-a,53,8d,23-2,8e,53,0,2f,8e-2,9a-2,8e-2,2f,4,4e,90,8e,77,88,6b,0-3,19,79,90,8e,5e,0,35,a0,0-3,6b-2,0-4,6b-2,0-d,8e-2,a0,93,8e,2f,3,53,73,e,0-6,8e-2,a0,93,8e,2f,1,3b,8b,8d,8f,84,13,0-83,27,43-2,22,0-4,23,41,46,33,b,0-4,12,41,49,31,0-4,12,41,49,31,0-a,1c,3b,9,a,3b,1c,0,18,4a-6,18,0,4,36,46,21,32,31,0-3,1,1b,43,49,31,0,18,4a,0-3,31-2,0-4,31-2,0-d,4a-5,18,1c,86,33,0-7,4a-5,18,0,1,2c,45,3f,19,0-ea,6,13,4,0-5a5,15-4,0-4,15-4,0-c,7,15,0-11,e-2,0-b,7,15,0-22,d,6,0-2,1,9,12,15,10,5,0-4,d,14,10,3,0-4,d,14,10,3,0-7,4,14,6,1,9,12,15,10,5,0-3,3,10,15,12,8,0-6,e,15,0-4,6,d,0-9,4,14,6,0-2,8,12,13,a,0-52,a0-4,0-4,a0-4,0-c,35,a0,0-11,6b-2,0-b,35,a0,0-8,18,4a,0-17,4,6d,21,0-2,1e,6e,93,9d,8a,5a,8,0-2,1b,7c,9a,88,3f,0-3,1b,7c,9a,88,3f,0-7,33,86,1c,1e,6e,93,9d,8a,5a,8,0,6,43,8c,9d,92,68,d,0-4,6,83,a0,0-4,21,6d,4,0-8,33,86,1c,0,e,68,92,98,72,0-52,22-2,4c,a0,0-4,22-2,4c,a0,0-c,35,a0,0-11,17-2,0-b,35,a0,0-8,35,a0,0-17,32,6c,7,0-2,28,5d,30,25,4d,90,43,0,9,68,7b,30,61,92,10,0,9,68,7b,30,61,92,10,0-5,e,73,53,3,28,5d,30,25,4d,90,43,0,26,90,59,28,44,8e,4b,0-3,2,42,81,a0,0-4,7,6d,33,0-7,e,73,53,3,4,58,90,4c,2a,57,0-44,25,3f-2,20,0-3,1,28,41,3c,16,0-4,35,a0,0-6,35,a0,0-c,35,a0,b,34,43,26,0-3,1,28,41,3c,16,0-3,2f,47-2,2f,0-4,4,33,43,20,30,2f,0,35,a0,b,34,43,26,0-2,18,47,64,a0,47-2,2f,0-13,7,6d,44,0-7,5,70,65,0,21,8b,2f,0,18,83,41,0,21,8b,2f,0,18,83,41,0-5,3a,8d,f,0-5,5,70,65,0,32,9d,8,0,4,6f,64,0-3,1c,75,40,a0,0-5,45,6d,7,0-6,3a,8d,f,0,1c,87,50,2,0-44,2,3a,8b,90,8e,84,0-2,2,3a,89,8f,90,7e,d,0-3,35,a0,0-6,35,a0,0-c,35,a0,58,88,93,8d,1c,0,2,3a,89,8f,90,7e,d,0-2,61,90,9b,6b,0-3,3,4b,91,90,77,88,6b,0,35,a0,58,88,93,8d,1c,0,30,90,96,a0,90-2,61,0-4,52-2,0-d,1c,86,24,0-5,5,10,35,85,3f,0,2e,99,e,8,10,72,5c,0,2e,99,e,8,10,72,5c,0-4,3,7a,58,0-4,5,10,35,85,3f,0,1b,7f,44,15,30,82,35,0-2,1,58,4a,35,a0,0-5,24,86,1c,0-5,3,7a,58,0-2,2d,97,23,d,e,6,0-42,1b,86,5d,12,8,2e,0-2,1a,85,3f,8,1e,81,4c,0-3,35,a0,0-6,35,a0,0-c,35,a0,4d,a,20,84,56,0,1a,85,3f,8,1e,81,4c,0-4,6b-2,0-3,1f,89,4e,9,2f,8d,6b,0,35,a0,4d,a,20,84,56,0-3,35,a0,0-7,6b-2,0-d,2d,97,c,0-5,35,a0,9d,67,1,0,34,9f,2,53-2,6c,68,0,34,9f,2,53-2,6c,68,0-4,32,88,1d,0-4,35,a0,9d,67,1,0-2,30,97,a0,9b,5f,0-3,1d,78,14,35,a0,0-5,d,97,2d,0-5,32,88,1d,0-2,34,9f,4b,90,95,65,8,0-41,2f,9a,13,0-5,2f,9a,7b,77,79,94,66,0-3,35,a0,0-6,35,a0,0-c,35,a0,d,0,3,6d,68,0,2f,9a,7b,77,79,94,66,0-4,6b-2,0-3,30,9b,e,0,7,72,6b,0,35,a0,d,0,3,6d,68,0-3,35,a0,0-7,1a-2,0-d,33,9e,3,0-5,d,29,55,87,24,0,33,9e,3,15,17,6d,66,0,33,9e,3,15,17,6d,66,0-3,c,70,56,3,0-4,d,29,55,87,24,0,12,70,66,30,51,87,26,0,9,66,41,1,35,a0,0-5,3,9e,33,0-4,c,70,56,3,0-2,34,9f,5d,30,4f,93,3c,0-41,33,9e,6,0-5,33,9d,60,5f-3,3f,0-3,35,a0,0-6,35,a0,0-c,35,a0,0-3,6b-2,0,33,9d,60,5f-3,3f,0-4,6b-2,0-3,33,9e,4,0,2,6d,6b,0,35,a0,0-3,6b-2,0-3,35,a0,0-16,33,9d,4,0-7,7,72,5f,0,2d,97,12,0,9,74,58,0,2d,97,12,0,9,74,58,0-3,38,8e,10,0-7,7,72,5f,0,30,9a,b,0,6,70,5f,0,2d,93,44,41,61,a0,41,15,0-3,4,9d,33,0-4,38,8e,10,0-3,2e,98,c,0,5,70,64,0-41,29,93,2b,2,1,4,0-2,28,92,1c,2,1,3,5,0-3,33,9d,8,0-5,33,9d,8,0-b,35,a0,0-3,6b-2,0,28,92,1c,2,1,3,5,0-4,6b-2,0-3,2b,95,22,1,11,7a,6b,0,35,a0,0-3,6b-2,0-3,34,9f,5,0-6,6-2,0-d,2b,95,f,0-3,3,5,1-2,d,76,63,0,1d,88,38,1,1e,87,3a,0,1d,88,38,1,1e,87,3a,0-2,1,78,5c,0-4,3,5,1-2,d,76,63,0,32,9d,12,1,a,73,63,0,32,97-3,9a,a0,97,32,0-3,10,95,2b,0-3,1,78,5c,0-4,20,8b,13,1,9,73,61,0-41,b,68,8b,50,45,6e,0-2,a,64,86,4e,43,5b,5c,0-3,1f,8a,63,3f,29,0-3,1f,8a,63,3f,29,0-9,35,a0,0-3,6b-2,0,a,64,86,4e,43,5b,5c,0,15,3d-2,7f-2,3d-2,15,f,73,81,47,60,94,6b,0,35,a0,0-3,6b-2,0-3,28,92,5d,3f,29,0-4,6b-2,0-d,18,83,29,0-3,2e,70,46,42,6f,97,2e,0,5,5d,88,4a,73,8c,9,0,5,5d,88,4a,73,8c,9,0-2,2f,89,1e,0-4,2e,70,46,42,6f,97,2e,0,1a,83,77,44,62,97,34,0-5,35,a0,0-5,29,83,18,0-3,2f,89,1e,0-4,8,63,78,44,60,95,31,0-42,14,67,8f-2,5f,0-3,12,62,8d,94,79,2f,0-3,5,3d,8d,99,66,0-3,5,3d,8d,99,66,0-9,33,9a,0-3,66-2,0-2,12,62,8d,94,79,2f,0,33,9a-6,33,1,20,7d,95,59,77,68,0,33,9a,0-3,66-2,0-3,9,4e,90,99,66,0-4,66-2,0-d,5,67,4b,0-3,17,61,8e,97,7f,43,3,0-2,12,6e,93,7c,30,0-3,12,6e,93,7c,30,0-2,b,6e,5a,4,0-4,17,61,8e,97,7f,43,3,0,3,2b,7e,96,88,4f,5,0-5,33,9a,0-5,4b,68,5,0-2,b,6e,5a,4,0-5,15,6e,93,89,51,4,0-82,1d,e,3,1d,81,4e,0-24,26,72,a,0-1a,1a,5d,11,0-1f,b,73,26,0-3,1a,5d,11,0-8e,61,7a,70,81,91,17,0-24,3,66,23,0-3c,23,67,3,0-94,12,50,64,52,1a,0-1264,e,2f,47,50,55,1c,0-8,1c,55,39,0-9,1c,55,50,46,2f,d,0-df,1f,ae,d9,f1,fa,ff,55,0-8,55,ff,aa,0-9,55,ff,fa,f0,d9,ad,1d,0-6c,aa,ff-2,0-6e,13,b7,ff,fd,ca,b2,aa,39,0-8,55,ff,aa,0-9,39,aa,b2,cb,fd,ff,b6,12,0-6b,aa,ff-2,0-6e,37,e1,ff,bf,20,8,0-a,55,ff,aa,0-b,8,21,c2,ff,e1,37,0-6b,aa,ff-2,0-6e,4e,f8,ff,69,0-c,55,ff,aa,0-d,6a,ff,f8,4e,0-2c,8,44,91,a2,88,4b,1,0-8,25,7c,9e,98,6a,f,0-e,23,81,a3,9b,72,19,0-5,5,38,82,9e,a6,9b,7a,50,f,0-8,aa,ff-2,0-6e,54,fe,ff,57,0-c,55,ff,aa,0-d,57,ff,fe,54,0-1b,10,40,52,47,24,0-8,55,ff-2,6c,bc,fd,ff-4,b5,2b,0-5,9,8e,f3,ff-4,da,4a,ff-2,aa,0-5,55,ff-2,56,75,ef,ff-4,aa,0-4,24,c2,fd,ff-6,aa,0-4,aa,ff-b,55,0-4,55,ff-2,55,0-5,aa,ff-2,0-3,79,ff-2,59,0-6,5a,ff-2,79,0,df,ff,c4,1a,0-8,1a,c4,ff,de,0,4c,f7,ff,d5,30,0-3,6,ab,ff,fb,9d,0-3,72,ff-2,6e,0-6,62,ff-2,75,0-3,55,ff-a,55,0-8,55,ff-2,55,0-c,55,ff,aa,0-d,55,ff-2,55,0-1a,38,a9,ea,fd,f1,cd,57,8,0-6,55,ff-2,da,fa,b7,64,63,b3,f9,fd,bc,3,0-3,2,6b,fa,ff,d1,78,5f,8a,f5,d9,ff-2,aa,0-5,55,ff-2,86,f1,d8,76,5b,78,c9,aa,0-3,10,a4,ff-2,ae,6d,59,68,a8,ee,aa,0-4,aa,ff-b,55,0-4,55,ff-2,55,0-5,aa,ff-2,0-3,2a,ff-2,a2,6,0-4,7,a3,ff-2,29,0,aa,ff,de,34,0-8,34,de,ff,a9,0,3,9e,fe,fd,ab,0-3,59,fb,ff,cd,27,0-3,1d,fa,ff,b6,12,0-4,b,ab,ff,fd,23,0-3,55,ff-a,55,0-8,55,ff-2,55,0-c,55,ff,aa,0-d,55,ff-2,55,0-19,10,ba,f9,ff-4,d4,46,0-6,55,ff-3,73,5,0-2,4,70,ff-2,6d,1,0-2,37,e0,ff,c2,9,0-3,43,e2,ff-2,aa,0-5,55,ff-2,f2,9e,13,0-3,2,40,0-3,42,ec,ff,98,0-5,11,4f,0-8,aa,ff-2,0-a,55,ff-2,55,0-5,aa,ff-2,0-4,c5,ff,db,31,0-4,32,dc,ff,c5,0-2,6a,fe,fa,59,0-8,59,fa,fd,69,0-2,1b,b7,ff-2,70,6,41,e0,ff,f0,36,0-5,a5,ff,ef,4b,0-4,3c,e5,ff,b7,0-a,2,55,ff-2,db,33,0-8,57,ff-2,55,0-c,55,ff,aa,0-d,55,ff-2,56,0-19,64,ff-7,b9,0-6,55,ff-2,e3,c,0-4,c,e2,ff,b7,12,0-2,77,fd,f1,52,0-4,7,96,ff-2,aa,0-5,55,ff-2,f4,1e,0-9,52,fc,ff,61,0-f,aa,ff-2,0-a,55,ff-2,55,0-5,aa,ff-2,0-4,76,fe,fa,61,0-4,62,fa,fe,76,0-2,45,ee,ff,89,0-8,89,ff,ee,44,0-3,37,f7,ff,de,3f,c0,fe,fb,86,0-6,55,f4,ff,96,0-4,77,fd,fb,66,0-a,29,ce,ff-2,69,5,0-8,63,ff,fb,51,0-c,55,ff,aa,0-d,51,fb,ff,62,0-19,99,ff-7,ee,0-6,55,ff-2,95,0-6,95,ff,df,35,0-2,bf,ff,ca,20,0-5,41,ff-2,aa,0-5,55,ff-2,a5,0-a,4a,f4,ff,c6,35,13,0-d,aa,ff-2,0-a,55,ff-2,55,0-5,aa,ff-2,0-4,34,de,ff,c0,0-4,c1,ff,de,34,0-2,23,cd,ff,cb,0-2,42,eb,e9,3f,0-2,cb,ff,cd,23,0-4,6e,f4,ff,f6,ff-2,a4,11,0-6,18,bf,ff,f3,14,0-2,4,da,ff,d1,27,0-9,8,b8,ff,fc,a3,0-a,a5,ff,e7,3d,0-c,55,ff,aa,0-d,3d,e7,ff,a4,0-8,d,31,4d,53,49,31,a,0-5,1a,13,0-3,99,ff-7,ee,0-6,55,ff-2,6e,0-6,6e,ff,f1,47,0-2,e4,ff,b6,c,0-5,1a,ff-2,aa,0-5,55,ff-2,75,0-a,27,d1,ff-2,df,bd,90,5e,18,0-a,aa,ff-2,0-a,55,ff-2,55,0-5,aa,ff-2,0-4,d,b4,ff,f7,18,0-2,19,f7,ff,b4,e,0-2,a,b2,ff,f7,9,0,6d,fd-2,68,0,9,f6,ff,b2,a,0-4,13,ab,ff-3,eb,24,0-7,1,7b,ff-2,63,0-2,35,fe,ff,9e,6,0-8,1,62,fd,ff,d1,2b,0-7,1,1a,66,f1,ff,bc,17,0-c,55,ff,aa,0-d,16,bb,ff,f1,65,1a,1,0-4,32,af,db,f7,fd,f3,db,a9,64,1d,5,1a,59,c2,4c,0-3,64,ff-7,b9,0-6,55,ff-2,5a,0-6,5b,ff,fb,51,0-2,f8,ff,ac,2,0-5,6,ff-2,aa,0-5,55,ff-2,5a,0-b,43,d8,fb,ff-4,f6,a4,17,0-8,aa,ff-2,0-a,55,ff-2,55,0-5,aa,ff-2,0-5,5e,ff-2,74,0-2,74,ff-2,5f,0-4,7a,ff-2,42,0,b8,e9,ec,b3,0,42,ff-2,7b,0-6,14,e5,ff,f1,5a,0-9,17,f4,ff,bf,16,5,99,ff-2,3c,0-9,46,e3,ff,f3,3c,0-7,55,ff-3,f1,ad,1c,0-d,55,ff,aa,0-e,19,aa,f0,ff-3,55,0-3,aa,f3,ce,b1,ad,bd,d9,fc,ff-5,eb,45,0-3,10,ba,f9,ff-4,d4,46,0-6,55,ff-2,5a,0-6,5b,ff,fb,51,0-2,f9,ff,ac,2,0-5,6,ff-2,aa,0-5,55,ff-2,55,0-c,2e,6d,b8,ea,ff-4,90,a,0-7,aa,ff-2,0-a,55,ff-2,55,0-5,aa,ff-2,0-5,15,f8,ff,b4,f,10,b4,ff,f9,16,0-4,45,ff-2,77,5,ef,ac,b1,ec,4,76,ff-2,46,0-6,13,e3,ff,f1,59,0-a,b0,ff,ec,44,24,ce,ff,e0,6,0-8,6,c5,ff,fc,8e,1,0-7,55,ff-3,f1,a8,16,0-d,55,ff,aa,0-e,14,a5,f0,ff-3,55,0-3,85,56,24,7,3,13,2f,65,ab,eb,fa,e1,a9,45,c,0-4,38,a9,ea,fd,f1,cd,57,8,0-6,55,ff-2,6e,0-6,6e,ff,f2,48,0-2,e6,ff,b6,c,0-5,1a,ff-2,aa,0-5,55,ff-2,55,0-f,1,38,91,f5,ff,e6,3c,0-7,aa,ff-2,0-a,55,ff-2,55,0-4,3,ad,ff-2,0-6,aa,ff,e8,3f,40,e8,ff,ab,0-5,b,f8,ff,b0,4a,fb,61,64,fc,46,af,ff,f8,c,0-5,14,ac,ff-3,eb,27,0-9,4c,f1,ff,a2,61,fa,fe,7e,0-8,a,8a,ff-2,ab,15,0-9,2,1b,66,f1,ff,b8,15,0-c,55,ff,aa,0-d,15,b7,ff,f0,64,1b,2,0-18,10,40,53,47,24,0-8,55,ff-2,95,0-6,94,ff,e0,36,0-2,c2,ff,c9,1f,0-5,41,ff-2,aa,0-5,55,ff-2,55,0-11,6,9a,ff,fa,50,0-7,aa,ff-2,0-a,53,fd,ff,5b,0-4,e,b8,ff-2,0-6,60,fa,fd,79,7a,fd,fa,61,0-6,ce,ff,cc,a0,e3,39,3b,e5,9c,cb,ff,cf,0-6,76,f5,ff,f6,ff-2,a9,15,0-8,1c,c6,ff,ee,bd,ff,e8,40,0-8,4b,e8,ff,f0,2b,0-d,a2,ff,e6,3c,0-c,55,ff,aa,0-d,3c,e6,ff,a1,0-28,55,ff-2,e3,c,0-4,b,e2,ff,ba,14,0-2,7a,fd,f0,51,0-4,7,96,ff-2,aa,0-5,55,ff-2,55,0-12,63,ff,fb,51,0-7,9f,ff-2,f,0-9,47,f1,ff,83,0-4,33,dc,ff-2,0-6,26,d0,ff,d8-2,ff,d1,27,0-6,8c,ff,f4-2,bb,12,14,bc," +"f2,f3,ff,8d,0-4,1,44,fb,ff,dc,3d,bd,fe,fd,94,2,0-8,71,ff-4,b1,e,0-7,1b,e2,ff,f0,5e,0-e,61,ff,fb,51,0-c,55,ff,aa,0-d,51,fb,ff,61,0-28,55,ff-3,73,5,0-2,4,6f,ff-2,71,1,0-2,39,e2,ff,c0,8,0-3,43,e2,ff-2,aa,0-5,55,ff-2,55,0-a,2b,4e,1,0-4,3,b2,ff,e6,3c,0-7,82,ff-2,48,0-9,31,db,ff,d1,6,0-3,8f,fb,ff-2,0-6,6,a0,ff,fd-2,ff,a2,6,0-6,5b,fb,ff-2,8d,1,2,8f,ff-2,fc,5d,0-4,25,c6,ff-2,66,5,3a,db,ff,f5,49,0-8,1c,f9,ff-3,6b,0-7,a,93,ff-2,9d,e,0-e,56,ff-2,55,0-c,55,ff,aa,0-d,55,ff-2,56,0-28,55,ff-2,db,f9,b6,63,62,b3,f9,fd,bf,4,0-3,2,6d,fa,ff,d0,77,5e,8a,f5,d7,ff-2,aa,0-5,55,ff-2,55,0-a,55,ff,dc,9a,65,58,75,c5,ff-2,91,a,0-7,31,f8,ff,e3,85,58,55-2,1c,0-4,8,9b,ff-2,bf,6a,66,ad,df,e1,ff-2,0-7,43,ff-4,45,0-7,35,df,ff-2,3f,0-2,41,ff-2,e0,36,0-3,a,b7,ff,fa,9a,0-3,4a,f6,ff,da,39,0-8,a4,ff-2,f3,10,0-7,4c,f6,ff,f7,62,55-6,1c,0-8,55,ff-2,55,0-c,55,ff,aa,0-d,55,ff-2,55,0-28,55,ff-2,6d,c1,fe,ff-4,b7,2d,0-5,9,8f,f3,ff-4,da,49,ff-2,aa,0-5,55,ff-2,55,0-a,55,ff-7,f8,a8,17,0-8,3,93,f7,ff-5,55,0-5,26,e0,ff-4,f6,5c,b0,ff-2,0-7,9,ea,ff-2,eb,a,0-7,1b,c5,ff,f4,a,0-2,b,f4,ff,c6,1c,0-2,2,6a,fd,ff,c7,23,0-3,2,95,fd,fe,bb,4,0-7,5b,fa,ff,b1,0-8,55,ff-a,55,0-8,55,ff-2,55,0-c,55,ff,aa,0-d,55,ff-2,55,0-28,55,ff-2,55,9,48,93,a2,89,4c,1,0-8,26,7d,9f,99,6b,10,0,ff-2,aa,0-5,39,aa-2,39,0-a,6,2c,62,84,a0,a7,99,76,27,1,0-a,2,2c,7c,9b,a9,aa-2,39,0-6,16,69,a2,a3,73,22,0,71,aa-2,0-8,6d,aa-2,6e,0-8,2,70,aa,7f,0-4,80,aa,72,2,0-2,24,95,aa-2,2b,0-5,15,87,aa-2,47,0-7,8c,ff,f5,54,0-8,39,aa-a,39,0-8,54,fe,ff,57,0-c,55,ff,aa,0-d,57,ff,fe,54,0-28,55,ff-2,55,0-16,ff-2,aa,0-76,4,e0,ff,d0,26,0-1c,4e,f8,ff,68,0-c,55,ff,aa,0-d,6a,ff,f8,4e,0-28,55,ff-2,55,0-16,ff-2,aa,0-75,1,60,ff-2,88,1,0-1c,37,e1,ff,bf,1f,7,0-a,55,ff,aa,0-b,8,20,c2,ff,e1,37,0-28,55,ff-2,55,0-16,ff-2,aa,0-74,1,3e,cd,ff,fd,2c,0-1d,13,b8,ff,fd,c9,b1,aa,39,0-8,55,ff,aa,0-9,39,aa,b2,ca,fd,ff,b6,12,0-28,55,ff-2,55,0-16,ff-2,aa,0-73,55,ff-3,f5,83,0-1f,20,af,d9,f1,fa,ff,55,0-8,55,ff,aa,0-9,55,ff,fa,f1,d9,ae,1e,0-29,55,ff-2,55,0-16,ff-2,aa,0-73,55,ff,fa,dd,70,13,0-20,e,2f,47,50,55,1c,0-8,55,ff,aa,0-9,1c,55,50,47,2f,e,0-ee,55,ff,aa,0-fd,1c,55,39,0-43a,20,55,52,8,0-fc,21,dc,fc,66,2,0-fc,34,d2,e9,53,0-1a,55,ff-2,55,0-25,aa,ff-2,0-19,9,63,b6,ed,fc,ff-2,aa,0-13,55,ff-2,55,0-11,aa,ff-2,0-e,ff-2,aa,0-8,aa,ff-2,0-b,aa,ff-6,aa,0-3b,2,45,f7,d5,12,0-19,55,ff-2,55,0-25,aa,ff-2,0-18,3,70,f6,ff-5,aa,0-13,55,ff-2,55,0-11,aa,ff-2,0-e,ff-2,aa,0-8,aa,ff-2,0-b,aa,ff-6,aa,0-3d,5c,eb,aa,14,0-18,55,ff-2,55,0-25,aa,ff-2,0-18,30,da,ff,cc,2b,6,0-16,55,ff-2,55,0-11,aa,ff-2,0-e,ff-2,aa,0-8,aa,ff-2,0-10,ff-2,aa,0-3d,a,42,4a,12,0-18,55,ff-2,55,0-25,aa,ff-2,0-18,4a,f4,ff,6c,0-18,55,ff-2,55,0-11,39,55-2,0-e,55-2,39,0-8,aa,ff-2,0-10,ff-2,aa,0-4a,6,21,35,47,50,54,4d,35,13,0-6,55,ff-2,55,4,23,49,51,44,26,1,0-9,9,2a,48,52,51,48,30,14,0-6,a,2f,4c,50,3e,18,0,aa,ff-2,0-6,1,18,40,50,52,43,1a,1,0-a,54,fe,ff,55,0-a,a,2f,4d,50,3d,17,0-8,55,ff-2,55,2,1a,45,51,47,25,0-27,aa,ff-2,0-10,ff-2,aa,0-b,9,38,51,36,1,4,3c,52,3d,d,0-8,2,1d,47,53,49,28,0-9,10,3a,4e,53,4a,2a,7,0-17,77,cb,df,f1,fa,fe,f7,df,ba,40,2,0-4,55,ff-2,55,6e,cb,f3,fb,ee,d0,65,a,0-7,21,a2,d4,f2,fc,fb,f2,da,be,0-5,13,9c,d9,f6,fa,e8,bf,33,aa,ff-2,0-6,60,bd,ea,fa,fc,ed,bf,5a,0-6,39,aa-3,c6,ff-2,c6,aa-4,71,0-4,10,99,d9,f7,fa,e7,bd,2c,71,aa-2,0-4,55,ff-2,55,4e,be,ef,fb,f1,cf,49,0-6,71,aa-6,0-a,aa-6,71,0-8,aa,ff-2,0-5,1b,a4,aa-2,75,0-6,ff-2,aa,0-8,71,aa-2,69,e2,fb,e0,4a,66,e6,fc,e7,85,0-4,39,aa-2,39,54,c2,f1,fd,f3,d2,4d,1,0-6,3c,ad,e4,f8,fd,f4,d4,97,10,0-16,aa,fc,e5,c1,b1,ad,b9,e5,fe,f2,71,0-4,55,ff-2,bb,fc,db,b1-2,da,fc,fb,95,2,0-5,56,e4,ff,f4,c3,af,b0,c0,e8,fe,0-4,24,c4,ff,f9,c3,af,bd,ea,dd-2,ff-2,0-4,f,8a,ff,fc,ca,b0,b4,d6,ff-2,6d,6,0-4,55,ff-b,aa,0-3,20,bd,ff,fb,c7,af,ba,e7,d7-2,ff-2,0-4,55,ff-2,98,f4,cc,ae,bc,f6,ff,e2,3d,0-5,aa,ff-6,0-a,ff-6,aa,0-8,aa,ff-2,0-4,39,cf,ff-2,aa,1d,0-6,ff-2,aa,0-8,aa,ff-2,d5,b3,f4,ff,ee,e6,b5,d9,ff,fe,26,0-3,55,ff-2,9e,f4,cc,ae,bc,f6,ff,e4,3f,0-4,2,49,f7,ff,e7,ba,ad,c2,f9,ff,c4,26,0-15,8f,74,3b,17,7,3,f,48,cf,ff,eb,17,0-3,55,ff-2,fd,ba,36,7-2,35,b9,ff,f8,3d,0-4,1a,e1,ff,e3,67,19,5,6,16,44,a5,0-4,8e,fb,f7,88,19,5,13,4b,f1,fe,ff-2,0-4,62,f1,f8,92,20,6,a,2c,c3,ff,de,34,0-4,1c,55-3,8e,ff-2,8e,55-4,39,0-3,84,fa,f9,92,1d,5,10,45,ed,fd,ff-2,0-4,55,ff-2,f5,91,22,4,12,89,fa,fe,89,0-5,39,55-3,c6,ff-2,0-a,55-4,ff-2,aa,0-8,aa,ff-2,0-3,20,d1,fe,ff,c3,1c,0-7,ff-2,aa,0-8,aa,ff-2,5d,9,aa,ff-2,b1,b,54,ff-2,60,0-3,55,ff-2,f6,91,22,4,12,89,fa,fe,8b,0-4,21,c5,ff,ed,46,10,3,18,87,f6,fb,92,0-1d,4b,ff-2,69,0-3,55,ff-2,f1,1b,0-4,19,f1,ff,ad,b,0-2,6,97,ff,fc,49,0-a,16,f7,ff,a7,c,0-4,6b,f9,ff-2,0-3,b,e6,ff,9e,a,0-4,38,e1,ff,91,0-8,55,ff-2,55,0-7,12,f4,ff,ad,f,0-4,66,f8,ff-2,0-4,55,ff-2,d8,4,0-3,22,cc,ff,d1,0-9,aa,ff-2,0-e,ff-2,aa,0-8,aa,ff-2,0-2,3f,d4,ff-2,a3,19,0-8,ff-2,aa,0-8,aa,ff-2,1b,0,6e,ff-2,71,0,18,ff-2,8a,0-3,55,ff-2,d8,4,0-3,22,cc,ff,d3,0-4,6d,fd,f7,64,0-4,c,a7,ff,fa,1a,0-1c,14,ff-2,90,0-3,55,ff-2,b3,0-6,b2,ff,d4,2a,0-2,23,cd,ff,ce,3,0-a,54,ff-2,5c,0-5,30,da,ff-2,0-3,44,ff-2,45,0-5,14,be,ff,cd,0-8,55,ff-2,55,0-7,4f,ff-2,61,0-5,2e,d8,ff-2,0-4,55,ff-2,8f,0-4,a,b4,ff,ee,0-9,aa,ff-2,0-e,ff-2,aa,0-8,aa,ff-2,0,26,d6,fe,ff,bc,18,0-9,ff-2,aa,0-8,aa,ff-2,a,0,5f,ff-2,60,0,9,ff-2,9c,0-3,55,ff-2,8f,0-4,a,b4,ff,f0,0-4,af,ff,d7,2d,0-5,5b,ff-2,58,0-15,4,1e,3f,4d,54,55-3,ff-2,a4,0-3,55,ff-2,76,0-6,77,ff,ef,45,0-2,43,ed,ff,81,0-b,8a,ff-2,21,0-5,11,bb,ff-2,0-3,86,ff-2,5e,54-3,55-2,57,c9,ff,f4,0-8,55,ff-2,55,0-7,87,ff-2,22,0-5,11,bb,ff-2,0-4,55,ff-2,62,0-4,1,ab,ff,fc,0-9,aa,ff-2,0-e,ff-2,aa,0-8,aa,ff-2,45,d9,ff,fe,9b,16,0-a,ff-2,aa,0-8,aa,ff-2,1,0,57,ff-2,56,0,2,ff-2,a7,0-3,55,ff-2,62,0-4,1,ab,ff,fe,0-4,e2,ff,b9,f,0-5,1f,ff-2,8c,0-14,f,8c,c8,e9,f7,fe,ff-5,a9,0-3,55,ff-2,5f,0-6,60,ff,f9,4f,0-2,50,fa,ff,63,0-b,9e,ff-2,a,0-5,6,b0,ff-2,0-3,a0,ff-2,fe-4,ff-5,fe,0-8,55,ff-2,55,0-7,9d,ff-2,b,0-5,5,af,ff-2,0-4,55,ff-2,57,0-5,aa,ff-2,0-9,aa,ff-2,0-e,ff-2,aa,0-8,aa,ff-2,db,ff-2,f6,20,0-b,ff-2,aa,0-8,aa,ff-2,0-2,55,ff-2,55,0-2,ff-2,aa,0-3,55,ff-2,57,0-5,aa,ff-2,0-4,f7,ff,ae,4,0-5,9,ff-2,a1,0-13,2b,ca,ff,fe,d5,ba,ac,aa-3,ff-2,aa,0-3,55,ff-2,58,0-6,59,ff,fc,52,0-2,54,fe,ff,59,0-b,a5,ff-2,3,0-5,2,ac,ff-2,0-3,a8,ff,f8,aa-a,0-8,55,ff-2,55,0-7,a6,ff-2,3,0-5,2,ac,ff-2,0-4,55,ff-2,55,0-5,aa,ff-2,0-9,aa,ff-2,0-e,ff-2,aa,0-8,aa,ff-6,98,d,0-a,ff-2,aa,0-8,aa,ff-2,0-2,55,ff-2,55,0-2,ff-2,aa,0-3,55,ff-2,55,0-5,aa,ff-2,0-4,fd,ff,ab,1,0-5,2,ff-2,a8,0-13,90,fd,fa,9b,2b,10,2,0-2,7,ff-2,aa,0-3,55,ff-2,63,0-6,63,ff,f6,4c,0-2,4e,f8,ff,68,0-b,99,ff-2,d,0-5,7,b1,ff-2,0-3,9c,ff,f2,0-12,55,ff-2,55,0-7,9a,ff-2,f,0-5,7,b1,ff-2,0-4,55,ff-2,55,0-5,aa,ff-2,0-9,aa,ff-2,0-e,ff-2,aa,0-8,aa,ff-2,fd,af,e2,ff,ee,5a,0-a,ff-2,aa,0-8,aa,ff-2,0-2,55,ff-2,55,0-2,ff-2,aa,0-3,55,ff-2,55,0-5,aa,ff-2,0-4,f3,ff,b0,6,0-5,d,ff-2,9e,0-13,e7,ff,c0,16,0-5,29,ff-2,aa,0-3,55,ff-2,8b,0-6,8a,ff,e4,3a,0-2,38,e2,ff,9d,0-b,75,ff-2,33,0-5,1b,c5,ff-2,0-3,72,ff-2,1e,0-11,55,ff-2,55,0-7,75,ff-2,38,0-5,1b,c5,ff-2,0-4,55,ff-2,55,0-5,aa,ff-2,0-9,aa,ff-2,0-e,ff-2,aa,0-8,aa,ff-2,8c,10,4a,e8,ff,ee,27,0-9,fe,ff,aa,0-8,aa,ff-2,0-2,55,ff-2,55,0-2,ff-2,aa,0-3,55,ff-2,55,0-5,aa,ff-2,0-4,d2,ff,c3,19,0-5,32,ff-2,7c,0-13,fc,ff,ae,4,0-5,6d,ff-2,aa,0-3,55,ff-2,c5,0-6,c3,ff,cb,21,0-2,1a,c4,ff,e3,8,0-a,43,ff-2,6c,0-5,39,e3,ff-2,0-3,37,ff-2,67,0-11,55,ff-2,55,0-7,41,ff-2,76,0-5,38,e2,ff-2,0-4,55,ff-2,55,0-5,aa,ff-2,0-9,aa,ff-2,0-e,ff-2,aa,0-8,aa,ff-2,f,0,9,86,ff-2,a6,12,0-8,f5,ff,af,5,0-7,aa,ff-2,0-2,55,ff-2,55,0-2,ff-2,aa,0-3,55,ff-2,55,0-5,aa,ff-2,0-4,a1,ff,e0,36,0-5,6d,ff-2,4c,0-13,e0,ff,cd,24,0-4,3d,d8,ff-2,aa,0-3,55,ff-3,4e,3,0-2,2,4b,ff-2,85,1,0-3,66,ff-2,8e,f,0-4,2,26,0-3,2,d9,ff,cd,27,0-3,6,a3,ff-3,0-4,c0,ff,d8,3e,0-5,1,28,16,0-8,55,ff-2,55,0-7,2,d6,ff,d4,32,0-3,4,a0,ff-3,0-4,55,ff-2,55,0-5,aa,ff-2,0-9,aa,ff-2,0-e,ff-2,aa,0-8,aa,ff-2,0-3,4,be,fe,fb,88,0-8,c9,ff,d0,26,0-7,aa,ff-2,0-2,55,ff-2,55,0-2,ff-2,aa,0-3,55,ff-2,55,0-5,aa,ff-2,0-4,4e,f1,ff,9b,4,0-3,28,cd,ff,e2,7,0-13,96,ff,f8,ab,2a,6,18,58,d3,e6,ff-2,aa,0-3,55,ff-2,fc,d9,64,e,d,61,d6,ff,ef,1f,0-4,d,c7,ff,f1,a3,32,9,a,28,79,cd,0-4,6c,f7,fb,b9,32,8,24,85,f7,fd,ff-2,0-4,4b,e6,fe,d5,5c,1a,3,12,49,8c,d2,4e,0-8,55,ff-2,55,0-8,68,f5,fc,c5,3c,b,20,7e,ef,f7,ff-2,0-4,55,ff-2,55,0-5,aa,ff-2,0-9,aa,ff-2,0-e,ff-2,aa,0-8,aa,ff-2,0-4,3f,df,ff,f1,37,0-7,7f,fe,f8,99,14,1,0-5,aa,ff-2,0-2,55,ff-2,55,0-2,ff-2,aa,0-3,55,ff-2,55,0-5,aa,ff-2,0-4,15,b3,ff,f6,7d,20,6,30,b9,fb,f9,78,0-14,20,ad,fe,ff-5,d2,44,ff-2,aa,0-3,55,ff-2,83,de,fe,ff-4,d6,49,0-6,1e,a1,f7,ff-7,0-4,9,79,f3,ff-4,fd,a0,c0,ff-2,0-5,45,d9,fc,ff-7,55,0-8,55,ff-2,55,0-8,8,76,f2,ff-4,fc,90,b8,ff,fe,0-4,55,ff-2,55,0-5,aa,ff-2,0-4,55,ff-b,aa,0-9,ff-2,aa,0-8,aa,ff-2,0-5,57,fa,ff,cd,28,0-6,1b,a8,ff-6,0-3,aa,ff-2,0-2,55,ff-2,55,0-2,ff-2,aa,0-3,55,ff-2,55,0-5,aa,ff-2,0-5,18,c3,f9,ff-5,f3,7f,c,0-15,1c,80,cc,f6,fa,d9,99,2f,3,ff-2,aa,0-3,55,ff-2,55,3d,9b,e7,f7,dd,a0,32,4,0-7,11,5f,aa,e6,fa,f9,e5,b7,7e,0-5,9,5d,b3,ee,f6,d1,83,18,aa,ff-2,0-6,31,7d,cf,f1,fd,f4,d9,b8,81,23,0-8,55,ff-2,55,0-9,8,5c,b5,ef,f5,cd,7c,14,ac,ff,f5,0-4,55,ff-2,55,0-5,aa,ff-2,0-4,55,ff-b,aa,0-9,ff-2,aa,0-8,aa,ff-2,0-5,5,a9,ff,fb,9d,0-7,1c,87,d4,f9,ff-3,0-3,aa,ff-2,0-2,55,ff-2,55,0-2,ff-2,aa,0-3,55,ff-2,55,0-5,aa,ff-2,0-6,20,70,cb,f1,fc,ea,ab,5a,9,0-7d,10,ba,ff,d8,0-29,7,ff-2,a3,0-cf,33,dd,ff,a1,0-29,26,ff-2,8a,0-c7,49,a7,47,23,8,3,10,33,c2,ff,e5,3e,0-28,18,99,ff,fe,42,0-c7,55,ff,ef,cd,b2,ad,ba,dd,ff-2,76,9,0-24,39,aa-3,c2,f4,ff,c6,7,0-c7,3c,c2,df,f0,fb,fd,f4,e1,b3,51,0-26,55,ff-3,f9,e6,9d,20,0-c8,4,18,35,46,51,53,4a,37,11,0-27,1c,55-3,4f,3c,c,0-76b,3,2e,80,9c-2,7f,2d,3,0-18,1,25,74,97,a4,92,59,1a,0-7a,aa-6,0-18,aa-6,0-28,55,ff-5,fd,f2,d2,9f,45,d,0-5,1b,af,fb,ff-4,fa,ad,1a,0-5,ff-5,fd,ec,cc,81,37,0-7,1c,a7,f8,ff-5,fc,ab,29,0-2,55,ff-e,55,0-2,ff-2,aa,0-6,aa,ff-2,0-2,40,ea,ff,9d,0-8,9d,ff,ea,40,eb,ff,b9,f,0-8,f,b9,ff,ea,0,56,fd,ff,b6,15,0-5,30,f8,ff,d1,2a,2e,d7,ff,ed,1a,0-6,1b,ef,ff,d7,2d,0-2,ff-d,55,0-6,ff-6,0-5,6a,ff-2,40,0-f,ff-6,0-b,17,d2,ff,e9,55,0-18,55,ff-9,ec,96,2,0-3,13,9f,ff-2,a6,67,69,a6,ff-2,9c,12,0-4,ff-8,fd,df,51,1,0-4,16,a3,ff-2,c1,77,5c,6d,b6,f4,ff,55,0-2,55,ff-e,55,0-2,ff-2,aa,0-6,aa,ff-2,0-2,1e,c8,ff,df,0-8,df,ff,c8,1e,c8,ff,c9,1f,0-8,20,ca,ff,c8,0,7,c2,ff,f3,61,0-4,10,a7,ff-2,69,3,5,80,ff-2,84,4,0-4,4,87,ff-2,80,5,0-2,ff-d,55,0-6,ff-2,c6,55-3,0-5,13,ef,ff,9f,8,0-e,55-3,c6,ff-2,0-a,d,92,ff-3,da,19,0-17,55,ff-2,55,0-2,3,15,5f,c4,ff-2,81,5,0-2,6d,f9,f3,70,0-4,70,f3,f8,69,0-4,ff-2,aa,0-2,3,1e,66,e1,ff,e7,46,0-4,74,fc,f5,82,0-5,24,ae,4b,0-8,55,ff-2,55,0-8,ff-2,aa,0-6,aa,ff-2,0-2,1,92,ff-2,35,0-6,35,ff-2,92,1,9e,ff,df,35,0-8,35,df,ff,9e,0-2,3b,e2,ff,e9,19,0-3,72,f8,ff,b9,1,0-2,a,db,ff,e5,43,0-4,45,e6,ff,da,9,0-c,3e,fb,ff,cf,29,0-6,ff-2,aa,0-9,83,fd,e7,41,0-11,aa,ff-2,0-9,1,87,f9,ea,75,d5,ff,ba,1d,0-16,55,ff-2,55,0-4,1,24,e6,ff,ce,24,0-2,cb,ff,c2,18,0-4,18,c2,ff,c8,0-4,ff-2,aa,0-5,60,ef,ff,9a,0-4,c5,ff,c9,1f,0-6,15,12,0-8,55,ff-2,55,0-8,ff-2,aa,0-6,aa,ff-2,0-3,50,ff-2,78,0-6,78,ff-2,50,0,7c,ff,f0,46,0-8,46,f0,ff,7b,0-2,8,8b,ff-2,88,5,0,16,e4,ff,e5,45,0-4,6b,f8,fe,aa,0-4,ac,fe,f8,6b,0-c,1a,b8,ff-2,5f,3,0-6,ff-2,aa,0-9,39,e1,fe,91,0-11,aa,ff-2,0-9,46,f2,ff,70,9,46,dd,f9,94,0-16,55,ff-2,55,0-6,7e,ff,f2,48,0,23,ff-2,77,0-6,79,ff-2,21,0-3,ff-2,aa,0-5,13,bd,ff,e2,0-4,f4,ff,ad,3,0-10,55,ff-2,55,0-8,ff-2,aa,0-6,aa,ff-2,0-3,9,f1,ff,bb,11,0-4,11,bb,ff,f1,9,0,55,fb,ff,61,0-8,62,ff,fb,55,0-3,c,da,ff,eb,4f,d,a0,ff-2,75,2,0-4,13,b0,ff-2,4a,0-2,4c,ff-2,b0,13,0-c,8f,fd-2,a7,0-8,ff-2,aa,0-9,5,94,ff,f6,1b,0-10,aa,ff-2,0-8,3f,dd,f4,83,0-3,39,e8,ff,6b,6,0-14,55,ff-2,55,0-6,5c,ff,fc,52,0,55,ff-2,48,0-6,49,ff-2,53,0-3,ff-2,aa,0-5,3,ad,ff,f8,0-4,f7,ff,ba,10,0-10,55,ff-2,55,0-8,ff-2,aa,0-6,aa,ff-2,0-4,b7,ff,dd,33,0-4,32,dc,ff,b8,0-2,42,ec,ff,83,0-2,4c,aa-2,4c,0-2,83,ff,ed,43,0-4,66,f5,ff,c2,51,ec,ff,d8,10,0-6,44,ff-2,b5,16-2,b6,ff-2,44,0-c,32,f2,ff,d9,34,0-8,ff-2,aa,0-a,32,fe,ff,78,0-10,aa,ff-2,0-7,b,c7,fe,98,12,0-4,65,ed,e2,45,0-14,55,ff-2,55,0-6,72,ff,f5,4b,0,80,ff-2,23,0-6,24,ff-2,7e,0-3,ff-2,aa,0-5,b,b5,ff,ec,0-4,c9,ff,f3,7c,12,0-f,55,ff-2,55,0-8,ff-2,aa,0-6,aa,ff-2,0-4,66,fc,fd,67,0-4,66,fd,fc,67,0-2,2d,d7,ff,ad,0-2,a2,ff-2,a2,0-2,ae,ff,d7,2d,0-4,d,a1,ff-2,f5,ff,ea,4b,0-8,a5,fe,f9,71,72,fa,fe,a4,0-c,1e,c3,ff,fb,55,0-9,ff-2,aa,0-b,b0,ff,d2,28,0-f,aa,ff-2,0-6,12,a3,fa,aa,4,0-5,2,5a,f5,e5,25,0-13,55,ff-2,55,0-5,1,c1,ff,e0,36,0,95,ff-2," +"10,0-6,11,ff-2,94,0-3,ff-2,aa,0-5,2a,d4,ff,bb,0-4,73,fa,ff,f5,b6,79,30,7,0-c,55,ff-2,55,0-8,ff-2,aa,0-6,aa,ff-2,0-4,3a,e4,ff,a9,0-4,a7,ff,e5,3b,0-2,1c,c6,ff,d0,0-2,d3,ff-2,d2,0-2,d0,ff,c6,1c,0-5,2d,f7,ff-3,9b,c,0-8,40,e3,ff,df,e0,ff,e3,3f,0-c,7f,f8,ff,b5,6,0-9,ff-2,aa,0-b,55,f2,f9,68,0-f,aa,ff-2,0-6,11,4a,50,1b,0-7,3,4b,55,22,0-13,55,ff-2,55,0-2,1,a,31,99,ff-2,9d,a,0,a2,ff-2,5,0-6,6,ff-2,a1,0-3,ff-2,aa,0-2,1,c,2b,b1,ff,e9,4b,0-4,e,84,f3,ff-4,f0,a5,57,e,0-9,55,ff-2,55,0-8,ff-2,aa,0-6,aa,ff-2,0-4,11,b9,ff,f2,a,0-2,a,f1,ff,ba,12,0-2,8,b0,ff,f6,4,11,fd,d7-2,fd,10,4,f6,ff,b0,8,0-6,80,fb,ff,e6,13,0-9,3,80,ff-4,80,3,0-b,39,fa,ff,d2,2b,0-a,ff-2,aa,0-b,12,b4,ff,db,8,0-e,aa,ff-2,0-28,55,ff-2,c6,aa-2,ab,b4,da,fb,ff,df,24,0-2,a7,ff-2,2,0-6,2,ff-2,a7,0-3,ff-2,e3,aa-2,ab,b6,d5,ff,f3,64,a,0-5,a,5b,b6,fd,ff-4,f4,9c,1d,0-8,55,ff-2,55,0-8,ff-2,aa,0-6,aa,ff-2,0-4,1,86,ff-2,41,0-2,3e,ff-2,87,1,0-3,96,ff-2,1d,40,ff,a3-2,ff,3f,1d,ff-2,96,0-7,6e,fb,ff,df,8,0-a,17,eb,ff-2,ea,17,0-b,17,b3,ff-2,64,3,0-a,ff-2,aa,0-c,60,ff-2,4b,0-e,aa,ff-2,0-28,55,ff-5,fe,f9,e9,d0,86,1a,0-3,9e,ff-2,8,0-6,a,ff-2,a1,0-3,ff-8,b8,32,0-a,15,4c,8d,ba,ef,ff-2,c1,7,0-7,55,ff-2,55,0-8,ff-2,aa,0-6,aa,ff-2,0-5,33,ff-2,93,2-2,91,ff-2,34,0-4,6c,ff-2,47,7c,fd,64-2,fd,7b,47,ff-2,6c,0-6,1c,ec,ff-3,83,6,0-a,73,ff-2,73,0-c,89,fc,fd,ac,0-c,ff-2,aa,0-c,4,da,ff,b9,13,0-d,aa,ff-2,0-28,55,ff-2,8e,55-2,54,4f,3f,26,2,0-4,92,ff-2,13,0-6,14,ff-2,93,0-3,ff-2,c7,5a,62,75,c0,fb,f8,bc,d,0-b,1,12,58,d7,ff,fe,42,0-7,55,ff-2,55,0-8,ff-2,aa,0-6,aa,ff-2,0-5,6,e9,ff,c1,18,16,bf,ff,ea,6,0-4,49,ff-2,6e,a7,eb,41-2,eb,a6,6e,ff-2,4a,0-5,6,8c,ff-4,df,38,0-a,55,ff-2,55,0-b,2d,f0,ff,db,38,0-c,ff-2,aa,0-d,79,fd,ec,46,0-d,aa,ff-2,0-28,55,ff-2,55,0-b,6f,ff-2,2f,0-6,30,ff-2,76,0-3,ff-2,aa,0-3,5,6f,fe,ff,99,b,0-d,46,ff-2,8d,0-7,55,ff-2,55,0-8,fc,ff,aa,0-6,aa,ff,fb,0-6,9b,ff,eb,42,40,e9,ff,9c,0-5,1f,ff-2,b3,c9,cb,21-2,cb,c8,b2,ff-2,20,0-5,51,ec,ff,d5,70,f4,ff,c0,7,0-9,55,ff-2,55,0-a,1b,bf,ff,fc,5a,0-d,ff-2,aa,0-d,26,cf,ff,b4,0-d,aa,ff-2,0-28,55,ff-2,55,0-b,4b,ff-2,53,0-6,53,ff-2,51,0-3,ff-2,aa,0-4,a,ca,ff,e7,40,0-d,d,ff-2,a4,0-7,55,ff-2,55,0-8,f4,ff,aa,0-5,1,ab,ff,f3,0-6,5c,fa,fe,73,6f,fd,fa,5d,0-5,5,f7,ff,e6,e8,b0,8-2,af,e7,e5,ff,f8,5,0-4,3,c4,ff,f3,61,16,b8,ff,fd,58,0-9,55,ff-2,55,0-a,79,f7,ff,ba,7,0-d,ff-2,aa,0-d,4,8a,ff,f7,24,0-c,aa,ff-2,0-28,55,ff-2,55,0-b,d,f5,ff,94,4,0-4,4,94,ff,f9,16,0-3,ff-2,aa,0-5,4c,ee,ff,b8,1,0-c,14,ff-2,98,0-7,55,ff-2,55,0-8,dc,ff,b0,6,0-4,7,b1,ff,dd,0-6,2c,d6,ff,c6,c2,ff,d7,2d,0-6,d2,ff-3,78,0-2,76,ff-3,d3,0-4,3,70,ff-2,9e,c,0,2b,f1,ff,d6,2f,0-8,55,ff-2,55,0-9,34,f8,ff,d5,2e,0-e,ff-2,aa,0-e,1a,f2,ff,97,6,0-b,aa,ff-2,0-28,55,ff-2,55,0-c,b5,ff,cf,25,0-4,25,ce,ff,c5,0-4,ff-2,aa,0-5,13,b9,ff,f9,2c,0-3,57,7,0-7,5c,ff-2,6e,0-7,55,ff-2,55,0-8,b7,ff,c6,1c,0-4,1d,c7,ff,b7,0-6,c,b3,ff,f7,f6,ff,b4,d,0-6,b0,ff-3,43,0-2,42,ff-3,b1,0-4,2a,d2,ff,f6,29,0-3,90,fe,fc,97,0-8,55,ff-2,55,0-8,15,ae,ff-2,6a,4,0-e,ff-2,aa,0-f,a5,ff,d7,2d,0-b,aa,ff-2,0-28,55,ff-2,55,0-c,3f,e6,ff,b4,28,9-2,28,b3,ff,ef,51,0-4,ff-2,aa,0-6,48,fe,ff,a3,a,0-2,fd,ca,58,2c,d,3,8,1e,6c,e5,ff,e7,15,0-7,55,ff-2,55,0-8,59,f4,fc,9a,21,7,8,21,9d,fc,f4,59,0-7,6b,ff-4,6d,0-7,85,ff-2,f7,a,0-2,a,f7,ff-2,87,0-3,2,a6,ff,f9,7a,0-4,1e,c0,ff,fe,46,0-7,55,ff-2,55,0-8,83,fb,fe,b1,0-10,ff-2,aa,0-f,3d,e6,ff,86,0-b,aa,ff-2,0-28,55,ff-2,55,0-c,9,77,ff-2,d2,b3-2,d2,ff-2,94,e,0-4,ff-2,aa,0-6,7,d4,ff,e1,37,0-2,ff-2,f5,d6,b7,ad,b2,c8,f6,ff,ed,65,0-8,55,ff-2,55,0-8,13,a3,ff,fd,cb,b1,b2,cb,fd,ff,a5,14,0-7,28,ff-4,2a,0-7,64,ff-2,ce,0-4,cc,ff-2,65,0-3,3a,f7,ff,ca,21,0-4,1,50,ff-2,b9,19,0-6,55,ff-2,55,0-8,ed,ff,fe,cd,aa-9,39,0-6,ff-2,aa,0-f,e,af,ff,e4,9,0-a,aa,ff-2,0-28,55,ff-2,55,0-e,5a,bc,ea,f8,ff-2,fc,99,2,0-5,ff-2,aa,0-7,5d,f6,ff,a1,0-2,3a,90,c8,e1,f6,fd,f9,ef,d3,a9,2d,0-9,55,ff-2,55,0-9,3,78,c7,ed,fa-2,ed,c7,7a,3,0-9,d3,ff-2,d5,0-8,47,f1,ff,8d,0-4,8b,ff,f2,48,0-2,1b,c1,ff,fa,45,0-7,a1,fd,fc,86,0-6,55,ff-2,55,0-8,ff-d,55,0-6,ff-2,aa,0-10,3e,fd,ff,6d,1,0-9,aa,ff-2,0-28,1c,55-2,1c,0-e,2,17,40,4e,7e,ed,fd,c2,13,0-5,55-2,39,0-7,13,4c,55,48,0-3,1,1e,37,4c,53,4f,45,29,9,0-a,1c,55-2,1c,0-a,3,1e,43,50-2,43,1e,3,0-a,3b,55-2,3c,0-8,15,4d,55,26,0-4,25,55,4e,15,0-2,14,4d,55,50,3,0-7,1f,53,55,43,0-6,1c,55-2,1c,0-8,55-d,1c,0-6,ff-2,aa,0-10,5,cf,ff,bd,18,0-9,aa,ff-2,0-3e,1,53,f0,ff,c5,2f,0-98,ff-2,aa,0-11,5c,f6,f7,60,0-9,aa,ff-2,0-3f,2,74,f1,ec,55,0-98,ff-2,e3,aa-3,0-e,20,ca,ff,bf,0-6,aa-3,e3,ff-2,0-40,3,56,2e,0-99,ff-6,0-18,ff-6,0-dc,55-6,0-18,55-6,0-16,aa-d,39,0-f2,ff-d,55,0-f2,55-d,1c,0-638,7,27,46,51,4d,3a,10,0-39,16,37,4b,52,49,34,b,0-77,2,17,40,4e-2,40,17,2,0-1a,42,aa-3,b,0-7,aa-6,9e,86,47,b,0-9,1a,9e,d1,f0,fb,f7,e4,b1,51,0-4,aa-4,a0,90,65,2c,0-8,39,aa-b,71,0-3,39,aa-b,0-6,7,57,c0,e1,f5,fc,f3,de,aa,4c,0-4,aa-2,71,0-7,aa-2,71,0-3,39,aa-a,39,0-7,71,aa-6,71,0-5,aa-2,71,0-7,4d,a7,aa,6e,0-2,39,aa-2,39,0-b,71,aa-2,9c,2b,0-5,56,aa-3,39,0-2,aa-3,65,0-6,aa-2,71,0-5,5c,bd,ea,f8-2,ea,bc,5a,0-a,17,38,4e,53,47,2e,3,0-9,aa,ff-3,57,0-7,ff-9,e1,4b,6,0-6,52,e1,ff,ed,bf,af,b8,d5,fd,ff,0-4,ff-8,ba,4d,1,0-5,55,ff-b,aa,0-3,55,ff-b,0-5,14,b2,fd,f9,d7,b4,ae,bd,dd,ff-2,0-4,ff-2,aa,0-7,ff-2,aa,0-3,55,ff-a,55,0-7,aa,ff-6,aa,0-5,ff-2,aa,0-5,4,4c,f7,ff,ae,1d,0-2,55,ff-2,55,0-b,aa,ff-3,76,0-4,11,ba,ff-3,55,0-2,ff-3,e9,c,0-5,ff-2,aa,0-3,9,78,ff-2,d2,b3,b4,d3,ff-2,76,9,0-6,a,5c,c1,e2,f8,fd,f1,d8,82,16,0-7,5,eb,ff-3,9b,3,0-6,ff-2,c6,55-3,62,8a,ed,ff,df,3e,0-5,1c,e1,ff,d1,54,15,5,e,2b,8c,ef,0-4,ff-2,c6,55,5f,74,b4,f2,ff,e8,52,1,0-4,55,ff-2,8e,55-8,39,0-3,55,ff-2,8e,55-8,0-4,a,8d,fe-2,81,2e,a,4,13,33,99,f3,0-4,ff-2,aa,0-7,ff-2,aa,0-3,1c,55-3,8e,ff-2,8e,55-3,1c,0-7,39,55-4,ff-2,aa,0-5,ff-2,aa,0-5,45,dc,ff,d1,20,0-3,55,ff-2,55,0-b,aa,ff-2,fb,bf,0-4,36,e0,fb,ff-2,55,0-2,ff-4,53,0-5,ff-2,aa,0-3,41,e6,ff,b4,28,9,a,29,b4,ff,e5,3f,0-5,1e,be,fe,f5,d1,b4,ae,c2,ed,ff,c6,12,0-6,4a,ff-2,fd,ff,d0,26,0-6,ff-2,aa,0-5,39,df,ff,b6,0-4,d,a5,ff,ea,21,0-6,41,0-4,ff-2,aa,0-4,1e,c1,fd,e1,40,0-4,55,ff-2,55,0-c,55,ff-2,55,0-c,5d,f3,f8,7e,0-6,1,45,0-4,ff-2,aa,0-7,ff-2,aa,0-7,55,ff-2,55,0-10,ff-2,aa,0-5,ff-2,aa,0-3,2,3e,f0,ff,bc,25,0-4,55,ff-2,55,0-b,aa,ff-2,b7,fd,1e,0-3,74,fe,b7,ff-2,55,0-2,ff-2,fb-2,b7,11,0-4,ff-2,aa,0-3,b6,ff,cf,25,0-4,25,cf,ff,b3,0-4,17,a7,ff,e9,60,27,a,4,18,50,ec,ff,77,1,0-4,1,90,ff-2,bf,ff,f2,4b,0-6,ff-2,aa,0-5,c,b6,ff,ea,0-4,38,e2,ff,8b,0-c,ff-2,aa,0-5,37,d9,fe,a0,0-4,55,ff-2,55,0-c,55,ff-2,55,0-c,bc,ff,cc,22,0-c,ff-2,aa,0-7,ff-2,aa,0-7,55,ff-2,55,0-10,ff-2,aa,0-5,ff-2,aa,0-3,38,d2,ff,de,29,0-5,55,ff-2,55,0-b,aa,ff-2,6f,fe,66,0-3,be,fc,70,ff-2,55,0-2,ff-2,dc-2,e7,3e,0-4,ff-2,aa,0-2,d,f5,ff,94,4,0-4,4,95,ff,f4,c,0-3,8b,fd,c8,2c,0-6,55,f0,d0,26,0-4,20,ca,ff,de,46,ef,ff,97,0-6,ff-2,aa,0-5,5,af,ff,f8,0-4,7b,ff,e8,3e,0-c,ff-2,aa,0-5,1,8e,ff,f9,15,0-3,55,ff-2,55,0-c,55,ff-2,55,0-b,22,ff-2,84,0-d,ff-2,aa,0-7,ff-2,aa,0-7,55,ff-2,55,0-10,ff-2,aa,0-5,ff-2,aa,0,1,32,e7,ff,c8,2f,0-6,55,ff-2,55,0-b,aa,ff-2,33,dd,b5,d,0,1d,fd,bc,55,ff-2,55,0-2,ff-2,ae,96,ff,9b,0-4,ff-2,aa,0-2,4b,ff-2,53,0-6,54,ff-2,4a,0-2,1b,f0,fe,42,1,0-6,1d,c7,ec,42,0-4,44,ed,ff,98,22,cc,ff,dd,0-6,ff-2,aa,0-5,19,c3,ff,d9,0-4,ad,ff,ce,24,0-c,ff-2,aa,0-6,53,ff-2,48,0-3,55,ff-2,55,0-c,55,ff-2,55,0-b,55,ff-2,4c,0-d,ff-2,aa,0-7,ff-2,aa,0-7,55,ff-2,55,0-10,ff-2,aa,0-5,ff-2,aa,0,2d,c6,ff,e8,33,1,0-6,55,ff-2,55,0-b,aa,ff-2,f,b7,db,31,0,66,fe,73,55,ff-2,55,0-2,ff-2,aa,3d,ff,ec,c,0-3,ff-2,aa,0-2,6f,ff-2,2f,0-6,30,ff-2,6e,0,2,81,ff,a2,0-3,15,88,dc,f5,c8,48,b3,fb,51,0-4,8b,ff,f3,4c,2,93,ff-2,37,0-5,ff-2,aa,0-3,7,1e,8a,f8,f6,72,0-4,dd,ff,b9,f,0-c,ff-2,aa,0-6,24,ff-2,7d,0-3,55,ff-2,55,0-c,55,ff-2,55,0-b,87,ff-2,20,0-d,ff-2,aa,0-7,ff-2,aa,0-7,55,ff-2,55,0-10,ff-2,aa,0-5,ff-2,aa,27,db,ff,d4,39,0-8,55,ff-2,55,0-b,aa,ff-2,0,6b,fd,6b,e,b5,e0,36,55,ff-2,55,0-2,ff-2,aa,0,c7,ff,6d,1,0-2,ff-2,aa,0-2,92,ff-2,14,0-6,15,ff-2,91,0,12,ba,f4,54,0-2,11,97,fe,ff-3,d9,df,ff,55,0-4,d2,ff,d1,27,0,4d,ff-2,7e,0-5,ff-2,e3,aa-3,b1,c8,f9-2,88,14,0-4,ee,ff,b0,6,0-c,ff-2,aa,0-6,f,ff-2,93,0-3,55,ff-2,c6,aa-8,0-4,55,ff-2,c6,aa-7,39,0-3,98,ff-2,d,0-d,ff-2,e3,aa-7,ff-2,aa,0-7,55,ff-2,55,0-10,ff-2,aa,0-5,ff-2,cd,b9,ff-2,a5,9,0-8,55,ff-2,55,0-b,aa,ff-2,0,22,fe,b3,31,db,bb,11,55,ff-2,55,0-2,ff-2,aa,0,6d,fc,b8,13,0-2,ff-2,aa,0-2,9d,ff-2,8,0-6,a,ff-2,9c,0,30,da,d3,29,0-2,6b,fa,da,58,9,26,bb,fd,ff,55,0-3,2b,ff-2,9c,4,0,7,ed,ff,c0,16,0-4,ff-8,ef,93,29,3,0-4,fb,ff,ac,2,0-c,ff-2,aa,0-6,2,ff-2,a3,0-3,55,ff-b,0-4,55,ff-a,55,0-3,a6,ff-2,3,0-4,39,55-4,39,0-3,ff-c,aa,0-7,55,ff-2,55,0-10,ff-2,aa,0-5,ff-4,fc,ff,f0,5e,0-8,55,ff-2,55,0-b,aa,ff-2,0-2,c4,fa,82,fd,70,0,55,ff-2,55,0-2,ff-2,aa,0,25,cf,f1,4f,0-2,ff-2,aa,0-2,a7,ff-2,2,0-6,2,ff-2,a6,0,43,ed,be,14,0-2,ba,ff,6b,3,0-2,3a,de,ff,55,0-3,73,ff-2,59,0-3,ad,ff,e4,3a,0-4,ff-2,c6,55-3,63,88,e5,ff,cc,42,0-4,f5,ff,ae,4,0-c,ff-2,aa,0-6,3,ff-2,a3,0-3,55,ff-2,8e,55-8,0-4,55,ff-2,8e,55-7,1c,0-3,9f,ff-2,8,0-4,aa,ff-4,aa,0-3,ff-2,c6,55-7,ff-2,aa,0-7,55,ff-2,55,0-10,ff-2,aa,0-5,ff-3,f4,8c,f0,ff,d9,10,0-7,55,ff-2,55,0-b,aa,ff-2,0-2,7a,ff,eb,ff,27,0,55,ff-2,55,0-2,ff-2,aa,0,5,92,ff,9e,0-2,ff-2,aa,0-2,a2,ff-2,5,0-6,6,ff-2,a1,0,4d,f7,b1,7,0-2,f1,ff,13,0-3,a,b4,ff,55,0-2,11,ba,ff,f3,c,0-3,5a,f9,ff,77,0-4,ff-2,aa,0-5,1b,b5,ff,e6,13,0-3,e3,ff,b6,c,0-c,ff-2,aa,0-6,e,ff-2,93,0-3,55,ff-2,55,0-c,55,ff-2,55,0-b,8d,ff-2,17,0-4,71,aa-2,ff-2,aa,0-3,ff-2,aa,0-7,ff-2,aa,0-7,55,ff-2,55,0-10,ff-2,aa,0-5,ff-2,e4,4d,7,88,ff-2,9d,d,0-6,55,ff-2,55,0-b,aa,ff-2,0-2,39,e3,ff,ca,0-2,55,ff-2,55,0-2,ff-2,aa,0-2,27,fa,f8,1b,0,ff-2,aa,0-2,96,ff-2,f,0-6,10,ff-2,94,0,53,fd,ac,2,0-2,fa,ff,5,0-3,3,ad,ff,55,0-2,34,de,ff,f3,aa-4,c0,f9,ff,be,0-4,ff-2,aa,0-6,4a,ff-2,5e,0-3,c5,ff,c4,1a,0-c,ff-2,aa,0-6,24,ff-2,7e,0-3,55,ff-2,55,0-c,55,ff-2,55,0-b,6d,ff-2,34,0-7,ff-2,aa,0-3,ff-2,aa,0-7,ff-2,aa,0-7,55,ff-2,55,0-10,ff-2,aa,0-5,ff-2,b0,6,0,16,dd,ff,ee,57,0-6,55,ff-2,55,0-b,aa,ff-2,0-2,15,bf,ff,80,0-2,55,ff-2,55,0-2,ff-2,aa,0-2,1,c3,ff,71,0,ff-2,aa,0-2,80,ff-2,23,0-6,23,ff-2,7e,0,4d,f7,b2,8,0-2,e1,ff,2b,0-3,16,c0,ff,55,0-2,6d,fe,ff-9,fc,1a,0-3,ff-2,aa,0-6,c,ff-2,9a,0-3,8c,ff,e0,36,0-c,ff-2,aa,0-6,52,ff-2,49,0-3,55,ff-2,55,0-c,55,ff-2,55,0-b,33,ff-2,6a,0-7,ff-2,aa,0-3,ff-2,aa,0-7,ff-2,aa,0-7,55,ff-2,55,0-f,9,ff-2,9e,0-5,ff-2,aa,0-3,49,e8,ff,e8,1e,0-5,55,ff-2,55,0-b,aa,ff-2,0-8,55,ff-2,55,0-2,ff-2,aa,0-3,58,f6,c8,1e,ff-2,aa,0-2,56,ff-2,48,0-6,48,ff-2,53,0,45,ef,bb,11,0-2,aa,ff,88,6,0-2,4d,eb,ff,55,0-2,b3,ff,e5,73,55-5,91,ff-2,5e,0-3,ff-2,aa,0-6,8,ff-2,a3,0-3,54,f5,fa,61,0-c,ff-2,aa,0-5,1,8d,ff,f9,16,0-3,55,ff-2,55,0-c,55,ff-2,55,0-b,8,e4,ff,a7,8,0-6,ff-2,aa,0-3,ff-2,aa,0-7,ff-2,aa,0-7,55,ff-2,55,0-f,1c,ff-2,8e,0-5,ff-2,aa,0-3,a,8e,ff-2,96,b,0-4,55,ff-2,55,0-b,aa,ff-2,0-8,55,ff-2,55,0-2,ff-2,aa,0-3,23,cd,f3,51,ff-2,aa,0-2,25,ff-2,77,0-6,78,ff-2,22,0,30,da,d6,2c,0-2,41,e6,f7,aa,5d,7b,eb,fb,ff,55,0,13,f9,ff,b1,d,0-5,19,f9,ff,ad,9,0-2,ff-2,aa,0-6,38,ff-2,87,0-3,1a,be,ff,d5,11,0-6,20,0-4,ff-2,aa,0-5,37,da,ff,a2,0-4,55,ff-2,55,0-c,55,ff-2,55,0-c,7c,fa,e9,50,0-6,ff-2,aa,0-3,ff-2,aa,0-7,ff-2,aa,0-7,55,ff-2,55,0-7,71,21,0-6,54,ff-2,5e,0-5,ff-2,aa,0-4,8,cd,ff,f5,6d,0-4,55,ff-2,55,0-b,aa,ff-2,0-8,55,ff-2,55,0-2,ff-2,aa,0-4,7b,ff,b9,ff-2,aa,0-3,cd,ff,c2,18,0-4,18,c1,ff,c9,0-2,16,c0,f2,4c,0-2,9,6d,fc,ff-3,c4,cd,ff,55,0,54,ff-2,77,0-7,cc,ff,d4,2a,0-2,ff-2,aa,0-5,10,9e,ff-2,47,0-3,1,57,ff-2,8c,11,0-4,37,ba,0-4,ff-2,aa,0-4,1d,c1,fd,e2,42,0-4,55,ff-2,55,0-c,55,ff-2,55,0-c,25,cd,ff,d0,23,0-4,5,ff-2,aa,0-3,ff-2,aa,0-7,ff-2,aa,0-7,55,ff-2,55,0-7,aa,be,41,0-4,10,a8,ff,fd,21,0-5,ff-2,aa,0-5,51,ea,ff,e4,1a,0-3,55,ff-2,55,0-b,aa,ff-2,0-8,55,ff-2,55,0-2,ff-2,aa,0-4,22,fb,f7,ff-2,aa,0-3,6f,fa,f3,70,0-4,6f,f3,f9,6a,0-3,80,ff,b1,1,0-3,35,88,a0,76,d,71,aa,39,6,a5,ff,fc,21,0-7,75,fd,f9,5c,0-2,ff-2,c6,55-3,60,7e,d6,ff,fa,a8,0-6,86,f2,ff,da,7e,5f,6f,a9,fb,ff,0-4,ff-2,c6,55,5f,73,b3,f2,ff,e9,54,1,0-4,55,ff-2,8e,55-8,39,0-3,55,ff-2,55,0-d,2e,dc,ff,ee,a3,65,5b,80,d1,ff-2,92,0-3,ff-2,aa,0-7,ff-2,aa,0-3,1c,55-3,8e,ff-2,8e,55-3,1c,0-3,aa,ff,fe,b7,76,5a,6d,c8,fd,fb,9a,0-6,ff-2,aa,0-5,3,77," +"ff-2,ad,13,0-2,55,ff-2,8e,55-8,39,0-2,aa,ff-2,0-8,55,ff-2,55,0-2,ff-2,aa,0-5,a9,ff-3,aa,0-3,14,a2,ff-2,a5,67-2,a5,ff-2,9e,12,0-3,23,fb,f6,3d,0-b,24,ce,ff,d5,1,0-7,41,ea,ff,9e,0-2,ff-9,fb,8f,1e,0-6,10,67,ef,ff-5,f6,a6,0-4,ff-8,bc,4f,1,0-5,55,ff-b,aa,0-3,55,ff-2,55,0-e,3c,b3,ff-6,f3,9f,20,0-3,ff-2,aa,0-7,ff-2,aa,0-3,55,ff-a,55,0-3,52,d7,fe,ff-6,a5,20,0-6,ff-2,aa,0-6,f,d0,ff,f3,67,0-2,55,ff-b,aa,0-2,aa,ff-2,0-8,55,ff-2,55,0-2,ff-2,aa,0-5,57,f4,ff-2,aa,0-4,1c,b2,fb,ff-4,fa,ae,1a,0-5,86,f8,d6,40,0-a,30,a1,aa,60,0-8,14,85,aa,99,0-2,aa-6,a0,8e,5c,1c,0-a,11,52,8e,a2,9a,74,20,0-5,aa-4,a1,91,67,2d,0-8,39,aa-b,71,0-3,39,aa-2,39,0-10,32,73,98,a4,8f,65,19,0-5,aa-2,71,0-7,aa-2,71,0-3,39,aa-a,39,0-4,3,2c,73,96,a6,9c,75,35,0-8,aa-2,71,0-7,36,a2,aa,9d,6,0,39,aa-b,71,0-2,71,aa-2,0-8,39,aa-2,39,0-2,aa-2,71,0-5,16,88,aa-2,71,0-5,4,30,82,9d,9c,80,2e,3,0-6,1e,be,fe,d8,4c,5,0-fb,14,ba,f8,fc,d6,86,67,5c,7c,b2,32,0-f6,1b,75,ec,ff-5,f9,56,0-f8,c,45,84,9e,a6,91,4f,e,0-9f6,c,4f,b6,e6,f6,df,8e,38,0-6,2,e,23,33,48,53,55-2,0-8,1c,48,8f,c2,ec,fa,f1,d6,94,4c,8,0-5,22,7b,af,d1,ef,fb,f0,d0,83,36,0-c,17,4f,55-2,0-6,1c,55-a,1c,0-6,1,1b,72,ba,e9,f9,ee,cf,90,25,0-4,55-c,39,0-5,1e,6d,c8,ed,f9,e7,a7,56,7,0-7,2f,82,d3,f2,f4,db,8c,3b,1,0-56,d,48,87,cb,ec,fa,ee,b8,69,11,0-7,83,ed,ff-4,fe,dc,3c,0-5,3b,b8,cd,dd,f2,fd,ff-2,0-8,c6,f0,ff-7,ee,87,12,0-4,55,ff-7,fd,dd,4d,1,0-a,80,f9,ff-2,0-6,55,ff-a,55,0-6,33,b9,fd,ff-6,55,0-4,ff-c,a7,0-4,12,c0,f9,ff-5,f2,79,9,0-5,34,d7,fc,ff-4,fe,df,49,0-56,7e,ed,ff-6,fa,96,14,0-4,1,5e,ff-2,a1,2f,d,46,d7,ff,d7,2f,0-4,53,f1,dd,cd,b8,e5,ff-2,0-8,ff,eb,ae,6d,27,c,e,37,aa,f4,fe,a8,3,0-3,4f,d4,90,4f,18,6,16,54,d6,ff,e7,48,0-9,34,f9,ff-3,0-6,55,ff-2,c6,aa-7,39,0-5,21,e3,ff,e3,86,26,9,19,50,bd,4b,0-4,aa-8,ab,e2,ff-2,5c,0-3,c,a6,ff,fb,81,21,8,31,bf,fd,f6,64,0-4,27,d1,ff,eb,6b,1c,9,33,b7,f9,e1,3e,0-55,aa,ea,aa,49,16,2,1d,9a,f4,fd,81,0-4,1a,c0,ff,d6,13,0-3,53,eb,fc,86,0-4,1a,47,33,23,e,ac,ff-2,0-8,b2,4c,d,0-5,13,a2,ff,f9,35,0-3,16,2a,1,0-5,4d,e6,ff,a2,0-8,12,aa,e8-2,ff-2,0-6,55,ff-2,55,0-c,7,92,ff,fb,51,6,0-4,17,13,0-c,18,c0,ff,f1,11,0-3,34,de,ff,bc,6,0-3,3a,dd,ff,bc,0-4,71,fb,f9,77,0-4,21,c3,fe,9b,0-55,84,48,d,0-4,1a,c4,ff,d5,0-4,52,f5,fa,63,0-4,a,aa,ff,ea,6,0-8,aa,ff-2,0-11,29,ff-2,8a,0-b,d,b7,ff,ea,0-8,75,f9,86,ae,ff-2,0-6,55,ff-2,55,0-c,3a,e4,fe,92,0-14,54,f3,ff,94,0-4,4f,f9,ff,68,0-4,a,b4,ff,f3,0-4,c3,ff,ce,24,0-5,55,ff,f5,d,0-5b,8,b2,ff,f7,0-4,87,ff,e3,39,0-5,72,ff-2,31,0-8,aa,ff-2,0-11,8,ff-2,a4,1,0-a,4,ae,ff,f9,0-7,18,e6,eb,19,aa,ff-2,0-6,55,ff-2,55,0-c,6e,fc,ed,47,0-14,a1,ff,ef,4b,0-4,51,fb,ff,5a,0-4,3,ad,ff,f7,0-4,e9,ff,b6,c,0-5,1c,ff-2,3d,0-2e,6,5b,2e,0-11,5b,31,3,0-16,30,d9,ff,e2,0-4,bb,ff,c7,1d,0-5,3b,ff-2,65,0-8,aa,ff-2,0-11,23,ff-2,af,5,0-a,1c,c6,ff,d4,0-6,e,a4,f5,67,0,aa,ff-2,0-6,55,ff-2,55,0-c,ac,ff,ca,20,f,38,51,4f,39,13,0-d,18,f8,ff,b8,13,0-4,38,e2,ff,7d,0-4,15,bf,ff,c5,0-4,fa,ff,ac,2,0-5,5,ff-2,70,0-7,55,ff-3,0-c,55,ff-3,0-10,f,3a,90,e4,ff,55,0-11,aa,fc,d0,67,2f,3,0-12,1d,ca,ff,fa,80,0-4,dc,ff,ba,10,0-5,21,ff-2,86,0-8,aa,ff-2,0-11,6a,ff-2,96,1,0-a,77,f4,fc,80,0-6,53,ee,be,18,0,aa,ff-2,0-6,55,ff-2,98,91,a5,9b,7f,38,6,0-6,d3,ff,b8,1f,a8,e2,fb,f9,e3,b9,34,0-c,6a,ff-2,72,1,0-4,f,a9,ff,d4,b,0-3,4b,ea,f7,6a,0-4,f3,ff,af,5,0-5,d,ff-2,8b,0-7,55,ff-3,0-c,55,ff-3,0-e,d,53,b5,e4,ff-2,f5,4b,0-11,97,ff-2,fa,d9,93,3c,0-10,1f,ad,ff-2,c3,22,0-4,f0,ff,af,5,6,33,4c,21,0,b,ff-2,9a,0-8,aa,ff-2,0-10,30,d5,ff,fc,3c,0-6,39,55,57,74,b9,ff,f3,8c,12,0-5,14,df,f7,37,0-2,aa,ff-2,0-6,55,ff-7,fe,d2,3e,5,0-4,ed,ff,c8,c0,e8,bc,ae,be,f2,ff,e7,4f,0-a,17,c1,ff,f1,11,0-6,13,bb,f6,ce,75,5c,85,f2,ed,78,a,0-4,d1,ff,c5,1b,0-5,42,ff-2,9f,0-7,55,ff-3,0-c,55,ff-3,0-b,e,43,89,eb,ff-2,ef,bb,79,18,0-2,aa,ff-d,55,0-2,39,8d,d2,f7,ff-2,cb,73,2b,7,0-b,15,ca,ff,fd,ca,18,0-5,f9,ff,ac,2,37,d5,f6,bb,0,4,ff-2,a4,0-8,aa,ff-2,0-f,3,ae,fc,ff,bb,4,0-6,aa,ff-4,dc,64,c,0-5,4,7f,ff,a6,1,0-2,aa,ff-2,0-6,4d,c7,8b,6b,5a,5d,81,c7,ff-2,db,45,0-4,f8,ff,f7,df,44,12,4,14,6e,eb,ff,cc,1,0-9,45,ed,ff,aa,0-8,1d,89,fc,ff-3,df,66,6,0-5,99,ff,e9,42,0-4,7,95,ff-2,a7,0-7,55,ff-3,0-c,55,ff-3,0-9,8,62,ae,e9,fe,ff,ef,92,4b,14,1,0-3,aa,ff-d,55,0-3,2,28,59,bc,f7,ff,fd,d5,9e,36,4,0-8,4,85,ff-2,c7,31,0-6,fa,ff,ac,2,38,d8,f7,bc,0,4,ff-2,a4,0-8,aa,ff-2,0-e,10,8f,ff-2,ce,2c,0-7,71,aa,ab,b7,d3,fd,f1,79,15,0-4,4d,e9,d4,2c,0-3,aa,ff-2,0-e,68,e8,ff,de,d,0-3,fd,ff,f1,54,0-4,2,84,ff-2,45,0-9,a2,ff,f0,4a,0-6,2,35,c9,fd,d8,b6,ad,bc,ee,fa,90,1f,0-4,3d,e6,ff,d2,34,d,4,19,81,e3,ff-2,a3,0-22,30,96,e8,ff-2,e0,b2,54,e,0-1d,1a,7c,bd,f1,ff,fd,d6,6d,18,0-6,2e,d8,ff,de,18,0-7,f0,ff,af,5,7,35,4d,21,0,b,ff-2,9a,0-8,aa,ff-2,0-e,82,f2,ff,f6,45,2,0-9,1,d,29,8d,f3,f6,98,0-3,3,c2,ff,76,4,0-3,aa,ff-2,0-e,8,8b,ff-2,4c,0-3,f6,ff,cb,21,0-5,38,ff-2,7c,0-8,d,ee,ff,c6,1c,0-6,2d,cd,ff,bd,2e,c,3,12,5d,e0,fa,ab,1,0-3,a,83,ff-2,dd,b7,ae,c3,f4,8e,ff-2,96,0-22,a2,ff-2,d6,81,36,d,0-20,1,16,4e,95,f1,ff,fb,51,0-6,47,f1,ff,7f,0-8,dc,ff,ba,10,0-5,20,ff-2,86,0-8,aa,ff-2,0-c,d,7c,ff-2,e3,52,0-e,3,7a,ff-2,44,0-2,70,ff,cd,5,0-4,aa,ff-2,0-f,25,ff-2,90,0-3,e1,ff,b0,6,0-5,b,ff-2,9e,0-8,6a,ff-2,73,0-7,a0,ff,d8,2e,0-5,5f,ff-2,4b,0-5,6e,c6,ef,fb,f6,da,6d,27,ff-2,7e,0-22,a2,ff-2,cd,79,31,b,0-20,1,13,48,8c,eb,ff,fb,51,0-6,53,fd,ff,57,0-8,bc,ff,c7,1d,0-5,3b,ff-2,66,0-8,aa,ff-2,0-c,79,f0,ff,f8,56,6,0-f,20,ff-2,8b,0-2,a9,ff,da,aa-5,e3,ff-2,aa-2,71,0-c,7,ff-2,a3,0-3,c7,ff,ac,2,0-5,4,ff-2,a5,0-7,10,b3,ff,fb,1e,0-7,e0,ff,b6,c,0-5,19,ff-2,8c,0-5,3,1e,45,51,4c,30,3,41,ff-2,56,0-22,30,97,e8,ff,fe,db,ad,4e,c,0-7,71,aa-d,39,0-7,17,76,b9,ed,ff,fd,d6,6e,18,0-6,55,ff-2,55,0-8,88,ff,e3,39,0-5,72,ff-2,31,0-8,aa,ff-2,0-a,d,79,ff-2,d9,4e,0-11,9,ff-2,a3,0-2,aa,ff-c,aa,0-c,18,ff-2,95,0-3,94,ff,b8,e,0-5,18,ff-2,92,0-7,47,ec,ff,ab,0-8,fa,ff,ad,3,0-5,7,ff-2,a4,0-b,2,89,ff,f9,1c,0-24,8,62,af,ea,fe,ff,ec,8e,4a,14,1,0-3,aa,ff-d,55,0-3,2,27,57,b8,f5,ff,fd,d5,9f,37,4,0-8,39,aa-2,39,0-8,52,f5,fa,63,0-4,a,aa,ff,ea,6,0-8,aa,ff-2,0-a,7a,f0,ff,e3,3d,4,0-11,2f,ff-2,90,0-2,39,55-7,c6,ff-2,55-2,39,0-c,54,ff-2,6c,0-3,5f,fb,d4,2a,0-5,48,ff-2,6d,0-7,8d,fe,f7,5a,0-8,eb,ff,bc,12,0-5,24,ff-2,95,0-b,20,c8,ff,c7,0-27,e,43,89,ec,ff-2,ee,ba,79,18,0-2,39,55-d,1c,0-2,3a,8d,d1,f6,ff-2,cb,73,2b,7,0-16,1b,c0,ff,d6,13,0-3,53,eb,fc,86,0-9,aa,ff-2,0-8,e,7c,ff,fe,ae,26,0-a,36,b,0-6,1b,af,ff,fd,42,0-a,aa,ff-2,0-6,35,9,0-6,35,cf,ff,ed,18,0-3,25,ce,fd,8d,3,0-3,15,b3,ff,f6,1f,0-6,e,ee,ff,c6,1d,0-8,a7,ff,ee,5d,0-4,c,93,ff-2,50,0-4,25,4,0-4,c,9d,fd,ef,52,0-8,55,ff-3,0-c,55,ff-3,0-e,d,54,b5,e4,ff-2,f6,4c,0-11,98,ff-2,fa,d9,94,3d,0-e,1c,55-2,1c,0-8,1,5f,ff-2,a0,2f,c,45,d7,ff,d7,2f,0-9,aa,ff-2,0-8,7e,f0,fb,a9,1a,0-b,e0,af,62,30,c,4,19,4c,bb,f7,ff,bf,7,0-a,aa,ff-2,0-6,df,ab,5a,29,a,6,23,64,d3,fd,f7,7e,0-4,4,76,ff,f3,7e,23,7,28,a3,f5,ff,a0,0-7,55,ff-2,87,3,0-8,4f,ec,ff,e0,5f,18,6,24,93,ef,ff,d7,d,0-4,97,92,3f,a,c,43,a0,fa,ff,9d,10,0-8,55,ff-3,0-c,55,ff-3,0-10,f,3a,90,e4,ff,55,0-11,aa,fd,d1,68,2f,3,0-f,55,ff-2,55,0-a,84,ed,ff-4,fe,dc,3d,0-6,aa,ff-a,0-4,ff-c,bb,11,0-2,ff-9,f5,9b,1c,0-b,aa,ff-2,0-6,ff-8,fd,e2,67,7,0-6,93,ef,ff-5,f9,9d,19,0-6,f,b5,ff,f9,21,0-9,2,5a,e3,fe,ff-5,fd,b9,2f,0-5,aa,ff-6,ee,9f,5,0-9,55,ff-3,0-c,59,ff-2,f6,0-13,6,5c,2e,0-11,5b,31,3,0-12,55,ff-2,55,0-a,c,4f,b7,e7,f6,e0,8f,38,0-7,aa,ff-a,0-4,ff-c,bb,11,0-2,72,9e,ca,e3,f7,fd,f2,da,9d,57,e,0-c,aa,ff-2,0-6,79,ab,d6,ec,fa,fc,eb,ca,81,3b,2,0-7,e,52,b3,e3,f9,ee,b9,6a,13,0-7,3a,e4,ff,c1,0-b,1,3d,89,d3,f1,fa,ec,b9,73,1d,1,0-5,4a,ae,db,f8,f7,dc,a8,4d,e,0-a,55,ff-3,0-c,7f,ff-2,ab,0-3c,55,ff-2,55,0-bc,c8,ff,e1,38,0-fb,c,f6,ff,9c,9,0-fb,4c,ff,f2,20,0-fc,86,ff,9d,0-890,55,1c,0-fe,ff,55,0-1b,22,7d,9f,a0,83,3e,9,0-1c,13,84,9b,2a,0-8,2a,9c,84,13,0-f,71-2,0-6d,55,ff-2,55,0-a,55,ff,aa,0-2,aa,ff,55,0-a,5b,fb,b3,d,0,f,fa-2,13,0-9,ff,56,0-8,10,3b,51,47,19,1,0-b,1,78,ef,ff-5,55,0-a,55,ff,aa,0-f,74,f9,a6,c,0-8,d,a7,f9,73,0-f,aa-2,0-51,20,ca,ff,bf,0-18,55,ff-2,55,0-a,55,ff,aa,0-2,aa,ff,55,0-a,90,ff,86,0-2,45,ff,d2,0-a,ff,57,0-7,f,a8,e5,fb,f1,b9,3d,0-b,2b,f1,ff,e8,8b,5f,84,ed,55,0-a,55,ff,aa,0-e,c,e1,ff,45,0-a,47,ff,e1,c,0-9,3c,41,0-3,aa-2,0-3,41,3c,0-4c,5c,f6,f7,60,0-18,55,ff-2,55,0-a,55,ff,aa,0-2,aa,ff,55,0-a,d8,ff,3e,0,1,8d,ff,88,0-6,28,74,c7,ee,ff,fb,e1,bf,86,23,0-2,10,a8,fe,df,b2,c7,fe,eb,1a,0-a,87,ff-2,49,0-3,23,21,0-a,55,ff,aa,0-d,3,7e,ff,c8,0-c,cb,ff,7d,3,0-8,b1,f9,97,32,0,aa-2,0,32,97,f9,b1,0-4b,5,cf,ff,bd,18,0-18,55,ff-2,55,0-a,55,ff,aa,0-2,aa,ff,55,0-9,16,fb,f7,c,0,10,b8,f8,55,0-5,2b,d1,fb,ff,fe,ff-5,55,0-2,3b,e5,df,4e,8,1d,c0,ff,70,0-a,a3,ff-2,c,0-f,55,ff,aa,0-d,20,c9,fd,72,0-c,75,fe,c8,1f,0-8,2a,7e,f1,d8,5f,b3-2,5f,d8,f1,7d,29,0-4b,3e,fd,ff,6d,1,0-18,55,ff-2,55,0-a,55,ff,aa,0-2,aa,ff,55,0-9,5a,ff,ba,0-2,34,de,d6,2c,0-4,1a,c2,ff,eb,60,12,ff,59,1a,3c,77,31,0-2,52,fc,b2,8,0-2,65,ff,a2,0-a,8d,ff-2,25,0-f,55,ff,aa,0-d,63,fa,dd,33,0-c,35,df,f9,61,0-a,20,8c,e5,fd-2,e5,8b,20,0-a,55,ff,aa,0-3f,e,af,ff,e4,9,0-19,55,ff-2,55,0-a,55,ff,aa,0-2,aa,ff,55,0-5,57,aa-3,d2,ff,de,aa-2,c0,f9,ed,b4,aa-2,0-2,43,ed,ff,8d,0-2,ff,55,0-6,49,f3,c4,1a,0-2,8e,ff,91,0-a,4c,ff-2,72,0-f,55,ff,aa,0-d,af,ff,bb,11,0-c,13,bd,ff,ac,0-b,e,b5,fd-2,b3,d,0-b,55,ff,aa,0-3f,3d,e6,ff,87,0-1a,55,ff-2,55,0-a,55,ff,aa,0-2,aa,ff,55,0-5,83,ff-e,0-2,52,fc,ff,61,0-2,ff,55,0-6,1c,be,fd,bb,64,8e,fc,f5,36,0-2,1,2e,7b,6f,3,0-4,bc,fe,d5,2d,0-e,55,ff,aa,0-c,c,f6,ff,87,0-e,8a,ff,f5,b,0-8,16,6e,db,d8,e6-2,d8,da,6d,16,0-9,55,ff,aa,0-3f,a5,ff,d7,2d,0-1a,55,ff-2,55,0-a,1c,55,39,0-2,39,55,1c,0-5,2c,55-2,7b,ec,e1,6f,55-2,e2,ff,81,55-3,0-2,45,ef,ff,a1,0-2,ff,55,0-6,1,42,ef,ff-3,f6,89,2,0,17,78,d8,ee,69,4,0-3,1,8f,fd,fb,92,0-e,1c,55,39,0-c,3b,ff-2,5a,0-e,5d,ff-2,38,0-7,50,b6,f4,b2,2f,af-2,2f,b2,f4,b6,4f,0-8,55,ff,aa,0-3e,1a,f2,ff,97,6,0-1a,54,fe-2,54,0-1a,57,f9,b6,e,0,e,fa-2,11,0-5,15,ae,ff-2,a2,56,ff,65,4,0-7,20,77,a3,92,36,3,30,7e,ed,d9,7b,19,0-4,22,a7,ff,fc,ff-2,58,3,0-1b,71,ff-2,2e,0-e,30,ff-2,6f,0-7,a7,ca,45,3,0,aa-2,0,4,45,ca,a6,0-8,55,ff,aa,0-3d,4,8a,ff,f7,24,0-1b,4f,f9-2,4f,0-1a,86,ff,8e,1,0,3e,ff,d6,0-7,2b,d3,ff-2,f8,ff,d6,9e,53,1,0-9,19,7b,d9,ed,7f,30,1,0-4,6,b5,fb,da,82,fd,ff,d3,2f,0-3,7,aa-2,0-15,8e,ff-2,16,0-e,18,ff-2,8d,0-7,1e,21,0-3,aa-2,0-3,21,1e,0-8,55,ff,aa,0-3d,26,cf,ff,b4,0-1c,47,f1-2,47,0-1a,c9,ff,4c,0-2,80,ff,94,0-8,d,59,b0,cc,ff-4,ba,2f,0-5,1,31,81,ee,d8,7a,18,0-6,5,85,ff,ec,28,0,82,f7,ff,c6,e,0-2,3,ff,f4,0-15,a3,ff-2,6,0-e,7,ff-2,a2,0-c,aa-2,0-7,55,ff-d,aa,0-37,79,fd,ec,46,0-1c,41,eb,ea,40,0-19,8,f5,fe,18,0,8,ac,fd,61,0-a,a,22,ff,97,b6,f9,fe,c4,4,0-3,1b,7d,da,ec,7d,2f,3,38,92,a2,6f,19,0-2,27,d0,ff,99,0-2,1a,b9,ff-2,78,4,0,c,ff,e4,0-15,a7,ff-2,2,0-e,3,ff-2,a6,0-c,39-2,0-7,55,ff-d,aa,0-15,39,aa-6,39,0-19,4,da,ff,b9,13,0-1c,38,e2-2,38,0-16,ff-e,83,0-9,ff,55,5,7e,ff-2,5e,0-2,46,ef,d7,77,17,0,2,8c,f7,ff-3,e7,36,0,4b,f5,ff,5f,0-3,1e,e3,ff,ef,5f,0,39,ff,b4,0-15,9c,ff-2,b,0-e,c,ff-2,9b,0-1b,55,ff,aa,0-1b,55,ff-6,55,0-19,5f,ff-2,4b,0-1d,12,4a-2,12,0-16,ff-e,83,0-9,ff,55,0,24,ff-2,94,0-2,29,7c,2e,1,0-2,38,f6,fb,8c,65,c1,fe,b4,17,52,fc,ff,61,0-4,66,f2,ff,de,1a,85,ff,7b,0-15,86,ff-2,1d,0-e,1f,ff-2,86,0-1b,55,ff,aa,0-1b,1c,55-6,1c,0-18,12,b4,ff,db,8,0-39,e,b8,f8,55,0-2,7a,ff,95,1,0-c,ff,55,0,8,ff-2,a2,0-8,92,ff,8b,0-2,1d,c7,f0,46,43,ed,ff,a4,0-4,6,80,ff-2,dd,ec,d9,30,0-15,5c,ff-2,3f,0-e,42,ff-2,5b,0-1b,55,ff,aa,0-3b,55,f2,f9,68,0-3a,2b,d5,df,35,0-2,b5,ff,5c,0-7,26,30,0-4,ff,55,0,2e,ff-2,80,0-8,a3,ff,64,0-2,8,b2,fb,51,23,cd,ff,f0,29,0-4,11,cd,ff-3,7f,7,0-15,2d,ff-2,66,0-e,69,ff-2,2c,0-1b,55,ff,aa,0-d,39,aa-3,0-1c,39,aa-3,0-a,b0,ff,d2,28,0-1e,55,ff-2,55,0-18,53,f7,ba,11,0,a,f5,fc,18,0-7,55,f7,89,3e,13,3,ff,58,2b,b3,ff,f1,24,0-8,78,ff,bd,1b,8,4f,e0,e4,3a,0,5f,fa,ff,d8,5b,16,4,a,29,a3,fe,ff-2,6d,2,0-16,e1,ff,a0,3,0-c,4,a3,ff,df,0-1c,55,ff,aa,0-d,55,ff-3,0-1c,55,ff-3,0-9,32,fe,ff,78,0-1f,55,ff-2,55,0-18,84,ff,8f,1,0,3a,ff,d9,1,0-7,55,ff,fd,e6,bd,aa,ff,c9,d2,fa,f5,7e,0-9,21,f0,fd,c5,b2,df,fe,a4,e,0,8,9a,f9,ff,f0,c0,ae,b4,d3,fe,df,f7,ff,cb,24,0-16,9a,ff,c4,1a,0-c,1c,c6,ff,98,0-1c,55,ff,aa,0-d,55,ff-3,0-1c,55,ff-3,0-8,5,94,ff,f6,1b,0-1f,55,ff-2,55,0-18,cd,ff,48,0-2,84,ff,92,0-8,c,50,ac,ce,ea,f8,ff,f9,e4,c1,4a,3,0-a,44,bf,f4,fb,e4,a5,d,0-3,5,4f,c0,e3,f8,fc,ee,d3,81,18,83,fb,fe,90,0-16,43,ec,ee,48,0-c,4b,f0,ec,43,0-2c,71,ff-2,c8,0-1c,55,ff-3,0-8,39,e1,fe,91,0-20,1c,55-2,1c,0-18,4e,55,e,0-2,35,55,27,0-a,8,24,40,50,ff,89,3a,17,0-c,1,1d,4a,51,3a,f,0-6,16,39,4e,52,44,29,2,0,19,51,55,45,0-16,13,ba,fe,89,0-c,8c,ff,ba,14,0-2c,ab,ff,f5,5f,0-1c,1c,55-3,0-8,83,fd,e7,41,0-51,2,ff,56,0-3d,48,fd,eb,f,0-a,10,ec,fd,4a,0-2c,6,ee,ff,b0,12,0-27,13,ef,ff,9f,8,0-51,1,ff,56,0-3d,6,c8,ff,60,0-a,62,ff,c8,6,0-2c,2f,ff-2,4d,0-28,6a,ff-2,40,0-53,ff,55,0-3e,41,e6,cb,21,0-8,22,cc,e6,41,0-2d,78,ff,bb,0-80,55,1c,0-3e,9,42,4e,15,0-8,15,4e,42,9,0-2d,32,55,2b,0-338"; + +IGL_INLINE void decompress_verasansmono_atlas(unsigned char* _fontatlas) +{ + std::string s = verasansmono_compressed_atlas; // Make a copy so that we can erase pieces as we parse the atlas + std::string delim_atlas = ","; + std::string delim_item = "-"; + size_t atlas_split = 0; // Locations found with delims above + size_t item_split = 0; + std::string curr_item; // Current element of the atlas string + int full_res = 0; // Running sum of the total bytes (256*256*1) + + while ((atlas_split = s.find(delim_atlas)) != std::string::npos) { + curr_item = s.substr(0, atlas_split); + if(curr_item.find(delim_item) != std::string::npos) + { + item_split = curr_item.find(delim_item); + unsigned int occurences = (unsigned int)std::stoi(curr_item.substr(item_split+1, curr_item.length()-1), 0, 16); + for(int i=0; i + +namespace igl +{ +namespace opengl +{ + +IGL_INLINE void decompress_verasansmono_atlas(unsigned char* _fontatlas); + +} + +} + +#ifndef IGL_STATIC_LIBRARY +# include "verasansmono_compressed.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/opengl/vertex_array.cpp b/src/external/libigl-2.3.0/include/igl/opengl/vertex_array.cpp new file mode 100644 index 000000000..c07113ad3 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/opengl/vertex_array.cpp @@ -0,0 +1,61 @@ +#include "vertex_array.h" +#include + +template < + typename DerivedV, + typename DerivedF> +IGL_INLINE void igl::opengl::vertex_array( + const Eigen::PlainObjectBase & V, + const Eigen::PlainObjectBase & F, + GLuint & va_id, + GLuint & ab_id, + GLuint & eab_id) +{ + // Inputs should be in RowMajor storage. If not, we have no choice but to + // create a copy. + if(!(V.Options & Eigen::RowMajor)) + { + Eigen::Matrix< + typename DerivedV::Scalar, + DerivedV::RowsAtCompileTime, + DerivedV::ColsAtCompileTime, + Eigen::RowMajor> VR = V; + return vertex_array(VR,F,va_id,ab_id,eab_id); + } + if(!(F.Options & Eigen::RowMajor)) + { + Eigen::Matrix< + typename DerivedF::Scalar, + DerivedF::RowsAtCompileTime, + DerivedF::ColsAtCompileTime, + Eigen::RowMajor> FR = F; + return vertex_array(V,FR,va_id,ab_id,eab_id); + } + // Generate and attach buffers to vertex array + glGenVertexArrays(1, &va_id); + glGenBuffers(1, &ab_id); + glGenBuffers(1, &eab_id); + glBindVertexArray(va_id); + glBindBuffer(GL_ARRAY_BUFFER, ab_id); + const auto size_VScalar = sizeof(typename DerivedV::Scalar); + const auto size_FScalar = sizeof(typename DerivedF::Scalar); + glBufferData(GL_ARRAY_BUFFER,size_VScalar*V.size(),V.data(),GL_STATIC_DRAW); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, eab_id); + assert(sizeof(GLuint) == size_FScalar && "F type does not match GLuint"); + glBufferData( + GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint)*F.size(), F.data(), GL_STATIC_DRAW); + glVertexAttribPointer( + 0, + V.cols(), + size_VScalar==sizeof(float)?GL_FLOAT:GL_DOUBLE, + GL_FALSE, + V.cols()*size_VScalar, + (GLvoid*)0); + glEnableVertexAttribArray(0); + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindVertexArray(0); +} + +#ifdef IGL_STATIC_LIBRARY +template void igl::opengl::vertex_array, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, unsigned int&, unsigned int&, unsigned int&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/opengl/vertex_array.h b/src/external/libigl-2.3.0/include/igl/opengl/vertex_array.h new file mode 100644 index 000000000..1342a9c90 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/opengl/vertex_array.h @@ -0,0 +1,38 @@ +#ifndef IGL_OPENGL_VERTEX_ARRAY_H +#define IGL_OPENGL_VERTEX_ARRAY_H +#include +#include +#include +namespace igl +{ + namespace opengl + { + // Create a GL_VERTEX_ARRAY for a given mesh (V,F) + // + // Inputs: + // V #V by dim list of mesh vertex positions + // F #F by 3 list of mesh triangle indices into V + // Outputs: + // va_id id of vertex array + // ab_id id of array buffer (vertex buffer object) + // eab_id id of element array buffer (element/face buffer object) + // + template < + typename DerivedV, + typename DerivedF> + IGL_INLINE void vertex_array( + // Note: Unlike most libigl functions, the **input** Eigen matrices must + // be `Eigen::PlainObjectBase` because we want to directly access it's + // underlying storage. It cannot be `Eigen::MatrixBase` (see + // http://stackoverflow.com/questions/25094948/) + const Eigen::PlainObjectBase & V, + const Eigen::PlainObjectBase & F, + GLuint & va_id, + GLuint & ab_id, + GLuint & eab_id); + } +} +#ifndef IGL_STATIC_LIBRARY +# include "vertex_array.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/orient_halfedges.cpp b/src/external/libigl-2.3.0/include/igl/orient_halfedges.cpp new file mode 100644 index 000000000..3b2abbdc6 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/orient_halfedges.cpp @@ -0,0 +1,48 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2020 Oded Stein +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "orient_halfedges.h" + +#include "oriented_facets.h" +#include "unique_simplices.h" + + +template +IGL_INLINE void +igl::orient_halfedges( + const Eigen::MatrixBase& F, + Eigen::PlainObjectBase& E, + Eigen::PlainObjectBase& oE) +{ + assert(F.cols()==3 && "This only works for triangle meshes."); + + using Int = typename DerivedF::Scalar; + + const Eigen::Index m = F.rows(); + + DerivedE allE, EE; + oriented_facets(F, allE); + Eigen::Matrix IA, IC; + unique_simplices(allE, EE, IA, IC); + + E.resize(m, 3); + oE.resize(m, 3); + for(Eigen::Index f=0; f, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/orient_halfedges.h b/src/external/libigl-2.3.0/include/igl/orient_halfedges.h new file mode 100644 index 000000000..b95864442 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/orient_halfedges.h @@ -0,0 +1,41 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2020 Oded Stein +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_ORIENT_HALFEDGES_H +#define IGL_ORIENT_HALFEDGES_H + +#include "igl_inline.h" +#include + + +namespace igl +{ + // Orients halfedges for a triangle mesh, assigning them to a unique edge. + // + // Inputs: + // F: input mesh connectivity + // + // Outputs: + // E: a mapping from each halfedge to each edge + // oE: the orientation of each halfedge compared to the orientation of the + // actual edge. Every edge appears positively oriented exactly once. + + template + IGL_INLINE void + orient_halfedges( + const Eigen::MatrixBase& F, + Eigen::PlainObjectBase& E, + Eigen::PlainObjectBase& oE); + +} + + +#ifndef IGL_STATIC_LIBRARY +# include "orient_halfedges.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/orient_outward.cpp b/src/external/libigl-2.3.0/include/igl/orient_outward.cpp new file mode 100644 index 000000000..0c422e615 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/orient_outward.cpp @@ -0,0 +1,96 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "orient_outward.h" +#include "per_face_normals.h" +#include "barycenter.h" +#include "doublearea.h" +#include + +template < + typename DerivedV, + typename DerivedF, + typename DerivedC, + typename DerivedFF, + typename DerivedI> +IGL_INLINE void igl::orient_outward( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const Eigen::MatrixBase & C, + Eigen::PlainObjectBase & FF, + Eigen::PlainObjectBase & I) +{ + using namespace Eigen; + using namespace std; + assert(C.rows() == F.rows()); + assert(F.cols() == 3); + assert(V.cols() == 3); + + // number of faces + const int m = F.rows(); + // number of patches + const int num_cc = C.maxCoeff()+1; + I.resize(num_cc); + if(&FF != &F) + { + FF = F; + } + DerivedV N,BC,BCmean; + Matrix A; + VectorXd totA(num_cc), dot(num_cc); + Matrix Z(1,1,1); + per_face_normals(V,F,Z.normalized(),N); + barycenter(V,F,BC); + doublearea(V,F,A); + BCmean.setConstant(num_cc,3,0); + dot.setConstant(num_cc,1,0); + totA.setConstant(num_cc,1,0); + // loop over faces + for(int f = 0;f, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::orient_outward, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/orient_outward.h b/src/external/libigl-2.3.0/include/igl/orient_outward.h new file mode 100644 index 000000000..5f4fdc31f --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/orient_outward.h @@ -0,0 +1,43 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_ORIENT_OUTWARD_H +#define IGL_ORIENT_OUTWARD_H +#include "igl_inline.h" +#include +namespace igl +{ + // Orient each component (identified by C) of a mesh (V,F) so the normals on + // average point away from the patch's centroid. + // + // Inputs: + // V #V by 3 list of vertex positions + // F #F by 3 list of triangle indices + // C #F list of components (output of orientable_patches) + // Outputs: + // FF #F by 3 list of new triangle indices such that FF(~I,:) = F(~I,:) and + // FF(I,:) = fliplr(F(I,:)) (OK if &FF = &F) + // I max(C)+1 list of whether face has been flipped + template < + typename DerivedV, + typename DerivedF, + typename DerivedC, + typename DerivedFF, + typename DerivedI> + IGL_INLINE void orient_outward( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const Eigen::MatrixBase & C, + Eigen::PlainObjectBase & FF, + Eigen::PlainObjectBase & I); +}; + +#ifndef IGL_STATIC_LIBRARY +# include "orient_outward.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/orientable_patches.cpp b/src/external/libigl-2.3.0/include/igl/orientable_patches.cpp new file mode 100644 index 000000000..54ae641b0 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/orientable_patches.cpp @@ -0,0 +1,107 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "orientable_patches.h" +#include "vertex_components.h" +#include "sort.h" +#include "unique_rows.h" +#include +#include + +template +IGL_INLINE void igl::orientable_patches( + const Eigen::MatrixBase & F, + Eigen::PlainObjectBase & C, + Eigen::SparseMatrix & A) +{ + using namespace Eigen; + using namespace std; + + // simplex size + assert(F.cols() == 3); + + // List of all "half"-edges: 3*#F by 2 + Matrix allE,sortallE,uE; + allE.resize(F.rows()*3,2); + Matrix IX; + VectorXi IA,IC; + allE.block(0*F.rows(),0,F.rows(),1) = F.col(1); + allE.block(0*F.rows(),1,F.rows(),1) = F.col(2); + allE.block(1*F.rows(),0,F.rows(),1) = F.col(2); + allE.block(1*F.rows(),1,F.rows(),1) = F.col(0); + allE.block(2*F.rows(),0,F.rows(),1) = F.col(0); + allE.block(2*F.rows(),1,F.rows(),1) = F.col(1); + // Sort each row + sort(allE,2,true,sortallE,IX); + //IC(i) tells us where to find sortallE(i,:) in uE: + // so that sortallE(i,:) = uE(IC(i),:) + unique_rows(sortallE,uE,IA,IC); + // uE2FT(e,f) = 1 means face f is adjacent to unique edge e + vector > uE2FTijv(IC.rows()); + for(int e = 0;e(e%F.rows(),IC(e),1); + } + SparseMatrix uE2FT(F.rows(),uE.rows()); + uE2FT.setFromTriplets(uE2FTijv.begin(),uE2FTijv.end()); + // kill non-manifold edges + for(int j=0; j<(int)uE2FT.outerSize();j++) + { + int degree = 0; + for(typename SparseMatrix::InnerIterator it (uE2FT,j); it; ++it) + { + degree++; + } + // Iterate over inside + if(degree > 2) + { + for(typename SparseMatrix::InnerIterator it (uE2FT,j); it; ++it) + { + uE2FT.coeffRef(it.row(),it.col()) = 0; + } + } + } + // Face-face Adjacency matrix + SparseMatrix uE2F; + uE2F = uE2FT.transpose().eval(); + A = uE2FT*uE2F; + // All ones + for(int j=0; j::InnerIterator it (A,j); it; ++it) + { + if(it.value() > 1) + { + A.coeffRef(it.row(),it.col()) = 1; + } + } + } + //% Connected components are patches + //%C = vertex_components(A); % alternative to graphconncomp from matlab_bgl + //[~,C] = graphconncomp(A); + // graph connected components + vertex_components(A,C); + +} + +template +IGL_INLINE void igl::orientable_patches( + const Eigen::MatrixBase & F, + Eigen::PlainObjectBase & C) +{ + Eigen::SparseMatrix A; + return orientable_patches(F,C,A); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +template void igl::orientable_patches, Eigen::Matrix, int>(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::SparseMatrix&); +template void igl::orientable_patches, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::orientable_patches, Eigen::Matrix, int>(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::SparseMatrix&); +template void igl::orientable_patches, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/orientable_patches.h b/src/external/libigl-2.3.0/include/igl/orientable_patches.h new file mode 100644 index 000000000..a77cf3cb8 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/orientable_patches.h @@ -0,0 +1,41 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_ORIENTABLE_PATCHES_H +#define IGL_ORIENTABLE_PATCHES_H +#include +#include +#include +namespace igl +{ + // Compute connected components of facets connected by manifold edges. + // + // Known bugs: This will detect a moebius strip as a single patch (manifold, + // non-orientable) and also non-manfiold, yet orientable patches. + // + // Q: Does this find exactly (manifold || orientable) patches? + // + // Inputs: + // F #F by simplex-size list of facets + // Outputs: + // C #F list of component ids + // A #F by #F adjacency matrix + // + template + IGL_INLINE void orientable_patches( + const Eigen::MatrixBase & F, + Eigen::PlainObjectBase & C, + Eigen::SparseMatrix & A); + template + IGL_INLINE void orientable_patches( + const Eigen::MatrixBase & F, + Eigen::PlainObjectBase & C); +}; +#ifndef IGL_STATIC_LIBRARY +# include "orientable_patches.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/oriented_facets.cpp b/src/external/libigl-2.3.0/include/igl/oriented_facets.cpp new file mode 100644 index 000000000..ebc122fa7 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/oriented_facets.cpp @@ -0,0 +1,58 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2017 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "oriented_facets.h" + +template +IGL_INLINE void igl::oriented_facets( + const Eigen::MatrixBase & F, + Eigen::PlainObjectBase & E) +{ + E.resize(F.rows()*F.cols(),F.cols()-1); + typedef typename DerivedE::Scalar EScalar; + switch(F.cols()) + { + case 4: + E.block(0*F.rows(),0,F.rows(),1) = F.col(1).template cast(); + E.block(0*F.rows(),1,F.rows(),1) = F.col(3).template cast(); + E.block(0*F.rows(),2,F.rows(),1) = F.col(2).template cast(); + + E.block(1*F.rows(),0,F.rows(),1) = F.col(0).template cast(); + E.block(1*F.rows(),1,F.rows(),1) = F.col(2).template cast(); + E.block(1*F.rows(),2,F.rows(),1) = F.col(3).template cast(); + + E.block(2*F.rows(),0,F.rows(),1) = F.col(0).template cast(); + E.block(2*F.rows(),1,F.rows(),1) = F.col(3).template cast(); + E.block(2*F.rows(),2,F.rows(),1) = F.col(1).template cast(); + + E.block(3*F.rows(),0,F.rows(),1) = F.col(0).template cast(); + E.block(3*F.rows(),1,F.rows(),1) = F.col(1).template cast(); + E.block(3*F.rows(),2,F.rows(),1) = F.col(2).template cast(); + return; + case 3: + E.block(0*F.rows(),0,F.rows(),1) = F.col(1).template cast(); + E.block(0*F.rows(),1,F.rows(),1) = F.col(2).template cast(); + E.block(1*F.rows(),0,F.rows(),1) = F.col(2).template cast(); + E.block(1*F.rows(),1,F.rows(),1) = F.col(0).template cast(); + E.block(2*F.rows(),0,F.rows(),1) = F.col(0).template cast(); + E.block(2*F.rows(),1,F.rows(),1) = F.col(1).template cast(); + return; + } +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::oriented_facets, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::oriented_facets, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::oriented_facets, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::oriented_facets, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::oriented_facets, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::oriented_facets, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::oriented_facets, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/oriented_facets.h b/src/external/libigl-2.3.0/include/igl/oriented_facets.h new file mode 100644 index 000000000..9e211cf9b --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/oriented_facets.h @@ -0,0 +1,42 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2017 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_ORIENTED_FACETS_H +#define IGL_ORIENTED_FACETS_H +#include "igl_inline.h" +#include +namespace igl +{ + // ORIENTED_FACETS Determines all "directed + // [facets](https://en.wikipedia.org/wiki/Simplex#Elements)" of a given set of + // simplicial elements. For a manifold triangle mesh, this computes all + // half-edges. For a manifold tetrahedral mesh, this computes all half-faces. + // + // Inputs: + // F #F by simplex_size list of simplices + // Outputs: + // E #E by simplex_size-1 list of facets, such that E.row(f+#F*c) is the + // facet opposite F(f,c) + // + // Note: this is not the same as igl::edges because this includes every + // directed edge including repeats (meaning interior edges on a surface will + // show up once for each direction and non-manifold edges may appear more than + // once for each direction). + // + // Note: This replaces the deprecated `all_edges` function + template + IGL_INLINE void oriented_facets( + const Eigen::MatrixBase & F, + Eigen::PlainObjectBase & E); +} + +#ifndef IGL_STATIC_LIBRARY +# include "oriented_facets.cpp" +#endif + +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/orth.cpp b/src/external/libigl-2.3.0/include/igl/orth.cpp new file mode 100644 index 000000000..467a4993e --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/orth.cpp @@ -0,0 +1,32 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "orth.h" + +// Broken Implementation +IGL_INLINE void igl::orth(const Eigen::MatrixXd &A, Eigen::MatrixXd &Q) +{ + + //perform svd on A = U*S*V' (V is not computed and only the thin U is computed) + Eigen::JacobiSVD svd(A, Eigen::ComputeThinU ); + Eigen::MatrixXd U = svd.matrixU(); + const Eigen::VectorXd S = svd.singularValues(); + + //get rank of A + int m = A.rows(); + int n = A.cols(); + double tol = std::max(m,n) * S.maxCoeff() * 2.2204e-16; + int r = 0; + for (int i = 0; i < S.rows(); ++r,++i) + { + if (S[i] < tol) + break; + } + + //keep r first columns of U + Q = U.block(0,0,U.rows(),r); +} diff --git a/src/external/libigl-2.3.0/include/igl/orth.h b/src/external/libigl-2.3.0/include/igl/orth.h new file mode 100644 index 000000000..a77cd6593 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/orth.h @@ -0,0 +1,43 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_ORTH_H +#define IGL_ORTH_H + +#include "igl_inline.h" +#include + +namespace igl +{ + // ORTH Orthogonalization. + // ORTH(A,Q) produces Q as an orthonormal basis for the range of A. + // That is, Q'*Q = I, the columns of Q span the same space as + // the columns of A, and the number of columns of Q is the + // rank of A. + // + // + // The algorithm uses singular value decomposition, SVD, instead of orthogonal + // factorization, QR. This doubles the computation time, but + // provides more reliable and consistent rank determination. + // Closely follows MATLAB implementation in orth.m + // + // Inputs: + // A m by n matrix + // Outputs: + // Q m by n matrix with orthonormal columns spanning same column space as + // A + // + // Known bugs: Implementation listed as "Broken" + IGL_INLINE void orth(const Eigen::MatrixXd &A, Eigen::MatrixXd &Q); +} + + +#ifndef IGL_STATIC_LIBRARY +# include "orth.cpp" +#endif +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/ortho.cpp b/src/external/libigl-2.3.0/include/igl/ortho.cpp new file mode 100644 index 000000000..e634eed74 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/ortho.cpp @@ -0,0 +1,33 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "ortho.h" + +template < typename DerivedP> +IGL_INLINE void igl::ortho( + const typename DerivedP::Scalar left, + const typename DerivedP::Scalar right, + const typename DerivedP::Scalar bottom, + const typename DerivedP::Scalar top, + const typename DerivedP::Scalar nearVal, + const typename DerivedP::Scalar farVal, + Eigen::PlainObjectBase & P) +{ + P.setIdentity(); + P(0,0) = 2. / (right - left); + P(1,1) = 2. / (top - bottom); + P(2,2) = - 2./ (farVal - nearVal); + P(0,3) = - (right + left) / (right - left); + P(1,3) = - (top + bottom) / (top - bottom); + P(2,3) = - (farVal + nearVal) / (farVal - nearVal); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::ortho >(Eigen::Matrix::Scalar, Eigen::Matrix::Scalar, Eigen::Matrix::Scalar, Eigen::Matrix::Scalar, Eigen::Matrix::Scalar, Eigen::Matrix::Scalar, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/ortho.h b/src/external/libigl-2.3.0/include/igl/ortho.h new file mode 100644 index 000000000..70b9cab4d --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/ortho.h @@ -0,0 +1,42 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_ORTHO_H +#define IGL_ORTHO_H +#include "igl_inline.h" + +#include + +namespace igl +{ + // Implementation of the deprecated glOrtho function. + // + // Inputs: + // left coordinate of left vertical clipping plane + // right coordinate of right vertical clipping plane + // bottom coordinate of bottom vertical clipping plane + // top coordinate of top vertical clipping plane + // nearVal distance to near plane + // farVal distance to far plane + // Outputs: + // P 4x4 perspective matrix + template < typename DerivedP> + IGL_INLINE void ortho( + const typename DerivedP::Scalar left, + const typename DerivedP::Scalar right, + const typename DerivedP::Scalar bottom, + const typename DerivedP::Scalar top, + const typename DerivedP::Scalar nearVal, + const typename DerivedP::Scalar farVal, + Eigen::PlainObjectBase & P); +} + +#ifndef IGL_STATIC_LIBRARY +# include "ortho.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/outer_element.cpp b/src/external/libigl-2.3.0/include/igl/outer_element.cpp new file mode 100644 index 000000000..59826f71e --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/outer_element.cpp @@ -0,0 +1,280 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Qingnan Zhou +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "outer_element.h" +#include +#include + +template < + typename DerivedV, + typename DerivedF, + typename DerivedI, + typename IndexType, + typename DerivedA + > +IGL_INLINE void igl::outer_vertex( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const Eigen::MatrixBase & I, + IndexType & v_index, + Eigen::PlainObjectBase & A) +{ + // Algorithm: + // Find an outer vertex (i.e. vertex reachable from infinity) + // Return the vertex with the largest X value. + // If there is a tie, pick the one with largest Y value. + // If there is still a tie, pick the one with the largest Z value. + // If there is still a tie, then there are duplicated vertices within the + // mesh, which violates the precondition. + typedef typename DerivedF::Scalar Index; + const Index INVALID = std::numeric_limits::max(); + const size_t num_selected_faces = I.rows(); + std::vector candidate_faces; + Index outer_vid = INVALID; + typename DerivedV::Scalar outer_val = 0; + for (size_t i=0; i outer_val) + { + outer_val = vx; + outer_vid = v; + candidate_faces = {f}; + } else if (v == outer_vid) + { + candidate_faces.push_back(f); + } else if (vx == outer_val) + { + // Break tie. + auto vy = V(v,1); + auto vz = V(v, 2); + auto outer_y = V(outer_vid, 1); + auto outer_z = V(outer_vid, 2); + assert(!(vy == outer_y && vz == outer_z)); + bool replace = (vy > outer_y) || + ((vy == outer_y) && (vz > outer_z)); + if (replace) + { + outer_val = vx; + outer_vid = v; + candidate_faces = {f}; + } + } + } + } + + assert(outer_vid != INVALID); + assert(candidate_faces.size() > 0); + v_index = outer_vid; + A.resize(candidate_faces.size(),1); + std::copy(candidate_faces.begin(), candidate_faces.end(), A.data()); +} + +template< + typename DerivedV, + typename DerivedF, + typename DerivedI, + typename IndexType, + typename DerivedA + > +IGL_INLINE void igl::outer_edge( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const Eigen::MatrixBase & I, + IndexType & v1, + IndexType & v2, + Eigen::PlainObjectBase & A) { + // Algorithm: + // Find an outer vertex first. + // Find the incident edge with largest abs slope when projected onto XY plane. + // If there is a tie, check the signed slope and use the positive one. + // If there is still a tie, break it using the projected slope onto ZX plane. + // If there is still a tie, again check the signed slope and use the positive one. + // If there is still a tie, then there are multiple overlapping edges, + // which violates the precondition. + typedef typename DerivedV::Scalar Scalar; + typedef typename DerivedV::Index Index; + typedef typename Eigen::Matrix ScalarArray3; + typedef typename Eigen::Matrix IndexArray3; + const Index INVALID = std::numeric_limits::max(); + + Index outer_vid; + Eigen::Matrix candidate_faces; + outer_vertex(V, F, I, outer_vid, candidate_faces); + const ScalarArray3& outer_v = V.row(outer_vid); + assert(candidate_faces.size() > 0); + + auto get_vertex_index = [&](const IndexArray3& f, Index vid) -> Index + { + if (f[0] == vid) return 0; + if (f[1] == vid) return 1; + if (f[2] == vid) return 2; + assert(false); + return -1; + }; + + auto unsigned_value = [](Scalar v) -> Scalar { + if (v < 0) return v * -1; + else return v; + }; + + Scalar outer_slope_YX = 0; + Scalar outer_slope_ZX = 0; + Index outer_opp_vid = INVALID; + bool infinite_slope_detected = false; + std::vector incident_faces; + auto check_and_update_outer_edge = [&](Index opp_vid, Index fid) { + if (opp_vid == outer_opp_vid) + { + incident_faces.push_back(fid); + return; + } + + const ScalarArray3 opp_v = V.row(opp_vid); + if (!infinite_slope_detected && outer_v[0] != opp_v[0]) + { + // Finite slope + const ScalarArray3 diff = opp_v - outer_v; + const Scalar slope_YX = diff[1] / diff[0]; + const Scalar slope_ZX = diff[2] / diff[0]; + const Scalar u_slope_YX = unsigned_value(slope_YX); + const Scalar u_slope_ZX = unsigned_value(slope_ZX); + bool update = false; + if (outer_opp_vid == INVALID) { + update = true; + } else { + const Scalar u_outer_slope_YX = unsigned_value(outer_slope_YX); + if (u_slope_YX > u_outer_slope_YX) { + update = true; + } else if (u_slope_YX == u_outer_slope_YX && + slope_YX > outer_slope_YX) { + update = true; + } else if (slope_YX == outer_slope_YX) { + const Scalar u_outer_slope_ZX = + unsigned_value(outer_slope_ZX); + if (u_slope_ZX > u_outer_slope_ZX) { + update = true; + } else if (u_slope_ZX == u_outer_slope_ZX && + slope_ZX > outer_slope_ZX) { + update = true; + } else if (slope_ZX == u_outer_slope_ZX) { + assert(false); + } + } + } + + if (update) { + outer_opp_vid = opp_vid; + outer_slope_YX = slope_YX; + outer_slope_ZX = slope_ZX; + incident_faces = {fid}; + } + } else if (!infinite_slope_detected) + { + // Infinite slope + outer_opp_vid = opp_vid; + infinite_slope_detected = true; + incident_faces = {fid}; + } + }; + + const size_t num_candidate_faces = candidate_faces.size(); + for (size_t i=0; i +IGL_INLINE void igl::outer_facet( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const Eigen::MatrixBase & N, + const Eigen::MatrixBase & I, + IndexType & f, + bool & flipped) { + // Algorithm: + // Find an outer edge. + // Find the incident facet with the largest absolute X normal component. + // If there is a tie, keep the one with positive X component. + // If there is still a tie, pick the face with the larger signed index + // (flipped face has negative index). + typedef typename DerivedV::Scalar Scalar; + typedef typename DerivedV::Index Index; + const size_t INVALID = std::numeric_limits::max(); + + Index v1,v2; + Eigen::Matrix incident_faces; + outer_edge(V, F, I, v1, v2, incident_faces); + assert(incident_faces.size() > 0); + + auto generic_fabs = [&](const Scalar& val) -> const Scalar { + if (val >= 0) return val; + else return -val; + }; + + Scalar max_nx = 0; + size_t outer_fid = INVALID; + const size_t num_incident_faces = incident_faces.size(); + for (size_t i=0; i generic_fabs(max_nx)) { + max_nx = nx; + outer_fid = fid; + } else if (nx == -max_nx && nx > 0) { + max_nx = nx; + outer_fid = fid; + } else if (nx == max_nx) { + if ((max_nx >= 0 && outer_fid < fid) || + (max_nx < 0 && outer_fid > fid)) { + max_nx = nx; + outer_fid = fid; + } + } + } + } + + assert(outer_fid != INVALID); + f = outer_fid; + flipped = max_nx < 0; +} + + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +template void igl::outer_facet, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, int>(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, int&, bool&); +template void igl::outer_facet, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, unsigned long>(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, unsigned long&, bool&); +template void igl::outer_facet, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, int>(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, int&, bool&); +template void igl::outer_facet, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, int>(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, int&, bool&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/outer_element.h b/src/external/libigl-2.3.0/include/igl/outer_element.h new file mode 100644 index 000000000..937873641 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/outer_element.h @@ -0,0 +1,110 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Qingan Zhou +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_OUTER_ELEMENT_H +#define IGL_OUTER_ELEMENT_H +#include "igl_inline.h" +#include +namespace igl +{ + // Find a vertex that is reachable from infinite without crossing any faces. + // Such vertex is called "outer vertex." + // + // Precondition: The input mesh must have all self-intersection resolved and + // no duplicated vertices. See cgal::remesh_self_intersections.h for how to + // obtain such input. + // + // Inputs: + // V #V by 3 list of vertex positions + // F #F by 3 list of triangle indices into V + // I #I list of facets to consider + // Outputs: + // v_index index of outer vertex + // A #A list of facets incident to the outer vertex + template < + typename DerivedV, + typename DerivedF, + typename DerivedI, + typename IndexType, + typename DerivedA + > + IGL_INLINE void outer_vertex( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const Eigen::MatrixBase & I, + IndexType & v_index, + Eigen::PlainObjectBase & A); + + + // Find an edge that is reachable from infinity without crossing any faces. + // Such edge is called "outer edge." + // + // Precondition: The input mesh must have all self-intersection resolved and + // no duplicated vertices. The correctness of the output depends on the fact + // that there is no edge overlap. See cgal::remesh_self_intersections.h for + // how to obtain such input. + // + // Inputs: + // V #V by 3 list of vertex positions + // F #F by 3 list of triangle indices into V + // I #I list of facets to consider + // Outputs: + // v1 index of the first end point of outer edge + // v2 index of the second end point of outer edge + // A #A list of facets incident to the outer edge + template< + typename DerivedV, + typename DerivedF, + typename DerivedI, + typename IndexType, + typename DerivedA + > + IGL_INLINE void outer_edge( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const Eigen::MatrixBase & I, + IndexType & v1, + IndexType & v2, + Eigen::PlainObjectBase & A); + + + // Find a facet that is reachable from infinity without crossing any faces. + // Such facet is called "outer facet." + // + // Precondition: The input mesh must have all self-intersection resolved. I.e + // there is no duplicated vertices, no overlapping edge and no intersecting + // faces (the only exception is there could be topologically duplicated faces). + // See cgal::remesh_self_intersections.h for how to obtain such input. + // + // Inputs: + // V #V by 3 list of vertex positions + // F #F by 3 list of triangle indices into V + // N #N by 3 list of face normals + // I #I list of facets to consider + // Outputs: + // f Index of the outer facet. + // flipped true iff the normal of f points inwards. + template< + typename DerivedV, + typename DerivedF, + typename DerivedN, + typename DerivedI, + typename IndexType + > + IGL_INLINE void outer_facet( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const Eigen::MatrixBase & N, + const Eigen::MatrixBase & I, + IndexType & f, + bool & flipped); +} + +#ifndef IGL_STATIC_LIBRARY +# include "outer_element.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/parallel_for.h b/src/external/libigl-2.3.0/include/igl/parallel_for.h new file mode 100644 index 000000000..b6f7f0295 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/parallel_for.h @@ -0,0 +1,188 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_PARALLEL_FOR_H +#define IGL_PARALLEL_FOR_H +#include "igl_inline.h" +#include + +//#warning "Defining IGL_PARALLEL_FOR_FORCE_SERIAL" +//#define IGL_PARALLEL_FOR_FORCE_SERIAL + +namespace igl +{ + // PARALLEL_FOR Functional implementation of a basic, open-mp style, parallel + // for loop. If the inner block of a for-loop can be rewritten/encapsulated in + // a single (anonymous/lambda) function call `func` so that the serial code + // looks like: + // + // for(int i = 0;i + inline bool parallel_for( + const Index loop_size, + const FunctionType & func, + const size_t min_parallel=0); + // PARALLEL_FOR Functional implementation of an open-mp style, parallel for + // loop with accumulation. For example, serial code separated into n chunks + // (each to be parallelized with a thread) might look like: + // + // Eigen::VectorXd S; + // const auto & prep_func = [&S](int n){ S = Eigen:VectorXd::Zero(n); }; + // const auto & func = [&X,&S](int i, int t){ S(t) += X(i); }; + // const auto & accum_func = [&S,&sum](int t){ sum += S(t); }; + // prep_func(n); + // for(int i = 0;i= number of threads as only + // argument + // func function handle taking iteration index i and thread id t as only + // arguments to compute inner block of for loop I.e. + // for(int i ...){ func(i,t); } + // accum_func function handle taking thread index as only argument, to be + // called after all calls of func, e.g., for serial accumulation across + // all n (potential) threads, see n in description of prep_func. + // min_parallel min size of loop_size such that parallel (non-serial) + // thread pooling should be attempted {0} + // Returns true iff thread pool was invoked + template< + typename Index, + typename PrepFunctionType, + typename FunctionType, + typename AccumFunctionType + > + inline bool parallel_for( + const Index loop_size, + const PrepFunctionType & prep_func, + const FunctionType & func, + const AccumFunctionType & accum_func, + const size_t min_parallel=0); +} + +// Implementation + +#include "default_num_threads.h" + +#include +#include +#include +#include +#include + +template +inline bool igl::parallel_for( + const Index loop_size, + const FunctionType & func, + const size_t min_parallel) +{ + using namespace std; + // no op preparation/accumulation + const auto & no_op = [](const size_t /*n/t*/){}; + // two-parameter wrapper ignoring thread id + const auto & wrapper = [&func](Index i,size_t /*t*/){ func(i); }; + return parallel_for(loop_size,no_op,wrapper,no_op,min_parallel); +} + +template< + typename Index, + typename PreFunctionType, + typename FunctionType, + typename AccumFunctionType> +inline bool igl::parallel_for( + const Index loop_size, + const PreFunctionType & prep_func, + const FunctionType & func, + const AccumFunctionType & accum_func, + const size_t min_parallel) +{ + assert(loop_size>=0); + if(loop_size==0) return false; + // Estimate number of threads in the pool + // http://ideone.com/Z7zldb +#ifdef IGL_PARALLEL_FOR_FORCE_SERIAL + const size_t nthreads = 1; +#else + const size_t nthreads = igl::default_num_threads(); +#endif + if(loop_size(nthreads)),(Index)1); + + // [Helper] Inner loop + const auto & range = [&func](const Index k1, const Index k2, const size_t t) + { + for(Index k = k1; k < k2; k++) func(k,t); + }; + prep_func(nthreads); + // Create pool and launch jobs + std::vector pool; + pool.reserve(nthreads); + // Inner range extents + Index i1 = 0; + Index i2 = std::min(0 + slice, loop_size); + { + size_t t = 0; + for (; t+1 < nthreads && i1 < loop_size; ++t) + { + pool.emplace_back(range, i1, i2, t); + i1 = i2; + i2 = std::min(i2 + slice, loop_size); + } + if (i1 < loop_size) + { + pool.emplace_back(range, i1, loop_size, t); + } + } + // Wait for jobs to finish + for (std::thread &t : pool) if (t.joinable()) t.join(); + // Accumulate across threads + for(size_t t = 0;t +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include +#include + +template +IGL_INLINE void igl::parallel_transport_angles( +const Eigen::PlainObjectBase& V, +const Eigen::PlainObjectBase& F, +const Eigen::PlainObjectBase& FN, +const Eigen::MatrixXi &E2F, +const Eigen::MatrixXi &F2E, +Eigen::PlainObjectBase &K) +{ + int numE = E2F.rows(); + + Eigen::VectorXi isBorderEdge; + isBorderEdge.setZero(numE,1); + for(unsigned i=0; i N0 = FN.row(fid0); +// Eigen::Matrix N1 = FN.row(fid1); + + // find common edge on triangle 0 and 1 + int fid0_vc = -1; + int fid1_vc = -1; + for (unsigned i=0;i<3;++i) + { + if (F2E(fid0,i) == eid) + fid0_vc = i; + if (F2E(fid1,i) == eid) + fid1_vc = i; + } + assert(fid0_vc != -1); + assert(fid1_vc != -1); + + Eigen::Matrix common_edge = V.row(F(fid0,(fid0_vc+1)%3)) - V.row(F(fid0,fid0_vc)); + common_edge.normalize(); + + // Map the two triangles in a new space where the common edge is the x axis and the N0 the z axis + Eigen::Matrix P; + Eigen::Matrix o = V.row(F(fid0,fid0_vc)); + Eigen::Matrix tmp = -N0.cross(common_edge); + P << common_edge, tmp, N0; + // P.transposeInPlace(); + + + Eigen::Matrix V0; + V0.row(0) = V.row(F(fid0,0)) -o; + V0.row(1) = V.row(F(fid0,1)) -o; + V0.row(2) = V.row(F(fid0,2)) -o; + + V0 = (P*V0.transpose()).transpose(); + + // assert(V0(0,2) < 1e-10); + // assert(V0(1,2) < 1e-10); + // assert(V0(2,2) < 1e-10); + + Eigen::Matrix V1; + V1.row(0) = V.row(F(fid1,0)) -o; + V1.row(1) = V.row(F(fid1,1)) -o; + V1.row(2) = V.row(F(fid1,2)) -o; + V1 = (P*V1.transpose()).transpose(); + + // assert(V1(fid1_vc,2) < 10e-10); + // assert(V1((fid1_vc+1)%3,2) < 10e-10); + + // compute rotation R such that R * N1 = N0 + // i.e. map both triangles to the same plane + double alpha = -atan2(V1((fid1_vc+2)%3,2),V1((fid1_vc+2)%3,1)); + + Eigen::Matrix R; + R << 1, 0, 0, + 0, cos(alpha), -sin(alpha) , + 0, sin(alpha), cos(alpha); + V1 = (R*V1.transpose()).transpose(); + + // assert(V1(0,2) < 1e-10); + // assert(V1(1,2) < 1e-10); + // assert(V1(2,2) < 1e-10); + + // measure the angle between the reference frames + // k_ij is the angle between the triangle on the left and the one on the right + Eigen::Matrix ref0 = V0.row(1) - V0.row(0); + Eigen::Matrix ref1 = V1.row(1) - V1.row(0); + + ref0.normalize(); + ref1.normalize(); + + double ktemp = atan2(ref1(1),ref1(0)) - atan2(ref0(1),ref0(0)); + + // just to be sure, rotate ref0 using angle ktemp... + Eigen::Matrix R2; + R2 << cos(ktemp), -sin(ktemp), sin(ktemp), cos(ktemp); + +// Eigen::Matrix tmp1 = R2*(ref0.head(2)).transpose(); + + // assert(tmp1(0) - ref1(0) < 1e-10); + // assert(tmp1(1) - ref1(1) < 1e-10); + + K[eid] = ktemp; + } + } + +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +template void igl::parallel_transport_angles, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::Matrix const&, Eigen::Matrix const&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/parallel_transport_angles.h b/src/external/libigl-2.3.0/include/igl/parallel_transport_angles.h new file mode 100644 index 000000000..e37d7f373 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/parallel_transport_angles.h @@ -0,0 +1,51 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Olga Diamanti +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef IGL_PARALLEL_TRANSPORT_ANGLE +#define IGL_PARALLEL_TRANSPORT_ANGLE +#include "igl_inline.h" + +#include +#include + +namespace igl { + // Given the per-face local bases computed via igl::local_basis, this function + // computes the angle between the two reference frames across each edge. + // Any two vectors across the edge whose 2D representation only differs by + // this angle are considered to be parallel. + + // Inputs: + // V #V by 3 list of mesh vertex coordinates + // F #F by 3 list of mesh faces (must be triangles) + // FN #F by 3 list of face normals + // E2F #E by 2 list of the edge-to-face relation (e.g. computed + // via igl::edge_topology) + // F2E #F by 3 list of the face-to-edge relation (e.g. computed + // via igl::edge_topology) + // Output: + // K #E by 1 list of the parallel transport angles (zero + // for all boundary edges) + // +template +IGL_INLINE void parallel_transport_angles( +const Eigen::PlainObjectBase&V, +const Eigen::PlainObjectBase&F, +const Eigen::PlainObjectBase&FN, +const Eigen::MatrixXi &E2F, +const Eigen::MatrixXi &F2E, +Eigen::PlainObjectBase&K); + +}; + + +#ifndef IGL_STATIC_LIBRARY +#include "parallel_transport_angles.cpp" +#endif + + +#endif /* defined(IGL_PARALLEL_TRANSPORT_ANGLE) */ diff --git a/src/external/libigl-2.3.0/include/igl/partition.cpp b/src/external/libigl-2.3.0/include/igl/partition.cpp new file mode 100644 index 000000000..d2ef34c94 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/partition.cpp @@ -0,0 +1,59 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "partition.h" +#include "mat_min.h" + +IGL_INLINE void igl::partition( + const Eigen::MatrixXd & W, + const int k, + Eigen::Matrix & G, + Eigen::Matrix & S, + Eigen::Matrix & D) +{ + // number of mesh vertices + int n = W.rows(); + + // Resize output + G.resize(n); + S.resize(k); + + // "Randomly" choose first seed + // Pick a vertex farthest from 0 + int s; + (W.array().square().matrix()).rowwise().sum().maxCoeff(&s); + + S(0) = s; + // Initialize distance to closest seed + D = ((W.rowwise() - W.row(s)).array().square()).matrix().rowwise().sum(); + G.setZero(); + + // greedily choose the remaining k-1 seeds + for(int i = 1;i Ds = + ((W.rowwise() - W.row(s)).array().square()).matrix().rowwise().sum(); + // Concatenation of D and Ds: DDs = [D Ds]; + Eigen::Matrix DDs; + // Make space for two columns + DDs.resize(D.rows(),2); + DDs.col(0) = D; + DDs.col(1) = Ds; + // Update D + // get minimum of old D and distance to this seed, C == 1 if new distance + // was smaller + Eigen::Matrix C; + igl::mat_min(DDs,2,D,C); + G = (C.array() ==0).select(G,i); + } + + +} diff --git a/src/external/libigl-2.3.0/include/igl/partition.h b/src/external/libigl-2.3.0/include/igl/partition.h new file mode 100644 index 000000000..167ebd0d7 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/partition.h @@ -0,0 +1,39 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_PARTITION_H +#define IGL_PARTITION_H +#include "igl_inline.h" +#include + +namespace igl +{ + // PARTITION partition vertices into groups based on each + // vertex's vector: vertices with similar coordinates (close in + // space) will be put in the same group. + // + // Inputs: + // W #W by dim coordinate matrix + // k desired number of groups default is dim + // Output: + // G #W list of group indices (1 to k) for each vertex, such that vertex i + // is assigned to group G(i) + // S k list of seed vertices + // D #W list of squared distances for each vertex to it's corresponding + // closest seed + IGL_INLINE void partition( + const Eigen::MatrixXd & W, + const int k, + Eigen::Matrix & G, + Eigen::Matrix & S, + Eigen::Matrix & D); +} + +#ifndef IGL_STATIC_LIBRARY +#include "partition.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/parula.cpp b/src/external/libigl-2.3.0/include/igl/parula.cpp new file mode 100644 index 000000000..42d12ac20 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/parula.cpp @@ -0,0 +1,52 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "parula.h" +#include "colormap.h" + +template +IGL_INLINE void igl::parula(const T x, T * rgb) +{ + igl::colormap(igl::COLOR_MAP_TYPE_PARULA,x, rgb); +} + +template +IGL_INLINE void igl::parula(const T f, T & r, T & g, T & b) +{ + igl::colormap(igl::COLOR_MAP_TYPE_PARULA, f, r, g, b); +} + +template +IGL_INLINE void igl::parula( + const Eigen::MatrixBase & Z, + const bool normalize, + Eigen::PlainObjectBase & C) +{ + igl::colormap(igl::COLOR_MAP_TYPE_PARULA, Z, normalize, C); +} +template +IGL_INLINE void igl::parula( + const Eigen::MatrixBase & Z, + const double min_z, + const double max_z, + Eigen::PlainObjectBase & C) +{ + igl::colormap(igl::COLOR_MAP_TYPE_PARULA, Z, min_z, max_z, C); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::parula, Eigen::Matrix >(Eigen::MatrixBase > const&, double, double, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::parula, Eigen::Matrix >(Eigen::MatrixBase > const&, bool, Eigen::PlainObjectBase >&); +template void igl::parula(double, double*); +template void igl::parula(double, double&, double&, double&); +template void igl::parula, Eigen::Matrix >(Eigen::MatrixBase > const&, bool, Eigen::PlainObjectBase >&); +template void igl::parula, Eigen::Matrix >(Eigen::MatrixBase > const&, bool, Eigen::PlainObjectBase >&); +template void igl::parula, Eigen::Matrix >(Eigen::MatrixBase > const&, double, double, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/parula.h b/src/external/libigl-2.3.0/include/igl/parula.h new file mode 100644 index 000000000..55cbd447f --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/parula.h @@ -0,0 +1,62 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_PARULA_H +#define IGL_PARULA_H +#include "igl_inline.h" +//#ifndef IGL_NO_EIGEN +# include +//#endif +namespace igl +{ + // PARULA like MATLAB's parula + // + // Inputs: + // m number of colors + // Outputs: + // J m by list of RGB colors between 0 and 1 + // + // Wrapper for directly computing [r,g,b] values for a given factor f between + // 0 and 1 + // + // Inputs: + // f factor determining color value as if 0 was min and 1 was max + // Outputs: + // r red value + // g green value + // b blue value + template + IGL_INLINE void parula(const T f, T * rgb); + template + IGL_INLINE void parula(const T f, T & r, T & g, T & b); + // Inputs: + // Z #Z list of factors + // normalize whether to normalize Z to be tightly between [0,1] + // Outputs: + // C #C by 3 list of rgb colors + template + IGL_INLINE void parula( + const Eigen::MatrixBase & Z, + const bool normalize, + Eigen::PlainObjectBase & C); + // Inputs: + // min_Z value at blue + // max_Z value at red + template + IGL_INLINE void parula( + const Eigen::MatrixBase & Z, + const double min_Z, + const double max_Z, + Eigen::PlainObjectBase & C); +}; + +#ifndef IGL_STATIC_LIBRARY +# include "parula.cpp" +#endif + +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/path_to_edges.cpp b/src/external/libigl-2.3.0/include/igl/path_to_edges.cpp new file mode 100644 index 000000000..97112e4af --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/path_to_edges.cpp @@ -0,0 +1,42 @@ +#include "path_to_edges.h" + +template +IGL_INLINE void igl::path_to_edges( + const Eigen::MatrixBase & I, + Eigen::PlainObjectBase & E, + bool make_loop) +{ + // Check that I is 1 dimensional + assert(I.size() == I.rows() || I.size() == I.cols()); + + if(make_loop) { + E.conservativeResize(I.size(), 2); + for(int i = 0; i < I.size() - 1; i++) { + E(i, 0) = I(i); + E(i, 1) = I(i + 1); + } + E(I.size() - 1, 0) = I(I.size() - 1); + E(I.size() - 1, 1) = I(0); + } else { + E.conservativeResize(I.size()-1, 2); + for(int i = 0; i < I.size()-1; i++) { + E(i, 0) = I(i); + E(i, 1) = I(i+1); + } + } +} + +template +IGL_INLINE void igl::path_to_edges( + const std::vector & I, + Eigen::PlainObjectBase & E, + bool make_loop) +{ + igl::path_to_edges(Eigen::Map>(I.data(), I.size()), E, make_loop); +} + +#ifdef IGL_STATIC_LIBRARY +template void igl::path_to_edges, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, bool); +template void igl::path_to_edges >(std::vector > const&, Eigen::PlainObjectBase >&, bool); +#endif + \ No newline at end of file diff --git a/src/external/libigl-2.3.0/include/igl/path_to_edges.h b/src/external/libigl-2.3.0/include/igl/path_to_edges.h new file mode 100644 index 000000000..81b03eee7 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/path_to_edges.h @@ -0,0 +1,45 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2019 Lawson Fulton lawsonfulton@gmail.com +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/ +#ifndef IGL_PATH_TO_EDGES_H +#define IGL_PATH_TO_EDGES_H + +#include "igl_inline.h" + +#include + +#include + +namespace igl +{ + // Given a path as an ordered list of N>=2 vertex indices I[0], I[1], ..., I[N-1] + // construct a list of edges [[I[0],I[1]], [I[1],I[2]], ..., [I[N-2], I[N-1]]] + // connecting each sequential pair of vertices. + // + // Inputs: + // I #I list of vertex indices + // make_loop bool If true, include an edge connecting I[N-1] to I[0] + // Outputs: + // E #I-1 by 2 list of edges + // + template + IGL_INLINE void path_to_edges( + const Eigen::MatrixBase & I, + Eigen::PlainObjectBase & E, + bool make_loop=false); + + template + IGL_INLINE void path_to_edges( + const std::vector & I, + Eigen::PlainObjectBase & E, + bool make_loop=false); + +} +#ifndef IGL_STATIC_LIBRARY +# include "path_to_edges.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/path_to_executable.cpp b/src/external/libigl-2.3.0/include/igl/path_to_executable.cpp new file mode 100644 index 000000000..fb42a79ba --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/path_to_executable.cpp @@ -0,0 +1,53 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "path_to_executable.h" +#ifdef __APPLE__ +# include +#endif +#if defined(_WIN32) +# include +#else + #include +#endif +#include + +IGL_INLINE std::string igl::path_to_executable() +{ + // http://pastebin.com/ffzzxPzi + using namespace std; + std::string path; + char buffer[1024]; + uint32_t size = sizeof(buffer); +#if defined (WIN32) + GetModuleFileName(nullptr,buffer,size); + path = buffer; +#elif defined (__APPLE__) + if(_NSGetExecutablePath(buffer, &size) == 0) + { + path = buffer; + } +#elif defined(UNIX) || defined(unix) || defined(__unix) || defined(__unix__) + int byte_count = readlink("/proc/self/exe", buffer, size); + if (byte_count != -1) + { + path = std::string(buffer, byte_count); + } +#elif defined(__FreeBSD__) + int mib[4]; + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PATHNAME; + mib[3] = -1; + sysctl(mib, 4, buffer, sizeof(buffer), NULL, 0); + path = buffer; +#elif defined(SUNOS) + path = getexecname(); +#endif + return path; +} + diff --git a/src/external/libigl-2.3.0/include/igl/path_to_executable.h b/src/external/libigl-2.3.0/include/igl/path_to_executable.h new file mode 100644 index 000000000..169c3400b --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/path_to_executable.h @@ -0,0 +1,21 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_PATH_TO_EXECUTABLE_H +#define IGL_PATH_TO_EXECUTABLE_H +#include "igl_inline.h" +#include +namespace igl +{ + // Return the path of the current executable. + // Note: Tested for Mac OS X + IGL_INLINE std::string path_to_executable(); +} +#ifndef IGL_STATIC_LIBRARY +# include "path_to_executable.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/pathinfo.cpp b/src/external/libigl-2.3.0/include/igl/pathinfo.cpp new file mode 100644 index 000000000..110535cd8 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/pathinfo.cpp @@ -0,0 +1,47 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "pathinfo.h" + +#include "dirname.h" +#include "basename.h" +// Verbose should be removed once everything working correctly +#include "verbose.h" +#include + +IGL_INLINE void igl::pathinfo( + const std::string & path, + std::string & dirname, + std::string & basename, + std::string & extension, + std::string & filename) +{ + dirname = igl::dirname(path); + basename = igl::basename(path); + std::string::reverse_iterator last_dot = + std::find( + basename.rbegin(), + basename.rend(), '.'); + // Was a dot found? + if(last_dot == basename.rend()) + { + // filename is same as basename + filename = basename; + // no extension + extension = ""; + }else + { + // extension is substring of basename + extension = std::string(last_dot.base(),basename.end()); + // filename is substring of basename + filename = std::string(basename.begin(),last_dot.base()-1); + } +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +#endif diff --git a/src/external/libigl-2.3.0/include/igl/pathinfo.h b/src/external/libigl-2.3.0/include/igl/pathinfo.h new file mode 100644 index 000000000..b59e48157 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/pathinfo.h @@ -0,0 +1,64 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_PATHINFO_H +#define IGL_PATHINFO_H +#include "igl_inline.h" + +#include + +namespace igl +{ + //// Decided not to use these + //const int PATHINFO_DIRNAME 01 + //const int PATHINFO_BASENAME 02 + //const int PATHINFO_EXTENSION 04 + //const int PATHINFO_FILENAME 08 + + // Function like PHP's pathinfo + // returns information about path + // Input: + // path string containing input path + // Outputs: + // dirname string containing dirname (see dirname.h) + // basename string containing basename (see basename.h) + // extension string containing extension (characters after last '.') + // filename string containing filename (characters of basename before last + // '.') + // + // + // Examples: + // + // input | dirname basename ext filename + // "/" | "/" "" "" "" + // "//" | "/" "" "" "" + // "/foo" | "/" "foo" "" "foo" + // "/foo/" | "/" "foo" "" "foo" + // "/foo//" | "/" "foo" "" "foo" + // "/foo/./" | "/foo" "." "" "" + // "/foo/bar" | "/foo" "bar" "" "bar" + // "/foo/bar." | "/foo" "bar." "" "bar" + // "/foo/bar.txt" | "/foo" "bar.txt" "txt" "bar" + // "/foo/bar.txt.zip" | "/foo" "bar.txt.zip" "zip" "bar.txt" + // "/foo/bar.dir/" | "/foo" "bar.dir" "dir" "bar" + // "/foo/bar.dir/file" | "/foo/bar.dir" "file" "" "file" + // "/foo/bar.dir/file.txt" | "/foo/bar.dir" "file.txt" "txt" "file" + // See also: basename, dirname + IGL_INLINE void pathinfo( + const std::string & path, + std::string & dirname, + std::string & basename, + std::string & extension, + std::string & filename); + +} + +#ifndef IGL_STATIC_LIBRARY +# include "pathinfo.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/per_corner_normals.cpp b/src/external/libigl-2.3.0/include/igl/per_corner_normals.cpp new file mode 100644 index 000000000..0eac79f41 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/per_corner_normals.cpp @@ -0,0 +1,205 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "per_corner_normals.h" + +#include "vertex_triangle_adjacency.h" +#include "per_face_normals.h" +#include "PI.h" +#include "doublearea.h" + +template +IGL_INLINE void igl::per_corner_normals( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + const double corner_threshold, + Eigen::PlainObjectBase & CN) +{ + using namespace Eigen; + using namespace std; + Eigen::Matrix FN; + per_face_normals(V,F,FN); + vector > VF,VFi; + vertex_triangle_adjacency(V.rows(),F,VF,VFi); + return per_corner_normals(V,F,FN,VF,corner_threshold,CN); +} + +template < + typename DerivedV, + typename DerivedF, + typename DerivedFN, + typename DerivedCN> +IGL_INLINE void igl::per_corner_normals( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + const Eigen::MatrixBase& FN, + const double corner_threshold, + Eigen::PlainObjectBase & CN) +{ + using namespace Eigen; + using namespace std; + vector > VF,VFi; + vertex_triangle_adjacency(V.rows(),F,VF,VFi); + return per_corner_normals(V,F,FN,VF,corner_threshold,CN); +} + +template < + typename DerivedV, + typename DerivedF, + typename DerivedFN, + typename IndexType, + typename DerivedCN> +IGL_INLINE void igl::per_corner_normals( + const Eigen::MatrixBase& /*V*/, + const Eigen::MatrixBase& F, + const Eigen::MatrixBase& FN, + const std::vector >& VF, + const double corner_threshold, + Eigen::PlainObjectBase & CN) +{ + using namespace Eigen; + using namespace std; + + // number of faces + const int m = F.rows(); + // valence of faces + const int n = F.cols(); + + // initialize output to ***zero*** + CN.setZero(m*n,3); + + // loop over faces + for(size_t i = 0;int(i) fn = FN.row(i); + // loop over corners + for(size_t j = 0;int(j) &incident_faces = VF[F(i,j)]; + // loop over faces sharing vertex of this corner + for(int k = 0;k<(int)incident_faces.size();k++) + { + Eigen::Matrix ifn = FN.row(incident_faces[k]); + // dot product between face's normal and other face's normal + double dp = fn.dot(ifn); + // if difference in normal is slight then add to average + if(dp > cos(corner_threshold*PI/180)) + { + // add to running sum + CN.row(i*n+j) += ifn; + // else ignore + }else + { + } + } + // normalize to take average + CN.row(i*n+j).normalize(); + } + } +} + + +template < + typename DerivedV, + typename DerivedI, + typename DerivedC, + typename DerivedN, + typename DerivedVV, + typename DerivedFF, + typename DerivedJ, + typename DerivedNN> +IGL_INLINE void igl::per_corner_normals( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & I, + const Eigen::MatrixBase & C, + const typename DerivedV::Scalar corner_threshold, + Eigen::PlainObjectBase & N, + Eigen::PlainObjectBase & VV, + Eigen::PlainObjectBase & FF, + Eigen::PlainObjectBase & J, + Eigen::PlainObjectBase & NN) +{ + const Eigen::Index m = C.size()-1; + typedef Eigen::Index Index; + Eigen::MatrixXd FN; + per_face_normals(V,I,C,FN,VV,FF,J); + typedef typename DerivedN::Scalar Scalar; + Eigen::Matrix AA; + doublearea(VV,FF,AA); + // VF[i](j) = p means p is the jth face incident on vertex i + // to-do micro-optimization to avoid vector + std::vector> VF(V.rows()); + for(Eigen::Index p = 0;p fn = FN.row(p); + for(Eigen::Index i = 0;i ifn = FN.row(n); + // dot product between face's normal and other face's normal + Scalar dp = fn.dot(ifn); + if(dp > cos(corner_threshold*igl::PI/180)) + { + // add to running sum + N.row(C(p)+i) += AA(n) * ifn; + } + } + N.row(C(p)+i).normalize(); + } + } + + // Relies on order of FF + NN.resize(FF.rows()*3,3); + { + Eigen::Index k = 0; + for(Eigen::Index p = 0;p, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::Matrix::Scalar, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::per_corner_normals, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, double, Eigen::PlainObjectBase >&); +template void igl::per_corner_normals, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, double, Eigen::PlainObjectBase >&); +template void igl::per_corner_normals, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, double, Eigen::PlainObjectBase >&); +template void igl::per_corner_normals, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, double, Eigen::PlainObjectBase >&); +template void igl::per_corner_normals, Eigen::Matrix, Eigen::Matrix, int, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, std::vector >, std::allocator > > > const&, double, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/per_corner_normals.h b/src/external/libigl-2.3.0/include/igl/per_corner_normals.h new file mode 100644 index 000000000..77913c891 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/per_corner_normals.h @@ -0,0 +1,96 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_PER_CORNER_NORMALS_H +#define IGL_PER_CORNER_NORMALS_H +#include "igl_inline.h" +#include +#include + +namespace igl +{ + // Compute vertex normals via vertex position list, face list + // Inputs: + // V #V by 3 eigen Matrix of mesh vertex 3D positions + // F #F by 3 eigen Matrix of face (triangle) indices + // corner_threshold threshold in degrees on sharp angles + // Output: + // CN #F*3 by 3 eigen Matrix of mesh vertex 3D normals, where the normal + // for corner F(i,j) is at CN(i*3+j,:) + template + IGL_INLINE void per_corner_normals( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + const double corner_threshold, + Eigen::PlainObjectBase & CN); + // Other Inputs: + // FN #F by 3 eigen Matrix of face normals + template < + typename DerivedV, + typename DerivedF, + typename DerivedFN, + typename DerivedCN> + IGL_INLINE void per_corner_normals( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + const Eigen::MatrixBase& FN, + const double corner_threshold, + Eigen::PlainObjectBase & CN); + // Other Inputs: + // VF map from vertices to list of incident faces + template < + typename DerivedV, + typename DerivedF, + typename DerivedFN, + typename IndexType, + typename DerivedCN> + IGL_INLINE void per_corner_normals( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + const Eigen::MatrixBase& FN, + const std::vector >& VF, + const double corner_threshold, + Eigen::PlainObjectBase & CN); + // Inputs: + // V #V by 3 list of mesh vertex positions + // I #I vectorized list of polygon corner indices into rows of some matrix V + // C #polygons+1 list of cumulative polygon sizes so that C(i+1)-C(i) = size of + // the ith polygon, and so I(C(i)) through I(C(i+1)-1) are the indices of + // the ith polygon + // corner_threshold threshold in degrees on sharp angles + // Outputs: + // N #I by 3 list of per corner normals + // VV #I+#polygons by 3 list of auxiliary triangle mesh vertex positions + // FF #I by 3 list of triangle indices into rows of VV + // J #I list of indices into original polygons + // NN #FF by 3 list of normals for each auxiliary triangle + template < + typename DerivedV, + typename DerivedI, + typename DerivedC, + typename DerivedN, + typename DerivedVV, + typename DerivedFF, + typename DerivedJ, + typename DerivedNN> + IGL_INLINE void per_corner_normals( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & I, + const Eigen::MatrixBase & C, + const typename DerivedV::Scalar corner_threshold, + Eigen::PlainObjectBase & N, + Eigen::PlainObjectBase & VV, + Eigen::PlainObjectBase & FF, + Eigen::PlainObjectBase & J, + Eigen::PlainObjectBase & NN); +} + +#ifndef IGL_STATIC_LIBRARY +# include "per_corner_normals.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/per_edge_normals.cpp b/src/external/libigl-2.3.0/include/igl/per_edge_normals.cpp new file mode 100644 index 000000000..c08283219 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/per_edge_normals.cpp @@ -0,0 +1,140 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "oriented_facets.h" +#include "doublearea.h" +#include "per_edge_normals.h" +#include "get_seconds.h" +#include "per_face_normals.h" +#include "unique_simplices.h" +#include + +template < + typename DerivedV, + typename DerivedF, + typename DerivedFN, + typename DerivedN, + typename DerivedE, + typename DerivedEMAP> +IGL_INLINE void igl::per_edge_normals( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + const PerEdgeNormalsWeightingType weighting, + const Eigen::MatrixBase& FN, + Eigen::PlainObjectBase & N, + Eigen::PlainObjectBase & E, + Eigen::PlainObjectBase & EMAP) + +{ + using namespace Eigen; + using namespace std; + assert(F.cols() == 3 && "Faces must be triangles"); + // number of faces + const int m = F.rows(); + // All occurrences of directed edges + Matrix allE; + oriented_facets(F,allE); + // Find unique undirected edges and mapping + Matrix _; + unique_simplices(allE,E,_,EMAP); + // now sort(allE,2) == E(EMAP,:), that is, if EMAP(i) = j, then E.row(j) is + // the undirected edge corresponding to the directed edge allE.row(i). + + Eigen::VectorXd W; + switch(weighting) + { + case PER_EDGE_NORMALS_WEIGHTING_TYPE_UNIFORM: + // Do nothing + break; + default: + assert(false && "Unknown weighting type"); + case PER_EDGE_NORMALS_WEIGHTING_TYPE_DEFAULT: + case PER_EDGE_NORMALS_WEIGHTING_TYPE_AREA: + { + doublearea(V,F,W); + break; + } + } + + N.setZero(E.rows(),3); + for(int f = 0;f +IGL_INLINE void igl::per_edge_normals( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + const PerEdgeNormalsWeightingType weighting, + Eigen::PlainObjectBase & N, + Eigen::PlainObjectBase & E, + Eigen::PlainObjectBase & EMAP) +{ + Eigen::Matrix FN; + per_face_normals(V,F,FN); + return per_edge_normals(V,F,weighting,FN,N,E,EMAP); +} + +template < + typename DerivedV, + typename DerivedF, + typename DerivedN, + typename DerivedE, + typename DerivedEMAP> +IGL_INLINE void igl::per_edge_normals( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + Eigen::PlainObjectBase & N, + Eigen::PlainObjectBase & E, + Eigen::PlainObjectBase & EMAP) +{ + return + per_edge_normals(V,F,PER_EDGE_NORMALS_WEIGHTING_TYPE_DEFAULT,N,E,EMAP); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::per_edge_normals, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, igl::PerEdgeNormalsWeightingType, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::per_edge_normals, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, igl::PerEdgeNormalsWeightingType, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::per_edge_normals, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, igl::PerEdgeNormalsWeightingType, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::per_edge_normals, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, igl::PerEdgeNormalsWeightingType, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::per_edge_normals, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, igl::PerEdgeNormalsWeightingType, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::per_edge_normals, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, igl::PerEdgeNormalsWeightingType, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::per_edge_normals, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, igl::PerEdgeNormalsWeightingType, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::per_edge_normals, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, igl::PerEdgeNormalsWeightingType, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::per_edge_normals, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::per_edge_normals, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, igl::PerEdgeNormalsWeightingType, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::per_edge_normals, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, igl::PerEdgeNormalsWeightingType, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::per_edge_normals, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, igl::PerEdgeNormalsWeightingType, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::per_edge_normals, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/per_edge_normals.h b/src/external/libigl-2.3.0/include/igl/per_edge_normals.h new file mode 100644 index 000000000..b40d72976 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/per_edge_normals.h @@ -0,0 +1,81 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_PER_EDGE_NORMALS_H +#define IGL_PER_EDGE_NORMALS_H +#include "igl_inline.h" +#include +namespace igl +{ + enum PerEdgeNormalsWeightingType + { + // Incident face normals have uniform influence on edge normal + PER_EDGE_NORMALS_WEIGHTING_TYPE_UNIFORM = 0, + // Incident face normals are averaged weighted by area + PER_EDGE_NORMALS_WEIGHTING_TYPE_AREA = 1, + // Area weights + PER_EDGE_NORMALS_WEIGHTING_TYPE_DEFAULT = 2, + NUM_PER_EDGE_NORMALS_WEIGHTING_TYPE = 3 + }; + // Compute face normals via vertex position list, face list + // Inputs: + // V #V by 3 eigen Matrix of mesh vertex 3D positions + // F #F by 3 eigen Matrix of face (triangle) indices + // weight weighting type + // FN #F by 3 matrix of 3D face normals per face + // Output: + // N #2 by 3 matrix of mesh edge 3D normals per row + // E #E by 2 matrix of edge indices per row + // EMAP #E by 1 matrix of indices from all edges to E + // + template < + typename DerivedV, + typename DerivedF, + typename DerivedFN, + typename DerivedN, + typename DerivedE, + typename DerivedEMAP> + IGL_INLINE void per_edge_normals( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + const PerEdgeNormalsWeightingType weight, + const Eigen::MatrixBase& FN, + Eigen::PlainObjectBase & N, + Eigen::PlainObjectBase & E, + Eigen::PlainObjectBase & EMAP); + template < + typename DerivedV, + typename DerivedF, + typename DerivedN, + typename DerivedE, + typename DerivedEMAP> + IGL_INLINE void per_edge_normals( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + const PerEdgeNormalsWeightingType weight, + Eigen::PlainObjectBase & N, + Eigen::PlainObjectBase & E, + Eigen::PlainObjectBase & EMAP); + template < + typename DerivedV, + typename DerivedF, + typename DerivedN, + typename DerivedE, + typename DerivedEMAP> + IGL_INLINE void per_edge_normals( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + Eigen::PlainObjectBase & N, + Eigen::PlainObjectBase & E, + Eigen::PlainObjectBase & EMAP); +} + +#ifndef IGL_STATIC_LIBRARY +# include "per_edge_normals.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/per_face_normals.cpp b/src/external/libigl-2.3.0/include/igl/per_face_normals.cpp new file mode 100644 index 000000000..2caec4c9b --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/per_face_normals.cpp @@ -0,0 +1,194 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "per_face_normals.h" +#include + +#define SQRT_ONE_OVER_THREE 0.57735026918962573 +template +IGL_INLINE void igl::per_face_normals( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + const Eigen::MatrixBase & Z, + Eigen::PlainObjectBase & N) +{ + N.resize(F.rows(),3); + // loop over faces + int Frows = F.rows(); +#pragma omp parallel for if (Frows>10000) + for(int i = 0; i < Frows;i++) + { + const Eigen::Matrix v1 = V.row(F(i,1)) - V.row(F(i,0)); + const Eigen::Matrix v2 = V.row(F(i,2)) - V.row(F(i,0)); + N.row(i) = v1.cross(v2);//.normalized(); + typename DerivedV::Scalar r = N.row(i).norm(); + if(r == 0) + { + N.row(i) = Z; + }else + { + N.row(i) /= r; + } + } +} + +template +IGL_INLINE void igl::per_face_normals( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + Eigen::PlainObjectBase & N) +{ + using namespace Eigen; + Matrix Z(0,0,0); + return per_face_normals(V,F,Z,N); +} + +template +IGL_INLINE void igl::per_face_normals_stable( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + Eigen::PlainObjectBase & N) +{ + using namespace Eigen; + typedef Matrix RowVectorV3; + typedef typename DerivedV::Scalar Scalar; + + const size_t m = F.rows(); + + N.resize(F.rows(),3); + // Grad all points + for(size_t f = 0;f sum3 = + [&sum3](Scalar a, Scalar b, Scalar c)->Scalar + { + if(fabs(c)>fabs(a)) + { + return sum3(c,b,a); + } + // c < a + if(fabs(c)>fabs(b)) + { + return sum3(a,c,b); + } + // c < a, c < b + if(fabs(b)>fabs(a)) + { + return sum3(b,a,c); + } + return (a+b)+c; + }; + + N(f,d) = sum3(n0(d),n1(d),n2(d)); + } + // sum better not be sure, or else NaN + N.row(f) /= N.row(f).norm(); + } + +} + +#include "cotmatrix.h" + +template < + typename DerivedV, + typename DerivedI, + typename DerivedC, + typename DerivedN, + typename DerivedVV, + typename DerivedFF, + typename DerivedJ> +IGL_INLINE void igl::per_face_normals( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & I, + const Eigen::MatrixBase & C, + Eigen::PlainObjectBase & N, + Eigen::PlainObjectBase & VV, + Eigen::PlainObjectBase & FF, + Eigen::PlainObjectBase & J) +{ + assert(V.cols() == 3); + typedef Eigen::Index Index; + typedef typename DerivedN::Scalar Scalar; + // Use Bunge et al. algorithm in igl::cotmatrix to insert a point for each + // polygon which minimizes squared area. + { + Eigen::SparseMatrix _1,_2,P; + igl::cotmatrix(V,I,C,_1,_2,P); + VV = P*V; + } + // number of polygons + const Eigen::Index m = C.size()-1; + N.resize(m,3); + FF.resize(C(m),3); + J.resize(C(m)); + { + Eigen::Index k = 0; + for(Eigen::Index p = 0;p V3; + N.row(p) += + V3(VV.row(I(C(p)+((i+0)%np)))-VV.row(V.rows()+p)).cross( + V3(VV.row(I(C(p)+((i+1)%np)))-VV.row(V.rows()+p))); + } + // normalize to take average + N.row(p) /= N.row(p).stableNorm(); + } + assert(k == FF.rows()); + } +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::per_face_normals, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::per_face_normals, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::per_face_normals, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::per_face_normals, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +// Nonsense template. Where'd this come from? AABB nonsense? +namespace igl{template<> void per_face_normals, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&){} } +template void igl::per_face_normals, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::per_face_normals, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::per_face_normals, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::per_face_normals, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::per_face_normals, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::per_face_normals, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::per_face_normals, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::per_face_normals, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::per_face_normals, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::per_face_normals, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::per_face_normals, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::per_face_normals, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::per_face_normals, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::per_face_normals,class Eigen::Matrix,class Eigen::Matrix >(class Eigen::MatrixBase > const &,class Eigen::MatrixBase > const &,class Eigen::PlainObjectBase > &); +template void igl::per_face_normals, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::per_face_normals_stable, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::per_face_normals_stable, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::per_face_normals_stable, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/per_face_normals.h b/src/external/libigl-2.3.0/include/igl/per_face_normals.h new file mode 100644 index 000000000..13745353e --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/per_face_normals.h @@ -0,0 +1,79 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_PER_FACE_NORMALS_H +#define IGL_PER_FACE_NORMALS_H +#include "igl_inline.h" +#include +namespace igl +{ + // Compute face normals via vertex position list, face list + // Inputs: + // V #V by 3 eigen Matrix of mesh vertex 3D positions + // F #F by 3 eigen Matrix of face (triangle) indices + // Z 3 vector normal given to faces with degenerate normal. + // Output: + // N #F by 3 eigen Matrix of mesh face (triangle) 3D normals + // + // Example: + // // Give degenerate faces (1/3,1/3,1/3)^0.5 + // per_face_normals(V,F,Vector3d(1,1,1).normalized(),N); + template + IGL_INLINE void per_face_normals( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + const Eigen::MatrixBase & Z, + Eigen::PlainObjectBase & N); + // Wrapper with Z = (0,0,0). Note that this means that row norms will be zero + // (i.e. not 1) for degenerate normals. + template + IGL_INLINE void per_face_normals( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + Eigen::PlainObjectBase & N); + // Special version where order of face indices is guaranteed not to effect + // output. + template + IGL_INLINE void per_face_normals_stable( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + Eigen::PlainObjectBase & N); + // Inputs: + // V #V by 3 list of mesh vertex positions + // I #I vectorized list of polygon corner indices into rows of some matrix V + // C #polygons+1 list of cumulative polygon sizes so that C(i+1)-C(i) = size of + // the ith polygon, and so I(C(i)) through I(C(i+1)-1) are the indices of + // the ith polygon + // corner_threshold threshold in degrees on sharp angles + // Outputs: + // N #polygons by 3 list of per face normals + // VV #I+#polygons by 3 list of auxiliary triangle mesh vertex positions + // FF #I by 3 list of triangle indices into rows of VV + // J #I list of indices into original polygons + template < + typename DerivedV, + typename DerivedI, + typename DerivedC, + typename DerivedN, + typename DerivedVV, + typename DerivedFF, + typename DerivedJ> + IGL_INLINE void per_face_normals( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & I, + const Eigen::MatrixBase & C, + Eigen::PlainObjectBase & N, + Eigen::PlainObjectBase & VV, + Eigen::PlainObjectBase & FF, + Eigen::PlainObjectBase & J); +} + +#ifndef IGL_STATIC_LIBRARY +# include "per_face_normals.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/per_vertex_attribute_smoothing.cpp b/src/external/libigl-2.3.0/include/igl/per_vertex_attribute_smoothing.cpp new file mode 100644 index 000000000..91021a309 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/per_vertex_attribute_smoothing.cpp @@ -0,0 +1,33 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "per_vertex_attribute_smoothing.h" +#include + +template +IGL_INLINE void igl::per_vertex_attribute_smoothing( + const Eigen::MatrixBase& Ain, + const Eigen::MatrixBase& F, + Eigen::PlainObjectBase & Aout) +{ + std::vector denominator(Ain.rows(), 0); + Aout = DerivedV::Zero(Ain.rows(), Ain.cols()); + for (int i = 0; i < F.rows(); ++i) { + for (int j = 0; j < 3; ++j) { + int j1 = (j + 1) % 3; + int j2 = (j + 2) % 3; + Aout.row(F(i, j)) += Ain.row(F(i, j1)) + Ain.row(F(i, j2)); + denominator[F(i, j)] += 2; + } + } + for (int i = 0; i < Ain.rows(); ++i) + Aout.row(i) /= denominator[i]; +} + +#ifdef IGL_STATIC_LIBRARY +template void igl::per_vertex_attribute_smoothing, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/per_vertex_attribute_smoothing.h b/src/external/libigl-2.3.0/include/igl/per_vertex_attribute_smoothing.h new file mode 100644 index 000000000..819c145f5 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/per_vertex_attribute_smoothing.h @@ -0,0 +1,32 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_PER_VERTEX_ATTRIBUTE_SMOOTHING_H +#define IGL_PER_VERTEX_ATTRIBUTE_SMOOTHING_H +#include "igl_inline.h" +#include + +namespace igl +{ + // Smooth vertex attributes using uniform Laplacian + // Inputs: + // Ain #V by #A eigen Matrix of mesh vertex attributes (each vertex has #A attributes) + // F #F by 3 eigne Matrix of face (triangle) indices + // Output: + // Aout #V by #A eigen Matrix of mesh vertex attributes + template + IGL_INLINE void per_vertex_attribute_smoothing( + const Eigen::MatrixBase& Ain, + const Eigen::MatrixBase& F, + Eigen::PlainObjectBase & Aout); +} + +#ifndef IGL_STATIC_LIBRARY +# include "per_vertex_attribute_smoothing.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/per_vertex_normals.cpp b/src/external/libigl-2.3.0/include/igl/per_vertex_normals.cpp new file mode 100644 index 000000000..a15f92317 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/per_vertex_normals.cpp @@ -0,0 +1,139 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "per_vertex_normals.h" + +#include "get_seconds.h" +#include "per_face_normals.h" +#include "doublearea.h" +#include "parallel_for.h" +#include "internal_angles.h" + +template < + typename DerivedV, + typename DerivedF, + typename DerivedN> +IGL_INLINE void igl::per_vertex_normals( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + const igl::PerVertexNormalsWeightingType weighting, + Eigen::PlainObjectBase & N) +{ + Eigen::Matrix PFN; + igl::per_face_normals(V,F,PFN); + return per_vertex_normals(V,F,weighting,PFN,N); +} + +template +IGL_INLINE void igl::per_vertex_normals( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + Eigen::PlainObjectBase & N) +{ + return per_vertex_normals(V,F,PER_VERTEX_NORMALS_WEIGHTING_TYPE_DEFAULT,N); +} + +template +IGL_INLINE void igl::per_vertex_normals( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + const igl::PerVertexNormalsWeightingType weighting, + const Eigen::MatrixBase& FN, + Eigen::PlainObjectBase & N) +{ + using namespace std; + // Resize for output + N.setZero(V.rows(),3); + + Eigen::Matrix + W(F.rows(),3); + switch(weighting) + { + case PER_VERTEX_NORMALS_WEIGHTING_TYPE_UNIFORM: + W.setConstant(1.); + break; + default: + assert(false && "Unknown weighting type"); + case PER_VERTEX_NORMALS_WEIGHTING_TYPE_DEFAULT: + case PER_VERTEX_NORMALS_WEIGHTING_TYPE_AREA: + { + Eigen::Matrix A; + doublearea(V,F,A); + W = A.replicate(1,3); + break; + } + case PER_VERTEX_NORMALS_WEIGHTING_TYPE_ANGLE: + internal_angles(V,F,W); + break; + } + + // loop over faces + for(int i = 0;i NN; + //parallel_for( + // F.rows(), + // [&NN,&N](const size_t n){ NN.resize(n,DerivedN::Zero(N.rows(),3));}, + // [&F,&W,&FN,&NN,&critical](const int i, const size_t t) + // { + // // throw normal at each corner + // for(int j = 0; j < 3;j++) + // { + // // Q: Does this need to be critical? + // // A: Yes. Different (i,j)'s could produce the same F(i,j) + // NN[t].row(F(i,j)) += W(i,j) * FN.row(i); + // } + // }, + // [&N,&NN](const size_t t){ N += NN[t]; }, + // 1000l); + + // take average via normalization + N.rowwise().normalize(); +} + +template < + typename DerivedV, + typename DerivedF, + typename DerivedFN, + typename DerivedN> +IGL_INLINE void igl::per_vertex_normals( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + const Eigen::MatrixBase& FN, + Eigen::PlainObjectBase & N) +{ + return + per_vertex_normals(V,F,PER_VERTEX_NORMALS_WEIGHTING_TYPE_DEFAULT,FN,N); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::per_vertex_normals, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, igl::PerVertexNormalsWeightingType, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::per_vertex_normals, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, igl::PerVertexNormalsWeightingType, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::per_vertex_normals, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, igl::PerVertexNormalsWeightingType, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::per_vertex_normals, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, igl::PerVertexNormalsWeightingType, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::per_vertex_normals, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, igl::PerVertexNormalsWeightingType, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::per_vertex_normals, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, igl::PerVertexNormalsWeightingType, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::per_vertex_normals, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, igl::PerVertexNormalsWeightingType, Eigen::PlainObjectBase >&); +template void igl::per_vertex_normals, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::per_vertex_normals, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, igl::PerVertexNormalsWeightingType, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::per_vertex_normals, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, igl::PerVertexNormalsWeightingType, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::per_vertex_normals, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/per_vertex_normals.h b/src/external/libigl-2.3.0/include/igl/per_vertex_normals.h new file mode 100644 index 000000000..be4ba0461 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/per_vertex_normals.h @@ -0,0 +1,80 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_PER_VERTEX_NORMALS_H +#define IGL_PER_VERTEX_NORMALS_H +#include "igl_inline.h" +#include +// Note: It would be nice to support more or all of the methods here: +// "A comparison of algorithms for vertex normal computation" +namespace igl +{ + enum PerVertexNormalsWeightingType + { + // Incident face normals have uniform influence on vertex normal + PER_VERTEX_NORMALS_WEIGHTING_TYPE_UNIFORM = 0, + // Incident face normals are averaged weighted by area + PER_VERTEX_NORMALS_WEIGHTING_TYPE_AREA = 1, + // Incident face normals are averaged weighted by incident angle of vertex + PER_VERTEX_NORMALS_WEIGHTING_TYPE_ANGLE = 2, + // Area weights + PER_VERTEX_NORMALS_WEIGHTING_TYPE_DEFAULT = 3, + NUM_PER_VERTEX_NORMALS_WEIGHTING_TYPE = 4 + }; + // Compute vertex normals via vertex position list, face list + // Inputs: + // V #V by 3 eigen Matrix of mesh vertex 3D positions + // F #F by 3 eigne Matrix of face (triangle) indices + // weighting Weighting type + // Output: + // N #V by 3 eigen Matrix of mesh vertex 3D normals + template < + typename DerivedV, + typename DerivedF, + typename DerivedN> + IGL_INLINE void per_vertex_normals( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + const igl::PerVertexNormalsWeightingType weighting, + Eigen::PlainObjectBase & N); + // Without weighting + template < + typename DerivedV, + typename DerivedF, + typename DerivedN> + IGL_INLINE void per_vertex_normals( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + Eigen::PlainObjectBase & N); + // Inputs: + // FN #F by 3 matrix of face (triangle) normals + template + IGL_INLINE void per_vertex_normals( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + const PerVertexNormalsWeightingType weighting, + const Eigen::MatrixBase& FN, + Eigen::PlainObjectBase & N); + // Without weighting + template < + typename DerivedV, + typename DerivedF, + typename DerivedFN, + typename DerivedN> + IGL_INLINE void per_vertex_normals( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + const Eigen::MatrixBase& FN, + Eigen::PlainObjectBase & N); + +} + +#ifndef IGL_STATIC_LIBRARY +# include "per_vertex_normals.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/per_vertex_point_to_plane_quadrics.cpp b/src/external/libigl-2.3.0/include/igl/per_vertex_point_to_plane_quadrics.cpp new file mode 100644 index 000000000..4503873ca --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/per_vertex_point_to_plane_quadrics.cpp @@ -0,0 +1,157 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "per_vertex_point_to_plane_quadrics.h" +#include "quadric_binary_plus_operator.h" +#include +#include +#include + + +IGL_INLINE void igl::per_vertex_point_to_plane_quadrics( + const Eigen::MatrixXd & V, + const Eigen::MatrixXi & F, + const Eigen::MatrixXi & EMAP, + const Eigen::MatrixXi & EF, + const Eigen::MatrixXi & EI, + std::vector< + std::tuple > & quadrics) +{ + using namespace std; + typedef std::tuple Quadric; + const int dim = V.cols(); + //// Quadrics per face + //std::vector face_quadrics(F.rows()); + // Initialize each vertex quadric to zeros + quadrics.resize( + V.rows(), + // gcc <=4.8 can't handle initializer lists correctly + Quadric{Eigen::MatrixXd::Zero(dim,dim),Eigen::RowVectorXd::Zero(dim),0}); + Eigen::MatrixXd I = Eigen::MatrixXd::Identity(dim,dim); + // Rather initial with zeros, initial with a small amount of energy pull + // toward original vertex position + const double w = 1e-10; + for(int v = 0;v(quadrics[v]) = w*I; + Eigen::RowVectorXd Vv = V.row(v); + std::get<1>(quadrics[v]) = w*-Vv; + std::get<2>(quadrics[v]) = w*Vv.dot(Vv); + } + // Generic nD qslim from "Simplifying Surfaces with Color and Texture + // using Quadric Error Metric" (follow up to original QSlim) + for(int f = 0;fQuadric + { + // Dimension of subspace + const int m = S.rows(); + // Weight face's quadric (v'*A*v + 2*b'*v + c) by area + // e1 and e2 should be perpendicular + Eigen::MatrixXd A = I; + Eigen::RowVectorXd b = -p; + double c = p.dot(p); + for(int i = 0;i edge opposite cth corner is boundary + // Boundary edge vector + const Eigen::RowVectorXd p = V.row(F(f,(infinite_corner+1)%3)); + Eigen::RowVectorXd ev = V.row(F(f,(infinite_corner+2)%3)) - p; + const double length = ev.norm(); + ev /= length; + // Face neighbor across boundary edge + int e = EMAP(f+F.rows()*infinite_corner); + int opp = EF(e,0) == f ? 1 : 0; + int n = EF(e,opp); + int nc = EI(e,opp); + assert( + ((F(f,(infinite_corner+1)%3) == F(n,(nc+1)%3) && + F(f,(infinite_corner+2)%3) == F(n,(nc+2)%3)) || + (F(f,(infinite_corner+1)%3) == F(n,(nc+2)%3) + && F(f,(infinite_corner+2)%3) == F(n,(nc+1)%3))) && + "Edge flaps not agreeing on shared edge"); + // Edge vector on opposite face + const Eigen::RowVectorXd eu = V.row(F(n,nc)) - p; + assert(!std::isinf(eu(0))); + // Matrix with vectors spanning plane as columns + Eigen::MatrixXd A(ev.size(),2); + A< qr(A); + const Eigen::MatrixXd Q = qr.householderQ(); + const Eigen::MatrixXd N = + Q.topRightCorner(ev.size(),ev.size()-2).transpose(); + assert(N.cols() == ev.size()); + assert(N.rows() == ev.size()-2); + Eigen::MatrixXd S(N.rows()+1,ev.size()); + S< +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_PER_VERTEX_POINT_TO_PLANE_QUADRICS_H +#define IGL_PER_VERTEX_POINT_TO_PLANE_QUADRICS_H +#include "igl_inline.h" +#include +#include +#include +namespace igl +{ + // Compute quadrics per vertex of a "closed" triangle mesh (V,F). Rather than + // follow the qslim paper, this implements the lesser-known _follow up_ + // "Simplifying Surfaces with Color and Texture using Quadric Error Metrics". + // This allows V to be n-dimensional (where the extra coordiantes store + // texture UVs, color RGBs, etc. + // + // Inputs: + // V #V by n list of vertex positions. Assumes that vertices with + // infinite coordinates are "points at infinity" being used to close up + // boundary edges with faces. This allows special subspace quadrice for + // boundary edges: There should never be more than one "point at + // infinity" in a single triangle. + // F #F by 3 list of triangle indices into V + // E #E by 2 list of edge indices into V. + // EMAP #F*3 list of indices into E, mapping each directed edge to unique + // unique edge in E + // EF #E by 2 list of edge flaps, EF(e,0)=f means e=(i-->j) is the edge of + // F(f,:) opposite the vth corner, where EI(e,0)=v. Similarly EF(e,1) " + // e=(j->i) + // EI #E by 2 list of edge flap corners (see above). + // Outputs: + // quadrics #V list of quadrics, where a quadric is a tuple {A,b,c} such + // that the quadratic energy of moving this vertex to position x is + // given by x'Ax - 2b + c + // + IGL_INLINE void per_vertex_point_to_plane_quadrics( + const Eigen::MatrixXd & V, + const Eigen::MatrixXi & F, + const Eigen::MatrixXi & EMAP, + const Eigen::MatrixXi & EF, + const Eigen::MatrixXi & EI, + std::vector< + std::tuple > & quadrics); +} +#ifndef IGL_STATIC_LIBRARY +# include "per_vertex_point_to_plane_quadrics.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/piecewise_constant_winding_number.cpp b/src/external/libigl-2.3.0/include/igl/piecewise_constant_winding_number.cpp new file mode 100644 index 000000000..4bf7d76f8 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/piecewise_constant_winding_number.cpp @@ -0,0 +1,82 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "piecewise_constant_winding_number.h" +#include "unique_edge_map.h" +#include "PI.h" + +template < + typename DerivedF, + typename DeriveduE, + typename uE2EType> +IGL_INLINE bool igl::piecewise_constant_winding_number( + const Eigen::MatrixBase& F, + const Eigen::MatrixBase& uE, + const std::vector >& uE2E) +{ + const size_t num_faces = F.rows(); + const size_t num_edges = uE.rows(); + const auto edge_index_to_face_index = [&](size_t ei) + { + return ei % num_faces; + }; + const auto is_consistent = [&](size_t fid, size_t s, size_t d) + { + if ((size_t)F(fid, 0) == s && (size_t)F(fid, 1) == d) return true; + if ((size_t)F(fid, 1) == s && (size_t)F(fid, 2) == d) return true; + if ((size_t)F(fid, 2) == s && (size_t)F(fid, 0) == d) return true; + + if ((size_t)F(fid, 0) == d && (size_t)F(fid, 1) == s) return false; + if ((size_t)F(fid, 1) == d && (size_t)F(fid, 2) == s) return false; + if ((size_t)F(fid, 2) == d && (size_t)F(fid, 0) == s) return false; + throw "Invalid face!!"; + }; + for (size_t i=0; i +IGL_INLINE bool igl::piecewise_constant_winding_number( + const Eigen::MatrixBase& F) +{ + Eigen::Matrix E, uE; + Eigen::Matrix EMAP; + std::vector > uE2E; + unique_edge_map(F, E, uE, EMAP, uE2E); + return piecewise_constant_winding_number(F,uE,uE2E); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template bool igl::piecewise_constant_winding_number, Eigen::Matrix, unsigned long>(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, std::vector >, std::allocator > > > const&); +template bool igl::piecewise_constant_winding_number, Eigen::Matrix, unsigned long>(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, std::vector >, std::allocator > > > const&); +#ifdef WIN32 +template bool igl::piecewise_constant_winding_number, class Eigen::Matrix, unsigned __int64>(class Eigen::MatrixBase> const &, class Eigen::MatrixBase> const &, class std::vector>, class std::allocator>>> const &); +template bool igl::piecewise_constant_winding_number, class Eigen::Matrix, unsigned __int64>(class Eigen::MatrixBase> const &, class Eigen::MatrixBase> const &, class std::vector>, class std::allocator>>> const &); +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/piecewise_constant_winding_number.h b/src/external/libigl-2.3.0/include/igl/piecewise_constant_winding_number.h new file mode 100644 index 000000000..ebbeb6e98 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/piecewise_constant_winding_number.h @@ -0,0 +1,49 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_PIECEWISE_CONSTANT_WINDING_NUMBER_H +#define IGL_PIECEWISE_CONSTANT_WINDING_NUMBER_H +#include "igl_inline.h" +#include +#include +namespace igl +{ + // PIECEWISE_CONSTANT_WINDING_NUMBER Determine if a given mesh induces a + // piecewise constant winding number field: Is this mesh valid input to solid + // set operations. **Assumes** that `(V,F)` contains no self-intersections + // (including degeneracies and co-incidences). If there are co-planar and + // co-incident vertex placements, a mesh could _fail_ this combinatorial test + // but still induce a piecewise-constant winding number _geometrically_. For + // example, consider a hemisphere with boundary and then pinch the boundary + // "shut" along a line segment. The **_bullet-proof_** check is to first + // resolve all self-intersections in `(V,F) -> (SV,SF)` (i.e. what the + // `igl::copyleft::cgal::piecewise_constant_winding_number` overload does). + // + // Inputs: + // F #F by 3 list of triangle indices into some (abstract) list of + // vertices V + // uE #uE by 2 list of unique edges indices into V + // uE2E #uE list of lists of indices into directed edges (#F * 3) + // Returns true if the mesh _combinatorially_ induces a piecewise constant + // winding number field. + // + template < + typename DerivedF, + typename DeriveduE, + typename uE2EType> + IGL_INLINE bool piecewise_constant_winding_number( + const Eigen::MatrixBase& F, + const Eigen::MatrixBase& uE, + const std::vector >& uE2E); + template + IGL_INLINE bool piecewise_constant_winding_number( + const Eigen::MatrixBase& F); +} +#ifndef IGL_STATIC_LIBRARY +# include "piecewise_constant_winding_number.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/pinv.cpp b/src/external/libigl-2.3.0/include/igl/pinv.cpp new file mode 100644 index 000000000..e3b2ceebb --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/pinv.cpp @@ -0,0 +1,42 @@ +#include "pinv.h" +#include +#include +#include + +template +void igl::pinv( + const Eigen::MatrixBase & A, + typename DerivedA::Scalar tol, + Eigen::PlainObjectBase & X) +{ + Eigen::JacobiSVD svd(A, Eigen::ComputeFullU | Eigen::ComputeFullV ); + typedef typename DerivedA::Scalar Scalar; + const Eigen::Matrix & U = svd.matrixU(); + const Eigen::Matrix & V = svd.matrixV(); + const Eigen::Matrix & S = svd.singularValues(); + if(tol < 0) + { + const Scalar smax = S.array().abs().maxCoeff(); + tol = + (Scalar)(std::max(A.rows(),A.cols())) * + (smax-std::nextafter(smax,std::numeric_limits::epsilon())); + } + const int rank = (S.array()>0).count(); + X = (V.leftCols(rank).array().rowwise() * + (1.0/S.head(rank).array()).transpose()).matrix()* + U.leftCols(rank).transpose(); +} + +template +void igl::pinv( + const Eigen::MatrixBase & A, + Eigen::PlainObjectBase & X) +{ + return pinv(A,-1,X); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::pinv, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/pinv.h b/src/external/libigl-2.3.0/include/igl/pinv.h new file mode 100644 index 000000000..12ccf3f29 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/pinv.h @@ -0,0 +1,33 @@ +#ifndef IGL_PINV_H +#define IGL_PINV_H +#include "igl_inline.h" +#include "deprecated.h" +#include +namespace igl +{ + // Compute the Moore-Penrose pseudoinverse + // + // Inputs: + // A m by n matrix + // tol tolerance (if negative then default is used) + // Outputs: + // X n by m matrix so that A*X*A = A and X*A*X = X and A*X = (A*X)' and + // (X*A) = (X*A)' + // + // Obsolete: Use Eigen::CompleteOrthogonalDecomposition + // .solve() or .pseudoinverse() instead. + template + IGL_DEPRECATED void pinv( + const Eigen::MatrixBase & A, + typename DerivedA::Scalar tol, + Eigen::PlainObjectBase & X); + // Wrapper using default tol + template + IGL_DEPRECATED void pinv( + const Eigen::MatrixBase & A, + Eigen::PlainObjectBase & X); +} +#ifndef IGL_STATIC_LIBRARY +# include "pinv.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/planarize_quad_mesh.cpp b/src/external/libigl-2.3.0/include/igl/planarize_quad_mesh.cpp new file mode 100644 index 000000000..24687e9a7 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/planarize_quad_mesh.cpp @@ -0,0 +1,245 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "planarize_quad_mesh.h" +#include "quad_planarity.h" +#include +#include +#include + +namespace igl +{ + template + class PlanarizerShapeUp + { + protected: + // number of faces, number of vertices + long numV, numF; + // references to the input faces and vertices + const Eigen::MatrixBase &Vin; + const Eigen::MatrixBase &Fin; + + // vector consisting of the vertex positions stacked: [x;y;z;x;y;z...] + // vector consisting of a weight per face (currently all set to 1) + // vector consisting of the projected face vertices (might be different for the same vertex belonging to different faces) + Eigen::Matrix Vv, weightsSqrt, P; + + // Matrices as in the paper + // Q: lhs matrix + // Ni: matrix that subtracts the mean of a face from the 4 vertices of a face + Eigen::SparseMatrix Q, Ni; + Eigen::SimplicialLDLT > solver; + + int maxIter; + double threshold; + const int ni = 4; + + // Matrix assemblers + inline void assembleQ(); + inline void assembleP(); + inline void assembleNi(); + + // Selects out of Vv the 4 vertices belonging to face fi + inline void assembleSelector(int fi, + Eigen::SparseMatrix &S); + + + public: + // Init - assemble stacked vector and lhs matrix, factorize + inline PlanarizerShapeUp(const Eigen::MatrixBase &V_, + const Eigen::MatrixBase &F_, + const int maxIter_, + const double &threshold_); + // Planarization - output to Vout + inline void planarize(Eigen::PlainObjectBase &Vout); + }; +} + +//Implementation + +template +inline igl::PlanarizerShapeUp::PlanarizerShapeUp(const Eigen::MatrixBase &V_, + const Eigen::MatrixBase &F_, + const int maxIter_, + const double &threshold_): +numV(V_.rows()), +numF(F_.rows()), +Vin(V_), +Fin(F_), +weightsSqrt(Eigen::Matrix::Ones(numF,1)), +maxIter(maxIter_), +threshold(threshold_) +{ + // assemble stacked vertex position vector + Vv.setZero(3*numV,1); + for (int i =0;i +inline void igl::PlanarizerShapeUp::assembleQ() +{ + std::vector > tripletList; + + // assemble the Ni matrix + assembleNi(); + + for (int fi = 0; fi< numF; fi++) + { + Eigen::SparseMatrix Sfi; + assembleSelector(fi, Sfi); + + // the final matrix per face + Eigen::SparseMatrix Qi = weightsSqrt(fi)*Ni*Sfi; + // put it in the correct block of Q + // todo: this can be made faster by omitting the selector matrix + for (int k=0; k::InnerIterator it(Qi,k); it; ++it) + { + typename DerivedV::Scalar val = it.value(); + int row = it.row(); + int col = it.col(); + tripletList.push_back(Eigen::Triplet(row+3*ni*fi,col,val)); + } + } + + Q.resize(3*ni*numF,3*numV); + Q.setFromTriplets(tripletList.begin(), tripletList.end()); + // the actual lhs matrix is Q'*Q + // prefactor that matrix + solver.compute(Q.transpose()*Q); + if(solver.info()!=Eigen::Success) + { + std::cerr << "Cholesky failed - PlanarizerShapeUp.cpp" << std::endl; + assert(0); + } +} + +template +inline void igl::PlanarizerShapeUp::assembleNi() +{ + std::vector> tripletList; + for (int ii = 0; ii< ni; ii++) + { + for (int jj = 0; jj< ni; jj++) + { + tripletList.push_back(Eigen::Triplet(3*ii+0,3*jj+0,-1./ni)); + tripletList.push_back(Eigen::Triplet(3*ii+1,3*jj+1,-1./ni)); + tripletList.push_back(Eigen::Triplet(3*ii+2,3*jj+2,-1./ni)); + } + tripletList.push_back(Eigen::Triplet(3*ii+0,3*ii+0,1.)); + tripletList.push_back(Eigen::Triplet(3*ii+1,3*ii+1,1.)); + tripletList.push_back(Eigen::Triplet(3*ii+2,3*ii+2,1.)); + } + Ni.resize(3*ni,3*ni); + Ni.setFromTriplets(tripletList.begin(), tripletList.end()); +} + +//assumes V stacked [x;y;z;x;y;z...]; +template +inline void igl::PlanarizerShapeUp::assembleSelector(int fi, + Eigen::SparseMatrix &S) +{ + + std::vector> tripletList; + for (int fvi = 0; fvi< ni; fvi++) + { + int vi = Fin(fi,fvi); + tripletList.push_back(Eigen::Triplet(3*fvi+0,3*vi+0,1.)); + tripletList.push_back(Eigen::Triplet(3*fvi+1,3*vi+1,1.)); + tripletList.push_back(Eigen::Triplet(3*fvi+2,3*vi+2,1.)); + } + + S.resize(3*ni,3*numV); + S.setFromTriplets(tripletList.begin(), tripletList.end()); + +} + +//project all faces to their closest planar face +template +inline void igl::PlanarizerShapeUp::assembleP() +{ + P.setZero(3*ni*numF); + for (int fi = 0; fi< numF; fi++) + { + // todo: this can be made faster by omitting the selector matrix + Eigen::SparseMatrix Sfi; + assembleSelector(fi, Sfi); + Eigen::SparseMatrix NSi = Ni*Sfi; + + Eigen::Matrix Vi = NSi*Vv; + Eigen::Matrix CC(3,ni); + for (int i = 0; i C = CC*CC.transpose(); + + // Alec: Doesn't compile + Eigen::EigenSolver> es(C); + // the real() is for compilation purposes + Eigen::Matrix lambda = es.eigenvalues().real(); + Eigen::Matrix U = es.eigenvectors().real(); + int min_i; + lambda.cwiseAbs().minCoeff(&min_i); + U.col(min_i).setZero(); + Eigen::Matrix PP = U*U.transpose()*CC; + for (int i = 0; i +inline void igl::PlanarizerShapeUp::planarize(Eigen::PlainObjectBase &Vout) +{ + Eigen::Matrix planarity; + Vout = Vin; + + for (int iter =0; iter oldMean, newMean; + oldMean = Vin.colwise().mean(); + newMean = Vout.colwise().mean(); + Vout.rowwise() += (oldMean - newMean); + +}; + + + +template +IGL_INLINE void igl::planarize_quad_mesh(const Eigen::MatrixBase &Vin, + const Eigen::MatrixBase &Fin, + const int maxIter, + const double &threshold, + Eigen::PlainObjectBase &Vout) +{ + PlanarizerShapeUp planarizer(Vin, Fin, maxIter, threshold); + planarizer.planarize(Vout); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +template void igl::planarize_quad_mesh, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, int, double const&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/planarize_quad_mesh.h b/src/external/libigl-2.3.0/include/igl/planarize_quad_mesh.h new file mode 100644 index 000000000..3d257da8a --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/planarize_quad_mesh.h @@ -0,0 +1,46 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_PLANARIZE_QUAD_MESH_H +#define IGL_PLANARIZE_QUAD_MESH_H +#include "igl_inline.h" +#include +namespace igl +{ + // Planarizes a given quad mesh using the algorithm described in the paper + // "Shape-Up: Shaping Discrete Geometry with Projections" by S. Bouaziz, + // M. Deuss, Y. Schwartzburg, T. Weise, M. Pauly, Computer Graphics Forum, + // Volume 31, Issue 5, August 2012, p. 1657-1667 + // (http://dl.acm.org/citation.cfm?id=2346802). + // The algorithm iterates between projecting each quad to its closest planar + // counterpart and stitching those quads together via a least squares + // optimization. It stops whenever all quads' non-planarity is less than a + // given threshold (suggested value: 0.01), or a maximum number of iterations + // is reached. + + + // Inputs: + // Vin #V by 3 eigen Matrix of mesh vertex 3D positions + // F #F by 4 eigen Matrix of face (quad) indices + // maxIter maximum numbers of iterations + // threshold minimum allowed threshold for non-planarity + // Output: + // Vout #V by 3 eigen Matrix of planar mesh vertex 3D positions + // + + template + IGL_INLINE void planarize_quad_mesh(const Eigen::MatrixBase &Vin, + const Eigen::MatrixBase &F, + const int maxIter, + const double &threshold, + Eigen::PlainObjectBase &Vout); +} +#ifndef IGL_STATIC_LIBRARY +# include "planarize_quad_mesh.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/png/readPNG.cpp b/src/external/libigl-2.3.0/include/igl/png/readPNG.cpp new file mode 100644 index 000000000..8d42ad8d9 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/png/readPNG.cpp @@ -0,0 +1,47 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Daniele Panozzo +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "readPNG.h" +#include + +IGL_INLINE bool igl::png::readPNG( + const std::string png_file, + Eigen::Matrix& R, + Eigen::Matrix& G, + Eigen::Matrix& B, + Eigen::Matrix& A +) +{ + int cols,rows,n; + unsigned char *data = stbi_load(png_file.c_str(), &cols, &rows, &n, 4); + if(data == NULL) { + return false; + } + + R.resize(cols,rows); + G.resize(cols,rows); + B.resize(cols,rows); + A.resize(cols,rows); + + for (unsigned i=0; i +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_PNG_READ_PNG_H +#define IGL_PNG_READ_PNG_H +#include "../igl_inline.h" +#include +#include + +namespace igl +{ + namespace png + { + // Read an image from a .png file into 4 memory buffers + // + // Input: + // png_file path to .png file + // Output: + // R,G,B,A texture channels + // Returns true on success, false on failure + // + IGL_INLINE bool readPNG(const std::string png_file, + Eigen::Matrix& R, + Eigen::Matrix& G, + Eigen::Matrix& B, + Eigen::Matrix& A + ); + } +} + +#ifndef IGL_STATIC_LIBRARY +# include "readPNG.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/png/render_to_png.cpp b/src/external/libigl-2.3.0/include/igl/png/render_to_png.cpp new file mode 100644 index 000000000..6533ad9ab --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/png/render_to_png.cpp @@ -0,0 +1,45 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "render_to_png.h" +#include + +#include "../opengl/gl.h" + +IGL_INLINE bool igl::png::render_to_png( + const std::string png_file, + const int width, + const int height, + const bool alpha, + const bool fast) +{ + unsigned char * data = new unsigned char[4*width*height]; + glReadPixels( + 0, + 0, + width, + height, + GL_RGBA, + GL_UNSIGNED_BYTE, + data); + //img->flip(); + if(!alpha) + { + for(int i = 0;i +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_PNG_RENDER_TO_PNG_H +#define IGL_PNG_RENDER_TO_PNG_H +#include + +#include +namespace igl +{ + namespace png + { + // + // Render current open GL image to .png file + // Inputs: + // png_file path to output .png file + // width width of scene and resulting image + // height height of scene and resulting image + // alpha whether to include alpha channel + // fast sacrifice compression ratio for speed + // Returns true only if no errors occurred + // + // See also: igl/render_to_tga which is faster but writes .tga files + IGL_INLINE bool render_to_png( + const std::string png_file, + const int width, + const int height, + const bool alpha = true, + const bool fast = false); + } +} + +#ifndef IGL_STATIC_LIBRARY +# include "render_to_png.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/png/render_to_png_async.cpp b/src/external/libigl-2.3.0/include/igl/png/render_to_png_async.cpp new file mode 100644 index 000000000..033701e63 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/png/render_to_png_async.cpp @@ -0,0 +1,54 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "render_to_png_async.h" +#include "../opengl/gl.h" +#include + +static IGL_INLINE bool render_to_png_async_helper( + unsigned char * img, int width, int height, + const std::string png_file, + const bool alpha, + const bool fast) +{ + //img->flip(); + if(!alpha) + { + for(int i = 0;i +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_PNG_RENDER_TO_PNG_ASYNC_H +#define IGL_PNG_RENDER_TO_PNG_ASYNC_H +#include +#include +//#include + +#include +namespace igl +{ + namespace png + { + // History: + // added multithreaded parameter and support, Alec Sept 3, 2012 + // + // Render current open GL image to .png file + // Inputs: + // png_file path to output .png file + // width width of scene and resulting image + // height height of scene and resulting image + // alpha whether to include alpha channel + // fast sacrifice compression ratio for speed + // Returns true only if no errors occurred + // + // See also: igl/render_to_tga which is faster but writes .tga files + IGL_INLINE std::thread render_to_png_async( + const std::string png_file, + const int width, + const int height, + const bool alpha = true, + const bool fast = false); + } +} + +#ifndef IGL_STATIC_LIBRARY +# include "render_to_png_async.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/png/texture_from_file.cpp b/src/external/libigl-2.3.0/include/igl/png/texture_from_file.cpp new file mode 100644 index 000000000..60e8c795c --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/png/texture_from_file.cpp @@ -0,0 +1,61 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "texture_from_file.h" + +#include "texture_from_png.h" +#include "../STR.h" +#include "../pathinfo.h" +#include "../opengl/report_gl_error.h" +//#include "../opengl2/texture_from_tga.h" +#include +#include +#include + +IGL_INLINE bool igl::png::texture_from_file(const std::string filename, GLuint & id) +{ + using namespace igl::opengl; + using namespace std; + // dirname, basename, extension and filename + string d,b,ext,f; + pathinfo(filename,d,b,ext,f); + // Convert extension to lower case + transform(ext.begin(), ext.end(), ext.begin(), ::tolower); + //if(ext == "tga") + //{ + // return texture_from_tga(filename,id); + //}else + if(ext == "png") + { + return texture_from_png(filename,id); + }else + { +#ifdef __APPLE__ + // Convert to a temporary png file + string tmp = "/var/tmp/.texture_from_file.png"; +#define PATH_TO_CONVERT "/opt/local/bin/convert" + string command = STR(PATH_TO_CONVERT<<" \""< +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_PNG_TEXTURE_FROM_FILE_H +#define IGL_PNG_TEXTURE_FROM_FILE_H +#include "../igl_inline.h" +#include "../opengl/gl.h" + +#include + +namespace igl +{ + namespace png + { + // Read an image from an image file and use it as a texture. Officially, + // only .tga and .png are supported. Any filetype read by + // ImageMagick's `convert` will work via an unsafe system call. + // + // Input: + // filename path to image file + // Output: + // id of generated openGL texture + // Returns true on success, false on failure + IGL_INLINE bool texture_from_file(const std::string filename, GLuint & id); + } +} + +#ifndef IGL_STATIC_LIBRARY +# include "texture_from_file.cpp" +#endif + +#endif + + + diff --git a/src/external/libigl-2.3.0/include/igl/png/texture_from_png.cpp b/src/external/libigl-2.3.0/include/igl/png/texture_from_png.cpp new file mode 100644 index 000000000..fde3c002c --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/png/texture_from_png.cpp @@ -0,0 +1,83 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "texture_from_png.h" + +#include "../opengl/report_gl_error.h" +#include + +IGL_INLINE bool igl::png::texture_from_png(const std::string png_file, const bool flip, GLuint & id) +{ + int width,height,n; + unsigned char *data = igl::stbi_load(png_file.c_str(), &width, &height, &n, 4); + if(data == NULL) { + return false; + } + + // Why do I need to flip? + /*if(flip) + { + yimg.flip(); + }*/ + + glGenTextures(1, &id); + glBindTexture(GL_TEXTURE_2D, id); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexImage2D( + GL_TEXTURE_2D, 0, GL_RGB, + width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); + glBindTexture(GL_TEXTURE_2D, 0); + + igl::stbi_image_free(data); + + return true; +} + +IGL_INLINE bool igl::png::texture_from_png(const std::string png_file, GLuint & id) +{ + return texture_from_png(png_file,false,id); +} + + +IGL_INLINE bool igl::png::texture_from_png( + const std::string png_file, + Eigen::Matrix& R, + Eigen::Matrix& G, + Eigen::Matrix& B, + Eigen::Matrix& A +) +{ + int width,height,n; + unsigned char *data = igl::stbi_load(png_file.c_str(), &width, &height, &n, 4); + if(data == NULL) { + return false; + } + + R.resize(height,width); + G.resize(height,width); + B.resize(height,width); + A.resize(height,width); + + for (unsigned j=0; j +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_PNG_TEXTURE_FROM_PNG_H +#define IGL_PNG_TEXTURE_FROM_PNG_H +#include "../igl_inline.h" +#include +#include + +#include "../opengl/gl.h" + +namespace igl +{ + namespace png + { + // Read an image from a .png file and use it as a texture + // + // Input: + // png_file path to .png file + // flip whether to flip the image vertically (A --> ∀) + // Output: + // id of generated openGL texture + // Returns true on success, false on failure + IGL_INLINE bool texture_from_png(const std::string png_file, const bool flip, GLuint & id); + IGL_INLINE bool texture_from_png(const std::string png_file, GLuint & id); + + // Read an image from a .png file and use it as a texture + // + // Input: + // png_file path to .png file + // Output: + // R,G,B,A texture channels + // Returns true on success, false on failure + // + // Todo: this is an inappropriate function name. This is really just + // reading a png.... Not necessarily as a texture. + IGL_INLINE bool texture_from_png(const std::string png_file, + Eigen::Matrix& R, + Eigen::Matrix& G, + Eigen::Matrix& B, + Eigen::Matrix& A + ); + } +} + +#ifndef IGL_STATIC_LIBRARY +# include "texture_from_png.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/png/writePNG.cpp b/src/external/libigl-2.3.0/include/igl/png/writePNG.cpp new file mode 100644 index 000000000..9ab68d775 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/png/writePNG.cpp @@ -0,0 +1,46 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Daniele Panozzo +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "writePNG.h" +#include +#include + +IGL_INLINE bool igl::png::writePNG( + const Eigen::Matrix& R, + const Eigen::Matrix& G, + const Eigen::Matrix& B, + const Eigen::Matrix& A, + const std::string png_file +) +{ + assert((R.rows() == G.rows()) && (G.rows() == B.rows()) && (B.rows() == A.rows())); + assert((R.cols() == G.cols()) && (G.cols() == B.cols()) && (B.cols() == A.cols())); + + const int comp = 4; // 4 Channels Red, Green, Blue, Alpha + const int stride_in_bytes = R.rows()*comp; // Length of one row in bytes + std::vector data(R.size()*comp,0); // The image itself; + + for (unsigned i = 0; i +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_PNG_WRITE_PNG_H +#define IGL_PNG_WRITE_PNG_H +#include "../igl_inline.h" +#include +#include + +namespace igl +{ + namespace png + { + // Writes an image to a png file + // + // Input: + // R,G,B,A texture channels + // Output: + // png_file path to .png file + // Returns true on success, false on failure + // + IGL_INLINE bool writePNG + ( + const Eigen::Matrix& R, + const Eigen::Matrix& G, + const Eigen::Matrix& B, + const Eigen::Matrix& A, + const std::string png_file + ); + } +} + +#ifndef IGL_STATIC_LIBRARY +# include "writePNG.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/point_in_circle.cpp b/src/external/libigl-2.3.0/include/igl/point_in_circle.cpp new file mode 100644 index 000000000..9c26d8c0d --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/point_in_circle.cpp @@ -0,0 +1,18 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "point_in_circle.h" + +IGL_INLINE bool igl::point_in_circle( + const double qx, + const double qy, + const double cx, + const double cy, + const double r) +{ + return (qx-cx)*(qx-cx) + (qy-cy)*(qy-cy) - r*r < 0; +} diff --git a/src/external/libigl-2.3.0/include/igl/point_in_circle.h b/src/external/libigl-2.3.0/include/igl/point_in_circle.h new file mode 100644 index 000000000..f19344c40 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/point_in_circle.h @@ -0,0 +1,34 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_POINT_IN_CIRCLE_H +#define IGL_POINT_IN_CIRCLE_H +#include "igl_inline.h" + +namespace igl +{ + // Determine if 2d point is in a circle + // Inputs: + // qx x-coordinate of query point + // qy y-coordinate of query point + // cx x-coordinate of circle center + // cy y-coordinate of circle center + // r radius of circle + // Returns true if query point is in circle, false otherwise + IGL_INLINE bool point_in_circle( + const double qx, + const double qy, + const double cx, + const double cy, + const double r); +} + +#ifndef IGL_STATIC_LIBRARY +# include "point_in_circle.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/point_in_poly.cpp b/src/external/libigl-2.3.0/include/igl/point_in_poly.cpp new file mode 100644 index 000000000..f0b07edf9 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/point_in_poly.cpp @@ -0,0 +1,51 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "point_in_poly.h" + +bool IGL_INLINE igl::point_in_poly( const std::vector >&poly, + const unsigned int xt, + const unsigned int yt) +{ + int npoints= poly.size(); + unsigned int xnew,ynew; + unsigned int xold,yold; + unsigned int x1,y1; + unsigned int x2,y2; + int i; + int inside=0; + + if (npoints < 3) { + return(0); + } + xold=poly[npoints-1][0]; + yold=poly[npoints-1][1]; + for (i=0 ; i < npoints ; i++) { + xnew=poly[i][0]; + ynew=poly[i][1]; + if (xnew > xold) { + x1=xold; + x2=xnew; + y1=yold; + y2=ynew; + } + else { + x1=xnew; + x2=xold; + y1=ynew; + y2=yold; + } + if ((xnew < xt) == (xt <= xold) /* edge "open" at one end */ + && ((long)yt-(long)y1)*(long)(x2-x1) + < ((long)y2-(long)y1)*(long)(xt-x1)) { + inside=!inside; + } + xold=xnew; + yold=ynew; + } + return (inside != 0); +} diff --git a/src/external/libigl-2.3.0/include/igl/point_in_poly.h b/src/external/libigl-2.3.0/include/igl/point_in_poly.h new file mode 100644 index 000000000..2b9c6e51b --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/point_in_poly.h @@ -0,0 +1,36 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_POINT_IN_POLY_H +#define IGL_POINT_IN_POLY_H +#include "igl_inline.h" + +#include + +namespace igl +{ + // Determine if 2d point is inside a 2D polygon + // Inputs: + // poly vector of polygon points, [0]=x, [1]=y. + // Polyline need not be closed (i.e. first point != last point), + // the line segment between last and first selected points is constructed + // within this function. + // x x-coordinate of query point + // y y-coordinate of query point + // Returns true if query point is in polygon, false otherwise + // from http://www.visibone.com/inpoly/ +bool IGL_INLINE point_in_poly( const std::vector >&poly, + const unsigned int xt, + const unsigned int yt); + +} + +#ifndef IGL_STATIC_LIBRARY +# include "point_in_poly.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/point_mesh_squared_distance.cpp b/src/external/libigl-2.3.0/include/igl/point_mesh_squared_distance.cpp new file mode 100644 index 000000000..70658f64e --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/point_mesh_squared_distance.cpp @@ -0,0 +1,62 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "point_mesh_squared_distance.h" +#include "AABB.h" +#include + +template < + typename DerivedP, + typename DerivedV, + typename DerivedEle, + typename DerivedsqrD, + typename DerivedI, + typename DerivedC> +IGL_INLINE void igl::point_mesh_squared_distance( + const Eigen::MatrixBase & P, + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & Ele, + Eigen::PlainObjectBase & sqrD, + Eigen::PlainObjectBase & I, + Eigen::PlainObjectBase & C) +{ + using namespace std; + const size_t dim = P.cols(); + assert((dim == 2 || dim == 3) && "P.cols() should be 2 or 3"); + assert(P.cols() == V.cols() && "P.cols() should equal V.cols()"); + switch(dim) + { + default: + assert(false && "Unsupported dim"); + // fall-through and pray + case 3: + { + AABB tree; + tree.init(V,Ele); + return tree.squared_distance(V,Ele,P,sqrD,I,C); + } + case 2: + { + AABB tree; + tree.init(V,Ele); + return tree.squared_distance(V,Ele,P,sqrD,I,C); + } + } +} + +#ifdef IGL_STATIC_LIBRARY +template void igl::point_mesh_squared_distance, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix>(Eigen::MatrixBase> const &, Eigen::MatrixBase> const &, Eigen::MatrixBase> const &, Eigen::PlainObjectBase> &, Eigen::PlainObjectBase> &, Eigen::PlainObjectBase> &); +template void igl::point_mesh_squared_distance, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase> const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::point_mesh_squared_distance, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase> const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::point_mesh_squared_distance, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase> const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::point_mesh_squared_distance, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); + +#ifdef WIN32 +template void igl::point_mesh_squared_distance, class Eigen::Matrix, class Eigen::Matrix, Eigen::Matrix, class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>, class Eigen::Matrix>(class Eigen::MatrixBase> const &, class Eigen::MatrixBase> const &, class Eigen::MatrixBase> const &, class Eigen::PlainObjectBase> &, class Eigen::PlainObjectBase> &, class Eigen::PlainObjectBase> &); +template void igl::point_mesh_squared_distance, class Eigen::Matrix, class Eigen::Matrix, class Eigen::Matrix, class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>, class Eigen::Matrix>(class Eigen::MatrixBase> const &, class Eigen::MatrixBase> const &, class Eigen::MatrixBase> const &, class Eigen::PlainObjectBase> &, class Eigen::PlainObjectBase> &, class Eigen::PlainObjectBase> &); +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/point_mesh_squared_distance.h b/src/external/libigl-2.3.0/include/igl/point_mesh_squared_distance.h new file mode 100644 index 000000000..e26486122 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/point_mesh_squared_distance.h @@ -0,0 +1,53 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_POINT_MESH_SQUARED_DISTANCE_H +#define IGL_POINT_MESH_SQUARED_DISTANCE_H +#include "igl_inline.h" +#include +#include + +namespace igl +{ + // Compute distances from a set of points P to a triangle mesh (V,F) + // + // Inputs: + // P #P by 3 list of query point positions + // V #V by 3 list of vertex positions + // Ele #Ele by (3|2|1) list of (triangle|edge|point) indices + // Outputs: + // sqrD #P list of smallest squared distances + // I #P list of primitive indices corresponding to smallest distances + // C #P by 3 list of closest points + // + // Known bugs: This only computes distances to given primitivess. So + // unreferenced vertices are ignored. However, degenerate primitives are + // handled correctly: triangle [1 2 2] is treated as a segment [1 2], and + // triangle [1 1 1] is treated as a point. So one _could_ add extra + // combinatorially degenerate rows to Ele for all unreferenced vertices to + // also get distances to points. +template < + typename DerivedP, + typename DerivedV, + typename DerivedEle, + typename DerivedsqrD, + typename DerivedI, + typename DerivedC> +IGL_INLINE void point_mesh_squared_distance( + const Eigen::MatrixBase &P, + const Eigen::MatrixBase &V, + const Eigen::MatrixBase &Ele, + Eigen::PlainObjectBase &sqrD, + Eigen::PlainObjectBase &I, + Eigen::PlainObjectBase &C); +} + +#ifndef IGL_STATIC_LIBRARY +# include "point_mesh_squared_distance.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/point_simplex_squared_distance.cpp b/src/external/libigl-2.3.0/include/igl/point_simplex_squared_distance.cpp new file mode 100644 index 000000000..358152981 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/point_simplex_squared_distance.cpp @@ -0,0 +1,185 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "point_simplex_squared_distance.h" +#include "project_to_line_segment.h" +#include "barycentric_coordinates.h" +#include +#include +#include + + + +template < + int DIM, + typename Derivedp, + typename DerivedV, + typename DerivedEle, + typename Derivedsqr_d, + typename Derivedc, + typename Derivedb> +IGL_INLINE void igl::point_simplex_squared_distance( + const Eigen::MatrixBase & p, + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & Ele, + const typename DerivedEle::Index primitive, + Derivedsqr_d & sqr_d, + Eigen::MatrixBase & c, + Eigen::PlainObjectBase & bary) +{ + typedef typename Derivedp::Scalar Scalar; + typedef typename Eigen::Matrix Vector; + typedef Vector Point; + //typedef Derivedb BaryPoint; + typedef Eigen::Matrix BaryPoint; + + const auto & Dot = [](const Point & a, const Point & b)->Scalar + { + return a.dot(b); + }; + // Real-time collision detection, Ericson, Chapter 5 + const auto & ClosestBaryPtPointTriangle = + [&Dot](Point p, Point a, Point b, Point c, BaryPoint& bary_out )->Point + { + // Check if P in vertex region outside A + Vector ab = b - a; + Vector ac = c - a; + Vector ap = p - a; + Scalar d1 = Dot(ab, ap); + Scalar d2 = Dot(ac, ap); + if (d1 <= 0.0 && d2 <= 0.0) { + // barycentric coordinates (1,0,0) + bary_out << 1, 0, 0; + return a; + } + // Check if P in vertex region outside B + Vector bp = p - b; + Scalar d3 = Dot(ab, bp); + Scalar d4 = Dot(ac, bp); + if (d3 >= 0.0 && d4 <= d3) { + // barycentric coordinates (0,1,0) + bary_out << 0, 1, 0; + return b; + } + // Check if P in edge region of AB, if so return projection of P onto AB + Scalar vc = d1*d4 - d3*d2; + if( a != b) + { + if (vc <= 0.0 && d1 >= 0.0 && d3 <= 0.0) { + Scalar v = d1 / (d1 - d3); + // barycentric coordinates (1-v,v,0) + bary_out << 1-v, v, 0; + return a + v * ab; + } + } + // Check if P in vertex region outside C + Vector cp = p - c; + Scalar d5 = Dot(ab, cp); + Scalar d6 = Dot(ac, cp); + if (d6 >= 0.0 && d5 <= d6) { + // barycentric coordinates (0,0,1) + bary_out << 0, 0, 1; + return c; + } + // Check if P in edge region of AC, if so return projection of P onto AC + Scalar vb = d5*d2 - d1*d6; + if (vb <= 0.0 && d2 >= 0.0 && d6 <= 0.0) { + Scalar w = d2 / (d2 - d6); + // barycentric coordinates (1-w,0,w) + bary_out << 1-w, 0, w; + return a + w * ac; + } + // Check if P in edge region of BC, if so return projection of P onto BC + Scalar va = d3*d6 - d5*d4; + if (va <= 0.0 && (d4 - d3) >= 0.0 && (d5 - d6) >= 0.0) { + Scalar w = (d4 - d3) / ((d4 - d3) + (d5 - d6)); + // barycentric coordinates (0,1-w,w) + bary_out << 0, 1-w, w; + return b + w * (c - b); + } + // P inside face region. Compute Q through its barycentric coordinates (u,v,w) + Scalar denom = 1.0 / (va + vb + vc); + Scalar v = vb * denom; + Scalar w = vc * denom; + bary_out << 1.0-v-w, v, w; + return a + ab * v + ac * w; // = u*a + v*b + w*c, u = va * denom = 1.0-v-w + }; + + assert(p.size() == DIM); + assert(V.cols() == DIM); + assert(Ele.cols() <= DIM+1); + assert(Ele.cols() <= 3 && "Only simplices up to triangles are considered"); + + assert((Derivedb::RowsAtCompileTime == 1 || Derivedb::ColsAtCompileTime == 1) && "bary must be Eigen Vector or Eigen RowVector"); + assert( + ((Derivedb::RowsAtCompileTime == -1 || Derivedb::ColsAtCompileTime == -1) || + (Derivedb::RowsAtCompileTime == Ele.cols() || Derivedb::ColsAtCompileTime == Ele.cols()) + ) && "bary must be Dynamic or size of Ele.cols()"); + + BaryPoint tmp_bary; + c = (const Derivedc &)ClosestBaryPtPointTriangle( + p, + V.row(Ele(primitive,0)), + // modulo is a HACK to handle points, segments and triangles. Because of + // this, we need 3d buffer for bary + V.row(Ele(primitive,1%Ele.cols())), + V.row(Ele(primitive,2%Ele.cols())), + tmp_bary); + bary.resize( Derivedb::RowsAtCompileTime == 1 ? 1 : Ele.cols(), Derivedb::ColsAtCompileTime == 1 ? 1 : Ele.cols()); + bary.head(Ele.cols()) = tmp_bary.head(Ele.cols()); + sqr_d = (p-c).squaredNorm(); +} + +template < + int DIM, + typename Derivedp, + typename DerivedV, + typename DerivedEle, + typename Derivedsqr_d, + typename Derivedc> +IGL_INLINE void igl::point_simplex_squared_distance( + const Eigen::MatrixBase & p, + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & Ele, + const typename DerivedEle::Index primitive, + Derivedsqr_d & sqr_d, + Eigen::MatrixBase & c) +{ + // Use Dynamic because we don't know Ele.cols() at compile time. + Eigen::Matrix b; + point_simplex_squared_distance( p, V, Ele, primitive, sqr_d, c, b ); +} + +namespace igl +{ + template <> IGL_INLINE void point_simplex_squared_distance<2>(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::Matrix::Index, float&, Eigen::MatrixBase >&) {assert(false);}; + template <> IGL_INLINE void point_simplex_squared_distance<2>(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::Matrix::Index, double&, Eigen::MatrixBase >&) {assert(false);}; + template <> IGL_INLINE void point_simplex_squared_distance<2>(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::Matrix::Index, double&, Eigen::MatrixBase >&) {assert(false);}; +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::point_simplex_squared_distance<3, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, double, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::Matrix::Index, double&, Eigen::MatrixBase >&); +// generated by autoexplicit.sh +template void igl::point_simplex_squared_distance<3, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, double, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::Matrix::Index, double&, Eigen::MatrixBase >&); +// generated by autoexplicit.sh +template void igl::point_simplex_squared_distance<3, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, float, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::Matrix::Index, float&, Eigen::MatrixBase >&); +// generated by autoexplicit.sh +// generated by autoexplicit.sh +template void igl::point_simplex_squared_distance<3, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, float, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::Matrix::Index, float&, Eigen::MatrixBase >&); +// generated by autoexplicit.sh +template void igl::point_simplex_squared_distance<3, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, float, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::Matrix::Index, float&, Eigen::MatrixBase >&); +template void igl::point_simplex_squared_distance<3, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, double, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::Matrix::Index, double&, Eigen::MatrixBase >&); +template void igl::point_simplex_squared_distance<2, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, double, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::Matrix::Index, double&, Eigen::MatrixBase >&); +template void igl::point_simplex_squared_distance<3, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, double, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::Matrix::Index, double&, Eigen::MatrixBase >&, Eigen::PlainObjectBase >&); +template void igl::point_simplex_squared_distance<3, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, double, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::Matrix::Index, double&, Eigen::MatrixBase >&, Eigen::PlainObjectBase >&); +template void igl::point_simplex_squared_distance<2, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, double, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::Matrix::Index, double&, Eigen::MatrixBase >&, Eigen::PlainObjectBase >&); +template void igl::point_simplex_squared_distance<2, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, double, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::Matrix::Index, double&, Eigen::MatrixBase >&, Eigen::PlainObjectBase >&); +template void igl::point_simplex_squared_distance<2, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, double, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::Matrix::Index, double&, Eigen::MatrixBase >&); +template void igl::point_simplex_squared_distance<3, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, double, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::Matrix::Index, double&, Eigen::MatrixBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/point_simplex_squared_distance.h b/src/external/libigl-2.3.0/include/igl/point_simplex_squared_distance.h new file mode 100644 index 000000000..0cc871cf0 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/point_simplex_squared_distance.h @@ -0,0 +1,72 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_POINT_SIMPLEX_SQUARED_DISTANCE_H +#define IGL_POINT_SIMPLEX_SQUARED_DISTANCE_H +#include "igl_inline.h" +#include +namespace igl +{ + // Determine squared distance from a point to linear simplex. + // + // Inputs: + // p d-long query point + // V #V by d list of vertices + // Ele #Ele by ss<=d+1 list of simplex indices into V + // i index into Ele of simplex + // Outputs: + // sqr_d squared distance of Ele(i) to p + // c closest point on Ele(i) + // + template < + int DIM, + typename Derivedp, + typename DerivedV, + typename DerivedEle, + typename Derivedsqr_d, + typename Derivedc> + IGL_INLINE void point_simplex_squared_distance( + const Eigen::MatrixBase & p, + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & Ele, + const typename DerivedEle::Index i, + Derivedsqr_d & sqr_d, + Eigen::MatrixBase & c); + // Determine squared distance from a point to linear simplex. + // Also return barycentric coordinate of closest point. + // + // Inputs: + // p d-long query point + // V #V by d list of vertices + // Ele #Ele by ss<=d+1 list of simplex indices into V + // i index into Ele of simplex + // Outputs: + // sqr_d squared distance of Ele(i) to p + // c closest point on Ele(i) + // b barycentric coordinates of closest point on Ele(i) + // + template < + int DIM, + typename Derivedp, + typename DerivedV, + typename DerivedEle, + typename Derivedsqr_d, + typename Derivedc, + typename Derivedb> + IGL_INLINE void point_simplex_squared_distance( + const Eigen::MatrixBase & p, + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & Ele, + const typename DerivedEle::Index i, + Derivedsqr_d & sqr_d, + Eigen::MatrixBase & c, + Eigen::PlainObjectBase & b); +} +#ifndef IGL_STATIC_LIBRARY +# include "point_simplex_squared_distance.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/polar_dec.cpp b/src/external/libigl-2.3.0/include/igl/polar_dec.cpp new file mode 100644 index 000000000..cdd358a07 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/polar_dec.cpp @@ -0,0 +1,97 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "polar_dec.h" +#include "polar_svd.h" +#ifdef _WIN32 +#else +# include +#endif +#include +#include +#include +#include + +// From Olga's CGAL mentee's ARAP code +template < + typename DerivedA, + typename DerivedR, + typename DerivedT, + typename DerivedU, + typename DerivedS, + typename DerivedV> +IGL_INLINE void igl::polar_dec( + const Eigen::PlainObjectBase & A, + Eigen::PlainObjectBase & R, + Eigen::PlainObjectBase & T, + Eigen::PlainObjectBase & U, + Eigen::PlainObjectBase & S, + Eigen::PlainObjectBase & V) +{ + using namespace std; + using namespace Eigen; + typedef typename DerivedA::Scalar Scalar; + + const Scalar th = std::sqrt(Eigen::NumTraits::dummy_precision()); + + Eigen::SelfAdjointEigenSolver eig; + feclearexcept(FE_UNDERFLOW); + eig.computeDirect(A.transpose()*A); + if(fetestexcept(FE_UNDERFLOW) || eig.eigenvalues()(0)/eig.eigenvalues()(2) th) + { + cout<<"resorting to svd 2..."< +IGL_INLINE void igl::polar_dec( + const Eigen::PlainObjectBase & A, + Eigen::PlainObjectBase & R, + Eigen::PlainObjectBase & T) +{ + DerivedA U; + DerivedA V; + Eigen::Matrix S; + return igl::polar_dec(A,R,T,U,S,V); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +template void igl::polar_dec, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::polar_dec, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/polar_dec.h b/src/external/libigl-2.3.0/include/igl/polar_dec.h new file mode 100644 index 000000000..2b995eabe --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/polar_dec.h @@ -0,0 +1,53 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_POLAR_DEC +#define IGL_POLAR_DEC +#include "igl_inline.h" +#include + +namespace igl +{ + // Computes the polar decomposition (R,T) of a matrix A + // Inputs: + // A 3 by 3 matrix to be decomposed + // Outputs: + // R 3 by 3 orthonormal matrix part of decomposition + // T 3 by 3 stretch matrix part of decomposition + // U 3 by 3 left-singular vectors + // S 3 by 1 singular values + // V 3 by 3 right-singular vectors + // + // + template < + typename DerivedA, + typename DerivedR, + typename DerivedT, + typename DerivedU, + typename DerivedS, + typename DerivedV> + IGL_INLINE void polar_dec( + const Eigen::PlainObjectBase & A, + Eigen::PlainObjectBase & R, + Eigen::PlainObjectBase & T, + Eigen::PlainObjectBase & U, + Eigen::PlainObjectBase & S, + Eigen::PlainObjectBase & V); + template < + typename DerivedA, + typename DerivedR, + typename DerivedT> + IGL_INLINE void polar_dec( + const Eigen::PlainObjectBase & A, + Eigen::PlainObjectBase & R, + Eigen::PlainObjectBase & T); +} +#ifndef IGL_STATIC_LIBRARY +# include "polar_dec.cpp" +#endif +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/polar_svd.cpp b/src/external/libigl-2.3.0/include/igl/polar_svd.cpp new file mode 100644 index 000000000..adf50e8fc --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/polar_svd.cpp @@ -0,0 +1,92 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "polar_svd.h" +#include +#include +#include + +// Adapted from Olga's CGAL mentee's ARAP code +template < + typename DerivedA, + typename DerivedR, + typename DerivedT> +IGL_INLINE void igl::polar_svd( + const Eigen::MatrixBase & A, + Eigen::PlainObjectBase & R, + Eigen::PlainObjectBase & T) +{ + typedef + Eigen::Matrix + MatA; + MatA U; + MatA V; + Eigen::Matrix S; + return igl::polar_svd(A,R,T,U,S,V); +} + +template < + typename DerivedA, + typename DerivedR, + typename DerivedT, + typename DerivedU, + typename DerivedS, + typename DerivedV> +IGL_INLINE void igl::polar_svd( + const Eigen::MatrixBase & A, + Eigen::PlainObjectBase & R, + Eigen::PlainObjectBase & T, + Eigen::PlainObjectBase & U, + Eigen::PlainObjectBase & S, + Eigen::PlainObjectBase & V) +{ + using namespace std; + typedef + Eigen::Matrix + MatA; + Eigen::JacobiSVD svd; + svd.compute(A, Eigen::ComputeFullU | Eigen::ComputeFullV ); + U = svd.matrixU(); + V = svd.matrixV(); + S = svd.singularValues(); + R = U*V.transpose(); + const auto & SVT = S.asDiagonal() * V.adjoint(); + // Check for reflection + if(R.determinant() < 0) + { + // Annoyingly the .eval() is necessary + auto W = V.eval(); + W.col(V.cols()-1) *= -1.; + R = U*W.transpose(); + T = W*SVT; + }else + { + T = V*SVT; + } +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::polar_svd >, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::polar_svd, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::polar_svd, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::polar_svd, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::polar_svd, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::polar_svd, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::polar_svd, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::polar_svd,Eigen::Matrix,Eigen::Matrix,Eigen::Matrix,Eigen::Matrix,Eigen::Matrix >(Eigen::MatrixBase > const &,Eigen::PlainObjectBase > &,Eigen::PlainObjectBase > &,Eigen::PlainObjectBase > &,Eigen::PlainObjectBase > &,Eigen::PlainObjectBase >&); +template void igl::polar_svd, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::polar_svd, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::polar_svd, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::polar_svd, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::polar_svd, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/polar_svd.h b/src/external/libigl-2.3.0/include/igl/polar_svd.h new file mode 100644 index 000000000..f0f38e7a1 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/polar_svd.h @@ -0,0 +1,54 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_POLAR_SVD +#define IGL_POLAR_SVD +#include "igl_inline.h" +#include + +namespace igl +{ + // Computes the polar decomposition (R,T) of a matrix A using SVD singular + // value decomposition + // + // Inputs: + // A 3 by 3 matrix to be decomposed + // Outputs: + // R 3 by 3 rotation matrix part of decomposition (**always rotataion**) + // T 3 by 3 stretch matrix part of decomposition + // U 3 by 3 left-singular vectors + // S 3 by 1 singular values + // V 3 by 3 right-singular vectors + // + // + template < + typename DerivedA, + typename DerivedR, + typename DerivedT, + typename DerivedU, + typename DerivedS, + typename DerivedV> + IGL_INLINE void polar_svd( + const Eigen::MatrixBase & A, + Eigen::PlainObjectBase & R, + Eigen::PlainObjectBase & T, + Eigen::PlainObjectBase & U, + Eigen::PlainObjectBase & S, + Eigen::PlainObjectBase & V); + template < + typename DerivedA, + typename DerivedR, + typename DerivedT> + IGL_INLINE void polar_svd( + const Eigen::MatrixBase & A, + Eigen::PlainObjectBase & R, + Eigen::PlainObjectBase & T); +} +#ifndef IGL_STATIC_LIBRARY +# include "polar_svd.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/polar_svd3x3.cpp b/src/external/libigl-2.3.0/include/igl/polar_svd3x3.cpp new file mode 100644 index 000000000..54ffb5900 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/polar_svd3x3.cpp @@ -0,0 +1,94 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "polar_svd3x3.h" +#include "svd3x3.h" +#ifdef __SSE__ +# include "svd3x3_sse.h" +#endif +#ifdef __AVX__ +# include "svd3x3_avx.h" +#endif + +template +IGL_INLINE void igl::polar_svd3x3(const Mat& A, Mat& R) +{ + // should be caught at compile time, but just to be 150% sure: + assert(A.rows() == 3 && A.cols() == 3); + + Eigen::Matrix U, Vt; + Eigen::Matrix S; + svd3x3(A, U, S, Vt); + R = U * Vt.transpose(); +} + +#ifdef __SSE__ +template +IGL_INLINE void igl::polar_svd3x3_sse(const Eigen::Matrix& A, Eigen::Matrix &R) +{ + // should be caught at compile time, but just to be 150% sure: + assert(A.rows() == 3*4 && A.cols() == 3); + + Eigen::Matrix U, Vt; + Eigen::Matrix S; + svd3x3_sse(A, U, S, Vt); + + for (int k=0; k<4; k++) + { + R.block(3*k, 0, 3, 3) = U.block(3*k, 0, 3, 3) * Vt.block(3*k, 0, 3, 3).transpose(); + } + + //// test: + //for (int k=0; k<4; k++) + //{ + // Eigen::Matrix3f Apart = A.block(3*k, 0, 3, 3); + // Eigen::Matrix3f Rpart; + // polar_svd3x3(Apart, Rpart); + + // Eigen::Matrix3f Rpart_SSE = R.block(3*k, 0, 3, 3); + // Eigen::Matrix3f diff = Rpart - Rpart_SSE; + // float diffNorm = diff.norm(); + + // int hu = 1; + //} + //// eof test +} +#endif + +#ifdef __AVX__ +template +IGL_INLINE void igl::polar_svd3x3_avx(const Eigen::Matrix& A, Eigen::Matrix &R) +{ + // should be caught at compile time, but just to be 150% sure: + assert(A.rows() == 3*8 && A.cols() == 3); + + Eigen::Matrix U, Vt; + Eigen::Matrix S; + svd3x3_avx(A, U, S, Vt); + + for (int k=0; k<8; k++) + { + R.block(3*k, 0, 3, 3) = U.block(3*k, 0, 3, 3) * Vt.block(3*k, 0, 3, 3).transpose(); + } + +} +#endif + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +template void igl::polar_svd3x3 >(Eigen::Matrix const&, Eigen::Matrix&); +template void igl::polar_svd3x3 >(Eigen::Matrix const &,Eigen::Matrix &); + +#ifdef __SSE__ +template void igl::polar_svd3x3_sse(Eigen::Matrix const&, Eigen::Matrix&); +#endif + +#ifdef __AVX__ +template void igl::polar_svd3x3_avx(Eigen::Matrix const&, Eigen::Matrix&); +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/polar_svd3x3.h b/src/external/libigl-2.3.0/include/igl/polar_svd3x3.h new file mode 100644 index 000000000..a579774e0 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/polar_svd3x3.h @@ -0,0 +1,43 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_POLAR_SVD3X3_H +#define IGL_POLAR_SVD3X3_H +#include +#include "igl_inline.h" +namespace igl +{ + // Computes the closest rotation to input matrix A using specialized 3x3 SVD + // singular value decomposition (WunderSVD3x3) + // + // Inputs: + // A 3 by 3 matrix to be decomposed + // Outputs: + // R 3 by 3 closest element in SO(3) (closeness in terms of Frobenius + // metric) + // + // This means that det(R) = 1. Technically it's not polar decomposition + // which guarantees positive semidefinite stretch factor (at the cost of + // having det(R) = -1). "• The orthogonal factors U and V will be true + // rotation matrices..." [McAdams, Selle, Tamstorf, Teran, Sefakis 2011] + // + template + IGL_INLINE void polar_svd3x3(const Mat& A, Mat& R); + #ifdef __SSE__ + template + IGL_INLINE void polar_svd3x3_sse(const Eigen::Matrix& A, Eigen::Matrix &R); + #endif + #ifdef __AVX__ + template + IGL_INLINE void polar_svd3x3_avx(const Eigen::Matrix& A, Eigen::Matrix &R); + #endif +} +#ifndef IGL_STATIC_LIBRARY +# include "polar_svd3x3.cpp" +#endif +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/polygon_corners.cpp b/src/external/libigl-2.3.0/include/igl/polygon_corners.cpp new file mode 100644 index 000000000..e090a9ca4 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/polygon_corners.cpp @@ -0,0 +1,70 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2020 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "polygon_corners.h" + +template < + typename PType, + typename DerivedI, + typename DerivedC> +IGL_INLINE void igl::polygon_corners( + const std::vector > & P, + Eigen::PlainObjectBase & I, + Eigen::PlainObjectBase & C) +{ + typedef typename DerivedI::Scalar IType; + // JD: Honestly you could do a first loop over P, compute C, and then fill the + // entries of I directly. No need for guesses and push_back(), or the extra + // copy at the end. That would be more efficient. + std::vector vI;vI.reserve(P.size()*4); + C.resize(P.size()+1); + C(0) = 0; + for(size_t p = 0;p(vI.data(),vI.size()); +} + +template < + typename DerivedQ, + typename DerivedI, + typename DerivedC> +IGL_INLINE void igl::polygon_corners( + const Eigen::MatrixBase & Q, + Eigen::PlainObjectBase & I, + Eigen::PlainObjectBase & C) +{ + I.resize(Q.size()); + C.resize(Q.rows()+1); + Eigen::Index c = 0; + C(0) = 0; + for(Eigen::Index p = 0;p, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::polygon_corners, Eigen::Matrix >(std::vector >, std::allocator > > > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/polygon_corners.h b/src/external/libigl-2.3.0/include/igl/polygon_corners.h new file mode 100644 index 000000000..6766d1f6d --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/polygon_corners.h @@ -0,0 +1,55 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2020 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_POLYGON_CORNERS_H +#define IGL_POLYGON_CORNERS_H +#include "igl_inline.h" +#include +#include + +namespace igl +{ + // Convert a list-of-lists polygon mesh faces representation to list of + // polygon corners and sizes + // + // Inputs: + // P #P list of lists of vertex indices into rows of some matrix V + // Outputs: + // I #I vectorized list of polygon corner indices into rows of some matrix V + // C #P+1 list of cumulative polygon sizes so that C(i+1)-C(i) = size of + // the ith polygon, and so I(C(i)) through I(C(i+1)-1) are the indices of + // the ith polygon + // + template < + typename PType, + typename DerivedI, + typename DerivedC> + IGL_INLINE void polygon_corners( + const std::vector > & P, + Eigen::PlainObjectBase & I, + Eigen::PlainObjectBase & C); + // Convert a pure k-gon list of polygon mesh indices to list of polygon corners + // and sizes + // + // Inputs: + // Q #Q by k list of polygon indices (ith row is a k-gon, unless Q(i,j) = + // -1 then it's a j-gon) + template < + typename DerivedQ, + typename DerivedI, + typename DerivedC> + IGL_INLINE void polygon_corners( + const Eigen::MatrixBase & Q, + Eigen::PlainObjectBase & I, + Eigen::PlainObjectBase & C); +} + +#ifndef IGL_STATIC_LIBRARY +# include "polygon_corners.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/polygons_to_triangles.cpp b/src/external/libigl-2.3.0/include/igl/polygons_to_triangles.cpp new file mode 100644 index 000000000..0ba8c412c --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/polygons_to_triangles.cpp @@ -0,0 +1,45 @@ +#include "polygons_to_triangles.h" + +template < + typename DerivedI, + typename DerivedC, + typename DerivedF, + typename DerivedJ> +IGL_INLINE void igl::polygons_to_triangles( + const Eigen::MatrixBase & I, + const Eigen::MatrixBase & C, + Eigen::PlainObjectBase & F, + Eigen::PlainObjectBase & J) +{ + // Each polygon results in #sides-2 triangles. So ∑#sides-2 + F.resize(C(C.size()-1) - (C.size()-1)*2,3); + J.resize(F.rows()); + { + int f = 0; + for(int p = 0;p, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::polygons_to_triangles, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::polygons_to_triangles, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::polygons_to_triangles, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/polygons_to_triangles.h b/src/external/libigl-2.3.0/include/igl/polygons_to_triangles.h new file mode 100644 index 000000000..e3d240fd7 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/polygons_to_triangles.h @@ -0,0 +1,46 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2020 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_POLYGONS_TO_TRIANGLES_H +#define IGL_POLYGONS_TO_TRIANGLES_H + +#include "igl_inline.h" +#include +#include + +namespace igl +{ + // Given a polygon mesh, trivially triangulate each polygon with a fan. This + // purely combinatorial triangulation will work well for convex/flat polygons + // and degrade otherwise. + // + // Inputs: + // I #I vectorized list of polygon corner indices into rows of some matrix V + // C #polygons+1 list of cumulative polygon sizes so that C(i+1)-C(i) = + // size of the ith polygon, and so I(C(i)) through I(C(i+1)-1) are the + // indices of the ith polygon + // Outputs: + // F #F by 3 list of triangle indices into rows of V + // J #F list of indices into 0:#P-1 of corresponding polygon + // + template < + typename DerivedI, + typename DerivedC, + typename DerivedF, + typename DerivedJ> + IGL_INLINE void polygons_to_triangles( + const Eigen::MatrixBase & I, + const Eigen::MatrixBase & C, + Eigen::PlainObjectBase & F, + Eigen::PlainObjectBase & J); +} + +#ifndef IGL_STATIC_LIBRARY +# include "polygons_to_triangles.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/predicates/ear_clipping.cpp b/src/external/libigl-2.3.0/include/igl/predicates/ear_clipping.cpp new file mode 100644 index 000000000..fc3cd1b79 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/predicates/ear_clipping.cpp @@ -0,0 +1,124 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2019 Hanxiao Shen +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +#include +#include "ear_clipping.h" +#include "point_inside_convex_polygon.h" +#include "predicates.h" + +template +IGL_INLINE void igl::predicates::ear_clipping( + const Eigen::MatrixBase& P, + const Eigen::MatrixBase& RT, + Eigen::PlainObjectBase& I, + Eigen::PlainObjectBase& eF, + Eigen::PlainObjectBase& nP +){ + typedef typename DerivedF::Scalar Index; + typedef typename DerivedP::Scalar Scalar; + static_assert(std::is_same::value, + "index type should be consistent"); + + // check whether vertex i is an ear + auto is_ear = []( + const Eigen::MatrixBase& P, + const Eigen::MatrixBase& RT, + const Eigen::Matrix& L, + const Eigen::Matrix& R, + const Index i + ){ + + Index a = L(i), b = R(i); + if(RT(i) != 0 || RT(a) != 0 || RT(b) != 0) return false; + Eigen::Matrix pa = P.row(a); + Eigen::Matrix pb = P.row(b); + Eigen::Matrix pi = P.row(i); + auto r = igl::predicates::orient2d(pa,pi,pb); + if(r == igl::predicates::Orientation::NEGATIVE || + r == igl::predicates::Orientation::COLLINEAR) return false; + + // check if any vertex is lying inside triangle (a,b,i); + Index k=R(b); + while(k!=a){ + Eigen::Matrix T(3,2); + T< q=P.row(k); + if(igl::predicates::point_inside_convex_polygon(T,q)) + return false; + k=R(k); + } + return true; + }; + + Eigen::Matrix L(P.rows()); + Eigen::Matrix R(P.rows()); + for(int i=0;i ears; // mark ears + Eigen::Matrix X; // clipped vertices + ears.setZero(P.rows()); + X.setZero(P.rows()); + + // initialize ears + for(int i=0;i, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/predicates/ear_clipping.h b/src/external/libigl-2.3.0/include/igl/predicates/ear_clipping.h new file mode 100644 index 000000000..79e6f9fe0 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/predicates/ear_clipping.h @@ -0,0 +1,51 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2019 Hanxiao Shen +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef IGL_PREDICATES_EAR_CLIPPING_H +#define IGL_PREDICATES_EAR_CLIPPING_H + +#include +#include "../igl_inline.h" + +namespace igl +{ + namespace predicates + { + + // Implementation of ear clipping triangulation algorithm for a 2D polygon. + // https://www.geometrictools.com/Documentation/TriangulationByEarClipping.pdf + // If the polygon is simple, all vertices will be clipped and the result mesh is (P,eF) + // Otherwise, the function will try to clip as many ears as possible. + // + // Input: + // P : n*2, size n 2D polygon + // RT: n*1, preserved vertices (do not clip) marked as 1, otherwise 0 + // Output: + // I : size #nP vector, maps index from nP to P, e.g. nP's ith vertex is origianlly I(i) in P + // eF: clipped ears, in original index of P + // nP: leftover vertices after clipping + + template + IGL_INLINE void ear_clipping( + const Eigen::MatrixBase& P, + const Eigen::MatrixBase& RT, + Eigen::PlainObjectBase& I, + Eigen::PlainObjectBase& eF, + Eigen::PlainObjectBase& nP + ); + + } +} + +#ifndef IGL_STATIC_LIBRARY +# include "ear_clipping.cpp" +#endif + + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/predicates/point_inside_convex_polygon.cpp b/src/external/libigl-2.3.0/include/igl/predicates/point_inside_convex_polygon.cpp new file mode 100644 index 000000000..cfec83e91 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/predicates/point_inside_convex_polygon.cpp @@ -0,0 +1,33 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2019 Hanxiao Shen +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +#include "point_inside_convex_polygon.h" + +template +IGL_INLINE bool igl::predicates::point_inside_convex_polygon( + const Eigen::MatrixBase& P, + const Eigen::MatrixBase& q +){ + EIGEN_STATIC_ASSERT_MATRIX_SPECIFIC_SIZE(DerivedP, Eigen::Dynamic, 2); + EIGEN_STATIC_ASSERT_MATRIX_SPECIFIC_SIZE(DerivedQ, 1, 2); + typedef typename DerivedP::Scalar Scalar; + for(int i=0;i a = P.row(i); + Eigen::Matrix b = P.row(i_1); + auto r = igl::predicates::orient2d(a,b,q); + if(r == igl::predicates::Orientation::COLLINEAR || + r == igl::predicates::Orientation::NEGATIVE) + return false; + } + return true; +} + +#ifdef IGL_STATIC_LIBRARY +template bool igl::predicates::point_inside_convex_polygon, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/predicates/point_inside_convex_polygon.h b/src/external/libigl-2.3.0/include/igl/predicates/point_inside_convex_polygon.h new file mode 100644 index 000000000..58b69aeca --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/predicates/point_inside_convex_polygon.h @@ -0,0 +1,39 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2019 Hanxiao Shen +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef IGL_PREDICATES_POINT_INSIDE_CONVEX_POLYGON_H +#define IGL_PREDICATES_POINT_INSIDE_CONVEX_POLYGON_H + + + +#include "../igl_inline.h" +#include +#include "predicates.h" + +namespace igl +{ + namespace predicates + { + // check whether 2d point lies inside 2d convex polygon + // Inputs: + // P: n*2 polygon, n >= 3 + // q: 2d query point + // Returns true if point is inside polygon + template + IGL_INLINE bool point_inside_convex_polygon( + const Eigen::MatrixBase& P, + const Eigen::MatrixBase& q + ); + } +} + +#ifndef IGL_STATIC_LIBRARY +# include "point_inside_convex_polygon.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/predicates/polygons_to_triangles.cpp b/src/external/libigl-2.3.0/include/igl/predicates/polygons_to_triangles.cpp new file mode 100644 index 000000000..8adb76c21 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/predicates/polygons_to_triangles.cpp @@ -0,0 +1,248 @@ +#include "polygons_to_triangles.h" +#include "ear_clipping.h" +#include "../sort.h" +#include "../slice.h" +#include + +template < + typename DerivedV, + typename DerivedI, + typename DerivedC, + typename DerivedF, + typename DerivedJ> +IGL_INLINE void igl::predicates::polygons_to_triangles( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & I, + const Eigen::MatrixBase & C, + Eigen::PlainObjectBase & F, + Eigen::PlainObjectBase & J) +{ + typedef Eigen::Index Index; + // Each polygon results in #sides-2 triangles. So ∑#sides-2 + F.resize(C(C.size()-1) - (C.size()-1)*2,3); + J.resize(F.rows()); + { + Index f = 0; + for(Index p = 0;p(); + break; + case 3: + { + Eigen::MatrixXd P = (pV.rowwise() - pV.colwise().mean()).template cast(); + Eigen::Matrix3d O = P.transpose() * P; + Eigen::EigenSolver es(O); + Eigen::Matrix3d C = es.eigenvectors().real(); + { + Eigen::Vector3d _1; + Eigen::Vector3i I; + igl::sort(es.eigenvalues().real().eval(),1,false,_1,I); + igl::slice(Eigen::Matrix3d(C),I,2,C); + } + S = P*C.leftCols(2); + break; + } + default: assert(false && "dim>3 not supported"); + } + + Eigen::VectorXi RT = Eigen::VectorXi::Zero(S.rows(),1); + Eigen::VectorXi _I; + Eigen::MatrixXd _nS; + + // compute signed area + { + double area = 0; + for(Index c = 0;c0 && c1) + //{ + // // Delaunay-ize + // Eigen::MatrixXd pl; + // igl::edge_lengths(pV,pF,pl); + + // typedef Eigen::Matrix MatrixX2I; + // typedef Eigen::Matrix VectorXI; + // MatrixX2I E,uE; + // VectorXI EMAP; + // std::vector > uE2E; + // igl::unique_edge_map(pF, E, uE, EMAP, uE2E); + // typedef Index Index; + // typedef double Scalar; + // const Index num_faces = pF.rows(); + // std::vector Q; + // Q.reserve(uE2E.size()); + // for (size_t uei=0; uei v3 /__f__\ v4 + // // \ e / \ f2 / + // // d\ | /a d\ /a + // // \|/ \ / + // // v2 v2 + // // + // // hmm... is the flip actually in the other direction? + // const Index f1 = uE2E[uei][0]%num_faces; + // const Index f2 = uE2E[uei][1]%num_faces; + // const Index c1 = uE2E[uei][0]/num_faces; + // const Index c2 = uE2E[uei][1]/num_faces; + // const size_t e_24 = f1 + ((c1 + 1) % 3) * num_faces; + // const size_t e_41 = f1 + ((c1 + 2) % 3) * num_faces; + // const size_t e_13 = f2 + ((c2 + 1) % 3) * num_faces; + // const size_t e_32 = f2 + ((c2 + 2) % 3) * num_faces; + // const size_t ue_24 = EMAP(e_24); + // const size_t ue_41 = EMAP(e_41); + // const size_t ue_13 = EMAP(e_13); + // const size_t ue_32 = EMAP(e_32); + // // new edge lengths + // const Index v1 = pF(f1, (c1+1)%3); + // const Index v2 = pF(f1, (c1+2)%3); + // const Index v4 = pF(f1, c1); + // const Index v3 = pF(f2, c2); + // { + // const Scalar e = pl(f1,c1); + // const Scalar a = pl(f1,(c1+1)%3); + // const Scalar b = pl(f1,(c1+2)%3); + // const Scalar c = pl(f2,(c2+1)%3); + // const Scalar d = pl(f2,(c2+2)%3); + // const double f = (pV.row(v3)-pV.row(v4)).norm(); + // // New order + // pl(f1,0) = f; + // pl(f1,1) = b; + // pl(f1,2) = c; + // pl(f2,0) = f; + // pl(f2,1) = d; + // pl(f2,2) = a; + // } + // prIndexf("%d,%d %d,%d -> %d,%d\n",uE(uei,0),uE(uei,1),v1,v2,v3,v4); + // igl::flip_edge(pF, E, uE, EMAP, uE2E, uei); + // std::cout<<" "< +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_POLYGONS_TO_TRIANGLES_H +#define IGL_POLYGONS_TO_TRIANGLES_H + +#include "../igl_inline.h" +#include +#include + +namespace igl +{ + namespace predicates + { + // Given a polygon mesh, trivially triangulate each polygon with a fan. This + // purely combinatorial triangulation will work well for convex/flat polygons + // and degrade otherwise. + // + // Inputs: + // V #V by dim list of vertex positions + // I #I vectorized list of polygon corner indices into rows of some matrix V + // C #polygons+1 list of cumulative polygon sizes so that C(i+1)-C(i) = + // size of the ith polygon, and so I(C(i)) through I(C(i+1)-1) are the + // indices of the ith polygon + // Outputs: + // F #F by 3 list of triangle indices into rows of V + // J #F list of indices into 0:#P-1 of corresponding polygon + // + template < + typename DerivedV, + typename DerivedI, + typename DerivedC, + typename DerivedF, + typename DerivedJ> + IGL_INLINE void polygons_to_triangles( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & I, + const Eigen::MatrixBase & C, + Eigen::PlainObjectBase & F, + Eigen::PlainObjectBase & J); + } +} + +#ifndef IGL_STATIC_LIBRARY +# include "polygons_to_triangles.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/predicates/predicates.cpp b/src/external/libigl-2.3.0/include/igl/predicates/predicates.cpp new file mode 100644 index 000000000..ca38d76bd --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/predicates/predicates.cpp @@ -0,0 +1,176 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2019 Qingnan Zhou +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include +#include +#include + +namespace igl { +namespace predicates { + +using REAL = IGL_PREDICATES_REAL; + +#ifdef LIBIGL_PREDICATES_USE_FLOAT +#define IGL_ASSERT_SCALAR(Vector) \ + static_assert( \ + std::is_same::value, \ + "Shewchuk's exact predicates only support float") +#else +#define IGL_ASSERT_SCALAR(Vector) \ + static_assert( \ + std::is_same::value || \ + std::is_same::value, \ + "Shewchuk's exact predicates only support float and double") +#endif + +IGL_INLINE void exactinit() { + // Thread-safe initialization using Meyers' singleton + class MySingleton { + public: + static MySingleton& instance() { + static MySingleton instance; + return instance; + } + private: + MySingleton() { ::exactinit(); } + }; + MySingleton::instance(); +} + +template +IGL_INLINE Orientation orient2d( + const Eigen::MatrixBase& pa, + const Eigen::MatrixBase& pb, + const Eigen::MatrixBase& pc) +{ + EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(Vector2D, 2); + IGL_ASSERT_SCALAR(Vector2D); + + using Point = Eigen::Matrix; + Point a{pa[0], pa[1]}; + Point b{pb[0], pb[1]}; + Point c{pc[0], pc[1]}; + + const auto r = ::orient2d(a.data(), b.data(), c.data()); + + if (r > 0) return Orientation::POSITIVE; + else if (r < 0) return Orientation::NEGATIVE; + else return Orientation::COLLINEAR; +} + +template +IGL_INLINE Orientation orient3d( + const Eigen::MatrixBase& pa, + const Eigen::MatrixBase& pb, + const Eigen::MatrixBase& pc, + const Eigen::MatrixBase& pd) +{ + EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(Vector3D, 3); + IGL_ASSERT_SCALAR(Vector3D); + + using Point = Eigen::Matrix; + Point a{pa[0], pa[1], pa[2]}; + Point b{pb[0], pb[1], pb[2]}; + Point c{pc[0], pc[1], pc[2]}; + Point d{pd[0], pd[1], pd[2]}; + + const auto r = ::orient3d(a.data(), b.data(), c.data(), d.data()); + + if (r > 0) return Orientation::POSITIVE; + else if (r < 0) return Orientation::NEGATIVE; + else return Orientation::COPLANAR; +} + +template +IGL_INLINE Orientation incircle( + const Eigen::MatrixBase& pa, + const Eigen::MatrixBase& pb, + const Eigen::MatrixBase& pc, + const Eigen::MatrixBase& pd) +{ + EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(Vector2D, 2); + IGL_ASSERT_SCALAR(Vector2D); + + using Point = Eigen::Matrix; + Point a{pa[0], pa[1]}; + Point b{pb[0], pb[1]}; + Point c{pc[0], pc[1]}; + Point d{pd[0], pd[1]}; + + const auto r = ::incircle(a.data(), b.data(), c.data(), d.data()); + + if (r > 0) return Orientation::INSIDE; + else if (r < 0) return Orientation::OUTSIDE; + else return Orientation::COCIRCULAR; +} + +template +IGL_INLINE Orientation insphere( + const Eigen::MatrixBase& pa, + const Eigen::MatrixBase& pb, + const Eigen::MatrixBase& pc, + const Eigen::MatrixBase& pd, + const Eigen::MatrixBase& pe) +{ + EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(Vector3D, 3); + IGL_ASSERT_SCALAR(Vector3D); + + using Point = Eigen::Matrix; + Point a{pa[0], pa[1], pa[2]}; + Point b{pb[0], pb[1], pb[2]}; + Point c{pc[0], pc[1], pc[2]}; + Point d{pd[0], pd[1], pd[2]}; + Point e{pe[0], pe[1], pe[2]}; + + const auto r = ::insphere(a.data(), b.data(), c.data(), d.data(), e.data()); + + if (r > 0) return Orientation::INSIDE; + else if (r < 0) return Orientation::OUTSIDE; + else return Orientation::COSPHERICAL; +} + +} +} + +#undef IGL_ASSERT_SCALAR + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation + +#define IGL_ORIENT2D(Vector) template igl::predicates::Orientation igl::predicates::orient2d(const Eigen::MatrixBase&, const Eigen::MatrixBase&, const Eigen::MatrixBase&) +#define IGL_INCIRCLE(Vector) template igl::predicates::Orientation igl::predicates::incircle(const Eigen::MatrixBase&, const Eigen::MatrixBase&, const Eigen::MatrixBase&, const Eigen::MatrixBase&) +#define IGL_ORIENT3D(Vector) template igl::predicates::Orientation igl::predicates::orient3d(const Eigen::MatrixBase&, const Eigen::MatrixBase&, const Eigen::MatrixBase&, const Eigen::MatrixBase&) +#define IGL_INSPHERE(Vector) template igl::predicates::Orientation igl::predicates::insphere(const Eigen::MatrixBase&, const Eigen::MatrixBase&, const Eigen::MatrixBase&, const Eigen::MatrixBase&, const Eigen::MatrixBase&) + +#define IGL_MATRIX(T, R, C) Eigen::Matrix +IGL_ORIENT2D(IGL_MATRIX(float, 1, 2)); +IGL_INCIRCLE(IGL_MATRIX(float, 1, 2)); +IGL_ORIENT2D(IGL_MATRIX(float, 2, 1)); +IGL_INCIRCLE(IGL_MATRIX(float, 2, 1)); +IGL_ORIENT3D(IGL_MATRIX(float, 1, 3)); +IGL_INSPHERE(IGL_MATRIX(float, 1, 3)); +IGL_ORIENT3D(IGL_MATRIX(float, 3, 1)); +IGL_INSPHERE(IGL_MATRIX(float, 3, 1)); + +#ifndef LIBIGL_PREDICATES_USE_FLOAT +IGL_ORIENT2D(IGL_MATRIX(double, 1, 2)); +IGL_INCIRCLE(IGL_MATRIX(double, 1, 2)); +IGL_ORIENT2D(IGL_MATRIX(double, 2, 1)); +IGL_INCIRCLE(IGL_MATRIX(double, 2, 1)); +IGL_ORIENT3D(IGL_MATRIX(double, 1, 3)); +IGL_INSPHERE(IGL_MATRIX(double, 1, 3)); +IGL_ORIENT3D(IGL_MATRIX(double, 3, 1)); +IGL_INSPHERE(IGL_MATRIX(double, 3, 1)); +#endif +#undef IGL_MATRIX + +#undef IGL_ORIENT2D +#undef IGL_ORIENT3D +#undef IGL_INCIRCLE +#undef IGL_INSPHERE + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/predicates/predicates.h b/src/external/libigl-2.3.0/include/igl/predicates/predicates.h new file mode 100644 index 000000000..353088694 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/predicates/predicates.h @@ -0,0 +1,100 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2019 Qingnan Zhou +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#pragma once +#ifndef IGL_PREDICATES_PREDICATES_H +#define IGL_PREDICATES_PREDICATES_H + +#include +#include + +namespace igl { + namespace predicates { + enum class Orientation { + POSITIVE=1, INSIDE=1, + NEGATIVE=-1, OUTSIDE=-1, + COLLINEAR=0, COPLANAR=0, COCIRCULAR=0, COSPHERICAL=0, DEGENERATE=0 + }; + + // Initialize internal variable used by predciates. Must be called before + // using exact predicates. It is safe to call this function from multiple + // threads. + IGL_INLINE void exactinit(); + + // Compute the orientation of the triangle formed by pa, pb, pc. + // + // Input: + // pa, pb, pc 2D points. + // + // Output: + // Return POSITIVE if pa, pb, pc are counterclockwise oriented. + // NEGATIVE if they are clockwise oriented. + // COLLINEAR if they are collinear. + template + IGL_INLINE Orientation orient2d( + const Eigen::MatrixBase& pa, + const Eigen::MatrixBase& pb, + const Eigen::MatrixBase& pc); + + // Compute the orientation of the tetrahedron formed by pa, pb, pc, pd. + // + // Input: + // pa, pb, pc, pd 3D points. + // + // Output: + // Return POSITIVE if pd is "below" the oriented plane formed by pa, pb and pc. + // NEGATIVE if pd is "above" the plane. + // COPLANAR if pd is on the plane. + template + IGL_INLINE Orientation orient3d( + const Eigen::MatrixBase& pa, + const Eigen::MatrixBase& pb, + const Eigen::MatrixBase& pc, + const Eigen::MatrixBase& pd); + + // Decide whether a point is inside/outside/on a circle. + // + // Input: + // pa, pb, pc 2D points that defines an oriented circle. + // pd 2D query point. + // + // Output: + // Return INSIDE if pd is inside of the circle defined by pa, pb and pc. + // OUSIDE if pd is outside of the circle. + // COCIRCULAR pd is exactly on the circle. + template + IGL_INLINE Orientation incircle( + const Eigen::MatrixBase& pa, + const Eigen::MatrixBase& pb, + const Eigen::MatrixBase& pc, + const Eigen::MatrixBase& pd); + + // Decide whether a point is inside/outside/on a sphere. + // + // Input: + // pa, pb, pc, pd 3D points that defines an oriented sphere. + // pe 3D query point. + // + // Output: + // Return INSIDE if pe is inside of the sphere defined by pa, pb, pc and pd. + // OUSIDE if pe is outside of the sphere. + // COSPHERICAL pd is exactly on the sphere. + template + IGL_INLINE Orientation insphere( + const Eigen::MatrixBase& pa, + const Eigen::MatrixBase& pb, + const Eigen::MatrixBase& pc, + const Eigen::MatrixBase& pd, + const Eigen::MatrixBase& pe); + } +} + +#ifndef IGL_STATIC_LIBRARY +# include "predicates.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/predicates/segment_segment_intersect.cpp b/src/external/libigl-2.3.0/include/igl/predicates/segment_segment_intersect.cpp new file mode 100644 index 000000000..acf97cfbe --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/predicates/segment_segment_intersect.cpp @@ -0,0 +1,52 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2019 Hanxiao Shen +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +#include "segment_segment_intersect.h" + +// https://www.geeksforgeeks.org/check-if-two-given-line-segments-intersect/ +template +IGL_INLINE bool igl::predicates::segment_segment_intersect( + const Eigen::MatrixBase& a, + const Eigen::MatrixBase& b, + const Eigen::MatrixBase& c, + const Eigen::MatrixBase& d +) +{ + typename DerivedP::Scalar Scalar; + + auto t1 = igl::predicates::orient2d(a,b,c); + auto t2 = igl::predicates::orient2d(b,c,d); + auto t3 = igl::predicates::orient2d(a,b,d); + auto t4 = igl::predicates::orient2d(a,c,d); + + // assume m,n,p are colinear, check whether p is in range [m,n] + auto on_segment = []( + const Eigen::MatrixBase& m, + const Eigen::MatrixBase& n, + const Eigen::MatrixBase& p + ){ + return ((p(0) >= std::min(m(0),n(0))) && + (p(0) <= std::max(m(0),n(0))) && + (p(1) >= std::min(m(1),n(1))) && + (p(1) <= std::max(m(1),n(1)))); + }; + + // colinear case + if((t1 == igl::predicates::Orientation::COLLINEAR && on_segment(a,b,c)) || + (t2 == igl::predicates::Orientation::COLLINEAR && on_segment(c,d,b)) || + (t3 == igl::predicates::Orientation::COLLINEAR && on_segment(a,b,d)) || + (t4 == igl::predicates::Orientation::COLLINEAR && on_segment(c,d,a))) + return true; + + // ordinary case + return (t1 != t3 && t2 != t4); +} + +#ifdef IGL_STATIC_LIBRARY +template bool igl::predicates::segment_segment_intersect >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/predicates/segment_segment_intersect.h b/src/external/libigl-2.3.0/include/igl/predicates/segment_segment_intersect.h new file mode 100644 index 000000000..4c1ac1ee1 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/predicates/segment_segment_intersect.h @@ -0,0 +1,44 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2019 Hanxiao Shen +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef IGL_PREDICATES_SEGMENT_SEGMENT_INTERSECT_H +#define IGL_PREDICATES_SEGMENT_SEGMENT_INTERSECT_H + +#include +#include +#include "predicates.h" +namespace igl +{ + namespace predicates + { + + // Given two segments in 2d test whether they intersect each other + // using predicates orient2d + // + // Inputs: + // A: 1st endpoint of segment 1 + // B: 2st endpoint of segment 1 + // C: 1st endpoint of segment 2 + // D: 2st endpoint of segment 2 + // Returns true if they intersect + + template + IGL_INLINE bool segment_segment_intersect( + // input: + const Eigen::MatrixBase& A, + const Eigen::MatrixBase& B, + const Eigen::MatrixBase& C, + const Eigen::MatrixBase& D + ); + + } +} +#ifndef IGL_STATIC_LIBRARY +# include "segment_segment_intersect.cpp" +#endif +#endif //IGL_PREDICATES_SEGMENT_SEGMENT_INTERSECT_H diff --git a/src/external/libigl-2.3.0/include/igl/principal_curvature.cpp b/src/external/libigl-2.3.0/include/igl/principal_curvature.cpp new file mode 100644 index 000000000..ae2760dd0 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/principal_curvature.cpp @@ -0,0 +1,936 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Daniele Panozzo +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "principal_curvature.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +// Lib IGL includes +#include +#include +#include +#include +#include + +typedef enum +{ + SPHERE_SEARCH, + K_RING_SEARCH +} searchType; + +typedef enum +{ + AVERAGE, + PROJ_PLANE +} normalType; + +class CurvatureCalculator +{ +public: + /* Row number i represents the i-th vertex, whose columns are: + curv[i][0] : K2 + curv[i][1] : K1 + curvDir[i][0] : PD1 + curvDir[i][1] : PD2 + */ + std::vector< std::vector > curv; + std::vector< std::vector > curvDir; + bool curvatureComputed; + class Quadric + { + public: + + IGL_INLINE Quadric () + { + a() = b() = c() = d() = e() = 1.0; + } + + IGL_INLINE Quadric(double av, double bv, double cv, double dv, double ev) + { + a() = av; + b() = bv; + c() = cv; + d() = dv; + e() = ev; + } + + IGL_INLINE double& a() { return data[0];} + IGL_INLINE double& b() { return data[1];} + IGL_INLINE double& c() { return data[2];} + IGL_INLINE double& d() { return data[3];} + IGL_INLINE double& e() { return data[4];} + + double data[5]; + + IGL_INLINE double evaluate(double u, double v) + { + return a()*u*u + b()*u*v + c()*v*v + d()*u + e()*v; + } + + IGL_INLINE double du(double u, double v) + { + return 2.0*a()*u + b()*v + d(); + } + + IGL_INLINE double dv(double u, double v) + { + return 2.0*c()*v + b()*u + e(); + } + + IGL_INLINE double duv(double u, double v) + { + return b(); + } + + IGL_INLINE double duu(double u, double v) + { + return 2.0*a(); + } + + IGL_INLINE double dvv(double u, double v) + { + return 2.0*c(); + } + + + IGL_INLINE static Quadric fit(const std::vector &VV) + { + assert(VV.size() >= 5); + if (VV.size() < 5) + { + std::cerr << "ASSERT FAILED! fit function requires at least 5 points: Only " << VV.size() << " were given." << std::endl; + exit(0); + } + + Eigen::MatrixXd A(VV.size(),5); + Eigen::MatrixXd b(VV.size(),1); + Eigen::MatrixXd sol(5,1); + + for(unsigned int c=0; c < VV.size(); ++c) + { + double u = VV[c][0]; + double v = VV[c][1]; + double n = VV[c][2]; + + A(c,0) = u*u; + A(c,1) = u*v; + A(c,2) = v*v; + A(c,3) = u; + A(c,4) = v; + + b(c) = n; + } + + sol=A.jacobiSvd(Eigen::ComputeThinU | Eigen::ComputeThinV).solve(b); + + return Quadric(sol(0),sol(1),sol(2),sol(3),sol(4)); + } + }; + +public: + + Eigen::MatrixXd vertices; + // Face list of current mesh (#F x 3) or (#F x 4) + // The i-th row contains the indices of the vertices that forms the i-th face in ccw order + Eigen::MatrixXi faces; + + std::vector > vertex_to_vertices; + std::vector > vertex_to_faces; + std::vector > vertex_to_faces_index; + Eigen::MatrixXd face_normals; + Eigen::MatrixXd vertex_normals; + + /* Size of the neighborhood */ + double sphereRadius; + int kRing; + + bool localMode; /* Use local mode */ + bool projectionPlaneCheck; /* Check collected vertices on tangent plane */ + bool montecarlo; + unsigned int montecarloN; + + searchType st; /* Use either a sphere search or a k-ring search */ + normalType nt; + + double lastRadius; + double scaledRadius; + std::string lastMeshName; + + /* Benchmark related variables */ + bool expStep; /* True if we want the radius to increase exponentially */ + int step; /* If expStep==false, by how much rhe radius increases on every step */ + int maxSize; /* The maximum limit of the radius in the benchmark */ + + IGL_INLINE CurvatureCalculator(); + IGL_INLINE void init(const Eigen::MatrixXd& V, const Eigen::MatrixXi& F); + + IGL_INLINE void finalEigenStuff(int, const std::vector&, Quadric&); + IGL_INLINE void fitQuadric(const Eigen::Vector3d&, const std::vector& ref, const std::vector& , Quadric *); + IGL_INLINE void applyProjOnPlane(const Eigen::Vector3d&, const std::vector&, std::vector&); + IGL_INLINE void getSphere(const int, const double, std::vector&, int min); + IGL_INLINE void getKRing(const int, const double,std::vector&); + IGL_INLINE Eigen::Vector3d project(const Eigen::Vector3d&, const Eigen::Vector3d&, const Eigen::Vector3d&); + IGL_INLINE void computeReferenceFrame(int, const Eigen::Vector3d&, std::vector&); + IGL_INLINE void getAverageNormal(int, const std::vector&, Eigen::Vector3d&); + IGL_INLINE void getProjPlane(int, const std::vector&, Eigen::Vector3d&); + IGL_INLINE void applyMontecarlo(const std::vector&,std::vector*); + IGL_INLINE void computeCurvature(); + IGL_INLINE void printCurvature(const std::string& outpath); + IGL_INLINE double getAverageEdge(); + + IGL_INLINE static int rotateForward (double *v0, double *v1, double *v2) + { + double t; + + if (std::abs(*v2) >= std::abs(*v1) && std::abs(*v2) >= std::abs(*v0)) + return 0; + + t = *v0; + *v0 = *v2; + *v2 = *v1; + *v1 = t; + + return 1 + rotateForward (v0, v1, v2); + } + + IGL_INLINE static void rotateBackward (int nr, double *v0, double *v1, double *v2) + { + double t; + + if (nr == 0) + return; + + t = *v2; + *v2 = *v0; + *v0 = *v1; + *v1 = t; + + rotateBackward (nr - 1, v0, v1, v2); + } + + IGL_INLINE static Eigen::Vector3d chooseMax (Eigen::Vector3d n, Eigen::Vector3d abc, double ab) + { + int max_i; + double max_sp; + Eigen::Vector3d nt[8]; + + n.normalize (); + abc.normalize (); + + max_sp = - std::numeric_limits::max(); + + for (int i = 0; i < 4; ++i) + { + nt[i] = n; + if (ab > 0) + { + switch (i) + { + case 0: + break; + + case 1: + nt[i][2] = -n[2]; + break; + + case 2: + nt[i][0] = -n[0]; + nt[i][1] = -n[1]; + break; + + case 3: + nt[i][0] = -n[0]; + nt[i][1] = -n[1]; + nt[i][2] = -n[2]; + break; + } + } + else + { + switch (i) + { + case 0: + nt[i][0] = -n[0]; + break; + + case 1: + nt[i][1] = -n[1]; + break; + + case 2: + nt[i][0] = -n[0]; + nt[i][2] = -n[2]; + break; + + case 3: + nt[i][1] = -n[1]; + nt[i][2] = -n[2]; + break; + } + } + + if (nt[i].dot(abc) > max_sp) + { + max_sp = nt[i].dot(abc); + max_i = i; + } + } + return nt[max_i]; + } + +}; + +class comparer +{ +public: + IGL_INLINE bool operator() (const std::pair& lhs, const std::pair&rhs) const + { + return lhs.second>rhs.second; + } +}; + +IGL_INLINE CurvatureCalculator::CurvatureCalculator() +{ + this->localMode=true; + this->projectionPlaneCheck=true; + this->sphereRadius=5; + this->st=SPHERE_SEARCH; + this->nt=AVERAGE; + this->montecarlo=false; + this->montecarloN=0; + this->kRing=3; + this->curvatureComputed=false; + this->expStep=true; +} + +IGL_INLINE void CurvatureCalculator::init(const Eigen::MatrixXd& V, const Eigen::MatrixXi& F) +{ + // Normalize vertices + vertices = V; + +// vertices = vertices.array() - vertices.minCoeff(); +// vertices = vertices.array() / vertices.maxCoeff(); +// vertices = vertices.array() * (1.0/igl::avg_edge_length(V,F)); + + faces = F; + igl::adjacency_list(F, vertex_to_vertices); + igl::vertex_triangle_adjacency(V, F, vertex_to_faces, vertex_to_faces_index); + igl::per_face_normals(V, F, face_normals); + igl::per_vertex_normals(V, F, face_normals, vertex_normals); +} + +IGL_INLINE void CurvatureCalculator::fitQuadric(const Eigen::Vector3d& v, const std::vector& ref, const std::vector& vv, Quadric *q) +{ + std::vector points; + points.reserve (vv.size()); + + for (unsigned int i = 0; i < vv.size(); ++i) { + + Eigen::Vector3d cp = vertices.row(vv[i]); + + // vtang non e` il v tangente!!! + Eigen::Vector3d vTang = cp - v; + + double x = vTang.dot(ref[0]); + double y = vTang.dot(ref[1]); + double z = vTang.dot(ref[2]); + points.push_back(Eigen::Vector3d (x,y,z)); + } + if (points.size() < 5) + { + std::cerr << "ASSERT FAILED! fit function requires at least 5 points: Only " << points.size() << " were given." << std::endl; + *q = Quadric(0,0,0,0,0); + } + else + { + *q = Quadric::fit (points); + } +} + +IGL_INLINE void CurvatureCalculator::finalEigenStuff(int i, const std::vector& ref, Quadric& q) +{ + + const double a = q.a(); + const double b = q.b(); + const double c = q.c(); + const double d = q.d(); + const double e = q.e(); + +// if (fabs(a) < 10e-8 || fabs(b) < 10e-8) +// { +// std::cout << "Degenerate quadric: " << i << std::endl; +// } + + double E = 1.0 + d*d; + double F = d*e; + double G = 1.0 + e*e; + + Eigen::Vector3d n = Eigen::Vector3d(-d,-e,1.0).normalized(); + + double L = 2.0 * a * n[2]; + double M = b * n[2]; + double N = 2 * c * n[2]; + + + // ----------------- Eigen stuff + Eigen::Matrix2d m; + m << L*G - M*F, M*E-L*F, M*E-L*F, N*E-M*F; + m = m / (E*G-F*F); + Eigen::SelfAdjointEigenSolver eig(m); + + Eigen::Vector2d c_val = eig.eigenvalues(); + Eigen::Matrix2d c_vec = eig.eigenvectors(); + + // std::cerr << "c_val:" << c_val << std::endl; + // std::cerr << "c_vec:" << c_vec << std::endl; + + // std::cerr << "c_vec:" << c_vec(0) << " " << c_vec(1) << std::endl; + + c_val = -c_val; + + Eigen::Vector3d v1, v2; + v1[0] = c_vec(0); + v1[1] = c_vec(1); + v1[2] = 0; //d * v1[0] + e * v1[1]; + + v2[0] = c_vec(2); + v2[1] = c_vec(3); + v2[2] = 0; //d * v2[0] + e * v2[1]; + + + // v1 = v1.normalized(); + // v2 = v2.normalized(); + + Eigen::Vector3d v1global = ref[0] * v1[0] + ref[1] * v1[1] + ref[2] * v1[2]; + Eigen::Vector3d v2global = ref[0] * v2[0] + ref[1] * v2[1] + ref[2] * v2[2]; + + v1global.normalize(); + v2global.normalize(); + + v1global *= c_val(0); + v2global *= c_val(1); + + if (c_val[0] > c_val[1]) + { + curv[i]=std::vector(2); + curv[i][0]=c_val(1); + curv[i][1]=c_val(0); + curvDir[i]=std::vector(2); + curvDir[i][0]=v2global; + curvDir[i][1]=v1global; + } + else + { + curv[i]=std::vector(2); + curv[i][0]=c_val(0); + curv[i][1]=c_val(1); + curvDir[i]=std::vector(2); + curvDir[i][0]=v1global; + curvDir[i][1]=v2global; + } + // ---- end Eigen stuff +} + +IGL_INLINE void CurvatureCalculator::getKRing(const int start, const double r, std::vector&vv) +{ + int bufsize=vertices.rows(); + vv.reserve(bufsize); + std::list > queue; + std::vector visited(bufsize, false); + queue.push_back(std::pair(start,0)); + visited[start]=true; + while (!queue.empty()) + { + int toVisit=queue.front().first; + int distance=queue.front().second; + queue.pop_front(); + vv.push_back(toVisit); + if (distance<(int)r) + { + for (unsigned int i=0; i (neighbor,distance+1)); + visited[neighbor]=true; + } + } + } + } +} + + +IGL_INLINE void CurvatureCalculator::getSphere(const int start, const double r, std::vector &vv, int min) +{ + int bufsize=vertices.rows(); + vv.reserve(bufsize); + std::list queue; + std::vector visited(bufsize, false); + queue.push_back(start); + visited[start]=true; + Eigen::Vector3d me=vertices.row(start); + std::priority_queue, std::vector >, comparer > extra_candidates; + while (!queue.empty()) + { + int toVisit=queue.front(); + queue.pop_front(); + vv.push_back(toVisit); + for (unsigned int i=0; i(neighbor,distance)); + visited[neighbor]=true; + } + } + } + while (!extra_candidates.empty() && (int)vv.size() cand=extra_candidates.top(); + extra_candidates.pop(); + vv.push_back(cand.first); + for (unsigned int i=0; i(neighbor,distance)); + visited[neighbor]=true; + } + } + } +} + +IGL_INLINE Eigen::Vector3d CurvatureCalculator::project(const Eigen::Vector3d& v, const Eigen::Vector3d& vp, const Eigen::Vector3d& ppn) +{ + return (vp - (ppn * ((vp - v).dot(ppn)))); +} + +IGL_INLINE void CurvatureCalculator::computeReferenceFrame(int i, const Eigen::Vector3d& normal, std::vector& ref ) +{ + + Eigen::Vector3d longest_v=Eigen::Vector3d(vertices.row(vertex_to_vertices[i][0])); + + longest_v=(project(vertices.row(i),longest_v,normal)-Eigen::Vector3d(vertices.row(i))).normalized(); + + /* L'ultimo asse si ottiene come prodotto vettoriale tra i due + * calcolati */ + Eigen::Vector3d y_axis=(normal.cross(longest_v)).normalized(); + ref[0]=longest_v; + ref[1]=y_axis; + ref[2]=normal; +} + +IGL_INLINE void CurvatureCalculator::getAverageNormal(int j, const std::vector& vv, Eigen::Vector3d& normal) +{ + normal=(vertex_normals.row(j)).normalized(); + if (localMode) + return; + + for (unsigned int i=0; i& vv, Eigen::Vector3d& ppn) +{ + int nr; + double a, b, c; + double nx, ny, nz; + double abcq; + + a = b = c = 0; + + if (localMode) + { + for (unsigned int i=0; i& vin, std::vector &vout) +{ + for (std::vector::const_iterator vpi = vin.begin(); vpi != vin.end(); ++vpi) + if (vertex_normals.row(*vpi) * ppn > 0.0) + vout.push_back(*vpi); +} + +IGL_INLINE void CurvatureCalculator::applyMontecarlo(const std::vector& vin, std::vector *vout) +{ + if (montecarloN >= vin.size ()) + { + *vout = vin; + return; + } + + float p = ((float) montecarloN) / (float) vin.size(); + for (std::vector::const_iterator vpi = vin.begin(); vpi != vin.end(); ++vpi) + { + float r; + if ((r = ((float)rand () / RAND_MAX)) < p) + { + vout->push_back(*vpi); + } + } +} + +IGL_INLINE void CurvatureCalculator::computeCurvature() +{ + //CHECK che esista la mesh + const size_t vertices_count=vertices.rows(); + + if (vertices_count ==0) + return; + + curvDir=std::vector< std::vector >(vertices_count); + curv=std::vector >(vertices_count); + + + + scaledRadius=getAverageEdge()*sphereRadius; + + std::vector vv; + std::vector vvtmp; + Eigen::Vector3d normal; + + //double time_spent; + //double searchtime=0, ref_time=0, fit_time=0, final_time=0; + + for (size_t i=0; i= 6 && vvtmp.size() ref(3); + computeReferenceFrame(i,normal,ref); + + Quadric q; + fitQuadric (me, ref, vv, &q); + finalEigenStuff(i,ref,q); + } + + lastRadius=sphereRadius; + curvatureComputed=true; +} + +IGL_INLINE void CurvatureCalculator::printCurvature(const std::string& outpath) +{ + using namespace std; + if (!curvatureComputed) + return; + + std::ofstream of; + of.open(outpath.c_str()); + + if (!of) + { + fprintf(stderr, "Error: could not open output file %s\n", outpath.c_str()); + return; + } + + int vertices_count=vertices.rows(); + of << vertices_count << endl; + for (int i=0; i +IGL_INLINE void igl::principal_curvature( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + Eigen::PlainObjectBase& PD1, + Eigen::PlainObjectBase& PD2, + Eigen::PlainObjectBase& PV1, + Eigen::PlainObjectBase& PV2, + std::vector& bad_vertices, + unsigned radius, + bool useKring) +{ + + if (radius < 2) + { + radius = 2; + std::cout << "WARNING: igl::principal_curvature needs a radius >= 2, fixing it to 2." << std::endl; + } + + // Preallocate memory + PD1.resize(V.rows(),3); + PD2.resize(V.rows(),3); + + // Preallocate memory + PV1.resize(V.rows(),1); + PV2.resize(V.rows(),1); + + // Precomputation + CurvatureCalculator cc; + cc.init(V.template cast(),F.template cast()); + cc.sphereRadius = radius; + + if (useKring) + { + cc.kRing = radius; + cc.st = K_RING_SEARCH; + } + + // Compute + cc.computeCurvature(); + + // Copy it back + for (unsigned i=0; i 10e-6) + { + bad_vertices.push_back((Index)i); + + PD1.row(i) *= 0; + PD2.row(i) *= 0; + } + } else { + bad_vertices.push_back((Index)i); + + PV1(i) = 0; + PV2(i) = 0; + PD1.row(i) << 0,0,0; + PD2.row(i) << 0,0,0; + } + } + +} + +template < + typename DerivedV, + typename DerivedF, + typename DerivedPD1, + typename DerivedPD2, + typename DerivedPV1, + typename DerivedPV2> +IGL_INLINE void igl::principal_curvature( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + Eigen::PlainObjectBase& PD1, + Eigen::PlainObjectBase& PD2, + Eigen::PlainObjectBase& PV1, + Eigen::PlainObjectBase& PV2, + unsigned radius, + bool useKring) +{ + if (radius < 2) + { + radius = 2; + std::cout << "WARNING: igl::principal_curvature needs a radius >= 2, fixing it to 2." << std::endl; + } + + // Preallocate memory + PD1.resize(V.rows(),3); + PD2.resize(V.rows(),3); + + // Preallocate memory + PV1.resize(V.rows(),1); + PV2.resize(V.rows(),1); + + // Precomputation + CurvatureCalculator cc; + cc.init(V.template cast(),F.template cast()); + cc.sphereRadius = radius; + + if (useKring) + { + cc.kRing = radius; + cc.st = K_RING_SEARCH; + } + + // Compute + cc.computeCurvature(); + + // Copy it back + for (unsigned i=0; i 10e-6) + { + std::cerr << "PRINCIPAL_CURVATURE: Something is wrong with vertex: " << i << std::endl; + PD1.row(i) *= 0; + PD2.row(i) *= 0; + } + } + +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::principal_curvature, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, unsigned int, bool); +template void igl::principal_curvature, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, unsigned int, bool); +template void igl::principal_curvature, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, unsigned int, bool); +template void igl::principal_curvature, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, int>(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, std::vector >&, unsigned int, bool); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/principal_curvature.h b/src/external/libigl-2.3.0/include/igl/principal_curvature.h new file mode 100644 index 000000000..d8b49b4b7 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/principal_curvature.h @@ -0,0 +1,93 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Daniele Panozzo +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_PRINCIPAL_CURVATURE_H +#define IGL_PRINCIPAL_CURVATURE_H + + +#include +#include + +#include + +#include "igl_inline.h" +//#include +//#include + + + +namespace igl +{ + + // Compute the principal curvature directions and magnitude of the given triangle mesh + // DerivedV derived from vertex positions matrix type: i.e. MatrixXd + // DerivedF derived from face indices matrix type: i.e. MatrixXi + // Inputs: + // V eigen matrix #V by 3 + // F #F by 3 list of mesh faces (must be triangles) + // radius controls the size of the neighbourhood used, 1 = average edge length + // + // Outputs: + // PD1 #V by 3 maximal curvature direction for each vertex. + // PD2 #V by 3 minimal curvature direction for each vertex. + // PV1 #V by 1 maximal curvature value for each vertex. + // PV2 #V by 1 minimal curvature value for each vertex. + // + // Return value: + // Function returns vector of indices of bad vertices if any. + // + // See also: average_onto_faces, average_onto_vertices + // + // This function has been developed by: Nikolas De Giorgis, Luigi Rocca and Enrico Puppo. + // The algorithm is based on: + // Efficient Multi-scale Curvature and Crease Estimation + // Daniele Panozzo, Enrico Puppo, Luigi Rocca + // GraVisMa, 2010 +template < + typename DerivedV, + typename DerivedF, + typename DerivedPD1, + typename DerivedPD2, + typename DerivedPV1, + typename DerivedPV2> +IGL_INLINE void principal_curvature( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + Eigen::PlainObjectBase& PD1, + Eigen::PlainObjectBase& PD2, + Eigen::PlainObjectBase& PV1, + Eigen::PlainObjectBase& PV2, + unsigned radius = 5, + bool useKring = true); + +template < + typename DerivedV, + typename DerivedF, + typename DerivedPD1, + typename DerivedPD2, + typename DerivedPV1, + typename DerivedPV2, + typename Index> +IGL_INLINE void principal_curvature( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + Eigen::PlainObjectBase& PD1, + Eigen::PlainObjectBase& PD2, + Eigen::PlainObjectBase& PV1, + Eigen::PlainObjectBase& PV2, + std::vector& bad_vertices, + unsigned radius = 5, + bool useKring = true); + +} + + +#ifndef IGL_STATIC_LIBRARY +#include "principal_curvature.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/print_ijv.cpp b/src/external/libigl-2.3.0/include/igl/print_ijv.cpp new file mode 100644 index 000000000..38b1dd22a --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/print_ijv.cpp @@ -0,0 +1,40 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "print_ijv.h" + +#include "find.h" +#include + +template +IGL_INLINE void igl::print_ijv( + const Eigen::SparseMatrix& X, + const int offset) +{ + Eigen::Matrix I; + Eigen::Matrix J; + Eigen::Matrix V; + igl::find(X,I,J,V); + // Concatenate I,J,V + Eigen::Matrix IJV(I.size(),3); + IJV.col(0) = I.cast(); + IJV.col(1) = J.cast(); + IJV.col(2) = V; + // Offset + if(offset != 0) + { + IJV.col(0).array() += offset; + IJV.col(1).array() += offset; + } + std::cout<(Eigen::SparseMatrix const&, int); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/print_ijv.h b/src/external/libigl-2.3.0/include/igl/print_ijv.h new file mode 100644 index 000000000..e45c1a76c --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/print_ijv.h @@ -0,0 +1,35 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_PRINT_IJV_H +#define IGL_PRINT_IJV_H +#include "igl_inline.h" +#define EIGEN_YES_I_KNOW_SPARSE_MODULE_IS_NOT_STABLE_YET +#include +#include +namespace igl +{ + // Prints a 3 column matrix representing [I,J,V] = find(X). That is, each + // row is the row index, column index and value for each non zero entry. Each + // row is printed on a new line + // + // Templates: + // T should be a eigen sparse matrix primitive type like int or double + // Input: + // X m by n matrix whose entries are to be sorted + // offset optional offset for I and J indices {0} + template + IGL_INLINE void print_ijv( + const Eigen::SparseMatrix& X, + const int offset=0); +} + +#ifndef IGL_STATIC_LIBRARY +# include "print_ijv.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/print_vector.cpp b/src/external/libigl-2.3.0/include/igl/print_vector.cpp new file mode 100644 index 000000000..b47753216 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/print_vector.cpp @@ -0,0 +1,59 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "print_vector.h" +#include +#include + + +template +IGL_INLINE void igl::print_vector( std::vector& v) +{ + using namespace std; + for (int i=0; i +IGL_INLINE void igl::print_vector( std::vector< std::vector >& v) +{ + using namespace std; + for (int i=0; i +IGL_INLINE void igl::print_vector( std::vector< std::vector< std::vector > >& v) +{ + using namespace std; + for (int m=0; m +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_PRINT_VECTOR_H +#define IGL_PRINT_VECTOR_H +#include "igl_inline.h" + +#include +namespace igl +{ + // Not clear what these are supposed to be doing. Currently they print + // vectors to standard error... + template + IGL_INLINE void print_vector( std::vector& v); + template + IGL_INLINE void print_vector( std::vector< std::vector >& v); + template + IGL_INLINE void print_vector(std::vector< std::vector< std::vector > >& v); +} + +#ifndef IGL_STATIC_LIBRARY +# include "print_vector.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/procrustes.cpp b/src/external/libigl-2.3.0/include/igl/procrustes.cpp new file mode 100644 index 000000000..b82d1552b --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/procrustes.cpp @@ -0,0 +1,142 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Stefan Brugger +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "procrustes.h" +#include "polar_svd.h" +#include "polar_dec.h" + +template < + typename DerivedX, + typename DerivedY, + typename Scalar, + typename DerivedR, + typename DerivedT> +IGL_INLINE void igl::procrustes( + const Eigen::MatrixBase& X, + const Eigen::MatrixBase& Y, + bool includeScaling, + bool includeReflections, + Scalar& scale, + Eigen::PlainObjectBase& R, + Eigen::PlainObjectBase& t) +{ + using namespace Eigen; + assert (X.rows() == Y.rows() && "Same number of points"); + assert(X.cols() == Y.cols() && "Points have same dimensions"); + + // Center data + const Matrix Xmean = X.colwise().mean(); + const Matrix Ymean = Y.colwise().mean(); + Matrix XC + = X.rowwise() - Xmean.transpose(); + Matrix YC + = Y.rowwise() - Ymean.transpose(); + + // Scale + scale = 1.; + if (includeScaling) + { + double scaleX = XC.norm() / XC.rows(); + double scaleY = YC.norm() / YC.rows(); + scale = scaleY/scaleX; + XC *= scale; + assert (std::abs(XC.norm() / XC.rows() - scaleY) < 1e-8); + } + + // Rotation + Matrix S = XC.transpose() * YC; + Matrix T; + if (includeReflections) + { + polar_dec(S,R,T); + }else + { + polar_svd(S,R,T); + } +// R.transposeInPlace(); + + // Translation + t = Ymean - scale*R.transpose()*Xmean; +} + + +template < + typename DerivedX, + typename DerivedY, + typename Scalar, + int DIM, + int TType> +IGL_INLINE void igl::procrustes( + const Eigen::MatrixBase& X, + const Eigen::MatrixBase& Y, + bool includeScaling, + bool includeReflections, + Eigen::Transform& T) +{ + using namespace Eigen; + double scale; + MatrixXd R; + VectorXd t; + procrustes(X,Y,includeScaling,includeReflections,scale,R,t); + + // Combine + T = Translation(t) * R * Scaling(scale); +} + +template < + typename DerivedX, + typename DerivedY, + typename DerivedR, + typename DerivedT> +IGL_INLINE void igl::procrustes( + const Eigen::MatrixBase& X, + const Eigen::MatrixBase& Y, + bool includeScaling, + bool includeReflections, + Eigen::PlainObjectBase& S, + Eigen::PlainObjectBase& t) +{ + double scale; + procrustes(X,Y,includeScaling,includeReflections,scale,S,t); + S *= scale; +} + +template < + typename DerivedX, + typename DerivedY, + typename DerivedR, + typename DerivedT> +IGL_INLINE void igl::procrustes( + const Eigen::MatrixBase& X, + const Eigen::MatrixBase& Y, + Eigen::PlainObjectBase& R, + Eigen::PlainObjectBase& t) +{ + procrustes(X,Y,false,false,R,t); +} + +template < + typename DerivedX, + typename DerivedY, + typename Scalar, + typename DerivedT> +IGL_INLINE void igl::procrustes( + const Eigen::MatrixBase& X, + const Eigen::MatrixBase& Y, + Eigen::Rotation2D& R, + Eigen::PlainObjectBase& t) +{ + using namespace Eigen; + assert (X.cols() == 2 && Y.cols() == 2 && "Points must have dimension 2"); + Matrix2d Rmat; + procrustes(X,Y,false,false,Rmat,t); + R.fromRotationMatrix(Rmat); +} + +#ifdef IGL_STATIC_LIBRARY +template void igl::procrustes, Eigen::Matrix, double, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, bool, bool, double&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/procrustes.h b/src/external/libigl-2.3.0/include/igl/procrustes.h new file mode 100644 index 000000000..8cacf2171 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/procrustes.h @@ -0,0 +1,137 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Stefan Brugger +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_PROCRUSTES_H +#define IGL_PROCRUSTES_H +#include "igl_inline.h" + +#include +#include + +namespace igl +{ + // Solve Procrustes problem in d dimensions. Given two point sets X,Y in R^d + // find best scale s, orthogonal R and translation t s.t. |s*X*R + t - Y|^2 + // is minimized. + // + // Templates: + // DerivedV point type + // Scalar scalar type + // DerivedR type of R + // DerivedT type of t + // Inputs: + // X #V by DIM first list of points + // Y #V by DIM second list of points + // includeScaling if scaling should be allowed + // includeReflections if R is allowed to be a reflection + // Outputs: + // scale scaling + // R orthogonal matrix + // t translation + // + // Example: + // MatrixXd X, Y; (containing 3d points as rows) + // double scale; + // MatrixXd R; + // VectorXd t; + // igl::procrustes(X,Y,true,false,scale,R,t); + // R *= scale; + // MatrixXd Xprime = (X * R).rowwise() + t.transpose(); + // + template < + typename DerivedX, + typename DerivedY, + typename Scalar, + typename DerivedR, + typename DerivedT> + IGL_INLINE void procrustes( + const Eigen::MatrixBase& X, + const Eigen::MatrixBase& Y, + bool includeScaling, + bool includeReflections, + Scalar& scale, + Eigen::PlainObjectBase& R, + Eigen::PlainObjectBase& t); + // Same as above but returns Eigen transformation object. + // + // Templates: + // DerivedV point type + // Scalar scalar type + // DIM point dimension + // TType type of transformation + // (Isometry,Affine,AffineCompact,Projective) + // Inputs: + // X #V by DIM first list of points + // Y #V by DIM second list of points + // includeScaling if scaling should be allowed + // includeReflections if R is allowed to be a reflection + // Outputs: + // T transformation that minimizes error + // + // Example: + // MatrixXd X, Y; (containing 3d points as rows) + // AffineCompact3d T; + // igl::procrustes(X,Y,true,false,T); + // MatrixXd Xprime = (X * T.linear()).rowwise() + T.translation().transpose(); + template < + typename DerivedX, + typename DerivedY, + typename Scalar, + int DIM, + int TType> + IGL_INLINE void procrustes( + const Eigen::MatrixBase& X, + const Eigen::MatrixBase& Y, + bool includeScaling, + bool includeReflections, + Eigen::Transform& T); + + + // Convenient wrapper that returns S=scale*R instead of scale and R separately + template < + typename DerivedX, + typename DerivedY, + typename DerivedR, + typename DerivedT> + IGL_INLINE void procrustes( + const Eigen::MatrixBase& X, + const Eigen::MatrixBase& Y, + bool includeScaling, + bool includeReflections, + Eigen::PlainObjectBase& S, + Eigen::PlainObjectBase& t); + + // Convenient wrapper for rigid case (no scaling, no reflections) + template < + typename DerivedX, + typename DerivedY, + typename DerivedR, + typename DerivedT> + IGL_INLINE void procrustes( + const Eigen::MatrixBase& X, + const Eigen::MatrixBase& Y, + Eigen::PlainObjectBase& R, + Eigen::PlainObjectBase& t); + + // Convenient wrapper for 2D case. + template < + typename DerivedX, + typename DerivedY, + typename Scalar, + typename DerivedT> + IGL_INLINE void procrustes( + const Eigen::MatrixBase& X, + const Eigen::MatrixBase& Y, + Eigen::Rotation2D& R, + Eigen::PlainObjectBase& t); +} + +#ifndef IGL_STATIC_LIBRARY + #include "procrustes.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/project.cpp b/src/external/libigl-2.3.0/include/igl/project.cpp new file mode 100644 index 000000000..5ce901f00 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/project.cpp @@ -0,0 +1,62 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "project.h" + +template +Eigen::Matrix igl::project( + const Eigen::Matrix& obj, + const Eigen::Matrix& model, + const Eigen::Matrix& proj, + const Eigen::Matrix& viewport) +{ + Eigen::Matrix tmp; + tmp << obj,1; + + tmp = model * tmp; + + tmp = proj * tmp; + + tmp = tmp.array() / tmp(3); + tmp = tmp.array() * 0.5f + 0.5f; + tmp(0) = tmp(0) * viewport(2) + viewport(0); + tmp(1) = tmp(1) * viewport(3) + viewport(1); + + return tmp.head(3); +} + +template +IGL_INLINE void igl::project( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& model, + const Eigen::MatrixBase& proj, + const Eigen::MatrixBase& viewport, + Eigen::PlainObjectBase & P) +{ + typedef typename DerivedP::Scalar PScalar; + Eigen::Matrix HV(V.rows(),4); + HV.leftCols(3) = V.template cast(); + HV.col(3).setConstant(1); + HV = (HV*model.template cast().transpose()* + proj.template cast().transpose()).eval(); + HV = (HV.array().colwise()/HV.col(3).array()).eval(); + HV = (HV.array() * 0.5 + 0.5).eval(); + HV.col(0) = (HV.array().col(0) * viewport(2) + viewport(0)).eval(); + HV.col(1) = (HV.array().col(1) * viewport(3) + viewport(1)).eval(); + P = HV.leftCols(3); +} + +#ifdef IGL_STATIC_LIBRARY +template void igl::project, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +// Explicit template instantiation +template Eigen::Matrix igl::project(Eigen::Matrix const&, Eigen::Matrix const&, Eigen::Matrix const&, Eigen::Matrix const&); +template Eigen::Matrix igl::project(Eigen::Matrix const&, Eigen::Matrix const&, Eigen::Matrix const&, Eigen::Matrix const&); +template void igl::project, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix>(const Eigen::MatrixBase>&, const Eigen::MatrixBase>&, const Eigen::MatrixBase>&, const Eigen::MatrixBase>&, Eigen::PlainObjectBase>&); +template void igl::project, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix>(const Eigen::MatrixBase>&, const Eigen::MatrixBase>&, const Eigen::MatrixBase>&, const Eigen::MatrixBase>&, Eigen::PlainObjectBase>&); +template void igl::project, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::project, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/project.h b/src/external/libigl-2.3.0/include/igl/project.h new file mode 100644 index 000000000..494636cb1 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/project.h @@ -0,0 +1,57 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_PROJECT_H +#define IGL_PROJECT_H +#include "igl_inline.h" +#include +namespace igl +{ + // Eigen reimplementation of gluProject + // Inputs: + // obj* 3D objects' x, y, and z coordinates respectively + // model model matrix + // proj projection matrix + // viewport viewport vector + // Returns: + // screen space x, y, and z coordinates respectively + template + IGL_INLINE Eigen::Matrix project( + const Eigen::Matrix& obj, + const Eigen::Matrix& model, + const Eigen::Matrix& proj, + const Eigen::Matrix& viewport); + // Inputs: + // V #V by 3 list of object points + // model model matrix + // proj projection matrix + // viewport viewport vector + // Outputs: + // P #V by 3 list of screen space points + // + // Known issue: + // The compiler will not complain if V and P are Vector3d, but the result + // will be incorrect. + // + // Example: + // igl::opengl::glfw::Viewer vr; + // ... + // igl::project(V,vr.core().view,vr.core().proj,vr.core().viewport,P); + template + IGL_INLINE void project( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& model, + const Eigen::MatrixBase& proj, + const Eigen::MatrixBase& viewport, + Eigen::PlainObjectBase & P); +} + +#ifndef IGL_STATIC_LIBRARY +# include "project.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/project_isometrically_to_plane.cpp b/src/external/libigl-2.3.0/include/igl/project_isometrically_to_plane.cpp new file mode 100644 index 000000000..dcaa3a8d1 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/project_isometrically_to_plane.cpp @@ -0,0 +1,63 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "project_isometrically_to_plane.h" +#include "edge_lengths.h" + +template < + typename DerivedV, + typename DerivedF, + typename DerivedU, + typename DerivedUF, + typename Scalar> +IGL_INLINE void igl::project_isometrically_to_plane( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + Eigen::PlainObjectBase & U, + Eigen::PlainObjectBase & UF, + Eigen::SparseMatrix& I) +{ + using namespace std; + using namespace Eigen; + assert(F.cols() == 3 && "F should contain triangles"); + typedef Eigen::Matrix MatrixX; + MatrixX l; + edge_lengths(V,F,l); + // Number of faces + const int m = F.rows(); + + // First corner at origin + U = DerivedU::Zero(m*3,2); + // Second corner along x-axis + U.block(m,0,m,1) = l.col(2); + // Third corner rotated onto plane + U.block(m*2,0,m,1) = + (-l.col(0).array().square() + + l.col(1).array().square() + + l.col(2).array().square())/(2.*l.col(2).array()); + U.block(m*2,1,m,1) = + (l.col(1).array().square()-U.block(m*2,0,m,1).array().square()).sqrt(); + + typedef Triplet IJV; + vector ijv; + ijv.reserve(3*m); + UF.resize(m,3); + for(int f = 0;f, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, double>(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::SparseMatrix&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/project_isometrically_to_plane.h b/src/external/libigl-2.3.0/include/igl/project_isometrically_to_plane.h new file mode 100644 index 000000000..6447ebcbf --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/project_isometrically_to_plane.h @@ -0,0 +1,49 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_PROJECT_ISOMETRICALLY_TO_PLANE_H +#define IGL_PROJECT_ISOMETRICALLY_TO_PLANE_H +#include "igl_inline.h" + +#include +#include + + +namespace igl +{ + // Project each triangle to the plane + // + // [U,UF,I] = project_isometrically_to_plane(V,F) + // + // Inputs: + // V #V by 3 list of vertex positions + // F #F by 3 list of mesh indices + // Outputs: + // U #F*3 by 2 list of triangle positions + // UF #F by 3 list of mesh indices into U + // I #V by #F*3 such that I(i,j) = 1 implies U(j,:) corresponds to V(i,:) + // + template < + typename DerivedV, + typename DerivedF, + typename DerivedU, + typename DerivedUF, + typename Scalar> + IGL_INLINE void project_isometrically_to_plane( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + Eigen::PlainObjectBase & U, + Eigen::PlainObjectBase & UF, + Eigen::SparseMatrix& I); +} + +#ifndef IGL_STATIC_LIBRARY +# include "project_isometrically_to_plane.cpp" +#endif + +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/project_to_line.cpp b/src/external/libigl-2.3.0/include/igl/project_to_line.cpp new file mode 100644 index 000000000..a7f3a690e --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/project_to_line.cpp @@ -0,0 +1,139 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "project_to_line.h" +#include +#include + +template < + typename DerivedP, + typename DerivedS, + typename DerivedD, + typename Derivedt, + typename DerivedsqrD> +IGL_INLINE void igl::project_to_line( + const Eigen::MatrixBase & P, + const Eigen::MatrixBase & S, + const Eigen::MatrixBase & D, + Eigen::PlainObjectBase & t, + Eigen::PlainObjectBase & sqrD) +{ + // http://mathworld.wolfram.com/Point-LineDistance3-Dimensional.html + + // number of dimensions +#ifndef NDEBUG + int dim = P.cols(); + assert(dim == S.size()); + assert(dim == D.size()); +#endif + // number of points + int np = P.rows(); + // vector from source to destination + DerivedD DmS = D-S; + double v_sqrlen = (double)(DmS.squaredNorm()); + assert(v_sqrlen != 0); + // resize output + t.resize(np,1); + sqrD.resize(np,1); + // loop over points +#pragma omp parallel for if (np>10000) + for(int i = 0;i +IGL_INLINE void igl::project_to_line( + const Scalar px, + const Scalar py, + const Scalar pz, + const Scalar sx, + const Scalar sy, + const Scalar sz, + const Scalar dx, + const Scalar dy, + const Scalar dz, + Scalar & projpx, + Scalar & projpy, + Scalar & projpz, + Scalar & t, + Scalar & sqrd) +{ + // vector from source to destination + Scalar dms[3]; + dms[0] = dx-sx; + dms[1] = dy-sy; + dms[2] = dz-sz; + Scalar v_sqrlen = dms[0]*dms[0] + dms[1]*dms[1] + dms[2]*dms[2]; + // line should have some length + assert(v_sqrlen != 0); + // vector from point to source + Scalar smp[3]; + smp[0] = sx-px; + smp[1] = sy-py; + smp[2] = sz-pz; + t = -(dms[0]*smp[0]+dms[1]*smp[1]+dms[2]*smp[2])/v_sqrlen; + // P projectred onto line + projpx = (1.0-t)*sx + t*dx; + projpy = (1.0-t)*sy + t*dy; + projpz = (1.0-t)*sz + t*dz; + // vector from projected point to p + Scalar pmprojp[3]; + pmprojp[0] = px-projpx; + pmprojp[1] = py-projpy; + pmprojp[2] = pz-projpz; + sqrd = pmprojp[0]*pmprojp[0] + pmprojp[1]*pmprojp[1] + pmprojp[2]*pmprojp[2]; +} + +template +IGL_INLINE void igl::project_to_line( + const Scalar px, + const Scalar py, + const Scalar pz, + const Scalar sx, + const Scalar sy, + const Scalar sz, + const Scalar dx, + const Scalar dy, + const Scalar dz, + Scalar & t, + Scalar & sqrd) +{ + Scalar projpx; + Scalar projpy; + Scalar projpz; + return igl::project_to_line( + px, py, pz, sx, sy, sz, dx, dy, dz, + projpx, projpy, projpz, t, sqrd); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::project_to_line, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::project_to_line, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::project_to_line, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::project_to_line const, -1, -1, false>, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase const, -1, -1, false> > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::project_to_line const, -1, -1, false>, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase const, -1, -1, false> > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::project_to_line, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::project_to_line(double, double, double, double, double, double, double, double, double, double&, double&); +template void igl::project_to_line(double, double, double, double, double, double, double, double, double, double&, double&,double&,double&, double&); +template void igl::project_to_line, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::project_to_line, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/project_to_line.h b/src/external/libigl-2.3.0/include/igl/project_to_line.h new file mode 100644 index 000000000..d11399a76 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/project_to_line.h @@ -0,0 +1,83 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_PROJECT_TO_LINE_H +#define IGL_PROJECT_TO_LINE_H +#include "igl_inline.h" +#include + +namespace igl +{ + // PROJECT_TO_LINE project points onto vectors, that is find the parameter + // t for a point p such that proj_p = (y-x).*t, additionally compute the + // squared distance from p to the line of the vector, such that + // |p - proj_p|² = sqr_d + // + // [T,sqrD] = project_to_line(P,S,D) + // + // Inputs: + // P #P by dim list of points to be projected + // S size dim start position of line vector + // D size dim destination position of line vector + // Outputs: + // T #P by 1 list of parameters + // sqrD #P by 1 list of squared distances + // + // + template < + typename DerivedP, + typename DerivedS, + typename DerivedD, + typename Derivedt, + typename DerivedsqrD> + IGL_INLINE void project_to_line( + const Eigen::MatrixBase & P, + const Eigen::MatrixBase & S, + const Eigen::MatrixBase & D, + Eigen::PlainObjectBase & t, + Eigen::PlainObjectBase & sqrD); + + // Same as above but for a single query point + template + IGL_INLINE void project_to_line( + const Scalar px, + const Scalar py, + const Scalar pz, + const Scalar sx, + const Scalar sy, + const Scalar sz, + const Scalar dx, + const Scalar dy, + const Scalar dz, + Scalar & projpx, + Scalar & projpy, + Scalar & projpz, + Scalar & t, + Scalar & sqrd); + + // Same as above but for a single query point + template + IGL_INLINE void project_to_line( + const Scalar px, + const Scalar py, + const Scalar pz, + const Scalar sx, + const Scalar sy, + const Scalar sz, + const Scalar dx, + const Scalar dy, + const Scalar dz, + Scalar & t, + Scalar & sqrd); + +} + +#ifndef IGL_STATIC_LIBRARY +# include "project_to_line.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/project_to_line_segment.cpp b/src/external/libigl-2.3.0/include/igl/project_to_line_segment.cpp new file mode 100644 index 000000000..71866fa33 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/project_to_line_segment.cpp @@ -0,0 +1,55 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "project_to_line_segment.h" +#include "project_to_line.h" +#include + +template < + typename DerivedP, + typename DerivedS, + typename DerivedD, + typename Derivedt, + typename DerivedsqrD> +IGL_INLINE void igl::project_to_line_segment( + const Eigen::MatrixBase & P, + const Eigen::MatrixBase & S, + const Eigen::MatrixBase & D, + Eigen::PlainObjectBase & t, + Eigen::PlainObjectBase & sqrD) +{ + project_to_line(P,S,D,t,sqrD); + const int np = P.rows(); + // loop over points and fix those that projected beyond endpoints +#pragma omp parallel for if (np>10000) + for(int p = 0;p1) + { + sqrD(p) = (Pp-D).squaredNorm(); + t(p) = 1; + } + } +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::project_to_line_segment, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::project_to_line_segment, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::project_to_line_segment, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::project_to_line_segment, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::project_to_line_segment, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/project_to_line_segment.h b/src/external/libigl-2.3.0/include/igl/project_to_line_segment.h new file mode 100644 index 000000000..2fe33f2d4 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/project_to_line_segment.h @@ -0,0 +1,50 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_PROJECT_TO_LINE_SEGMENT_H +#define IGL_PROJECT_TO_LINE_SEGMENT_H +#include "igl_inline.h" +#include + +namespace igl +{ + // PROJECT_TO_LINE_SEGMENT project points onto vectors, that is find the parameter + // t for a point p such that proj_p = (y-x).*t, additionally compute the + // squared distance from p to the line of the vector, such that + // |p - proj_p|² = sqr_d + // + // [T,sqrD] = project_to_line_segment(P,S,D) + // + // Inputs: + // P #P by dim list of points to be projected + // S size dim start position of line vector + // D size dim destination position of line vector + // Outputs: + // T #P by 1 list of parameters + // sqrD #P by 1 list of squared distances + // + // + template < + typename DerivedP, + typename DerivedS, + typename DerivedD, + typename Derivedt, + typename DerivedsqrD> + IGL_INLINE void project_to_line_segment( + const Eigen::MatrixBase & P, + const Eigen::MatrixBase & S, + const Eigen::MatrixBase & D, + Eigen::PlainObjectBase & t, + Eigen::PlainObjectBase & sqrD); +} + +#ifndef IGL_STATIC_LIBRARY +# include "project_to_line_segment.cpp" +#endif + +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/projection_constraint.cpp b/src/external/libigl-2.3.0/include/igl/projection_constraint.cpp new file mode 100644 index 000000000..fb05398f9 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/projection_constraint.cpp @@ -0,0 +1,50 @@ +#include "projection_constraint.h" + +template < + typename DerivedUV, + typename DerivedM, + typename DerivedVP, + typename DerivedA, + typename DerivedB> +void igl::projection_constraint( + const Eigen::MatrixBase & UV, + const Eigen::MatrixBase & _M, + const Eigen::MatrixBase & VP, + Eigen::PlainObjectBase & A, + Eigen::PlainObjectBase & B) +{ + typedef typename DerivedA::Scalar Scalar; + const Scalar u = UV(0); + const Scalar v = UV(1); + const Scalar cu = VP(0); + const Scalar cv = VP(1); + const Scalar w = VP(2); + const Scalar h = VP(3); + // u = cu + w*(0.5 + 0.5*((M.row(0)*X) / (M.row(3)*X) )) + // u-cu = w*(0.5 + 0.5*((M.row(0)*X) / (M.row(3)*X) )) + // (u-cu)/w = 0.5 + 0.5*((M.row(0)*X) / (M.row(3)*X) ) + // (u-cu)/w - 0.5 = 0.5*((M.row(0)*X) / (M.row(3)*X) ) + // 2.*(u-cu)/w - 1 = ((M.row(0)*X) / (M.row(3)*X) ) + // (2.*(u - cu)/w - 1) * M.row(3)*X = M.row(0)*X + // (2.*(u - cu)/w - 1) * M.row(3)*X - M.row(0)*X = 0 + // (2.*(u - cu)/w - 1) * (M.block(3,0,1,3)*x + M(3,3)) - M.block(0,0,1,3)*x - M(0,3) = 0 + // (2.*(u - cu)/w - 1) * (M.block(3,0,1,3)*x + M(3,3)) - M.block(0,0,1,3)*x = M(0,3) + // ((2.*(u - cu)/w - 1) * M.block(3,0,1,3) - M.block(0,0,1,3))*x = M(0,3) - (2.*(u - cu)/w - 1)*M(3,3) + Eigen::Matrix M = _M.template cast(); + A.resize(2,3); + A<< + ((2.*(u - cu)/w - 1.) * M.block(3,0,1,3) - M.block(0,0,1,3)), + ((2.*(v - cv)/h - 1.) * M.block(3,0,1,3) - M.block(1,0,1,3)); + B.resize(2,1); + B<< + M(0,3) - (2.*(u - cu)/w - 1.)*M(3,3), + M(1,3) - (2.*(v - cv)/h - 1.)*M(3,3); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::projection_constraint, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::projection_constraint, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/projection_constraint.h b/src/external/libigl-2.3.0/include/igl/projection_constraint.h new file mode 100644 index 000000000..4db366d1b --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/projection_constraint.h @@ -0,0 +1,43 @@ +#ifndef IGL_PROJECTION_CONSTRAINT_H +#define IGL_PROJECTION_CONSTRAINT_H + +#include + +namespace igl +{ + // Construct two constraint equations of the form: + // + // A z = B + // + // with A 2x3 and B 2x1, where z is the 3d position of point in the scene, + // given the current projection matrix (e.g. gl_proj * gl_modelview), viewport + // (corner u/v and width/height) and screen space point x,y. Satisfying this + // equation means that z projects to screen space point (x,y). + // + // Inputs: + // UV 2-long uv-coordinates of screen space point + // M 4 by 4 projection matrix + // VP 4-long viewport: (corner_u, corner_v, width, height) + // Outputs: + // A 2 by 3 system matrix + // B 2 by 1 right-hand side + template < + typename DerivedUV, + typename DerivedM, + typename DerivedVP, + typename DerivedA, + typename DerivedB> + void projection_constraint( + const Eigen::MatrixBase & UV, + const Eigen::MatrixBase & M, + const Eigen::MatrixBase & VP, + Eigen::PlainObjectBase & A, + Eigen::PlainObjectBase & B); +} + +#ifndef IGL_STATIC_LIBRARY +# include "projection_constraint.cpp" +#endif + +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/pseudonormal_test.cpp b/src/external/libigl-2.3.0/include/igl/pseudonormal_test.cpp new file mode 100644 index 000000000..2708a52fe --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/pseudonormal_test.cpp @@ -0,0 +1,227 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "pseudonormal_test.h" +#include "barycentric_coordinates.h" +#include "doublearea.h" +#include "project_to_line_segment.h" +#include +template < + typename DerivedV, + typename DerivedF, + typename DerivedFN, + typename DerivedVN, + typename DerivedEN, + typename DerivedEMAP, + typename Derivedq, + typename Derivedc, + typename Scalar, + typename Derivedn> +IGL_INLINE void igl::pseudonormal_test( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const Eigen::MatrixBase & FN, + const Eigen::MatrixBase & VN, + const Eigen::MatrixBase & EN, + const Eigen::MatrixBase & EMAP, + const Eigen::MatrixBase & q, + const int f, + Eigen::PlainObjectBase & c, + Scalar & s, + Eigen::PlainObjectBase & n) +{ + using namespace Eigen; + const auto & qc = q-c; + typedef Eigen::Matrix RowVector3S; + RowVector3S b; + // Using barycentric coorindates to determine whether close to a vertex/edge + // seems prone to error when dealing with nearly degenerate triangles: Even + // the barycenter (1/3,1/3,1/3) can be made arbitrarily close to an + // edge/vertex + // + const RowVector3S A = V.row(F(f,0)); + const RowVector3S B = V.row(F(f,1)); + const RowVector3S C = V.row(F(f,2)); + + const double area = [&A,&B,&C]() + { + Matrix area; + doublearea(A,B,C,area); + return area(0); + }(); + // These were chosen arbitrarily. In a floating point scenario, I'm not sure + // the best way to determine if c is on a vertex/edge or in the middle of the + // face: specifically, I'm worrying about degenerate triangles where + // barycentric coordinates are error-prone. + const double MIN_DOUBLE_AREA = 1e-4; + const double epsilon = 1e-12; + if(area>MIN_DOUBLE_AREA) + { + barycentric_coordinates( c,A,B,C,b); + // Determine which normal to use + const int type = (b.array()<=epsilon).template cast().sum(); + switch(type) + { + case 2: + // Find vertex + for(int x = 0;x<3;x++) + { + if(b(x)>epsilon) + { + n = VN.row(F(f,x)); + break; + } + } + break; + case 1: + // Find edge + for(int x = 0;x<3;x++) + { + if(b(x)<=epsilon) + { + n = EN.row(EMAP(F.rows()*x+f)); + break; + } + } + break; + default: + assert(false && "all barycentric coords zero."); + case 0: + n = FN.row(f); + break; + } + }else + { + // Check each vertex + bool found = false; + for(int v = 0;v<3 && !found;v++) + { + if( (c-V.row(F(f,v))).norm() < epsilon) + { + found = true; + n = VN.row(F(f,v)); + } + } + // Check each edge + for(int e = 0;e<3 && !found;e++) + { + const RowVector3S s = V.row(F(f,(e+1)%3)); + const RowVector3S d = V.row(F(f,(e+2)%3)); + Matrix sqr_d_j_x(1,1); + Matrix t(1,1); + project_to_line_segment(c,s,d,t,sqr_d_j_x); + if(sqrt(sqr_d_j_x(0)) < epsilon) + { + n = EN.row(EMAP(F.rows()*e+f)); + found = true; + } + } + // Finally just use face + if(!found) + { + n = FN.row(f); + } + } + s = (qc.dot(n) >= 0 ? 1. : -1.); +} + +template < + typename DerivedV, + typename DerivedF, + typename DerivedEN, + typename DerivedVN, + typename Derivedq, + typename Derivedc, + typename Scalar, + typename Derivedn> +IGL_INLINE void igl::pseudonormal_test( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & E, + const Eigen::MatrixBase & EN, + const Eigen::MatrixBase & VN, + const Eigen::MatrixBase & q, + const int e, + Eigen::PlainObjectBase & c, + Scalar & s, + Eigen::PlainObjectBase & n) +{ + using namespace Eigen; + const auto & qc = q-c; + const double len = (V.row(E(e,1))-V.row(E(e,0))).norm(); + // barycentric coordinates + // this .head() nonsense is for "ridiculus" templates instantiations that AABB + // needs to compile + Eigen::Matrix + b((c-V.row(E(e,1))).norm()/len,(c-V.row(E(e,0))).norm()/len); + //b((c-V.row(E(e,1)).head(c.size())).norm()/len,(c-V.row(E(e,0)).head(c.size())).norm()/len); + // Determine which normal to use + const double epsilon = 1e-12; + const int type = (b.array()<=epsilon).template cast().sum(); + switch(type) + { + case 1: + // Find vertex + for(int x = 0;x<2;x++) + { + if(b(x)>epsilon) + { + n = VN.row(E(e,x)).head(2); + break; + } + } + break; + default: + assert(false && "all barycentric coords zero."); + case 0: + n = EN.row(e).head(2); + break; + } + s = (qc.dot(n) >= 0 ? 1. : -1.); +} + +// This is a bullshit template because AABB annoyingly needs templates for bad +// combinations of 3D V with DIM=2 AABB +// +// _Define_ as a no-op rather than monkeying around with the proper code above +namespace igl +{ + template <> IGL_INLINE void pseudonormal_test(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, int, Eigen::PlainObjectBase >&, float&, Eigen::PlainObjectBase >&){assert(false);}; + template <> IGL_INLINE void pseudonormal_test(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, int, Eigen::PlainObjectBase >&, float&, Eigen::PlainObjectBase >&){assert(false);}; + template <> IGL_INLINE void pseudonormal_test(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, int, Eigen::PlainObjectBase >&, double&, Eigen::PlainObjectBase >&){assert(false);}; + template <> IGL_INLINE void pseudonormal_test(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, int, Eigen::PlainObjectBase >&, double&, Eigen::PlainObjectBase >&){assert(false);}; + template <> IGL_INLINE void pseudonormal_test(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, int, Eigen::PlainObjectBase >&, float&, Eigen::PlainObjectBase >&) {assert(false);}; + template <> IGL_INLINE void pseudonormal_test(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, int, Eigen::PlainObjectBase >&, float&, Eigen::PlainObjectBase >&){assert(false);}; + template <> IGL_INLINE void pseudonormal_test(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, int, Eigen::PlainObjectBase >&, float&, Eigen::PlainObjectBase >&){assert(false);}; + template <> IGL_INLINE void pseudonormal_test(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, int, Eigen::PlainObjectBase >&, double&, Eigen::PlainObjectBase >&){assert(false);}; + template <> IGL_INLINE void pseudonormal_test(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, int, Eigen::PlainObjectBase >&, double&, Eigen::PlainObjectBase >&){assert(false);}; +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::pseudonormal_test, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, double, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, int, Eigen::PlainObjectBase >&, double&, Eigen::PlainObjectBase >&); +template void igl::pseudonormal_test, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, double, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, int, Eigen::PlainObjectBase >&, double&, Eigen::PlainObjectBase >&); +// NEW +template void igl::pseudonormal_test, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, float, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, int, Eigen::PlainObjectBase >&, float&, Eigen::PlainObjectBase >&); +template void igl::pseudonormal_test, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, float, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, int, Eigen::PlainObjectBase >&, float&, Eigen::PlainObjectBase >&); +template void igl::pseudonormal_test, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, float, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, int, Eigen::PlainObjectBase >&, float&, Eigen::PlainObjectBase >&); +template void igl::pseudonormal_test, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, float, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, int, Eigen::PlainObjectBase >&, float&, Eigen::PlainObjectBase >&); +template void igl::pseudonormal_test, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, double, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, int, Eigen::PlainObjectBase >&, double&, Eigen::PlainObjectBase >&); +// OLD +template void igl::pseudonormal_test, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, double, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, int, Eigen::PlainObjectBase >&, double&, Eigen::PlainObjectBase >&); +template void igl::pseudonormal_test, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, float, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, int, Eigen::PlainObjectBase >&, float&, Eigen::PlainObjectBase >&); +template void igl::pseudonormal_test, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, float, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, int, Eigen::PlainObjectBase >&, float&, Eigen::PlainObjectBase >&); +template void igl::pseudonormal_test, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, float, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, int, Eigen::PlainObjectBase >&, float&, Eigen::PlainObjectBase >&); +template void igl::pseudonormal_test, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, double, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, int, Eigen::PlainObjectBase >&, double&, Eigen::PlainObjectBase >&); +template void igl::pseudonormal_test, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, double, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, int, Eigen::PlainObjectBase >&, double&, Eigen::PlainObjectBase >&); +template void igl::pseudonormal_test, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, double, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, int, Eigen::PlainObjectBase >&, double&, Eigen::PlainObjectBase >&); +template void igl::pseudonormal_test, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Block, 1, -1, false>, Eigen::Matrix, double, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase, 1, -1, false> > const&, int, Eigen::PlainObjectBase >&, double&, Eigen::PlainObjectBase >&); +template void igl::pseudonormal_test, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, float, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, int, Eigen::PlainObjectBase >&, float&, Eigen::PlainObjectBase >&); +template void igl::pseudonormal_test, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, double, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, int, Eigen::PlainObjectBase >&, double&, Eigen::PlainObjectBase >&); +template void igl::pseudonormal_test, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, double, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, int, Eigen::PlainObjectBase >&, double&, Eigen::PlainObjectBase >&); +template void igl::pseudonormal_test, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, double, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, int, Eigen::PlainObjectBase >&, double&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/pseudonormal_test.h b/src/external/libigl-2.3.0/include/igl/pseudonormal_test.h new file mode 100644 index 000000000..fc07946fb --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/pseudonormal_test.h @@ -0,0 +1,78 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_PSEUDONORMAL_TEST_H +#define IGL_PSEUDONORMAL_TEST_H +#include "igl_inline.h" +#include +namespace igl +{ + // Given a mesh (V,F), a query point q, and a point on (V,F) c, determine + // whether q is inside (V,F) --> s=-1 or outside (V,F) s=1, based on the + // sign of the dot product between (q-c) and n, where n is the normal _at c_, + // carefully chosen according to [Bærentzen & Aanæs 2005] + // + // Inputs: + // V #V by 3 list of vertex positions + // F #F by 3 list of triangle indices + // FN #F by 3 list of triangle normals + // VN #V by 3 list of vertex normals (ANGLE WEIGHTING) + // EN #E by 3 list of edge normals (UNIFORM WEIGHTING) + // EMAP #F*3 mapping edges in F to E + // q Query point + // f index into F to face to which c belongs + // c Point on (V,F) + // Outputs: + // s sign + // n normal + template < + typename DerivedV, + typename DerivedF, + typename DerivedFN, + typename DerivedVN, + typename DerivedEN, + typename DerivedEMAP, + typename Derivedq, + typename Derivedc, + typename Scalar, + typename Derivedn> + IGL_INLINE void pseudonormal_test( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const Eigen::MatrixBase & FN, + const Eigen::MatrixBase & VN, + const Eigen::MatrixBase & EN, + const Eigen::MatrixBase & EMAP, + const Eigen::MatrixBase & q, + const int f, + Eigen::PlainObjectBase & c, + Scalar & s, + Eigen::PlainObjectBase & n); + template < + typename DerivedV, + typename DerivedF, + typename DerivedEN, + typename DerivedVN, + typename Derivedq, + typename Derivedc, + typename Scalar, + typename Derivedn> + IGL_INLINE void pseudonormal_test( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & E, + const Eigen::MatrixBase & EN, + const Eigen::MatrixBase & VN, + const Eigen::MatrixBase & q, + const int e, + Eigen::PlainObjectBase & c, + Scalar & s, + Eigen::PlainObjectBase & n); +} +#ifndef IGL_STATIC_LIBRARY +# include "pseudonormal_test.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/pso.cpp b/src/external/libigl-2.3.0/include/igl/pso.cpp new file mode 100644 index 000000000..bf24a3a8c --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/pso.cpp @@ -0,0 +1,174 @@ +#include "pso.h" +#include +#include +#include +#include + +template < + typename Scalar, + typename DerivedX, + typename DerivedLB, + typename DerivedUB> +IGL_INLINE Scalar igl::pso( + const std::function< Scalar (DerivedX &) > f, + const Eigen::MatrixBase & LB, + const Eigen::MatrixBase & UB, + const int max_iters, + const int population, + DerivedX & X) +{ + const Eigen::Array P = + Eigen::Array::Zero(LB.size(),1); + return igl::pso(f,LB,UB,P,max_iters,population,X); +} + +template < + typename Scalar, + typename DerivedX, + typename DerivedLB, + typename DerivedUB, + typename DerivedP> +IGL_INLINE Scalar igl::pso( + const std::function< Scalar (DerivedX &) > f, + const Eigen::MatrixBase & LB, + const Eigen::MatrixBase & UB, + const Eigen::DenseBase & P, + const int max_iters, + const int population, + DerivedX & X) +{ + const int dim = LB.size(); + assert(UB.size() == dim && "UB should match LB size"); + assert(P.size() == dim && "P should match LB size"); + typedef std::vector > VectorList; + VectorList position(population); + VectorList best_position(population); + VectorList velocity(population); + Eigen::Matrix best_f(population); + // https://en.wikipedia.org/wiki/Particle_swarm_optimization#Algorithm + // + // g → X + // p_i → best[i] + // v_i → velocity[i] + // x_i → position[i] + Scalar min_f = std::numeric_limits::max(); + for(int p=0;p UB(d)) + { + position[p](d) = UB(d); + if(velocity[p](d) > 0.0) velocity[p](d) *= -1.0; + } +#else +//#warning "trying no bounds on periodic" +// // TODO: I'm not sure this is the right thing to do/enough. The +// // velocities could be weird. Suppose the current "best" value is ε and +// // the value is -ε and the "periodic bounds" [0,2π]. Moding will send +// // the value to 2π-ε but the "velocity" term will now be huge pointing +// // all the way from 2π-ε to ε. +// // +// // Q: Would it be enough to try (all combinations) of ±(UB-LB) before +// // computing velocities to "best"s? In the example above, instead of +// // +// // v += best - p = ε - (2π-ε) = -2π+2ε +// // +// // you'd use +// // +// // v += / argmin |b - p| \ - p = (ε+2π)-(2π-ε) = 2ε +// // | | +// // \ b∈{best, best+2π, best-2π} / +// // +// // Though, for multivariate b,p,v this would seem to explode +// // combinatorially. +// // +// // Maybe periodic things just shouldn't be bounded and we hope that the +// // forces toward the current minima "regularize" them away from insane +// // values. +// if(P(d)) +// { +// position[p](d) = std::fmod(position[p](d)-LB(d),UB(d)-LB(d))+LB(d); +// }else +// { +// position[p](d) = std::max(LB(d),std::min(UB(d),position[p](d))); +// } + position[p](d) = std::max(LB(d),std::min(UB(d),position[p](d))); +#endif + } + const Scalar fp = f(position[p]); + if(fp=max_iters) + { + break; + } + } + return min_f; +} + +#ifdef IGL_STATIC_LIBRARY +template float igl::pso, Eigen::Matrix, Eigen::Matrix >(std::function&)>, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, int, int, Eigen::Matrix&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/pso.h b/src/external/libigl-2.3.0/include/igl/pso.h new file mode 100644 index 000000000..d2a2ccdff --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/pso.h @@ -0,0 +1,59 @@ +#ifndef IGL_PSO_H +#define IGL_PSO_H +#include +#include +#include + +namespace igl +{ + // Solve the problem: + // + // minimize f(x) + // subject to lb ≤ x ≤ ub + // + // by particle swarm optimization (PSO). + // + // Inputs: + // f function that evaluates the objective for a given "particle" location + // LB #X vector of lower bounds + // UB #X vector of upper bounds + // max_iters maximum number of iterations + // population number of particles in swarm + // Outputs: + // X best particle seen so far + // Returns objective corresponding to best particle seen so far + template < + typename Scalar, + typename DerivedX, + typename DerivedLB, + typename DerivedUB> + IGL_INLINE Scalar pso( + const std::function< Scalar (DerivedX &) > f, + const Eigen::MatrixBase & LB, + const Eigen::MatrixBase & UB, + const int max_iters, + const int population, + DerivedX & X); + // Inputs: + // P whether each DOF is periodic + template < + typename Scalar, + typename DerivedX, + typename DerivedLB, + typename DerivedUB, + typename DerivedP> + IGL_INLINE Scalar pso( + const std::function< Scalar (DerivedX &) > f, + const Eigen::MatrixBase & LB, + const Eigen::MatrixBase & UB, + const Eigen::DenseBase & P, + const int max_iters, + const int population, + DerivedX & X); +} + +#ifndef IGL_STATIC_LIBRARY +# include "pso.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/qslim.cpp b/src/external/libigl-2.3.0/include/igl/qslim.cpp new file mode 100644 index 000000000..62195437c --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/qslim.cpp @@ -0,0 +1,84 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "qslim.h" + +#include "collapse_edge.h" +#include "connect_boundary_to_infinity.h" +#include "decimate.h" +#include "edge_flaps.h" +#include "is_edge_manifold.h" +#include "max_faces_stopping_condition.h" +#include "per_vertex_point_to_plane_quadrics.h" +#include "qslim_optimal_collapse_edge_callbacks.h" +#include "quadric_binary_plus_operator.h" +#include "remove_unreferenced.h" +#include "slice.h" +#include "slice_mask.h" + +IGL_INLINE bool igl::qslim( + const Eigen::MatrixXd & V, + const Eigen::MatrixXi & F, + const size_t max_m, + Eigen::MatrixXd & U, + Eigen::MatrixXi & G, + Eigen::VectorXi & J, + Eigen::VectorXi & I) +{ + using namespace igl; + + // Original number of faces + const int orig_m = F.rows(); + // Tracking number of faces + int m = F.rows(); + typedef Eigen::MatrixXd DerivedV; + typedef Eigen::MatrixXi DerivedF; + DerivedV VO; + DerivedF FO; + igl::connect_boundary_to_infinity(V,F,VO,FO); + // decimate will not work correctly on non-edge-manifold meshes. By extension + // this includes meshes with non-manifold vertices on the boundary since these + // will create a non-manifold edge when connected to infinity. + if(!is_edge_manifold(FO)) + { + return false; + } + Eigen::VectorXi EMAP; + Eigen::MatrixXi E,EF,EI; + edge_flaps(FO,E,EMAP,EF,EI); + // Quadrics per vertex + typedef std::tuple Quadric; + std::vector quadrics; + per_vertex_point_to_plane_quadrics(VO,FO,EMAP,EF,EI,quadrics); + // State variables keeping track of edge we just collapsed + int v1 = -1; + int v2 = -1; + // Callbacks for computing and updating metric + decimate_cost_and_placement_callback cost_and_placement; + decimate_pre_collapse_callback pre_collapse; + decimate_post_collapse_callback post_collapse; + qslim_optimal_collapse_edge_callbacks( + E,quadrics,v1,v2, cost_and_placement, pre_collapse,post_collapse); + // Call to greedy decimator + bool ret = decimate( + VO, FO, + cost_and_placement, + max_faces_stopping_condition(m,orig_m,max_m), + pre_collapse, + post_collapse, + E, EMAP, EF, EI, + U, G, J, I); + // Remove phony boundary faces and clean up + const Eigen::Array keep = (J.array() +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_QSLIM_H +#define IGL_QSLIM_H +#include "igl_inline.h" +#include +namespace igl +{ + + // Decimate (simplify) a triangle mesh in nD according to the paper + // "Simplifying Surfaces with Color and Texture using Quadric Error Metrics" + // by [Garland and Heckbert, 1987] (technically a followup to qslim). The + // mesh can have open boundaries but should be edge-manifold. + // + // Inputs: + // V #V by dim list of vertex positions. Assumes that vertices with + // infinite coordinates are "points at infinity" being used to close up + // boundary edges with faces. This allows special subspace quadrice for + // boundary edges: There should never be more than one "point at + // infinity" in a single triangle. + // F #F by 3 list of triangle indices into V + // max_m desired number of output faces + // Outputs: + // U #U by dim list of output vertex posistions (can be same ref as V) + // G #G by 3 list of output face indices into U (can be same ref as F) + // J #G list of indices into F of birth face + // I #U list of indices into V of birth vertices + IGL_INLINE bool qslim( + const Eigen::MatrixXd & V, + const Eigen::MatrixXi & F, + const size_t max_m, + Eigen::MatrixXd & U, + Eigen::MatrixXi & G, + Eigen::VectorXi & J, + Eigen::VectorXi & I); +} +#ifndef IGL_STATIC_LIBRARY +# include "qslim.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/qslim_optimal_collapse_edge_callbacks.cpp b/src/external/libigl-2.3.0/include/igl/qslim_optimal_collapse_edge_callbacks.cpp new file mode 100644 index 000000000..ba9c5b9f3 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/qslim_optimal_collapse_edge_callbacks.cpp @@ -0,0 +1,94 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "qslim_optimal_collapse_edge_callbacks.h" +#include "quadric_binary_plus_operator.h" +#include + +IGL_INLINE void igl::qslim_optimal_collapse_edge_callbacks( + Eigen::MatrixXi & E, + std::vector > & + quadrics, + int & v1, + int & v2, + decimate_cost_and_placement_callback & cost_and_placement, + decimate_pre_collapse_callback & pre_collapse, + decimate_post_collapse_callback & post_collapse) +{ + typedef std::tuple Quadric; + cost_and_placement = [&quadrics,&v1,&v2]( + const int e, + const Eigen::MatrixXd & V, + const Eigen::MatrixXi & /*F*/, + const Eigen::MatrixXi & E, + const Eigen::VectorXi & /*EMAP*/, + const Eigen::MatrixXi & /*EF*/, + const Eigen::MatrixXi & /*EI*/, + double & cost, + Eigen::RowVectorXd & p) + { + // Combined quadric + Quadric quadric_p; + quadric_p = quadrics[E(e,0)] + quadrics[E(e,1)]; + // Quadric: p'Ap + 2b'p + c + // optimal point: Ap = -b, or rather because we have row vectors: pA=-b + const auto & A = std::get<0>(quadric_p); + const auto & b = std::get<1>(quadric_p); + const auto & c = std::get<2>(quadric_p); + p = -b*A.inverse(); + cost = p.dot(p*A) + 2*p.dot(b) + c; + // Force infs and nans to infinity + if(std::isinf(cost) || cost!=cost) + { + cost = std::numeric_limits::infinity(); + // Prevent NaNs. Actually NaNs might be useful for debugging. + p.setConstant(0); + } + }; + // Remember endpoints + pre_collapse = [&v1,&v2]( + const Eigen::MatrixXd & ,/*V*/ + const Eigen::MatrixXi & ,/*F*/ + const Eigen::MatrixXi & E , + const Eigen::VectorXi & ,/*EMAP*/ + const Eigen::MatrixXi & ,/*EF*/ + const Eigen::MatrixXi & ,/*EI*/ + const igl::min_heap< std::tuple > & ,/*Q*/ + const Eigen::VectorXi & ,/*EQ*/ + const Eigen::MatrixXd & ,/*C*/ + const int e)->bool + { + v1 = E(e,0); + v2 = E(e,1); + return true; + }; + // update quadric + post_collapse = [&v1,&v2,&quadrics]( + const Eigen::MatrixXd & , /*V*/ + const Eigen::MatrixXi & , /*F*/ + const Eigen::MatrixXi & , /*E*/ + const Eigen::VectorXi & ,/*EMAP*/ + const Eigen::MatrixXi & , /*EF*/ + const Eigen::MatrixXi & , /*EI*/ + const igl::min_heap< std::tuple > & ,/*Q*/ + const Eigen::VectorXi & ,/*EQ*/ + const Eigen::MatrixXd & , /*C*/ + const int , /*e*/ + const int , /*e1*/ + const int , /*e2*/ + const int , /*f1*/ + const int , /*f2*/ + const bool collapsed + )->void + { + if(collapsed) + { + quadrics[v1 +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_QSLIM_OPTIMAL_COLLAPSE_EDGE_CALLBACKS_H +#define IGL_QSLIM_OPTIMAL_COLLAPSE_EDGE_CALLBACKS_H +#include "igl_inline.h" +#include "decimate_callback_types.h" +#include +#include +#include +#include +#include +namespace igl +{ + // Prepare callbacks for decimating edges using the qslim optimal placement + // metric. + // + // Inputs: + // E #E by 2 list of working edges + // quadrics reference to list of working per vertex quadrics + // v1 working variable to maintain end point of collapsed edge + // v2 working variable to maintain end point of collapsed edge + // Outputs + // cost_and_placement callback for evaluating cost of edge collapse and + // determining placement of vertex (see collapse_edge) + // pre_collapse callback before edge collapse (see collapse_edge) + // post_collapse callback after edge collapse (see collapse_edge) + IGL_INLINE void qslim_optimal_collapse_edge_callbacks( + Eigen::MatrixXi & E, + std::vector > & + quadrics, + int & v1, + int & v2, + decimate_cost_and_placement_callback & cost_and_placement, + decimate_pre_collapse_callback & pre_collapse, + decimate_post_collapse_callback & post_collapse); +} +#ifndef IGL_STATIC_LIBRARY +# include "qslim_optimal_collapse_edge_callbacks.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/quad_grid.cpp b/src/external/libigl-2.3.0/include/igl/quad_grid.cpp new file mode 100644 index 000000000..4aa403461 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/quad_grid.cpp @@ -0,0 +1,97 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2019 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "quad_grid.h" +#include "grid.h" + +template< + typename DerivedV, + typename DerivedQ, + typename DerivedE> +IGL_INLINE void igl::quad_grid( + const int nx, + const int ny, + Eigen::PlainObjectBase & V, + Eigen::PlainObjectBase & Q, + Eigen::PlainObjectBase & E) +{ + grid(Eigen::Vector2i(nx,ny),V); + return igl::quad_grid(nx,ny,Q,E); +} + +template< + typename DerivedQ, + typename DerivedE> +IGL_INLINE void igl::quad_grid( + const int nx, + const int ny, + Eigen::PlainObjectBase & Q, + Eigen::PlainObjectBase & E) +{ + Eigen::MatrixXi I(nx,ny); + Q.resize( (nx-1)*(ny-1),4); + E.resize((nx-1)*ny + (ny-1)*nx,2); + { + int v = 0; + int q = 0; + int e = 0; + // Ordered to match igl::grid + for(int y = 0;y0) + { + E(e,0) = I(x,y); + E(e,1) = I(x,y-1); + e++; + } + // Add a horizontal edge + if(x>0) + { + E(e,0) = I(x,y); + E(e,1) = I(x-1,y); + e++; + } + // Add two triangles + if(x>0 && y>0) + { + // -1,0----0,0 + // | / | + // | / | + // | / | + // | / | + // -1,-1---0,-1 + Q(q,0) = I(x-0,y-0); + Q(q,1) = I(x-1,y-0); + Q(q,2) = I(x-1,y-1); + Q(q,3) = I(x-0,y-1); + q++; + //F(f,2) = I(x-0,y-0); + //F(f,1) = I(x-1,y-0); + //F(f,0) = I(x-1,y-1); + //f++; + //F(f,2) = I(x-0,y-0); + //F(f,1) = I(x-1,y-1); + //F(f,0) = I(x-0,y-1); + //f++; + } + } + } + } +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +template void igl::quad_grid, Eigen::Matrix, Eigen::Matrix >(int, int, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/quad_grid.h b/src/external/libigl-2.3.0/include/igl/quad_grid.h new file mode 100644 index 000000000..db9592e4d --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/quad_grid.h @@ -0,0 +1,50 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2019 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_QUAD_GRID_H +#define IGL_QUAD_GRID_H + +#include +#include + +namespace igl +{ + // Generate a quad mesh over a regular grid. + // + // Inputs: + // nx number of vertices in the x direction + // ny number of vertices in the y direction + // Outputs: + // V nx*ny by 2 list of vertex positions + // Q (nx-1)*(ny-1) by 4 list of quad indices into V + // E (nx-1)*ny+(ny-1)*nx by 2 list of undirected quad edge indices into V + // + // See also: grid, triangulated_grid + template< + typename DerivedV, + typename DerivedQ, + typename DerivedE> + IGL_INLINE void quad_grid( + const int nx, + const int ny, + Eigen::PlainObjectBase & V, + Eigen::PlainObjectBase & Q, + Eigen::PlainObjectBase & E); + template< + typename DerivedQ, + typename DerivedE> + IGL_INLINE void quad_grid( + const int nx, + const int ny, + Eigen::PlainObjectBase & Q, + Eigen::PlainObjectBase & E); +} + +#ifndef IGL_STATIC_LIBRARY +# include "quad_grid.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/quad_planarity.cpp b/src/external/libigl-2.3.0/include/igl/quad_planarity.cpp new file mode 100644 index 000000000..17b67dd12 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/quad_planarity.cpp @@ -0,0 +1,39 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "quad_planarity.h" +#include + +template +IGL_INLINE void igl::quad_planarity( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + Eigen::PlainObjectBase & P) +{ + int nf = F.rows(); + P.setZero(nf,1); + for (int i =0; i &v1 = V.row(F(i,0)); + const Eigen::Matrix &v2 = V.row(F(i,1)); + const Eigen::Matrix &v3 = V.row(F(i,2)); + const Eigen::Matrix &v4 = V.row(F(i,3)); + Eigen::Matrix diagCross=(v3-v1).cross(v4-v2); + typename DerivedV::Scalar denom = + diagCross.norm()*(((v3-v1).norm()+(v4-v2).norm())/2); + if (fabs(denom)<1e-8) + //degenerate quad is still planar + P(i) = 0; + else + P(i) = (diagCross.dot(v2-v1)/denom); + } +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +template void igl::quad_planarity, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/quad_planarity.h b/src/external/libigl-2.3.0/include/igl/quad_planarity.h new file mode 100644 index 000000000..b6a535c7b --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/quad_planarity.h @@ -0,0 +1,32 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_QUAD_PLANARITY_H +#define IGL_QUAD_PLANARITY_H +#include "igl_inline.h" +#include +namespace igl +{ + // Compute planarity of the faces of a quad mesh + // Inputs: + // V #V by 3 eigen Matrix of mesh vertex 3D positions + // F #F by 4 eigen Matrix of face (quad) indices + // Output: + // P #F by 1 eigen Matrix of mesh face (quad) planarities + // + template + IGL_INLINE void quad_planarity( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + Eigen::PlainObjectBase & P); +} + +#ifndef IGL_STATIC_LIBRARY +# include "quad_planarity.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/quadprog.cpp b/src/external/libigl-2.3.0/include/igl/quadprog.cpp new file mode 100644 index 000000000..717b04661 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/quadprog.cpp @@ -0,0 +1,124 @@ +#include "quadprog.h" +#include "min_quad_with_fixed.h" +#include +#include + +template +IGL_INLINE Eigen::Matrix igl::quadprog( + const Eigen::Matrix & H, + const Eigen::Matrix & f, + const Eigen::Matrix & A, + const Eigen::Matrix & b, + const Eigen::Matrix & lb, + const Eigen::Matrix & ub) +{ + // Alec 16/2/2021: + // igl::quadprog implements a very simple primal active set method. The new + // igl::min_quad_with_fixed is very fast for small dense problems so the + // iterations of igl::quadprog become very fast. Even if it ends up doing many + // more iterations than igl::copyleft::quadprog it would be much faster (in + // reality it doesn't do that many more iterations). It's a healthy 10-100x + // faster than igl::copyleft::quadprog for specific cases of QPs. + // + // Unfortunately, that set is limited. igl::quadprog is really good at tiny + // box-constrained QPs with a positive definite objective (like the kind that show + // up in dual contouring). igl::copyleft::quadprog handles more general problems + // (and also starts to beat igl::quadprog when the number of variables gets over + // ~20). I tried extending igl::quadprog so that we could use it for + // igl::copyleft::progressive_hulls and drop igl::copyleft::quadprog but it was + // trickier than I thought. Something like qpmad or the non GPL version of + // quadrog++ would be good future PR. + // + typedef Eigen::Matrix VectorSn; + typedef Eigen::Array Arraybn; + assert( (lb.array() < ub.array() ).all() ); + const int dyn_n = n == Eigen::Dynamic ? H.rows() : n; + VectorSn x(dyn_n); + VectorSn bc = VectorSn::Constant(dyn_n,1,-1e26); + Arraybn k = Arraybn::Constant(dyn_n,1,false); + Eigen::Index iter; + // n³ is probably way too conservative. + for(iter = 0;iter(H,f,k,bc,A,b); + // constraint violations + VectorSn vl = lb-x; + VectorSn vu = x-ub; + + // try to add/remove constraints + Eigen::Index best_add = -1; Scalar worst_offense = 0; + bool add_lower; + Eigen::Index best_remove = -1; Scalar worst_lambda = 0; + for(Eigen::Index i = 0;iworst_offense) + { + best_add = i; + add_lower = true; + worst_offense = vl(i); + } + if(vu(i)>worst_offense) + { + best_add = i; + add_lower = false; + worst_offense = vu(i); + } + // bias toward adding constraints + if(best_add<0 && k(i)) + { + const Scalar sign = bc(i)==ub(i)?1:-1; + const Scalar lambda_i = sign * (H.row(i)*x+f(i)); + if(lambda_i > worst_lambda) + { + best_remove = i; + worst_lambda = lambda_i; + } + } + } + // bias toward adding constraints + if(best_add >= 0) + { + const auto i = best_add; + assert(!k(i)); + bc(i) = add_lower ? lb(i) : ub(i); + k(i) = true; + }else if(best_remove >= 0) + { + const auto i = best_remove; + assert(k(i)); + k(i) = false; + }else /*if(best_add < 0 && best_remove < 0)*/ + { + return x; + } + } + // Should never happen. + assert(false && "quadprog failed after too many iterations"); + return VectorSn::Zero(dyn_n); +} + +template +IGL_INLINE Eigen::Matrix igl::quadprog( + const Eigen::Matrix & H, + const Eigen::Matrix & f, + const Eigen::Matrix & lb, + const Eigen::Matrix & ub) +{ + const int m = n == Eigen::Dynamic ? Eigen::Dynamic : 0; + // Windows needs template parameters spelled out + return quadprog( + H,f, + Eigen::Matrix(0,H.cols()), + Eigen::Matrix(0,1), + lb,ub); +} + + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +template Eigen::Matrix igl::quadprog(Eigen::Matrix const&, Eigen::Matrix const&, Eigen::Matrix const&, Eigen::Matrix const&); +template Eigen::Matrix igl::quadprog(Eigen::Matrix const&, Eigen::Matrix const&, Eigen::Matrix const&, Eigen::Matrix const&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/quadprog.h b/src/external/libigl-2.3.0/include/igl/quadprog.h new file mode 100644 index 000000000..b5818cd17 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/quadprog.h @@ -0,0 +1,87 @@ +#ifndef IGL_QUADPROG_H +#define IGL_QUADPROG_H +#include "igl_inline.h" +#include +namespace igl +{ + // Solve a convex quadratic program. Optimized for small dense problems. + // Still works for Eigen::Dynamic (and then everything needs to be Dynamic). + // + // min_x ½ xᵀ H x + xᵀf + // subject to: + // lbi ≤ Ai x ≤ ubi + // lb ≤ x ≤ u + // + // Templates: + // Scalar (e.g., double) + // n #H or Eigen::Dynamic if not known at compile time + // ni #Ai or Eigen::Dynamic if not known at compile time + // Inputs: + // H #H by #H quadratic coefficients (only lower triangle used) + // f #H linear coefficients + // Ai #Ai by #H list of linear equality constraint coefficients + // lbi #Ai list of linear equality lower bounds + // ubi #Ai list of linear equality upper bounds + // lb #H list of lower bounds + // ub #H list of lower bounds + // Returns #H-long solution x + template + IGL_INLINE Eigen::Matrix quadprog( + const Eigen::Matrix & H, + const Eigen::Matrix & f, + const Eigen::Matrix & Ai, + const Eigen::Matrix & lbi, + const Eigen::Matrix & ubi, + const Eigen::Matrix & lb, + const Eigen::Matrix & ub); + // min_x ½ xᵀ H x + xᵀf + // subject to: + // A x = b + // lb ≤ x ≤ u + // + // Templates: + // Scalar (e.g., double) + // n #H or Eigen::Dynamic if not known at compile time + // m #A or Eigen::Dynamic if not known at compile time + // Inputs: + // H #H by #H quadratic coefficients (only lower triangle used) + // f #H linear coefficients + // A #A by #H list of linear equality constraint coefficients + // b #A list of linear equality lower bounds + // lb #H list of lower bounds + // ub #H list of lower bounds + // Returns #H-long solution x + template + IGL_INLINE Eigen::Matrix quadprog( + const Eigen::Matrix & H, + const Eigen::Matrix & f, + const Eigen::Matrix & A, + const Eigen::Matrix & b, + const Eigen::Matrix & lb, + const Eigen::Matrix & ub); + // min_x ½ xᵀ H x + xᵀf + // subject to: + // lb ≤ x ≤ u + // + // Templates: + // Scalar (e.g., double) + // n #H or Eigen::Dynamic if not known at compile time + // Inputs: + // H #H by #H quadratic coefficients (only lower triangle used) + // f #H linear coefficients + // lb #H list of lower bounds + // ub #H list of lower bounds + // Returns #H-long solution x + template + IGL_INLINE Eigen::Matrix quadprog( + const Eigen::Matrix & H, + const Eigen::Matrix & f, + const Eigen::Matrix & lb, + const Eigen::Matrix & ub); +} + +#ifndef IGL_STATIC_LIBRARY +# include "quadprog.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/quadric_binary_plus_operator.cpp b/src/external/libigl-2.3.0/include/igl/quadric_binary_plus_operator.cpp new file mode 100644 index 000000000..eb3fd695e --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/quadric_binary_plus_operator.cpp @@ -0,0 +1,24 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "quadric_binary_plus_operator.h" + +IGL_INLINE std::tuple< Eigen::MatrixXd, Eigen::RowVectorXd, double> + igl::operator+( + const std::tuple< Eigen::MatrixXd, Eigen::RowVectorXd, double> & a, + const std::tuple< Eigen::MatrixXd, Eigen::RowVectorXd, double> & b) +{ + std::tuple< + Eigen::MatrixXd, + Eigen::RowVectorXd, + double> c; + std::get<0>(c) = (std::get<0>(a) + std::get<0>(b)).eval(); + std::get<1>(c) = (std::get<1>(a) + std::get<1>(b)).eval(); + std::get<2>(c) = (std::get<2>(a) + std::get<2>(b)); + return c; +} + diff --git a/src/external/libigl-2.3.0/include/igl/quadric_binary_plus_operator.h b/src/external/libigl-2.3.0/include/igl/quadric_binary_plus_operator.h new file mode 100644 index 000000000..3c6b845d8 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/quadric_binary_plus_operator.h @@ -0,0 +1,35 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_QUADRIC_BINARY_PLUS_OPERATOR_H +#define IGL_QUADRIC_BINARY_PLUS_OPERATOR_H +#include "igl_inline.h" +#include +#include + +namespace igl +{ + // A binary addition operator for Quadric tuples compatible with qslim, + // computing c = a+b + // + // Inputs: + // a QSlim quadric + // b QSlim quadric + // Output + // c QSlim quadric + // + IGL_INLINE std::tuple< Eigen::MatrixXd, Eigen::RowVectorXd, double> + operator+( + const std::tuple< Eigen::MatrixXd, Eigen::RowVectorXd, double> & a, + const std::tuple< Eigen::MatrixXd, Eigen::RowVectorXd, double> & b); +} + +#ifndef IGL_STATIC_LIBRARY +# include "quadric_binary_plus_operator.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/quat_conjugate.cpp b/src/external/libigl-2.3.0/include/igl/quat_conjugate.cpp new file mode 100644 index 000000000..5856ea72d --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/quat_conjugate.cpp @@ -0,0 +1,27 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "quat_conjugate.h" + +template +IGL_INLINE void igl::quat_conjugate( + const Q_type *q1, + Q_type *out) +{ + out[0] = -q1[0]; + out[1] = -q1[1]; + out[2] = -q1[2]; + out[3] = q1[3]; +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::quat_conjugate(double const*, double*); +// generated by autoexplicit.sh +template void igl::quat_conjugate(float const*, float*); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/quat_conjugate.h b/src/external/libigl-2.3.0/include/igl/quat_conjugate.h new file mode 100644 index 000000000..32ccb3b5b --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/quat_conjugate.h @@ -0,0 +1,32 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_QUAT_CONJUGATE_H +#define IGL_QUAT_CONJUGATE_H +#include "igl_inline.h" + +namespace igl +{ + // Compute conjugate of given quaternion + // http://en.wikipedia.org/wiki/Quaternion#Conjugation.2C_the_norm.2C_and_reciprocal + // A Quaternion, q, is defined here as an arrays of four scalars (x,y,z,w), + // such that q = x*i + y*j + z*k + w + // Inputs: + // q1 input quaternion + // Outputs: + // out result of conjugation, allowed to be same as input + template + IGL_INLINE void quat_conjugate( + const Q_type *q1, + Q_type *out); +}; + +#ifndef IGL_STATIC_LIBRARY +# include "quat_conjugate.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/quat_mult.cpp b/src/external/libigl-2.3.0/include/igl/quat_mult.cpp new file mode 100644 index 000000000..beb7baba5 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/quat_mult.cpp @@ -0,0 +1,34 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "quat_mult.h" + +#include +// http://www.antisphere.com/Wiki/tools:anttweakbar +template +IGL_INLINE void igl::quat_mult( + const Q_type *q1, + const Q_type *q2, + Q_type *out) +{ + // output can't be either of the inputs + assert(q1 != out); + assert(q2 != out); + + out[0] = q1[3]*q2[0] + q1[0]*q2[3] + q1[1]*q2[2] - q1[2]*q2[1]; + out[1] = q1[3]*q2[1] + q1[1]*q2[3] + q1[2]*q2[0] - q1[0]*q2[2]; + out[2] = q1[3]*q2[2] + q1[2]*q2[3] + q1[0]*q2[1] - q1[1]*q2[0]; + out[3] = q1[3]*q2[3] - (q1[0]*q2[0] + q1[1]*q2[1] + q1[2]*q2[2]); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::quat_mult(double const*, double const*, double*); +// generated by autoexplicit.sh +template void igl::quat_mult(float const*, float const*, float*); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/quat_mult.h b/src/external/libigl-2.3.0/include/igl/quat_mult.h new file mode 100644 index 000000000..4a7ba654f --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/quat_mult.h @@ -0,0 +1,33 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_QUAT_MULT_H +#define IGL_QUAT_MULT_H +#include "igl_inline.h" + +namespace igl +{ + // Computes out = q1 * q2 with quaternion multiplication + // A Quaternion, q, is defined here as an arrays of four scalars (x,y,z,w), + // such that q = x*i + y*j + z*k + w + // Inputs: + // q1 left quaternion + // q2 right quaternion + // Outputs: + // out result of multiplication + template + IGL_INLINE void quat_mult( + const Q_type *q1, + const Q_type *q2, + Q_type *out); +}; + +#ifndef IGL_STATIC_LIBRARY +# include "quat_mult.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/quat_to_axis_angle.cpp b/src/external/libigl-2.3.0/include/igl/quat_to_axis_angle.cpp new file mode 100644 index 000000000..1aa59fad6 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/quat_to_axis_angle.cpp @@ -0,0 +1,75 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "quat_to_axis_angle.h" +#include "EPS.h" +#include "PI.h" +#include +#include +// +// http://www.antisphere.com/Wiki/tools:anttweakbar +template +IGL_INLINE void igl::quat_to_axis_angle( + const Q_type *q, + Q_type *axis, + Q_type & angle) +{ + if( fabs(q[3])>(1.0 + igl::EPS()) ) + { + //axis[0] = axis[1] = axis[2] = 0; // no, keep the previous value + angle = 0; + } + else + { + double a; + if( q[3]>=1.0f ) + a = 0; // and keep V + else if( q[3]<=-1.0f ) + a = PI; // and keep V + else if( fabs(q[0]*q[0]+q[1]*q[1]+q[2]*q[2]+q[3]*q[3])()) + { + a = 0; + }else + { + a = acos(q[3]); + if( a*angle<0 ) // Preserve the sign of angle + a = -a; + double f = 1.0f / sin(a); + axis[0] = q[0] * f; + axis[1] = q[1] * f; + axis[2] = q[2] * f; + } + angle = 2.0*a; + } + + // if( angle>FLOAT_PI ) + // angle -= 2.0f*FLOAT_PI; + // else if( angle<-FLOAT_PI ) + // angle += 2.0f*FLOAT_PI; + //angle = RadToDeg(angle); + + if( fabs(angle)()&& fabs(axis[0]*axis[0]+axis[1]*axis[1]+axis[2]*axis[2])()) + { + axis[0] = 1.0e-7; // all components cannot be null + } +} + +template +IGL_INLINE void igl::quat_to_axis_angle_deg( + const Q_type *q, + Q_type *axis, + Q_type & angle) +{ + igl::quat_to_axis_angle(q,axis,angle); + angle = angle*(180.0/PI); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +template void igl::quat_to_axis_angle(float const*, float*, float&); +template void igl::quat_to_axis_angle_deg(float const*, float*, float&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/quat_to_axis_angle.h b/src/external/libigl-2.3.0/include/igl/quat_to_axis_angle.h new file mode 100644 index 000000000..77ea10e5c --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/quat_to_axis_angle.h @@ -0,0 +1,40 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_QUAT_TO_AXIS_ANGLE_H +#define IGL_QUAT_TO_AXIS_ANGLE_H +#include "igl_inline.h" + +namespace igl +{ + // Convert quat representation of a rotation to axis angle + // A Quaternion, q, is defined here as an arrays of four scalars (x,y,z,w), + // such that q = x*i + y*j + z*k + w + // Inputs: + // q quaternion + // Outputs: + // axis 3d vector + // angle scalar in radians + template + IGL_INLINE void quat_to_axis_angle( + const Q_type *q, + Q_type *axis, + Q_type & angle); + // Wrapper with angle in degrees + template + IGL_INLINE void quat_to_axis_angle_deg( + const Q_type *q, + Q_type *axis, + Q_type & angle); +} + +#ifndef IGL_STATIC_LIBRARY +# include "quat_to_axis_angle.cpp" +#endif + +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/quat_to_mat.cpp b/src/external/libigl-2.3.0/include/igl/quat_to_mat.cpp new file mode 100644 index 000000000..22ec07b94 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/quat_to_mat.cpp @@ -0,0 +1,44 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "quat_to_mat.h" + +template +IGL_INLINE void igl::quat_to_mat(const Q_type * quat, Q_type * mat) +{ + Q_type yy2 = 2.0f * quat[1] * quat[1]; + Q_type xy2 = 2.0f * quat[0] * quat[1]; + Q_type xz2 = 2.0f * quat[0] * quat[2]; + Q_type yz2 = 2.0f * quat[1] * quat[2]; + Q_type zz2 = 2.0f * quat[2] * quat[2]; + Q_type wz2 = 2.0f * quat[3] * quat[2]; + Q_type wy2 = 2.0f * quat[3] * quat[1]; + Q_type wx2 = 2.0f * quat[3] * quat[0]; + Q_type xx2 = 2.0f * quat[0] * quat[0]; + mat[0*4+0] = - yy2 - zz2 + 1.0f; + mat[0*4+1] = xy2 + wz2; + mat[0*4+2] = xz2 - wy2; + mat[0*4+3] = 0; + mat[1*4+0] = xy2 - wz2; + mat[1*4+1] = - xx2 - zz2 + 1.0f; + mat[1*4+2] = yz2 + wx2; + mat[1*4+3] = 0; + mat[2*4+0] = xz2 + wy2; + mat[2*4+1] = yz2 - wx2; + mat[2*4+2] = - xx2 - yy2 + 1.0f; + mat[2*4+3] = 0; + mat[3*4+0] = mat[3*4+1] = mat[3*4+2] = 0; + mat[3*4+3] = 1; +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::quat_to_mat(double const*, double*); +// generated by autoexplicit.sh +template void igl::quat_to_mat(float const*, float*); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/quat_to_mat.h b/src/external/libigl-2.3.0/include/igl/quat_to_mat.h new file mode 100644 index 000000000..4291b291e --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/quat_to_mat.h @@ -0,0 +1,30 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_QUAT_TO_MAT_H +#define IGL_QUAT_TO_MAT_H +#include "igl_inline.h" +// Name history: +// quat2mat until 16 Sept 2011 +namespace igl +{ + // Convert a quaternion to a 4x4 matrix + // A Quaternion, q, is defined here as an arrays of four scalars (x,y,z,w), + // such that q = x*i + y*j + z*k + w + // Input: + // quat pointer to four elements of quaternion (x,y,z,w) + // Output: + // mat pointer to 16 elements of matrix + template + IGL_INLINE void quat_to_mat(const Q_type * quat, Q_type * mat); +} + +#ifndef IGL_STATIC_LIBRARY +# include "quat_to_mat.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/quats_to_column.cpp b/src/external/libigl-2.3.0/include/igl/quats_to_column.cpp new file mode 100644 index 000000000..a4a88a666 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/quats_to_column.cpp @@ -0,0 +1,33 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "quats_to_column.h" + +IGL_INLINE void igl::quats_to_column( + const std::vector< + Eigen::Quaterniond,Eigen::aligned_allocator > vQ, + Eigen::VectorXd & Q) +{ + Q.resize(vQ.size()*4); + for(int q = 0;q<(int)vQ.size();q++) + { + auto & xyzw = vQ[q].coeffs(); + for(int c = 0;c<4;c++) + { + Q(q*4+c) = xyzw(c); + } + } +} + +IGL_INLINE Eigen::VectorXd igl::quats_to_column( + const std::vector< + Eigen::Quaterniond,Eigen::aligned_allocator > vQ) +{ + Eigen::VectorXd Q; + quats_to_column(vQ,Q); + return Q; +} diff --git a/src/external/libigl-2.3.0/include/igl/quats_to_column.h b/src/external/libigl-2.3.0/include/igl/quats_to_column.h new file mode 100644 index 000000000..4a7795ae1 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/quats_to_column.h @@ -0,0 +1,37 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_QUATS_TO_COLUMN_H +#define IGL_QUATS_TO_COLUMN_H +#include "igl_inline.h" +#include +#include +#include +#include +namespace igl +{ + // "Columnize" a list of quaternions (q1x,q1y,q1z,q1w,q2x,q2y,q2z,q2w,...) + // + // Inputs: + // vQ n-long list of quaternions + // Outputs: + // Q n*4-long list of coefficients + IGL_INLINE void quats_to_column( + const std::vector< + Eigen::Quaterniond,Eigen::aligned_allocator > vQ, + Eigen::VectorXd & Q); + IGL_INLINE Eigen::VectorXd quats_to_column( + const std::vector< + Eigen::Quaterniond,Eigen::aligned_allocator > vQ); +} + +#ifndef IGL_STATIC_LIBRARY +# include "quats_to_column.cpp" +#endif + +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/ramer_douglas_peucker.cpp b/src/external/libigl-2.3.0/include/igl/ramer_douglas_peucker.cpp new file mode 100644 index 000000000..4f09a1bea --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/ramer_douglas_peucker.cpp @@ -0,0 +1,150 @@ +#include "ramer_douglas_peucker.h" + +#include "LinSpaced.h" +#include "find.h" +#include "cumsum.h" +#include "histc.h" +#include "slice.h" +#include "project_to_line.h" +#include "EPS.h" +#include "slice_mask.h" + +template +IGL_INLINE void igl::ramer_douglas_peucker( + const Eigen::MatrixBase & P, + const typename DerivedP::Scalar tol, + Eigen::PlainObjectBase & S, + Eigen::PlainObjectBase & J) +{ + typedef typename DerivedP::Scalar Scalar; + // number of vertices + const int n = P.rows(); + // Trivial base case + if(n <= 1) + { + J = DerivedJ::Zero(n); + S = P; + return; + } + // number of dimensions + const int m = P.cols(); + Eigen::Array I = + Eigen::Array::Constant(n,1,true); + const auto stol = tol*tol; + std::function simplify; + simplify = [&I,&P,&stol,&simplify](const int ixs, const int ixe)->void + { + assert(ixe>ixs); + Scalar sdmax = 0; + typename Eigen::Matrix::Index ixc = -1; + if((ixe-ixs)>1) + { + Scalar sdes = (P.row(ixe)-P.row(ixs)).squaredNorm(); + Eigen::Matrix sD; + const auto & Pblock = P.block(ixs+1,0,((ixe+1)-ixs)-2,P.cols()); + if(sdes<=EPS()) + { + sD = (Pblock.rowwise()-P.row(ixs)).rowwise().squaredNorm(); + }else + { + Eigen::Matrix T; + project_to_line(Pblock,P.row(ixs).eval(),P.row(ixe).eval(),T,sD); + } + sdmax = sD.maxCoeff(&ixc); + // Index full P + ixc = ixc+(ixs+1); + } + if(sdmax <= stol) + { + if(ixs != ixe-1) + { + I.block(ixs+1,0,((ixe+1)-ixs)-2,1).setConstant(false); + } + }else + { + simplify(ixs,ixc); + simplify(ixc,ixe); + } + }; + simplify(0,n-1); + slice_mask(P,I,1,S); + find(I,J); +} + +template < + typename DerivedP, + typename DerivedS, + typename DerivedJ, + typename DerivedQ> +IGL_INLINE void igl::ramer_douglas_peucker( + const Eigen::MatrixBase & P, + const typename DerivedP::Scalar tol, + Eigen::PlainObjectBase & S, + Eigen::PlainObjectBase & J, + Eigen::PlainObjectBase & Q) +{ + typedef typename DerivedP::Scalar Scalar; + ramer_douglas_peucker(P,tol,S,J); + const int n = P.rows(); + assert(n>=2 && "Curve should be at least 2 points"); + typedef Eigen::Matrix VectorXS; + // distance traveled along high-res curve + VectorXS L(n); + L(0) = 0; + L.block(1,0,n-1,1) = (P.bottomRows(n-1)-P.topRows(n-1)).rowwise().norm(); + // Give extra on end + VectorXS T; + cumsum(L,1,T); + T.conservativeResize(T.size()+1); + T(T.size()-1) = T(T.size()-2); + // index of coarse point before each fine vertex + Eigen::VectorXi B; + { + Eigen::VectorXi N; + histc(igl::LinSpaced(n,0,n-1),J,N,B); + } + // Add extra point at end + J.conservativeResize(J.size()+1); + J(J.size()-1) = J(J.size()-2); + Eigen::VectorXi s,d; + // Find index in original list of "start" vertices + slice(J,B,s); + // Find index in original list of "destination" vertices + slice(J,(B.array()+1).matrix().eval(),d); + // Parameter between start and destination is linear in arc-length + VectorXS Ts,Td; + slice(T,s,Ts); + slice(T,d,Td); + T = ((T.head(T.size()-1)-Ts).array()/(Td-Ts).array()).eval(); + for(int t =0;t= S.rows()) + { + MB(b) = S.rows()-1; + } + } + DerivedS SMB; + slice(S,MB,1,SMB); + Q = SB.array() + ((SMB.array()-SB.array()).colwise()*T.array()); + + // Remove extra point at end + J.conservativeResize(J.size()-1); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::ramer_douglas_peucker, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::Matrix::Scalar, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::ramer_douglas_peucker, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::Matrix::Scalar, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/ramer_douglas_peucker.h b/src/external/libigl-2.3.0/include/igl/ramer_douglas_peucker.h new file mode 100644 index 000000000..dcfe47e85 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/ramer_douglas_peucker.h @@ -0,0 +1,49 @@ +#ifndef IGL_RAMER_DOUGLAS_PEUCKER_H +#define IGL_RAMER_DOUGLAS_PEUCKER_H +#include "igl_inline.h" +#include +namespace igl +{ + // Ramer-Douglas-Peucker piecewise-linear curve simplification. + // + // Inputs: + // P #P by dim ordered list of vertices along the curve + // tol tolerance (maximal euclidean distance allowed between the new line + // and a vertex) + // Outputs: + // S #S by dim ordered list of points along the curve + // J #S list of indices into P so that S = P(J,:) + template + IGL_INLINE void ramer_douglas_peucker( + const Eigen::MatrixBase & P, + const typename DerivedP::Scalar tol, + Eigen::PlainObjectBase & S, + Eigen::PlainObjectBase & J); + // Run (Ramer-)Duglass-Peucker curve simplification but keep track of where + // every point on the original curve maps to on the simplified curve. + // + // Inputs: + // P #P by dim list of points, (use P([1:end 1],:) for loops) + // tol DP tolerance + // Outputs: + // S #S by dim list of points along simplified curve + // J #S indices into P of simplified points + // Q #P by dim list of points mapping along simplified curve + // + template < + typename DerivedP, + typename DerivedS, + typename DerivedJ, + typename DerivedQ> + IGL_INLINE void ramer_douglas_peucker( + const Eigen::MatrixBase & P, + const typename DerivedP::Scalar tol, + Eigen::PlainObjectBase & S, + Eigen::PlainObjectBase & J, + Eigen::PlainObjectBase & Q); + +} +#ifndef IGL_STATIC_LIBRARY +# include "ramer_douglas_peucker.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/random_dir.cpp b/src/external/libigl-2.3.0/include/igl/random_dir.cpp new file mode 100644 index 000000000..f30783418 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/random_dir.cpp @@ -0,0 +1,52 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "random_dir.h" +#include +#include + +IGL_INLINE Eigen::Vector3d igl::random_dir() +{ + using namespace Eigen; + double z = (double)rand() / (double)RAND_MAX*2.0 - 1.0; + double t = (double)rand() / (double)RAND_MAX*2.0*PI; + // http://www.altdevblogaday.com/2012/05/03/generating-uniformly-distributed-points-on-sphere/ + double r = sqrt(1.0-z*z); + double x = r * cos(t); + double y = r * sin(t); + return Vector3d(x,y,z); +} + +IGL_INLINE Eigen::MatrixXd igl::random_dir_stratified(const int n) +{ + using namespace Eigen; + using namespace std; + const double m = std::floor(sqrt(double(n))); + MatrixXd N(n,3); + int row = 0; + for(int i = 0;i +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_RANDOM_DIR_H +#define IGL_RANDOM_DIR_H +#include "igl_inline.h" + +#include + +namespace igl +{ + // Generate a uniformly random unit direction in 3D, return as vector + IGL_INLINE Eigen::Vector3d random_dir(); + // Generate n stratified uniformly random unit directions in 3d, return as rows + // of an n by 3 matrix + // + // Inputs: + // n number of directions + // Return n by 3 matrix of random directions + IGL_INLINE Eigen::MatrixXd random_dir_stratified(const int n); +} + +#ifndef IGL_STATIC_LIBRARY +# include "random_dir.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/random_points_on_mesh.cpp b/src/external/libigl-2.3.0/include/igl/random_points_on_mesh.cpp new file mode 100644 index 000000000..de552e606 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/random_points_on_mesh.cpp @@ -0,0 +1,120 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "random_points_on_mesh.h" +#include "doublearea.h" +#include "cumsum.h" +#include "histc.h" +#include +#include + +template +IGL_INLINE void igl::random_points_on_mesh( + const int n, + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + Eigen::PlainObjectBase & B, + Eigen::PlainObjectBase & FI) +{ + using namespace Eigen; + using namespace std; + typedef typename DerivedV::Scalar Scalar; + typedef Matrix VectorXs; + VectorXs A; + doublearea(V,F,A); + // Should be traingle mesh. Although Turk's method 1 generalizes... + assert(F.cols() == 3); + VectorXs C; + VectorXs A0(A.size()+1); + A0(0) = 0; + A0.bottomRightCorner(A.size(),1) = A; + // Even faster would be to use the "Alias Table Method" + cumsum(A0,1,C); + const Scalar Cmax = C(C.size()-1); + assert(Cmax > 0 && "Total surface area should be positive"); + // Why is this more accurate than `C /= C(C.size()-1)` ? + for(int i = 0;i= 0); + assert(R.maxCoeff() <= 1); + histc(R,C,FI); + FI = FI.array().min(F.rows() - 1); // fix the bin when R(i) == 1 exactly + const VectorXs S = (VectorXs::Random(n,1).array() + 1.)/2.; + const VectorXs T = (VectorXs::Random(n,1).array() + 1.)/2.; + B.resize(n,3); + B.col(0) = 1.-T.array().sqrt(); + B.col(1) = (1.-S.array()) * T.array().sqrt(); + B.col(2) = S.array() * T.array().sqrt(); +} + +template < + typename DerivedV, + typename DerivedF, + typename DerivedB, + typename DerivedFI, + typename DerivedX> +IGL_INLINE void igl::random_points_on_mesh( + const int n, + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + Eigen::PlainObjectBase & B, + Eigen::PlainObjectBase & FI, + Eigen::PlainObjectBase & X) +{ + random_points_on_mesh(n,V,F,B,FI); + X = DerivedX::Zero(B.rows(),V.cols()); + for(int x = 0;x +IGL_INLINE void igl::random_points_on_mesh( + const int n, + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + Eigen::SparseMatrix & B, + Eigen::PlainObjectBase & FI) +{ + using namespace Eigen; + using namespace std; + Matrix BC; + random_points_on_mesh(n,V,F,BC,FI); + vector > BIJV; + BIJV.reserve(n*3); + for(int s = 0;s= 0); + const int v = F(FI(s),c); + BIJV.push_back(Triplet(s,v,BC(s,c))); + } + } + B.resize(n,V.rows()); + B.reserve(n*3); + B.setFromTriplets(BIJV.begin(),BIJV.end()); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::random_points_on_mesh, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(int, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::random_points_on_mesh, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(int, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::random_points_on_mesh, Eigen::Matrix, float, Eigen::Matrix >(int, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::SparseMatrix&, Eigen::PlainObjectBase >&); +template void igl::random_points_on_mesh, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(int, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::random_points_on_mesh, Eigen::Matrix, double, Eigen::Matrix >(int, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::SparseMatrix&, Eigen::PlainObjectBase >&); +template void igl::random_points_on_mesh, Eigen::Matrix, double, Eigen::Matrix >(int, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::SparseMatrix&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/random_points_on_mesh.h b/src/external/libigl-2.3.0/include/igl/random_points_on_mesh.h new file mode 100644 index 000000000..b3e96d4c9 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/random_points_on_mesh.h @@ -0,0 +1,65 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_RANDOM_POINTS_ON_MESH_H +#define IGL_RANDOM_POINTS_ON_MESH_H + +#include "igl_inline.h" +#include +#include + +namespace igl +{ + // RANDOM_POINTS_ON_MESH Randomly sample a mesh (V,F) n times. + // + // Inputs: + // n number of samples + // V #V by dim list of mesh vertex positions + // F #F by 3 list of mesh triangle indices + // Outputs: + // B n by 3 list of barycentric coordinates, ith row are coordinates of + // ith sampled point in face FI(i) + // FI n list of indices into F + // + template + IGL_INLINE void random_points_on_mesh( + const int n, + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + Eigen::PlainObjectBase & B, + Eigen::PlainObjectBase & FI); + // Outputs: + // X n by dim list of sample positions. + template < + typename DerivedV, + typename DerivedF, + typename DerivedB, + typename DerivedFI, + typename DerivedX> + IGL_INLINE void random_points_on_mesh( + const int n, + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + Eigen::PlainObjectBase & B, + Eigen::PlainObjectBase & FI, + Eigen::PlainObjectBase & X); + // Outputs: + // B n by #V sparse matrix so that B*V produces a list of sample points + template + IGL_INLINE void random_points_on_mesh( + const int n, + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + Eigen::SparseMatrix & B, + Eigen::PlainObjectBase & FI); +} + +#ifndef IGL_STATIC_LIBRARY +# include "random_points_on_mesh.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/random_quaternion.cpp b/src/external/libigl-2.3.0/include/igl/random_quaternion.cpp new file mode 100644 index 000000000..2d042e33f --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/random_quaternion.cpp @@ -0,0 +1,84 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "random_quaternion.h" +#include "PI.h" + +template +IGL_INLINE Eigen::Quaternion igl::random_quaternion() +{ + const auto & unit_rand = []()->Scalar + { + return ((Scalar)rand() / (Scalar)RAND_MAX); + }; +#ifdef false + // http://mathproofs.blogspot.com/2005/05/uniformly-distributed-random-unit.html + const Scalar t0 = 2.*igl::PI*unit_rand(); + const Scalar t1 = acos(1.-2.*unit_rand()); + const Scalar t2 = 0.5*(igl::PI*unit_rand() + acos(unit_rand())); + return Eigen::Quaternion( + 1.*sin(t0)*sin(t1)*sin(t2), + 1.*cos(t0)*sin(t1)*sin(t2), + 1.*cos(t1)*sin(t2), + 1.*cos(t2)); +#elif false + // "Uniform Random Rotations" [Shoemake 1992] method 1 + const auto & uurand = [&unit_rand]()->Scalar + { + return unit_rand()*2.-1.; + }; + Scalar x = uurand(); + Scalar y = uurand(); + Scalar z = uurand(); + Scalar w = uurand(); + const auto & hype = [&uurand](Scalar & x, Scalar & y)->Scalar + { + Scalar s1; + while((s1 = x*x + y*y) > 1.0) + { + x = uurand(); + y = uurand(); + } + return s1; + }; + Scalar s1 = hype(x,y); + Scalar s2 = hype(z,w); + Scalar num1 = -2.*log(s1); + Scalar num2 = -2.*log(s2); + Scalar r = num1 + num2; + Scalar root1 = sqrt((num1/s1)/r); + Scalar root2 = sqrt((num2/s2)/r); + return Eigen::Quaternion( + x*root1, + y*root1, + z*root2, + w*root2); +#else + // Shoemake method 2 + const Scalar x0 = unit_rand(); + const Scalar x1 = unit_rand(); + const Scalar x2 = unit_rand(); + const Scalar r1 = sqrt(1.0 - x0); + const Scalar r2 = sqrt(x0); + const Scalar t1 = 2.*igl::PI*x1; + const Scalar t2 = 2.*igl::PI*x2; + const Scalar c1 = cos(t1); + const Scalar s1 = sin(t1); + const Scalar c2 = cos(t2); + const Scalar s2 = sin(t2); + return Eigen::Quaternion( + s1*r1, + c1*r1, + s2*r2, + c2*r2); +#endif +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +template Eigen::Quaternion igl::random_quaternion(); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/random_quaternion.h b/src/external/libigl-2.3.0/include/igl/random_quaternion.h new file mode 100644 index 000000000..dfa36022b --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/random_quaternion.h @@ -0,0 +1,21 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_RANDOM_QUATERNION_H +#define IGL_RANDOM_QUATERNION_H +#include "igl_inline.h" +#include +namespace igl +{ + // Return a random quaternion via uniform sampling of the 4-sphere + template + IGL_INLINE Eigen::Quaternion random_quaternion(); +} +#ifndef IGL_STATIC_LIBRARY +#include "random_quaternion.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/random_search.cpp b/src/external/libigl-2.3.0/include/igl/random_search.cpp new file mode 100644 index 000000000..d248d73e6 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/random_search.cpp @@ -0,0 +1,36 @@ +#include "random_search.h" +#include +#include + +template < + typename Scalar, + typename DerivedX, + typename DerivedLB, + typename DerivedUB> +IGL_INLINE Scalar igl::random_search( + const std::function< Scalar (DerivedX &) > f, + const Eigen::MatrixBase & LB, + const Eigen::MatrixBase & UB, + const int iters, + DerivedX & X) +{ + Scalar min_f = std::numeric_limits::max(); + const int dim = LB.size(); + assert(UB.size() == dim && "UB should match LB size"); + for(int iter = 0;iter, Eigen::Matrix, Eigen::Matrix >(std::function&)>, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, int, Eigen::Matrix&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/random_search.h b/src/external/libigl-2.3.0/include/igl/random_search.h new file mode 100644 index 000000000..8573e88cf --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/random_search.h @@ -0,0 +1,42 @@ +#ifndef IGL_RANDOM_SEARCH_H +#define IGL_RANDOM_SEARCH_H +#include "igl_inline.h" +#include +#include +namespace igl +{ + // Solve the problem: + // + // minimize f(x) + // subject to lb ≤ x ≤ ub + // + // by uniform random search. + // + // Inputs: + // f function to minimize + // LB #X vector of finite lower bounds + // UB #X vector of finite upper bounds + // iters number of iterations + // Outputs: + // X #X optimal parameter vector + // Returns f(X) + // + template < + typename Scalar, + typename DerivedX, + typename DerivedLB, + typename DerivedUB> + IGL_INLINE Scalar random_search( + const std::function< Scalar (DerivedX &) > f, + const Eigen::MatrixBase & LB, + const Eigen::MatrixBase & UB, + const int iters, + DerivedX & X); +} + +#ifndef IGL_STATIC_LIBRARY +# include "random_search.cpp" +#endif + +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/randperm.cpp b/src/external/libigl-2.3.0/include/igl/randperm.cpp new file mode 100644 index 000000000..3c9ac266c --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/randperm.cpp @@ -0,0 +1,73 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "randperm.h" +#include "colon.h" +#include + +template +IGL_INLINE void igl::randperm( + const int n, + Eigen::PlainObjectBase & I, + URBG && urbg) +{ + Eigen::VectorXi II; + igl::colon(0,1,n-1,II); + I = II; + + std::shuffle(I.data(),I.data()+n, urbg); +} + +template +IGL_INLINE void igl::randperm( + const int n, + Eigen::PlainObjectBase & I) +{ + return igl::randperm(n, I, std::minstd_rand(std::rand())); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +template void igl::randperm, std::minstd_rand0>(int, Eigen::PlainObjectBase >&, std::minstd_rand0 &&); +template void igl::randperm, std::minstd_rand0 &>(int, Eigen::PlainObjectBase >&, std::minstd_rand0 &); +template void igl::randperm, std::minstd_rand0>(int, Eigen::PlainObjectBase >&, std::minstd_rand0 &&); +template void igl::randperm, std::minstd_rand0 &>(int, Eigen::PlainObjectBase >&, std::minstd_rand0 &); +template void igl::randperm, std::minstd_rand>(int, Eigen::PlainObjectBase >&, std::minstd_rand &&); +template void igl::randperm, std::minstd_rand &>(int, Eigen::PlainObjectBase >&, std::minstd_rand &); +template void igl::randperm, std::minstd_rand>(int, Eigen::PlainObjectBase >&, std::minstd_rand &&); +template void igl::randperm, std::minstd_rand &>(int, Eigen::PlainObjectBase >&, std::minstd_rand &); +template void igl::randperm, std::mt19937>(int, Eigen::PlainObjectBase >&, std::mt19937 &&); +template void igl::randperm, std::mt19937 &>(int, Eigen::PlainObjectBase >&, std::mt19937 &); +template void igl::randperm, std::mt19937>(int, Eigen::PlainObjectBase >&, std::mt19937 &&); +template void igl::randperm, std::mt19937 &>(int, Eigen::PlainObjectBase >&, std::mt19937 &); +template void igl::randperm, std::mt19937_64>(int, Eigen::PlainObjectBase >&, std::mt19937_64 &&); +template void igl::randperm, std::mt19937_64 &>(int, Eigen::PlainObjectBase >&, std::mt19937_64 &); +template void igl::randperm, std::mt19937_64>(int, Eigen::PlainObjectBase >&, std::mt19937_64 &&); +template void igl::randperm, std::mt19937_64 &>(int, Eigen::PlainObjectBase >&, std::mt19937_64 &); +template void igl::randperm, std::ranlux24_base>(int, Eigen::PlainObjectBase >&, std::ranlux24_base &&); +template void igl::randperm, std::ranlux24_base &>(int, Eigen::PlainObjectBase >&, std::ranlux24_base &); +template void igl::randperm, std::ranlux24_base>(int, Eigen::PlainObjectBase >&, std::ranlux24_base &&); +template void igl::randperm, std::ranlux24_base &>(int, Eigen::PlainObjectBase >&, std::ranlux24_base &); +template void igl::randperm, std::ranlux48_base>(int, Eigen::PlainObjectBase >&, std::ranlux48_base &&); +template void igl::randperm, std::ranlux48_base &>(int, Eigen::PlainObjectBase >&, std::ranlux48_base &); +template void igl::randperm, std::ranlux48_base>(int, Eigen::PlainObjectBase >&, std::ranlux48_base &&); +template void igl::randperm, std::ranlux48_base &>(int, Eigen::PlainObjectBase >&, std::ranlux48_base &); +template void igl::randperm, std::ranlux24>(int, Eigen::PlainObjectBase >&, std::ranlux24 &&); +template void igl::randperm, std::ranlux24 &>(int, Eigen::PlainObjectBase >&, std::ranlux24 &); +template void igl::randperm, std::ranlux24>(int, Eigen::PlainObjectBase >&, std::ranlux24 &&); +template void igl::randperm, std::ranlux24 &>(int, Eigen::PlainObjectBase >&, std::ranlux24 &); +template void igl::randperm, std::ranlux48>(int, Eigen::PlainObjectBase >&, std::ranlux48 &&); +template void igl::randperm, std::ranlux48 &>(int, Eigen::PlainObjectBase >&, std::ranlux48 &); +template void igl::randperm, std::ranlux48>(int, Eigen::PlainObjectBase >&, std::ranlux48 &&); +template void igl::randperm, std::ranlux48 &>(int, Eigen::PlainObjectBase >&, std::ranlux48 &); +template void igl::randperm, std::knuth_b>(int, Eigen::PlainObjectBase >&, std::knuth_b &&); +template void igl::randperm, std::knuth_b &>(int, Eigen::PlainObjectBase >&, std::knuth_b &); +template void igl::randperm, std::knuth_b>(int, Eigen::PlainObjectBase >&, std::knuth_b &&); +template void igl::randperm, std::knuth_b &>(int, Eigen::PlainObjectBase >&, std::knuth_b &); +template void igl::randperm>(int, Eigen::PlainObjectBase >&); +template void igl::randperm>(int, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/randperm.h b/src/external/libigl-2.3.0/include/igl/randperm.h new file mode 100644 index 000000000..30c2ba489 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/randperm.h @@ -0,0 +1,39 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_RANDPERM_H +#define IGL_RANDPERM_H +#include "igl_inline.h" +#include +#include +namespace igl +{ + // Like matlab's randperm(n) but minus 1 + // + // When urbg is not specified, randperm will use default random bit generator + // std::minstd_rand initialized with random seed generated by std::rand() + // + // Inputs: + // n number of elements + // urbg An instance of UnformRandomBitGenerator. + // Outputs: + // I n list of rand permutation of 0:n-1 + template + IGL_INLINE void randperm( + const int n, + Eigen::PlainObjectBase & I, + URBG && urbg); + + template + IGL_INLINE void randperm( + const int n, + Eigen::PlainObjectBase & I); +} +#ifndef IGL_STATIC_LIBRARY +# include "randperm.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/ray_box_intersect.cpp b/src/external/libigl-2.3.0/include/igl/ray_box_intersect.cpp new file mode 100644 index 000000000..95a9daaa7 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/ray_box_intersect.cpp @@ -0,0 +1,150 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "ray_box_intersect.h" +#include + +template < + typename Derivedsource, + typename Deriveddir, + typename Scalar> +IGL_INLINE bool igl::ray_box_intersect( + const Eigen::MatrixBase & origin, + const Eigen::MatrixBase & dir, + const Eigen::AlignedBox & box, + const Scalar & t0, + const Scalar & t1, + Scalar & tmin, + Scalar & tmax) +{ +#ifdef false + // https://github.com/RMonica/basic_next_best_view/blob/master/src/RayTracer.cpp + const auto & intersectRayBox = []( + const Eigen::Vector3f& rayo, + const Eigen::Vector3f& rayd, + const Eigen::Vector3f& bmin, + const Eigen::Vector3f& bmax, + float & tnear, + float & tfar + )->bool + { + Eigen::Vector3f bnear; + Eigen::Vector3f bfar; + // Checks for intersection testing on each direction coordinate + // Computes + float t1, t2; + tnear = -1e+6f, tfar = 1e+6f; //, tCube; + bool intersectFlag = true; + for (int i = 0; i < 3; ++i) { + // std::cout << "coordinate " << i << ": bmin " << bmin(i) << ", bmax " << bmax(i) << std::endl; + assert(bmin(i) <= bmax(i)); + if (::fabs(rayd(i)) < 1e-6) { // Ray parallel to axis i-th + if (rayo(i) < bmin(i) || rayo(i) > bmax(i)) { + intersectFlag = false; + } + } + else { + // Finds the nearest and the farthest vertices of the box from the ray origin + if (::fabs(bmin(i) - rayo(i)) < ::fabs(bmax(i) - rayo(i))) { + bnear(i) = bmin(i); + bfar(i) = bmax(i); + } + else { + bnear(i) = bmax(i); + bfar(i) = bmin(i); + } + // std::cout << " bnear " << bnear(i) << ", bfar " << bfar(i) << std::endl; + // Finds the distance parameters t1 and t2 of the two ray-box intersections: + // t1 must be the closest to the ray origin rayo. + t1 = (bnear(i) - rayo(i)) / rayd(i); + t2 = (bfar(i) - rayo(i)) / rayd(i); + if (t1 > t2) { + std::swap(t1,t2); + } + // The two intersection values are used to saturate tnear and tfar + if (t1 > tnear) { + tnear = t1; + } + if (t2 < tfar) { + tfar = t2; + } + // std::cout << " t1 " << t1 << ", t2 " << t2 << ", tnear " << tnear << ", tfar " << tfar + // << " tnear > tfar? " << (tnear > tfar) << ", tfar < 0? " << (tfar < 0) << std::endl; + if(tnear > tfar) { + intersectFlag = false; + } + if(tfar < 0) { + intersectFlag = false; + } + } + } + // Checks whether intersection occurs or not + return intersectFlag; + }; + float tmin_f, tmax_f; + bool ret = intersectRayBox( + origin. template cast(), + dir. template cast(), + box.min().template cast(), + box.max().template cast(), + tmin_f, + tmax_f); + tmin = tmin_f; + tmax = tmax_f; + return ret; +#else + using namespace Eigen; + // This should be precomputed and provided as input + typedef Matrix RowVector3S; + const RowVector3S inv_dir( 1./dir(0),1./dir(1),1./dir(2)); + const std::array sign = { inv_dir(0)<0, inv_dir(1)<0, inv_dir(2)<0}; + // http://people.csail.mit.edu/amy/papers/box-jgt.pdf + // "An Efficient and Robust Ray–Box Intersection Algorithm" + Scalar tymin, tymax, tzmin, tzmax; + std::array bounds = {box.min(),box.max()}; + tmin = ( bounds[sign[0]](0) - origin(0)) * inv_dir(0); + tmax = ( bounds[1-sign[0]](0) - origin(0)) * inv_dir(0); + tymin = (bounds[sign[1]](1) - origin(1)) * inv_dir(1); + tymax = (bounds[1-sign[1]](1) - origin(1)) * inv_dir(1); + if ( (tmin > tymax) || (tymin > tmax) ) + { + return false; + } + if (tymin > tmin) + { + tmin = tymin; + } + if (tymax < tmax) + { + tmax = tymax; + } + tzmin = (bounds[sign[2]](2) - origin(2)) * inv_dir(2); + tzmax = (bounds[1-sign[2]](2) - origin(2)) * inv_dir(2); + if ( (tmin > tzmax) || (tzmin > tmax) ) + { + return false; + } + if (tzmin > tmin) + { + tmin = tzmin; + } + if (tzmax < tmax) + { + tmax = tzmax; + } + if(!( (tmin < t1) && (tmax > t0) )) + { + return false; + } + return true; +#endif +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +template bool igl::ray_box_intersect, Eigen::Matrix, double>(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::AlignedBox const&, double const&, double const&, double&, double&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/ray_box_intersect.h b/src/external/libigl-2.3.0/include/igl/ray_box_intersect.h new file mode 100644 index 000000000..6b6e14aaa --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/ray_box_intersect.h @@ -0,0 +1,44 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_RAY_BOX_INTERSECT_H +#define IGL_RAY_BOX_INTERSECT_H +#include "igl_inline.h" +#include +#include +namespace igl +{ + // Determine whether a ray origin+t*dir and box intersect within the ray's parameterized + // range (t0,t1) + // + // Inputs: + // source 3-vector origin of ray + // dir 3-vector direction of ray + // box axis aligned box + // t0 hit only if hit.t less than t0 + // t1 hit only if hit.t greater than t1 + // Outputs: + // tmin minimum of interval of overlap within [t0,t1] + // tmax maximum of interval of overlap within [t0,t1] + // Returns true if hit + template < + typename Derivedsource, + typename Deriveddir, + typename Scalar> + IGL_INLINE bool ray_box_intersect( + const Eigen::MatrixBase & source, + const Eigen::MatrixBase & dir, + const Eigen::AlignedBox & box, + const Scalar & t0, + const Scalar & t1, + Scalar & tmin, + Scalar & tmax); +} +#ifndef IGL_STATIC_LIBRARY +# include "ray_box_intersect.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/ray_mesh_intersect.cpp b/src/external/libigl-2.3.0/include/igl/ray_mesh_intersect.cpp new file mode 100644 index 000000000..444ee8322 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/ray_mesh_intersect.cpp @@ -0,0 +1,90 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "ray_mesh_intersect.h" + +extern "C" +{ +#include "raytri.c" +} + +template < + typename Derivedsource, + typename Deriveddir, + typename DerivedV, + typename DerivedF> +IGL_INLINE bool igl::ray_mesh_intersect( + const Eigen::MatrixBase & s, + const Eigen::MatrixBase & dir, + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + std::vector & hits) +{ + using namespace Eigen; + using namespace std; + // Should be but can't be const + Vector3d s_d = s.template cast(); + Vector3d dir_d = dir.template cast(); + hits.clear(); + hits.reserve(F.rows()); + + // loop over all triangles + for(int f = 0;f(); + RowVector3d v1 = V.row(F(f,1)).template cast(); + RowVector3d v2 = V.row(F(f,2)).template cast(); + // shoot ray, record hit + double t,u,v; + if(intersect_triangle1( + s_d.data(), dir_d.data(), v0.data(), v1.data(), v2.data(), &t, &u, &v) && + t>0) + { + hits.push_back({(int)f,(int)-1,(float)u,(float)v,(float)t}); + } + } + // Sort hits based on distance + std::sort( + hits.begin(), + hits.end(), + [](const Hit & a, const Hit & b)->bool{ return a.t < b.t;}); + return hits.size() > 0; +} + +template < + typename Derivedsource, + typename Deriveddir, + typename DerivedV, + typename DerivedF> +IGL_INLINE bool igl::ray_mesh_intersect( + const Eigen::MatrixBase & source, + const Eigen::MatrixBase & dir, + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + igl::Hit & hit) +{ + std::vector hits; + ray_mesh_intersect(source,dir,V,F,hits); + if(hits.size() > 0) + { + hit = hits.front(); + return true; + }else + { + return false; + } +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template bool igl::ray_mesh_intersect, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, std::vector >&); +template bool igl::ray_mesh_intersect, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, std::vector >&); +template bool igl::ray_mesh_intersect, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, igl::Hit&); +template bool igl::ray_mesh_intersect, Eigen::Matrix, Eigen::Matrix, Eigen::Block const, 1, -1, false> >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase const, 1, -1, false> > const&, igl::Hit&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/ray_mesh_intersect.h b/src/external/libigl-2.3.0/include/igl/ray_mesh_intersect.h new file mode 100644 index 000000000..5e10dc942 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/ray_mesh_intersect.h @@ -0,0 +1,58 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_RAY_MESH_INTERSECT_H +#define IGL_RAY_MESH_INTERSECT_H +#include "igl_inline.h" +#include "Hit.h" +#include +#include +namespace igl +{ + // Shoot a ray against a mesh (V,F) and collect all hits. If you have many + // rays, consider using AABB.h + // + // Inputs: + // source 3-vector origin of ray + // dir 3-vector direction of ray + // V #V by 3 list of mesh vertex positions + // F #F by 3 list of mesh face indices into V + // Outputs: + // hits **sorted** list of hits + // Returns true if there were any hits (hits.size() > 0) + // + // See also: AABB.h + template < + typename Derivedsource, + typename Deriveddir, + typename DerivedV, + typename DerivedF> + IGL_INLINE bool ray_mesh_intersect( + const Eigen::MatrixBase & source, + const Eigen::MatrixBase & dir, + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + std::vector & hits); + // Outputs: + // hit first hit, set only if it exists + // Returns true if there was a hit + template < + typename Derivedsource, + typename Deriveddir, + typename DerivedV, + typename DerivedF> + IGL_INLINE bool ray_mesh_intersect( + const Eigen::MatrixBase & source, + const Eigen::MatrixBase & dir, + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + igl::Hit & hit); +} +#ifndef IGL_STATIC_LIBRARY +# include "ray_mesh_intersect.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/ray_sphere_intersect.cpp b/src/external/libigl-2.3.0/include/igl/ray_sphere_intersect.cpp new file mode 100644 index 000000000..8a05c2a12 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/ray_sphere_intersect.cpp @@ -0,0 +1,74 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "ray_sphere_intersect.h" + +template < + typename Derivedo, + typename Derivedd, + typename Derivedc, + typename r_type, + typename t_type> +IGL_INLINE int igl::ray_sphere_intersect( + const Eigen::PlainObjectBase & ao, + const Eigen::PlainObjectBase & d, + const Eigen::PlainObjectBase & ac, + r_type r, + t_type & t0, + t_type & t1) +{ + Eigen::Vector3d o = ao-ac; + // http://wiki.cgsociety.org/index.php/Ray_Sphere_Intersection + //Compute A, B and C coefficients + double a = d.dot(d); + double b = 2 * d.dot(o); + double c = o.dot(o) - (r * r); + + //Find discriminant + double disc = b * b - 4 * a * c; + + // if discriminant is negative there are no real roots, so return + // false as ray misses sphere + if (disc < 0) + { + return 0; + } + + // compute q as described above + double distSqrt = sqrt(disc); + double q; + if (b < 0) + { + q = (-b - distSqrt)/2.0; + } else + { + q = (-b + distSqrt)/2.0; + } + + // compute t0 and t1 + t0 = q / a; + double _t1 = c/q; + if(_t1 == t0) + { + return 1; + } + t1 = _t1; + // make sure t0 is smaller than t1 + if (t0 > t1) + { + // if t0 is bigger than t1 swap them around + double temp = t0; + t0 = t1; + t1 = temp; + } + return 2; +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +template int igl::ray_sphere_intersect, Eigen::Matrix, Eigen::Matrix, double, double>(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, double, double&, double&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/ray_sphere_intersect.h b/src/external/libigl-2.3.0/include/igl/ray_sphere_intersect.h new file mode 100644 index 000000000..b4dfea379 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/ray_sphere_intersect.h @@ -0,0 +1,46 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_RAY_SPHERE_INTERSECT_H +#define IGL_RAY_SPHERE_INTERSECT_H +#include "igl_inline.h" +#include +namespace igl +{ + // Compute the intersection between a ray from O in direction D and a sphere + // centered at C with radius r + // + // Inputs: + // o origin of ray + // d direction of ray + // c center of sphere + // r radius of sphere + // Outputs: + // t0 parameterization of first hit (set only if exists) so that hit + // position = o + t0*d + // t1 parameterization of second hit (set only if exists) + // + // Returns the number of hits + template < + typename Derivedo, + typename Derivedd, + typename Derivedc, + typename r_type, + typename t_type> + IGL_INLINE int ray_sphere_intersect( + const Eigen::PlainObjectBase & o, + const Eigen::PlainObjectBase & d, + const Eigen::PlainObjectBase & c, + r_type r, + t_type & t0, + t_type & t1); +} +#ifndef IGL_STATIC_LIBRARY +#include "ray_sphere_intersect.cpp" +#endif +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/raytri.c b/src/external/libigl-2.3.0/include/igl/raytri.c new file mode 100644 index 000000000..b5e7f7b1f --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/raytri.c @@ -0,0 +1,267 @@ +/* Ray-Triangle Intersection Test Routines */ +/* Different optimizations of my and Ben Trumbore's */ +/* code from journals of graphics tools (JGT) */ +/* http://www.acm.org/jgt/ */ +/* by Tomas Moller, May 2000 */ + + +// Alec: this file is listed as "Public Domain" +// http://fileadmin.cs.lth.se/cs/Personal/Tomas_Akenine-Moller/code/ + +// Alec: I've added an include guard, made all functions inline and added +// IGL_RAY_TRI_ to #define macros +#ifndef IGL_RAY_TRI_C +#define IGL_RAY_TRI_C + +#include + +#define IGL_RAY_TRI_EPSILON 0.000001 +#define IGL_RAY_TRI_CROSS(dest,v1,v2) \ + dest[0]=v1[1]*v2[2]-v1[2]*v2[1]; \ + dest[1]=v1[2]*v2[0]-v1[0]*v2[2]; \ + dest[2]=v1[0]*v2[1]-v1[1]*v2[0]; +#define IGL_RAY_TRI_DOT(v1,v2) (v1[0]*v2[0]+v1[1]*v2[1]+v1[2]*v2[2]) +#define IGL_RAY_TRI_SUB(dest,v1,v2) \ + dest[0]=v1[0]-v2[0]; \ + dest[1]=v1[1]-v2[1]; \ + dest[2]=v1[2]-v2[2]; + +/* the original jgt code */ +inline int intersect_triangle(double orig[3], double dir[3], + double vert0[3], double vert1[3], double vert2[3], + double *t, double *u, double *v) +{ + double edge1[3], edge2[3], tvec[3], pvec[3], qvec[3]; + double det,inv_det; + + /* find vectors for two edges sharing vert0 */ + IGL_RAY_TRI_SUB(edge1, vert1, vert0); + IGL_RAY_TRI_SUB(edge2, vert2, vert0); + + /* begin calculating determinant - also used to calculate U parameter */ + IGL_RAY_TRI_CROSS(pvec, dir, edge2); + + /* if determinant is near zero, ray lies in plane of triangle */ + det = IGL_RAY_TRI_DOT(edge1, pvec); + + if (det > -IGL_RAY_TRI_EPSILON && det < IGL_RAY_TRI_EPSILON) + return 0; + inv_det = 1.0 / det; + + /* calculate distance from vert0 to ray origin */ + IGL_RAY_TRI_SUB(tvec, orig, vert0); + + /* calculate U parameter and test bounds */ + *u = IGL_RAY_TRI_DOT(tvec, pvec) * inv_det; + if (*u < 0.0 || *u > 1.0) + return 0; + + /* prepare to test V parameter */ + IGL_RAY_TRI_CROSS(qvec, tvec, edge1); + + /* calculate V parameter and test bounds */ + *v = IGL_RAY_TRI_DOT(dir, qvec) * inv_det; + if (*v < 0.0 || *u + *v > 1.0) + return 0; + + /* calculate t, ray intersects triangle */ + *t = IGL_RAY_TRI_DOT(edge2, qvec) * inv_det; + + return 1; +} + + +/* code rewritten to do tests on the sign of the determinant */ +/* the division is at the end in the code */ +inline int intersect_triangle1(double orig[3], double dir[3], + double vert0[3], double vert1[3], double vert2[3], + double *t, double *u, double *v) +{ + double edge1[3], edge2[3], tvec[3], pvec[3], qvec[3]; + double det,inv_det; + + /* find vectors for two edges sharing vert0 */ + IGL_RAY_TRI_SUB(edge1, vert1, vert0); + IGL_RAY_TRI_SUB(edge2, vert2, vert0); + + /* begin calculating determinant - also used to calculate U parameter */ + IGL_RAY_TRI_CROSS(pvec, dir, edge2); + + /* if determinant is near zero, ray lies in plane of triangle */ + det = IGL_RAY_TRI_DOT(edge1, pvec); + + if (det > IGL_RAY_TRI_EPSILON) + { + /* calculate distance from vert0 to ray origin */ + IGL_RAY_TRI_SUB(tvec, orig, vert0); + + /* calculate U parameter and test bounds */ + *u = IGL_RAY_TRI_DOT(tvec, pvec); + if (*u < 0.0 || *u > det) + return 0; + + /* prepare to test V parameter */ + IGL_RAY_TRI_CROSS(qvec, tvec, edge1); + + /* calculate V parameter and test bounds */ + *v = IGL_RAY_TRI_DOT(dir, qvec); + if (*v < 0.0 || *u + *v > det) + return 0; + + } + else if(det < -IGL_RAY_TRI_EPSILON) + { + /* calculate distance from vert0 to ray origin */ + IGL_RAY_TRI_SUB(tvec, orig, vert0); + + /* calculate U parameter and test bounds */ + *u = IGL_RAY_TRI_DOT(tvec, pvec); +/* printf("*u=%f\n",(float)*u); */ +/* printf("det=%f\n",det); */ + if (*u > 0.0 || *u < det) + return 0; + + /* prepare to test V parameter */ + IGL_RAY_TRI_CROSS(qvec, tvec, edge1); + + /* calculate V parameter and test bounds */ + *v = IGL_RAY_TRI_DOT(dir, qvec) ; + if (*v > 0.0 || *u + *v < det) + return 0; + } + else return 0; /* ray is parallel to the plane of the triangle */ + + + inv_det = 1.0 / det; + + /* calculate t, ray intersects triangle */ + *t = IGL_RAY_TRI_DOT(edge2, qvec) * inv_det; + (*u) *= inv_det; + (*v) *= inv_det; + + return 1; +} + +/* code rewritten to do tests on the sign of the determinant */ +/* the division is before the test of the sign of the det */ +inline int intersect_triangle2(double orig[3], double dir[3], + double vert0[3], double vert1[3], double vert2[3], + double *t, double *u, double *v) +{ + double edge1[3], edge2[3], tvec[3], pvec[3], qvec[3]; + double det,inv_det; + + /* find vectors for two edges sharing vert0 */ + IGL_RAY_TRI_SUB(edge1, vert1, vert0); + IGL_RAY_TRI_SUB(edge2, vert2, vert0); + + /* begin calculating determinant - also used to calculate U parameter */ + IGL_RAY_TRI_CROSS(pvec, dir, edge2); + + /* if determinant is near zero, ray lies in plane of triangle */ + det = IGL_RAY_TRI_DOT(edge1, pvec); + + /* calculate distance from vert0 to ray origin */ + IGL_RAY_TRI_SUB(tvec, orig, vert0); + inv_det = 1.0 / det; + + if (det > IGL_RAY_TRI_EPSILON) + { + /* calculate U parameter and test bounds */ + *u = IGL_RAY_TRI_DOT(tvec, pvec); + if (*u < 0.0 || *u > det) + return 0; + + /* prepare to test V parameter */ + IGL_RAY_TRI_CROSS(qvec, tvec, edge1); + + /* calculate V parameter and test bounds */ + *v = IGL_RAY_TRI_DOT(dir, qvec); + if (*v < 0.0 || *u + *v > det) + return 0; + + } + else if(det < -IGL_RAY_TRI_EPSILON) + { + /* calculate U parameter and test bounds */ + *u = IGL_RAY_TRI_DOT(tvec, pvec); + if (*u > 0.0 || *u < det) + return 0; + + /* prepare to test V parameter */ + IGL_RAY_TRI_CROSS(qvec, tvec, edge1); + + /* calculate V parameter and test bounds */ + *v = IGL_RAY_TRI_DOT(dir, qvec) ; + if (*v > 0.0 || *u + *v < det) + return 0; + } + else return 0; /* ray is parallel to the plane of the triangle */ + + /* calculate t, ray intersects triangle */ + *t = IGL_RAY_TRI_DOT(edge2, qvec) * inv_det; + (*u) *= inv_det; + (*v) *= inv_det; + + return 1; +} + +/* code rewritten to do tests on the sign of the determinant */ +/* the division is before the test of the sign of the det */ +/* and one IGL_RAY_TRI_CROSS has been moved out from the if-else if-else */ +inline int intersect_triangle3(double orig[3], double dir[3], + double vert0[3], double vert1[3], double vert2[3], + double *t, double *u, double *v) +{ + double edge1[3], edge2[3], tvec[3], pvec[3], qvec[3]; + double det,inv_det; + + /* find vectors for two edges sharing vert0 */ + IGL_RAY_TRI_SUB(edge1, vert1, vert0); + IGL_RAY_TRI_SUB(edge2, vert2, vert0); + + /* begin calculating determinant - also used to calculate U parameter */ + IGL_RAY_TRI_CROSS(pvec, dir, edge2); + + /* if determinant is near zero, ray lies in plane of triangle */ + det = IGL_RAY_TRI_DOT(edge1, pvec); + + /* calculate distance from vert0 to ray origin */ + IGL_RAY_TRI_SUB(tvec, orig, vert0); + inv_det = 1.0 / det; + + IGL_RAY_TRI_CROSS(qvec, tvec, edge1); + + if (det > IGL_RAY_TRI_EPSILON) + { + *u = IGL_RAY_TRI_DOT(tvec, pvec); + if (*u < 0.0 || *u > det) + return 0; + + /* calculate V parameter and test bounds */ + *v = IGL_RAY_TRI_DOT(dir, qvec); + if (*v < 0.0 || *u + *v > det) + return 0; + + } + else if(det < -IGL_RAY_TRI_EPSILON) + { + /* calculate U parameter and test bounds */ + *u = IGL_RAY_TRI_DOT(tvec, pvec); + if (*u > 0.0 || *u < det) + return 0; + + /* calculate V parameter and test bounds */ + *v = IGL_RAY_TRI_DOT(dir, qvec) ; + if (*v > 0.0 || *u + *v < det) + return 0; + } + else return 0; /* ray is parallel to the plane of the triangle */ + + *t = IGL_RAY_TRI_DOT(edge2, qvec) * inv_det; + (*u) *= inv_det; + (*v) *= inv_det; + + return 1; +} +#endif diff --git a/src/external/libigl-2.3.0/include/igl/readBF.cpp b/src/external/libigl-2.3.0/include/igl/readBF.cpp new file mode 100644 index 000000000..03099ea7e --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/readBF.cpp @@ -0,0 +1,114 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "readBF.h" +#include "list_to_matrix.h" +#include +#include +#include +#include +#include +template < + typename DerivedWI, + typename DerivedP, + typename DerivedO> +IGL_INLINE bool igl::readBF( + const std::string & filename, + Eigen::PlainObjectBase & WI, + Eigen::PlainObjectBase & P, + Eigen::PlainObjectBase & O) +{ + using namespace std; + ifstream is(filename); + if(!is.is_open()) + { + return false; + } + string line; + std::vector vWI; + std::vector vP; + std::vector > vO; + while(getline(is, line)) + { + int wi,p; + double cx,cy,cz; + if(sscanf(line.c_str(), "%d %d %lg %lg %lg",&wi,&p,&cx,&cy,&cz) != 5) + { + return false; + } + vWI.push_back(wi); + vP.push_back(p); + vO.push_back({cx,cy,cz}); + } + list_to_matrix(vWI,WI); + list_to_matrix(vP,P); + list_to_matrix(vO,O); + return true; +} + +template < + typename DerivedWI, + typename DerivedbfP, + typename DerivedO, + typename DerivedC, + typename DerivedBE, + typename DerivedP> +IGL_INLINE bool igl::readBF( + const std::string & filename, + Eigen::PlainObjectBase & WI, + Eigen::PlainObjectBase & bfP, + Eigen::PlainObjectBase & offsets, + Eigen::PlainObjectBase & C, + Eigen::PlainObjectBase & BE, + Eigen::PlainObjectBase & P) +{ + using namespace Eigen; + using namespace std; + if(!readBF(filename,WI,bfP,offsets)) + { + return false; + } + + C.resize(WI.rows(),3); + vector computed(C.rows(),false); + // better not be cycles in bfP + std::function locate_tip; + locate_tip = + [&offsets,&computed,&bfP,&locate_tip,&C](const int w)->Eigen::RowVector3d + { + if(w<0) return Eigen::RowVector3d(0,0,0); + if(computed[w]) return C.row(w); + computed[w] = true; + return C.row(w) = locate_tip(bfP(w)) + offsets.row(w); + }; + int num_roots = (bfP.array() == -1).count(); + BE.resize(WI.rows()-num_roots,2); + P.resize(BE.rows()); + for(int c = 0;c=0); + // weight associated with this bone + const int wi = WI(c); + if(wi >= 0) + { + // index into C + const int p = bfP(c); + assert(p >= 0 && "No weights for roots allowed"); + // index into BE + const int pwi = WI(p); + P(wi) = pwi; + BE(wi,0) = p; + BE(wi,1) = c; + } + } + return true; +} + +#ifdef IGL_STATIC_LIBRARY +template bool igl::readBF, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(std::basic_string, std::allocator > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/readBF.h b/src/external/libigl-2.3.0/include/igl/readBF.h new file mode 100644 index 000000000..a2b010c85 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/readBF.h @@ -0,0 +1,67 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_READBF_H +#define IGL_READBF_H +#include "igl_inline.h" +#include +#include +namespace igl +{ + // Read a bones forest from a file, returns a list of bone roots + // Input: + // file_name path to .bf bones tree file + // Output: + // WI #B list of unique weight indices + // P #B list of parent indices into B, -1 for roots + // O #B by 3 list of tip offset vectors from parent (or position for roots) + // Returns true on success, false on errors + template < + typename DerivedWI, + typename DerivedP, + typename DerivedO> + IGL_INLINE bool readBF( + const std::string & filename, + Eigen::PlainObjectBase & WI, + Eigen::PlainObjectBase & P, + Eigen::PlainObjectBase & O); + // Read bone forest into pure bone-skeleton format, expects only bones (no + // point handles), and that a root in the .bf <---> no weight attachment. + // + // Input: + // file_name path to .bf bones tree file + // Output: + // WI #B list of unique weight indices + // P #B list of parent indices into B, -1 for roots + // O #B by 3 list of tip offset vectors from parent (or position for roots) + // C #C by 3 list of absolute joint locations + // BE #BE by 3 list of bone indices into C, in order of weight index + // P #BE list of parent bone indices into BE, -1 means root bone + // Returns true on success, false on errors + // + // See also: readTGF, bone_parents, forward_kinematics + template < + typename DerivedWI, + typename DerivedbfP, + typename DerivedO, + typename DerivedC, + typename DerivedBE, + typename DerivedP> + IGL_INLINE bool readBF( + const std::string & filename, + Eigen::PlainObjectBase & WI, + Eigen::PlainObjectBase & bfP, + Eigen::PlainObjectBase & O, + Eigen::PlainObjectBase & C, + Eigen::PlainObjectBase & BE, + Eigen::PlainObjectBase & P); +} + +#ifndef IGL_STATIC_LIBRARY +# include "readBF.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/readCSV.cpp b/src/external/libigl-2.3.0/include/igl/readCSV.cpp new file mode 100644 index 000000000..dbe0240f2 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/readCSV.cpp @@ -0,0 +1,72 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "readCSV.h" + +#include +#include +#include +#include + +#include + +template +IGL_INLINE bool igl::readCSV( + const std::string str, + Eigen::Matrix& M) +{ + using namespace std; + + std::vector > Mt; + + std::ifstream infile(str.c_str()); + std::string line; + while (std::getline(infile, line)) + { + std::istringstream iss(line); + vector temp; + Scalar a; + char ch; + while (iss >> a){ + temp.push_back(a); + if(!(iss >> ch)) + break; + } + + if (temp.size() != 0) // skip empty lines + Mt.push_back(temp); + } + + if (Mt.size() != 0) + { + // Verify that it is indeed a matrix + for (unsigned i = 0; i +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_READ_CSV_H +#define IGL_READ_CSV_H + +#include "igl/igl_inline.h" +#include +#include +#include + +namespace igl +{ + // read a matrix from a csv file into a Eigen matrix + // Templates: + // Scalar type for the matrix + // Inputs: + // str path to .csv file + // Outputs: + // M eigen matrix + template + IGL_INLINE bool readCSV( + const std::string str, + Eigen::Matrix& M); +} + +#ifndef IGL_STATIC_LIBRARY +# include "readCSV.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/readDMAT.cpp b/src/external/libigl-2.3.0/include/igl/readDMAT.cpp new file mode 100644 index 000000000..5560109f2 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/readDMAT.cpp @@ -0,0 +1,231 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "readDMAT.h" + +#include "verbose.h" +#include +#include +#include +#include + +// Static helper method reads the first to elements in the given file +// Inputs: +// fp file pointer of .dmat file that was just opened +// Outputs: +// num_rows number of rows +// num_cols number of columns +// Returns +// 0 success +// 1 did not find header +// 2 bad num_cols +// 3 bad num_rows +// 4 bad line ending +static inline int readDMAT_read_header(FILE * fp, int & num_rows, int & num_cols) +{ + // first line contains number of rows and number of columns + int res = fscanf(fp,"%d %d",&num_cols,&num_rows); + if(res != 2) + { + return 1; + } + // check that number of columns and rows are sane + if(num_cols < 0) + { + fprintf(stderr,"IOError: readDMAT() number of columns %d < 0\n",num_cols); + return 2; + } + if(num_rows < 0) + { + fprintf(stderr,"IOError: readDMAT() number of rows %d < 0\n",num_rows); + return 3; + } + // finish reading header + char lf; + + if(fread(&lf, sizeof(char), 1, fp)!=1 || !(lf == '\n' || lf == '\r')) + { + fprintf(stderr,"IOError: bad line ending in header\n"); + return 4; + } + + return 0; +} + +#ifndef IGL_NO_EIGEN +template +IGL_INLINE bool igl::readDMAT(const std::string file_name, + Eigen::PlainObjectBase & W) +{ + FILE * fp = fopen(file_name.c_str(),"rb"); + if(fp == NULL) + { + fprintf(stderr,"IOError: readDMAT() could not open %s...\n",file_name.c_str()); + return false; + } + int num_rows,num_cols; + int head_success = readDMAT_read_header(fp,num_rows,num_cols); + if(head_success != 0) + { + if(head_success == 1) + { + fprintf(stderr, + "IOError: readDMAT() first row should be [num cols] [num rows]...\n"); + } + fclose(fp); + return false; + } + + // Resize output to fit matrix, only if non-empty since this will trigger an + // error on fixed size matrices before reaching binary data. + bool empty = num_rows == 0 || num_cols == 0; + if(!empty) + { + W.resize(num_rows,num_cols); + } + + // Loop over columns slowly + for(int j = 0;j < num_cols;j++) + { + // loop over rows (down columns) quickly + for(int i = 0;i < num_rows;i++) + { + double d; + if(fscanf(fp," %lg",&d) != 1) + { + fclose(fp); + fprintf( + stderr, + "IOError: readDMAT() bad format after reading %d entries\n", + j*num_rows + i); + return false; + } + W(i,j) = d; + } + } + + // Try to read header for binary part + head_success = readDMAT_read_header(fp,num_rows,num_cols); + if(head_success == 0) + { + assert(W.size() == 0); + // Resize for output + W.resize(num_rows,num_cols); + std::unique_ptr Wraw(new double[num_rows*num_cols]); + fread(Wraw.get(), sizeof(double), num_cols*num_rows, fp); + // Loop over columns slowly + for(int j = 0;j < num_cols;j++) + { + // loop over rows (down columns) quickly + for(int i = 0;i < num_rows;i++) + { + W(i,j) = Wraw[j*num_rows+i]; + } + } + }else + { + // we skipped resizing before in case there was binary data + if(empty) + { + // This could trigger an error if using fixed size matrices. + W.resize(num_rows,num_cols); + } + } + + fclose(fp); + return true; +} +#endif + +template +IGL_INLINE bool igl::readDMAT( + const std::string file_name, + std::vector > & W) +{ + FILE * fp = fopen(file_name.c_str(),"r"); + if(fp == NULL) + { + fprintf(stderr,"IOError: readDMAT() could not open %s...\n",file_name.c_str()); + return false; + } + int num_rows,num_cols; + bool head_success = readDMAT_read_header(fp,num_rows,num_cols); + if(head_success != 0) + { + if(head_success == 1) + { + fprintf(stderr, + "IOError: readDMAT() first row should be [num cols] [num rows]...\n"); + } + fclose(fp); + return false; + } + + // Resize for output + W.resize(num_rows,typename std::vector(num_cols)); + + // Loop over columns slowly + for(int j = 0;j < num_cols;j++) + { + // loop over rows (down columns) quickly + for(int i = 0;i < num_rows;i++) + { + double d; + if(fscanf(fp," %lg",&d) != 1) + { + fclose(fp); + fprintf( + stderr, + "IOError: readDMAT() bad format after reading %d entries\n", + j*num_rows + i); + return false; + } + W[i][j] = (Scalar)d; + } + } + + // Try to read header for binary part + head_success = readDMAT_read_header(fp,num_rows,num_cols); + if(head_success == 0) + { + assert(W.size() == 0); + // Resize for output + W.resize(num_rows,typename std::vector(num_cols)); + std::unique_ptr Wraw(new double[num_rows*num_cols]); + fread(Wraw.get(), sizeof(double), num_cols*num_rows, fp); + // Loop over columns slowly + for(int j = 0;j < num_cols;j++) + { + // loop over rows (down columns) quickly + for(int i = 0;i < num_rows;i++) + { + W[i][j] = Wraw[j*num_rows+i]; + } + } + } + + fclose(fp); + return true; +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template bool igl::readDMAT >(std::basic_string, std::allocator >, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template bool igl::readDMAT >(std::string, Eigen::PlainObjectBase >&); +template bool igl::readDMAT(std::string, std::vector >, std::allocator > > >&); +template bool igl::readDMAT >(std::string, Eigen::PlainObjectBase >&); +template bool igl::readDMAT >(std::string, Eigen::PlainObjectBase >&); +template bool igl::readDMAT >(std::string, Eigen::PlainObjectBase >&); +template bool igl::readDMAT >(std::string, Eigen::PlainObjectBase >&); +template bool igl::readDMAT >(std::string, Eigen::PlainObjectBase >&); +template bool igl::readDMAT >(std::string, Eigen::PlainObjectBase >&); +template bool igl::readDMAT >(std::string, Eigen::PlainObjectBase >&); +template bool igl::readDMAT >( std::string, Eigen::PlainObjectBase >&); +template bool igl::readDMAT >(std::string, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/readDMAT.h b/src/external/libigl-2.3.0/include/igl/readDMAT.h new file mode 100644 index 000000000..e09c492c1 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/readDMAT.h @@ -0,0 +1,53 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_READDMAT_H +#define IGL_READDMAT_H +#include "igl_inline.h" +// .dmat is a simple ascii matrix file type, defined as follows. The first line +// is always: +// <#columns> <#rows> +// Then the coefficients of the matrix are given separated by whitespace with +// columns running fastest. +// +// Example: +// The matrix m = [1 2 3; 4 5 6]; +// corresponds to a .dmat file containing: +// 3 2 +// 1 4 2 5 3 6 +#include +#include +#ifndef IGL_NO_EIGEN +# include +#endif +namespace igl +{ + // Read a matrix from an ascii dmat file + // + // Inputs: + // file_name path to .dmat file + // Outputs: + // W eigen matrix containing read-in coefficients + // Returns true on success, false on error + // +#ifndef IGL_NO_EIGEN + template + IGL_INLINE bool readDMAT(const std::string file_name, + Eigen::PlainObjectBase & W); +#endif + // Wrapper for vector of vectors + template + IGL_INLINE bool readDMAT( + const std::string file_name, + std::vector > & W); +} + +#ifndef IGL_STATIC_LIBRARY +# include "readDMAT.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/readMESH.cpp b/src/external/libigl-2.3.0/include/igl/readMESH.cpp new file mode 100644 index 000000000..024c75b9f --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/readMESH.cpp @@ -0,0 +1,223 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "readMESH.h" +#include + + +template +IGL_INLINE bool igl::readMESH( + const std::string mesh_file_name, + Eigen::PlainObjectBase& V, + Eigen::PlainObjectBase& T, + Eigen::PlainObjectBase& F) +{ + using namespace std; + FILE * mesh_file = fopen(mesh_file_name.c_str(),"r"); + if(NULL==mesh_file) + { + fprintf(stderr,"IOError: %s could not be opened...",mesh_file_name.c_str()); + return false; + } + return readMESH(mesh_file,V,T,F); +} + +template +IGL_INLINE bool igl::readMESH( + FILE * mesh_file, + Eigen::PlainObjectBase& V, + Eigen::PlainObjectBase& T, + Eigen::PlainObjectBase& F) +{ + using namespace std; +#ifndef LINE_MAX +# define LINE_MAX 2048 +#endif + char line[LINE_MAX]; + bool still_comments; + + // eat comments at beginning of file + const auto eat_comments = [&]()->bool + { + bool still_comments= true; + bool has_line = false; + while(still_comments) + { + has_line = fgets(line,LINE_MAX,mesh_file) != NULL; + still_comments = (line[0] == '#' || line[0] == '\n'); + } + return has_line; + }; + eat_comments(); + + char str[LINE_MAX]; + sscanf(line," %s",str); + // check that first word is MeshVersionFormatted + if(0!=strcmp(str,"MeshVersionFormatted")) + { + fprintf(stderr, + "Error: first word should be MeshVersionFormatted not %s\n",str); + fclose(mesh_file); + return false; + } + int version = -1; + if(2 != sscanf(line,"%s %d",str,&version)) { fscanf(mesh_file," %d",&version); } + if(version != 1 && version != 2) + { + fprintf(stderr,"Error: second word should be 1 or 2 not %d\n",version); + fclose(mesh_file); + return false; + } + + while(eat_comments()) + { + sscanf(line," %s",str); + int extra; + // check that third word is Dimension + if(0==strcmp(str,"Dimension")) + { + int three = -1; + if(2 != sscanf(line,"%s %d",str,&three)) + { + // 1 appears on next line? + fscanf(mesh_file," %d",&three); + } + if(three != 3) + { + fprintf(stderr,"Error: only Dimension 3 supported not %d\n",three); + fclose(mesh_file); + return false; + } + }else if(0==strcmp(str,"Vertices")) + { + int number_of_vertices; + if(1 != fscanf(mesh_file," %d",&number_of_vertices) || number_of_vertices > 1000000000) + { + fprintf(stderr,"Error: expecting number of vertices less than 10^9...\n"); + fclose(mesh_file); + return false; + } + // allocate space for vertices + V.resize(number_of_vertices,3); + for(int i = 0;i, Eigen::Matrix, Eigen::Matrix >(FILE*, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template bool igl::readMESH, Eigen::Matrix, Eigen::Matrix >(std::basic_string, std::allocator >, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template bool igl::readMESH, Eigen::Matrix, Eigen::Matrix >(std::basic_string, std::allocator >, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template bool igl::readMESH, Eigen::Matrix, Eigen::Matrix >(std::basic_string, std::allocator >, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template bool igl::readMESH, Eigen::Matrix, Eigen::Matrix >(std::basic_string, std::allocator >, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template bool igl::readMESH, Eigen::Matrix, Eigen::Matrix >(FILE*, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template bool igl::readMESH, Eigen::Matrix, Eigen::Matrix >(FILE*, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template bool igl::readMESH, Eigen::Matrix, Eigen::Matrix >(FILE*, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template bool igl::readMESH, Eigen::Matrix, Eigen::Matrix >(FILE*, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template bool igl::readMESH, Eigen::Matrix, Eigen::Matrix >(std::basic_string, std::allocator >, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/readMESH.h b/src/external/libigl-2.3.0/include/igl/readMESH.h new file mode 100644 index 000000000..b9b763035 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/readMESH.h @@ -0,0 +1,78 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_READMESH_H +#define IGL_READMESH_H +#include "igl_inline.h" + +#include +#include +#include +#include + +namespace igl +{ + // load a tetrahedral volume mesh from a .mesh file + // + // Templates: + // Scalar type for positions and vectors (will be read as double and cast + // to Scalar) + // Index type for indices (will be read as int and cast to Index) + // Input: + // mesh_file_name path of .mesh file + // Outputs: + // V double matrix of vertex positions #V by 3 + // T #T list of tet indices into vertex positions + // F #F list of face indices into vertex positions + // + // Known bugs: Holes and regions are not supported + template + IGL_INLINE bool readMESH( + const std::string mesh_file_name, + std::vector > & V, + std::vector > & T, + std::vector > & F); + // Inputs: + // mesh_file pointer to already opened .mesh file + // Outputs: + // mesh_file closed file + template + IGL_INLINE bool readMESH( + FILE * mesh_file, + std::vector > & V, + std::vector > & T, + std::vector > & F); + + // Input: + // mesh_file_name path of .mesh file + // Outputs: + // V eigen double matrix #V by 3 + // T eigen int matrix #T by 4 + // F eigen int matrix #F by 3 + template + IGL_INLINE bool readMESH( + const std::string mesh_file_name, + Eigen::PlainObjectBase& V, + Eigen::PlainObjectBase& T, + Eigen::PlainObjectBase& F); + // Inputs: + // mesh_file pointer to already opened .mesh file + // Outputs: + // mesh_file closed file + template + IGL_INLINE bool readMESH( + FILE * mesh_file, + Eigen::PlainObjectBase& V, + Eigen::PlainObjectBase& T, + Eigen::PlainObjectBase& F); +} + +#ifndef IGL_STATIC_LIBRARY +# include "readMESH.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/readMSH.cpp b/src/external/libigl-2.3.0/include/igl/readMSH.cpp new file mode 100644 index 000000000..2e8a787b1 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/readMSH.cpp @@ -0,0 +1,211 @@ +// high level interface for MshLoader +// +// Copyright (C) 2020 Vladimir Fonov +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "readMSH.h" +#include "MshLoader.h" +#include + +IGL_INLINE bool igl::readMSH(const std::string &msh, + Eigen::MatrixXd &X, + Eigen::MatrixXi &Tri, + Eigen::MatrixXi &Tet, + Eigen::VectorXi &TriTag, + Eigen::VectorXi &TetTag, + std::vector &XFields, + std::vector &XF, + std::vector &EFields, + std::vector &TriF, + std::vector &TetF + ) +{ + try + { + igl::MshLoader _loader(msh); + const int USETAG = 1; + + #ifndef NDEBUG + std::cout<<"readMSH:Total number of nodes:" << _loader.get_nodes().size()<c_str() << ":" << _loader.get_node_fields()[i-std::begin(_loader.get_node_fields_names())].size() << std::endl; + } + + std::cout << "readMSH:Element fields:" << std::endl; + for(auto i=std::begin(_loader.get_element_fields_names()); i!=std::end(_loader.get_element_fields_names()); i++) + { + std::cout << i->c_str() << ":" << _loader.get_element_fields()[i-std::begin(_loader.get_element_fields_names())].size() << std::endl; + } + + if(_loader.is_element_map_identity()) + std::cout<<"readMSH:Element ids map is identity"< > + node_map( _loader.get_nodes().data(), _loader.get_nodes().size()/3, 3 ); + + X = node_map; + XFields = _loader.get_element_fields_names(); + XF.resize(_loader.get_node_fields().size()); + XFields = _loader.get_node_fields_names(); + for(size_t i=0;i<_loader.get_node_fields().size();++i) + { + Eigen::Map< const Eigen::Matrix > + field_map( _loader.get_node_fields()[i].data(), + _loader.get_node_fields()[i].size()/_loader.get_node_fields_components()[i], + _loader.get_node_fields_components()[i] ); + XF[i] = field_map; + } + + // calculate number of elements + std::map element_counts; + + for(auto i:_loader.get_elements_types()) + { + auto j=element_counts.insert({i,1}); + if(!j.second) (*j.first).second+=1; + } + #ifndef NDEBUG + std::cout<<"ReadMSH: elements found"<second; + if(n_tet_el_!=std::end(element_counts)) + n_tet_el=n_tet_el_->second; + + Tri.resize(n_tri_el,3); + Tet.resize(n_tet_el,4); + TriTag.resize(n_tri_el); + TetTag.resize(n_tet_el); + size_t el_start = 0; + TriF.resize(_loader.get_element_fields().size()); + TetF.resize(_loader.get_element_fields().size()); + for(size_t i=0;i<_loader.get_element_fields().size();++i) + { + TriF[i].resize(n_tri_el,_loader.get_element_fields_components()[i]); + TetF[i].resize(n_tet_el,_loader.get_element_fields_components()[i]); + } + EFields = _loader.get_element_fields_names(); + int i_tri = 0; + int i_tet = 0; + + for(size_t i=0;i<_loader.get_elements_lengths().size();++i) + { + if(_loader.get_elements_types()[i]==MshLoader::ELEMENT_TRI ) + { + assert(_loader.get_elements_lengths()[i]==3); + + Tri(i_tri, 0) = _loader.get_elements()[el_start ]; + Tri(i_tri, 1) = _loader.get_elements()[el_start+1]; + Tri(i_tri, 2) = _loader.get_elements()[el_start+2]; + + TriTag(i_tri) = _loader.get_elements_tags()[1][i]; + + for(size_t j=0;j<_loader.get_element_fields().size();++j) + for(size_t k=0;k<_loader.get_element_fields_components()[j];++k) + TriF[j](i_tri,k) = _loader.get_element_fields()[j][_loader.get_element_fields_components()[j]*i+k]; + + ++i_tri; + } else if(_loader.get_elements_types()[i]==MshLoader::ELEMENT_TET ) { + assert(_loader.get_elements_lengths()[i]==4); + + Tet(i_tet, 0) = _loader.get_elements()[el_start ]; + Tet(i_tet, 1) = _loader.get_elements()[el_start+1]; + Tet(i_tet, 2) = _loader.get_elements()[el_start+2]; + Tet(i_tet, 3) = _loader.get_elements()[el_start+3]; + + TetTag(i_tet) = _loader.get_elements_tags()[USETAG][i]; + + for(size_t j=0;j<_loader.get_element_fields().size();++j) + for(size_t k=0;k<_loader.get_element_fields_components()[j];++k) + TetF[j](i_tet,k) = _loader.get_element_fields()[j][_loader.get_element_fields_components()[j]*i+k]; + + ++i_tet; + } else { + // else: it's unsupported type of the element, ignore for now + std::cerr<<"readMSH: unsupported element type: "<<_loader.get_elements_types()[i] << + ", length: "<< _loader.get_elements_lengths()[i] < XFields; + std::vector XF; + std::vector EFields; + std::vector TriF; + std::vector TetF; + return igl::readMSH(msh,X,Tri,Tet,TriTag,TetTag,XFields,XF,EFields,TriF,TetF); +} + +IGL_INLINE bool igl::readMSH(const std::string &msh, + Eigen::MatrixXd &X, + Eigen::MatrixXi &Tri, + Eigen::VectorXi &TriTag + ) +{ + Eigen::MatrixXi Tet; + Eigen::VectorXi TetTag; + + std::vector XFields; + std::vector XF; + std::vector EFields; + std::vector TriF; + std::vector TetF; + + return igl::readMSH(msh,X,Tri,Tet,TriTag,TetTag,XFields,XF,EFields,TriF,TetF); +} + +IGL_INLINE bool igl::readMSH(const std::string &msh, + Eigen::MatrixXd &X, + Eigen::MatrixXi &Tri + ) +{ + Eigen::MatrixXi Tet; + Eigen::VectorXi TetTag; + Eigen::VectorXi TriTag; + + std::vector XFields; + std::vector XF; + std::vector EFields; + std::vector TriF; + std::vector TetF; + + return igl::readMSH(msh,X,Tri,Tet,TriTag,TetTag,XFields,XF,EFields,TriF,TetF); +} diff --git a/src/external/libigl-2.3.0/include/igl/readMSH.h b/src/external/libigl-2.3.0/include/igl/readMSH.h new file mode 100644 index 000000000..53f5f8e09 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/readMSH.h @@ -0,0 +1,103 @@ +// high level interface for MshLoader.h/.cpp + +// Copyright (C) 2020 Vladimir Fonov +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distribute +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_READ_MSH_H +#define IGL_READ_MSH_H +#include "igl_inline.h" + +#include +#include +#include + + +namespace igl +{ + // read triangle surface mesh and tetrahedral volume mesh from .msh file + // Inputs: + // msh - file name + // Outputs: + // X eigen double matrix of vertex positions #X by 3 + // Tri #Tri eigen integer matrix of triangular faces indices into vertex positions + // Tet #Tet eigen integer matrix of tetrahedral indices into vertex positions + // TriTag #Tri eigen integer vector of tags associated with surface faces + // TetTag #Tet eigen integer vector of tags associated with volume elements + // XFields #XFields list of strings with field names associated with nodes + // XF #XFields list of eigen double matrices, fields associated with nodes + // EFields #EFields list of strings with field names associated with elements + // TriF #EFields list of eigen double matrices, fields associated with surface elements + // TetF #EFields list of eigen double matrices, fields associated with volume elements + // Known bugs: + // only version 2.2 of .msh file is supported (gmsh 3.X) + // only triangle surface elements and tetrahedral volumetric elements are supported + // only 3D information is supported + // only the 1st tag per element is returned (physical) + // same element fields are expected to be associated with surface elements and volumetric elements + IGL_INLINE bool readMSH(const std::string &msh, + Eigen::MatrixXd &X, + Eigen::MatrixXi &Tri, + Eigen::MatrixXi &Tet, + Eigen::VectorXi &TriTag, + Eigen::VectorXi &TetTag, + std::vector &XFields, + std::vector &XF, + std::vector &EFields, + std::vector &TriF, + std::vector &TetF + ); + + // read triangle surface mesh and tetrahedral volume mesh from .msh file + // ignoring any fields + // Inputs: + // msh - file name + // Outputs: + // X eigen double matrix of vertex positions #X by 3 + // Tri #Tri eigen integer matrix of triangular faces indices into vertex positions + // Tet #Tet eigen integer matrix of tetrahedral indices into vertex positions + // TriTag #Tri eigen integer vector of tags associated with surface faces + // TetTag #Tet eigen integer vector of tags associated with volume elements + IGL_INLINE bool readMSH(const std::string &msh, + Eigen::MatrixXd &X, + Eigen::MatrixXi &Tri, + Eigen::MatrixXi &Tet, + Eigen::VectorXi &TriTag, + Eigen::VectorXi &TetTag + ); + + // read triangle surface mesh and tetrahedral volume mesh from .msh file + // ignoring any fields, and any volumetric elements + // Inputs: + // msh - file name + // Outputs: + // X eigen double matrix of vertex positions #X by 3 + // Tri #Tri eigen integer matrix of triangular faces indices into vertex positions + // TriTag #Tri eigen integer vector of tags associated with surface faces + IGL_INLINE bool readMSH(const std::string &msh, + Eigen::MatrixXd &X, + Eigen::MatrixXi &Tri, + Eigen::VectorXi &TriTag + ); + + // read triangle surface mesh and tetrahedral volume mesh from .msh file + // ignoring any fields, and any volumetric elements and tags + // Inputs: + // msh - file name + // Outputs: + // X eigen double matrix of vertex positions #X by 3 + // Tri #Tri eigen integer matrix of triangular faces indices into vertex positions + IGL_INLINE bool readMSH(const std::string &msh, + Eigen::MatrixXd &X, + Eigen::MatrixXi &Tri + ); + +} + + +#ifndef IGL_STATIC_LIBRARY +# include "readMSH.cpp" +#endif + +#endif //IGL_READ_MSH_H diff --git a/src/external/libigl-2.3.0/include/igl/readNODE.cpp b/src/external/libigl-2.3.0/include/igl/readNODE.cpp new file mode 100644 index 000000000..cb775e599 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/readNODE.cpp @@ -0,0 +1,161 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "readNODE.h" +#include "matrix_to_list.h" +#include + +template +IGL_INLINE bool igl::readNODE( + const std::string node_file_name, + std::vector > & V, + std::vector > & I) +{ + // TODO: should be templated + Eigen::MatrixXd mV; + Eigen::MatrixXi mI; + if(igl::readNODE(node_file_name,mV,mI)) + { + matrix_to_list(mV,V); + matrix_to_list(mI,I); + return true; + }else + { + return false; + } +} + +template +IGL_INLINE bool igl::readNODE( + const std::string node_file_name, + Eigen::PlainObjectBase& V, + Eigen::PlainObjectBase& I) +{ + using namespace std; + FILE * node_file = fopen(node_file_name.c_str(),"r"); + if(NULL==node_file) + { + fprintf(stderr,"readNODE: IOError: %s could not be opened...\n", + node_file_name.c_str()); + return false; + } +#ifndef LINE_MAX +# define LINE_MAX 2048 +#endif + char line[LINE_MAX]; + bool still_comments; + + // eat comments at beginning of file + still_comments= true; + while(still_comments) + { + fgets(line,LINE_MAX,node_file); + still_comments = (line[0] == '#' || line[0] == '\n'); + } + + // Read header + // n number of points + // dim dimension + // num_attr number of attributes + // num_bm number of boundary markers + int n,dim,num_attr,num_bm; + int head_count = sscanf(line,"%d %d %d %d", &n, &dim, &num_attr, &num_bm); + if(head_count!=4) + { + fprintf(stderr,"readNODE: Error: incorrect header in %s...\n", + node_file_name.c_str()); + fclose(node_file); + return false; + } + if(num_attr) + { + fprintf(stderr,"readNODE: Error: %d attributes found in %s. " + "Attributes are not supported...\n", + num_attr, + node_file_name.c_str()); + fclose(node_file); + return false; + } + // Just quietly ignore boundary markers + //if(num_bm) + //{ + // fprintf(stderr,"readNODE: Warning: %d boundary markers found in %s. " + // "Boundary markers are ignored...\n", + // num_bm, + // node_file_name.c_str()); + //} + + // resize output + V.resize(n,dim); + I.resize(n,1); + + int line_no = 0; + int p = 0; + while (fgets(line, LINE_MAX, node_file) != NULL) + { + line_no++; + // Skip comments and blank lines + if(line[0] == '#' || line[0] == '\n') + { + continue; + } + char * l = line; + int offset; + + if(sscanf(l,"%d%n",&I(p),&offset) != 1) + { + fprintf(stderr,"readNODE Error: bad index (%d) in %s...\n", + line_no, + node_file_name.c_str()); + fclose(node_file); + return false; + } + // adjust offset + l += offset; + + // Read coordinates + for(int d = 0;d, Eigen::Matrix >(std::basic_string, std::allocator >, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/readNODE.h b/src/external/libigl-2.3.0/include/igl/readNODE.h new file mode 100644 index 000000000..a4bdb4774 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/readNODE.h @@ -0,0 +1,50 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_READNODE_H +#define IGL_READNODE_H +#include "igl_inline.h" + +#include +#include +#include + +namespace igl +{ + // load a list of points from a .node file + // + // Templates: + // Scalar type for positions and vectors (will be read as double and cast + // to Scalar) + // Index type for indices (will be read as int and cast to Index) + // Input: + // node_file_name path of .node file + // Outputs: + // V double matrix of vertex positions #V by dim + // I list of indices (first tells whether 0 or 1 indexed) + template + IGL_INLINE bool readNODE( + const std::string node_file_name, + std::vector > & V, + std::vector > & I); + + // Input: + // node_file_name path of .node file + // Outputs: + // V eigen double matrix #V by dim + template + IGL_INLINE bool readNODE( + const std::string node_file_name, + Eigen::PlainObjectBase& V, + Eigen::PlainObjectBase& I); +} + +#ifndef IGL_STATIC_LIBRARY +# include "readNODE.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/readOBJ.cpp b/src/external/libigl-2.3.0/include/igl/readOBJ.cpp new file mode 100644 index 000000000..8694e69a5 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/readOBJ.cpp @@ -0,0 +1,439 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "readOBJ.h" + +#include "list_to_matrix.h" +#include "max_size.h" +#include "min_size.h" +#include "polygon_corners.h" +#include "polygons_to_triangles.h" + +#include +#include +#include +#include +#include + +template +IGL_INLINE bool igl::readOBJ( + const std::string obj_file_name, + std::vector > & V, + std::vector > & TC, + std::vector > & N, + std::vector > & F, + std::vector > & FTC, + std::vector > & FN) +{ + // Open file, and check for error + FILE * obj_file = fopen(obj_file_name.c_str(),"r"); + if(NULL==obj_file) + { + fprintf(stderr,"IOError: %s could not be opened...\n", + obj_file_name.c_str()); + return false; + } + std::vector> FM; + return igl::readOBJ(obj_file,V,TC,N,F,FTC,FN, FM); +} + +template +IGL_INLINE bool igl::readOBJ( + const std::string obj_file_name, + std::vector > & V, + std::vector > & TC, + std::vector > & N, + std::vector > & F, + std::vector > & FTC, + std::vector > & FN, + std::vector> &FM) +{ + // Open file, and check for error + FILE * obj_file = fopen(obj_file_name.c_str(),"r"); + if(NULL==obj_file) + { + fprintf(stderr,"IOError: %s could not be opened...\n", + obj_file_name.c_str()); + return false; + } + return igl::readOBJ(obj_file,V,TC,N,F,FTC,FN,FM); +} + +template +IGL_INLINE bool igl::readOBJ( + FILE * obj_file, + std::vector > & V, + std::vector > & TC, + std::vector > & N, + std::vector > & F, + std::vector > & FTC, + std::vector > & FN, + std::vector> &FM) +{ + // File open was successful so clear outputs + V.clear(); + TC.clear(); + N.clear(); + F.clear(); + FTC.clear(); + FN.clear(); + + // variables and constants to assist parsing the .obj file + // Constant strings to compare against + std::string v("v"); + std::string vn("vn"); + std::string vt("vt"); + std::string f("f"); + std::string tic_tac_toe("#"); +#ifndef IGL_LINE_MAX +# define IGL_LINE_MAX 2048 +#endif + +#ifndef MATERIAL_LINE_MAX +# define MATERIAL_LINE_MAX 2048 +#endif + + char line[IGL_LINE_MAX]; + char currentmaterialref[MATERIAL_LINE_MAX] = ""; + bool FMwasinit = false; + int line_no = 1, previous_face_no=0, current_face_no = 0; + while (fgets(line, IGL_LINE_MAX, obj_file) != NULL) + { + char type[IGL_LINE_MAX]; + // Read first word containing type + if(sscanf(line, "%s",type) == 1) + { + // Get pointer to rest of line right after type + char * l = &line[strlen(type)]; + if(type == v) + { + std::istringstream ls(&line[1]); + std::vector vertex{ std::istream_iterator(ls), std::istream_iterator() }; + + if (vertex.size() < 3) + { + fprintf(stderr, + "Error: readOBJ() vertex on line %d should have at least 3 coordinates", + line_no); + fclose(obj_file); + return false; + } + + V.push_back(vertex); + }else if(type == vn) + { + double x[3]; + int count = + sscanf(l,"%lf %lf %lf\n",&x[0],&x[1],&x[2]); + if(count != 3) + { + fprintf(stderr, + "Error: readOBJ() normal on line %d should have 3 coordinates", + line_no); + fclose(obj_file); + return false; + } + std::vector normal(count); + for(int i = 0;i tex(count); + for(int i = 0;iint + { + return i<0 ? i+V.size() : i-1; + }; + const auto & shift_t = [&TC](const int i)->int + { + return i<0 ? i+TC.size() : i-1; + }; + const auto & shift_n = [&N](const int i)->int + { + return i<0 ? i+N.size() : i-1; + }; + std::vector f; + std::vector ftc; + std::vector fn; + // Read each "word" after type + char word[IGL_LINE_MAX]; + int offset; + while(sscanf(l,"%s%n",word,&offset) == 1) + { + // adjust offset + l += offset; + // Process word + long int i,it,in; + if(sscanf(word,"%ld/%ld/%ld",&i,&it,&in) == 3) + { + f.push_back(shift(i)); + ftc.push_back(shift_t(it)); + fn.push_back(shift_n(in)); + }else if(sscanf(word,"%ld/%ld",&i,&it) == 2) + { + f.push_back(shift(i)); + ftc.push_back(shift_t(it)); + }else if(sscanf(word,"%ld//%ld",&i,&in) == 2) + { + f.push_back(shift(i)); + fn.push_back(shift_n(in)); + }else if(sscanf(word,"%ld",&i) == 1) + { + f.push_back(shift(i)); + }else + { + fprintf(stderr, + "Error: readOBJ() face on line %d has invalid element format\n", + line_no); + fclose(obj_file); + return false; + } + } + if( + (f.size()>0 && fn.size() == 0 && ftc.size() == 0) || + (f.size()>0 && fn.size() == f.size() && ftc.size() == 0) || + (f.size()>0 && fn.size() == 0 && ftc.size() == f.size()) || + (f.size()>0 && fn.size() == f.size() && ftc.size() == f.size())) + { + // No matter what add each type to lists so that lists are the + // correct lengths + F.push_back(f); + FTC.push_back(ftc); + FN.push_back(fn); + current_face_no++; + }else + { + fprintf(stderr, + "Error: readOBJ() face on line %d has invalid format\n", line_no); + fclose(obj_file); + return false; + } + }else if(strlen(type) >= 1 && strcmp("usemtl",type)==0 ) + { + if(FMwasinit){ + FM.push_back(std::make_tuple(currentmaterialref,previous_face_no,current_face_no-1)); + previous_face_no = current_face_no; + } + else{ + FMwasinit=true; + } + sscanf(l, "%s\n", currentmaterialref); + } + else if(strlen(type) >= 1 && (type[0] == '#' || + type[0] == 'g' || + type[0] == 's' || + strcmp("mtllib",type)==0)) + { + //ignore comments or other shit + }else + { + //ignore any other lines + fprintf(stderr, + "Warning: readOBJ() ignored non-comment line %d:\n %s", + line_no, + line); + } + }else + { + // ignore empty line + } + line_no++; + } + if(strcmp(currentmaterialref,"")!=0) + FM.push_back(std::make_tuple(currentmaterialref,previous_face_no,current_face_no-1)); + fclose(obj_file); + + assert(F.size() == FN.size()); + assert(F.size() == FTC.size()); + + return true; +} + +template +IGL_INLINE bool igl::readOBJ( + const std::string obj_file_name, + std::vector > & V, + std::vector > & F) +{ + std::vector > TC,N; + std::vector > FTC,FN; + std::vector> FM; + + return readOBJ(obj_file_name,V,TC,N,F,FTC,FN); +} + +template < + typename DerivedV, + typename DerivedTC, + typename DerivedCN, + typename DerivedF, + typename DerivedFTC, + typename DerivedFN> +IGL_INLINE bool igl::readOBJ( + const std::string str, + Eigen::PlainObjectBase& V, + Eigen::PlainObjectBase& TC, + Eigen::PlainObjectBase& CN, + Eigen::PlainObjectBase& F, + Eigen::PlainObjectBase& FTC, + Eigen::PlainObjectBase& FN) +{ + std::vector > vV,vTC,vN; + std::vector > vF,vFTC,vFN; + bool success = igl::readOBJ(str,vV,vTC,vN,vF,vFTC,vFN); + if(!success) + { + // readOBJ(str,vV,vTC,vN,vF,vFTC,vFN) should have already printed an error + // message to stderr + return false; + } + bool V_rect = igl::list_to_matrix(vV,V); + const char * format = "Failed to cast %s to matrix: min (%d) != max (%d)\n"; + if(!V_rect) + { + printf(format,"V",igl::min_size(vV),igl::max_size(vV)); + return false; + } + bool F_rect = igl::list_to_matrix(vF,F); + if(!F_rect) + { + printf(format,"F",igl::min_size(vF),igl::max_size(vF)); + return false; + } + if(!vN.empty()) + { + bool VN_rect = igl::list_to_matrix(vN,CN); + if(!VN_rect) + { + printf(format,"CN",igl::min_size(vN),igl::max_size(vN)); + return false; + } + } + + if(!vFN.empty() && !vFN[0].empty()) + { + bool FN_rect = igl::list_to_matrix(vFN,FN); + if(!FN_rect) + { + printf(format,"FN",igl::min_size(vFN),igl::max_size(vFN)); + return false; + } + } + + if(!vTC.empty()) + { + + bool T_rect = igl::list_to_matrix(vTC,TC); + if(!T_rect) + { + printf(format,"TC",igl::min_size(vTC),igl::max_size(vTC)); + return false; + } + } + if(!vFTC.empty()&& !vFTC[0].empty()) + { + + bool FTC_rect = igl::list_to_matrix(vFTC,FTC); + if(!FTC_rect) + { + printf(format,"FTC",igl::min_size(vFTC),igl::max_size(vFTC)); + return false; + } + } + return true; +} + +template +IGL_INLINE bool igl::readOBJ( + const std::string str, + Eigen::PlainObjectBase& V, + Eigen::PlainObjectBase& F) +{ + std::vector > vV,vTC,vN; + std::vector > vF,vFTC,vFN; + bool success = igl::readOBJ(str,vV,vTC,vN,vF,vFTC,vFN); + if(!success) + { + // readOBJ(str,vV,vTC,vN,vF,vFTC,vFN) should have already printed an error + // message to stderr + return false; + } + bool V_rect = igl::list_to_matrix(vV,V); + if(!V_rect) + { + // igl::list_to_matrix(vV,V) already printed error message to std err + return false; + } + bool F_rect = igl::list_to_matrix(vF,F); + if(!F_rect) + { + // igl::list_to_matrix(vF,F) already printed error message to std err + return false; + } + return true; +} + +template +IGL_INLINE bool igl::readOBJ( + const std::string str, + Eigen::PlainObjectBase& V, + Eigen::PlainObjectBase& I, + Eigen::PlainObjectBase& C) +{ + // we should flip this so that the base implementation uses arrays. + std::vector > vV,vTC,vN; + std::vector > vF,vFTC,vFN; + bool success = igl::readOBJ(str,vV,vTC,vN,vF,vFTC,vFN); + if(!success) + { + // readOBJ(str,vV,vTC,vN,vF,vFTC,vFN) should have already printed an error + // message to stderr + return false; + } + if(!igl::list_to_matrix(vV,V)) + { + return false; + } + igl::polygon_corners(vF,I,C); + return true; +} + + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template bool igl::readOBJ, Eigen::Matrix, Eigen::Matrix >(std::basic_string, std::allocator >, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template bool igl::readOBJ(std::basic_string, std::allocator >, std::vector >, std::allocator > > >&, std::vector >, std::allocator > > >&, std::vector >, std::allocator > > >&, std::vector >, std::allocator > > >&, std::vector >, std::allocator > > >&, std::vector >, std::allocator > > >&); +template bool igl::readOBJ(std::basic_string, std::allocator >, std::vector >, std::allocator > > >&, std::vector >, std::allocator > > >&, std::vector >, std::allocator > > >&, std::vector >, std::allocator > > >&, std::vector >, std::allocator > > >&, std::vector >, std::allocator > > >&, std::vector, std::allocator >, int, int>, std::allocator, std::allocator >, int, int> > >&); +template bool igl::readOBJ(std::basic_string, std::allocator >, std::vector >, std::allocator > > >&, std::vector >, std::allocator > > >&); +template bool igl::readOBJ, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(std::basic_string, std::allocator >, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template bool igl::readOBJ, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(std::basic_string, std::allocator >, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template bool igl::readOBJ, Eigen::Matrix >(std::basic_string, std::allocator >, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template bool igl::readOBJ, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(std::basic_string, std::allocator >, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template bool igl::readOBJ, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(std::basic_string, std::allocator >, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/readOBJ.h b/src/external/libigl-2.3.0/include/igl/readOBJ.h new file mode 100644 index 000000000..926010eb5 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/readOBJ.h @@ -0,0 +1,143 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef IGL_READOBJ_H +#define IGL_READOBJ_H +#include "igl_inline.h" +// History: +// return type changed from void to bool Alec 18 Sept 2011 +// added pure vector of vectors version that has much more support Alec 31 Oct +// 2011 + +#ifndef IGL_NO_EIGEN +# include +#endif +#include +#include +#include + +namespace igl +{ + // Read a mesh from an ascii obj file, filling in vertex positions, normals + // and texture coordinates. Mesh may have faces of any number of degree + // + // Templates: + // Scalar type for positions and vectors (will be read as double and cast + // to Scalar) + // Index type for indices (will be read as int and cast to Index) + // Inputs: + // str path to .obj file + // Outputs: + // V double matrix of vertex positions #V by 3 + // TC double matrix of texture coordinats #TC by 2 + // N double matrix of corner normals #N by 3 + // F #F list of face indices into vertex positions + // FTC #F list of face indices into vertex texture coordinates + // FN #F list of face indices into vertex normals + // Returns true on success, false on errors + template + IGL_INLINE bool readOBJ( + const std::string obj_file_name, + std::vector > & V, + std::vector > & TC, + std::vector > & N, + std::vector > & F, + std::vector > & FTC, + std::vector > & FN); + // Read a mesh from an ascii obj file, filling in vertex positions, normals + // and texture coordinates. Mesh may have faces of any number of degree + // + // Templates: + // Scalar type for positions and vectors (will be read as double and cast + // to Scalar) + // Index type for indices (will be read as int and cast to Index) + // Inputs: + // str path to .obj file + // Outputs: + // V double matrix of vertex positions #V by 3 + // TC double matrix of texture coordinats #TC by 2 + // N double matrix of corner normals #N by 3 + // F #F list of face indices into vertex positions + // FTC #F list of face indices into vertex texture coordinates + // FN #F list of face indices into vertex normals + // FM #tuple list containing (vertex index, normal index, texture coordinates index, material) + // Returns true on success, false on errors + template + IGL_INLINE bool readOBJ( + const std::string obj_file_name, + std::vector > & V, + std::vector > & TC, + std::vector > & N, + std::vector > & F, + std::vector > & FTC, + std::vector > & FN, + std::vector> &FM + ); + + // Inputs: + // obj_file pointer to already opened .obj file + // Outputs: + // obj_file closed file + template + IGL_INLINE bool readOBJ( + FILE * obj_file, + std::vector > & V, + std::vector > & TC, + std::vector > & N, + std::vector > & F, + std::vector > & FTC, + std::vector > & FN, + std::vector> &FM); + // Just V and F + template + IGL_INLINE bool readOBJ( + const std::string obj_file_name, + std::vector > & V, + std::vector > & F); + // Eigen Wrappers. These will return true only if the data is perfectly + // "rectangular": All faces are the same degree, all have the same number of + // textures/normals etc. + template < + typename DerivedV, + typename DerivedTC, + typename DerivedCN, + typename DerivedF, + typename DerivedFTC, + typename DerivedFN> + IGL_INLINE bool readOBJ( + const std::string str, + Eigen::PlainObjectBase& V, + Eigen::PlainObjectBase& TC, + Eigen::PlainObjectBase& CN, + Eigen::PlainObjectBase& F, + Eigen::PlainObjectBase& FTC, + Eigen::PlainObjectBase& FN); + template + IGL_INLINE bool readOBJ( + const std::string str, + Eigen::PlainObjectBase& V, + Eigen::PlainObjectBase& F); + // Outputs: + // I #I vectorized list of polygon corner indices into rows of some matrix V + // C #P+1 list of cumulative polygon sizes so that C(i+1)-C(i) = size of + // the ith polygon, and so I(C(i)) through I(C(i+1)-1) are the indices of + // the ith polygon + template + IGL_INLINE bool readOBJ( + const std::string str, + Eigen::PlainObjectBase& V, + Eigen::PlainObjectBase& I, + Eigen::PlainObjectBase& C); + +} + +#ifndef IGL_STATIC_LIBRARY +# include "readOBJ.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/readOFF.cpp b/src/external/libigl-2.3.0/include/igl/readOFF.cpp new file mode 100644 index 000000000..11d7e0efc --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/readOFF.cpp @@ -0,0 +1,268 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "readOFF.h" +#include "list_to_matrix.h" + +template +IGL_INLINE bool igl::readOFF( + const std::string off_file_name, + std::vector > & V, + std::vector > & F, + std::vector > & N, + std::vector > & C) +{ + using namespace std; + FILE * off_file = fopen(off_file_name.c_str(),"r"); + if(NULL==off_file) + { + printf("IOError: %s could not be opened...\n",off_file_name.c_str()); + return false; + } + return readOFF(off_file,V,F,N,C); +} + +template +IGL_INLINE bool igl::readOFF( + FILE * off_file, + std::vector > & V, + std::vector > & F, + std::vector > & N, + std::vector > & C) +{ + using namespace std; + V.clear(); + F.clear(); + N.clear(); + C.clear(); + + // First line is always OFF + char header[1000]; + const std::string OFF("OFF"); + const std::string NOFF("NOFF"); + const std::string COFF("COFF"); + if(fscanf(off_file,"%s\n",header)!=1 + || !( + string(header).compare(0, OFF.length(), OFF)==0 || + string(header).compare(0, COFF.length(), COFF)==0 || + string(header).compare(0,NOFF.length(),NOFF)==0)) + { + printf("Error: readOFF() first line should be OFF or NOFF or COFF, not %s...",header); + fclose(off_file); + return false; + } + bool has_normals = string(header).compare(0,NOFF.length(),NOFF)==0; + bool has_vertexColors = string(header).compare(0,COFF.length(),COFF)==0; + // Second line is #vertices #faces #edges + int number_of_vertices; + int number_of_faces; + int number_of_edges; + char tic_tac_toe; + char line[1000]; + bool still_comments = true; + while(still_comments) + { + fgets(line,1000,off_file); + still_comments = (line[0] == '#' || line[0] == '\n'); + } + sscanf(line,"%d %d %d",&number_of_vertices,&number_of_faces,&number_of_edges); + V.resize(number_of_vertices); + if (has_normals) + N.resize(number_of_vertices); + if (has_vertexColors) + C.resize(number_of_vertices); + F.resize(number_of_faces); + //printf("%s %d %d %d\n",(has_normals ? "NOFF" : "OFF"),number_of_vertices,number_of_faces,number_of_edges); + // Read vertices + for(int i = 0;i= 3) + { + std::vector vertex; + vertex.resize(3); + vertex[0] = x; + vertex[1] = y; + vertex[2] = z; + V[i] = vertex; + + if (has_normals) + { + std::vector normal; + normal.resize(3); + normal[0] = nx; + normal[1] = ny; + normal[2] = nz; + N[i] = normal; + } + + if (has_vertexColors) + { + C[i].resize(3); + C[i][0] = nx / 255.0; + C[i][1] = ny / 255.0; + C[i][2] = nz / 255.0; + } + i++; + }else if( + fscanf(off_file,"%[#]",&tic_tac_toe)==1) + { + char comment[1000]; + fscanf(off_file,"%[^\n]",comment); + }else + { + printf("Error: bad line (%d)\n",i); + if(feof(off_file)) + { + fclose(off_file); + return false; + } + } + } + // Read faces + for(int i = 0;i face; + int valence; + if(fscanf(off_file,"%d",&valence)==1) + { + face.resize(valence); + for(int j = 0;j +IGL_INLINE bool igl::readOFF( + const std::string str, + Eigen::PlainObjectBase& V, + Eigen::PlainObjectBase& F) +{ + std::vector > vV; + std::vector > vN; + std::vector > vF; + std::vector > vC; + bool success = igl::readOFF(str,vV,vF,vN,vC); + if(!success) + { + // readOFF(str,vV,vF,vN,vC) should have already printed an error + // message to stderr + return false; + } + bool V_rect = igl::list_to_matrix(vV,V); + if(!V_rect) + { + // igl::list_to_matrix(vV,V) already printed error message to std err + return false; + } + bool F_rect = igl::list_to_matrix(vF,F); + if(!F_rect) + { + // igl::list_to_matrix(vF,F) already printed error message to std err + return false; + } + return true; +} + + +template +IGL_INLINE bool igl::readOFF( + const std::string str, + Eigen::PlainObjectBase& V, + Eigen::PlainObjectBase& F, + Eigen::PlainObjectBase& N) +{ + std::vector > vV; + std::vector > vN; + std::vector > vF; + std::vector > vC; + bool success = igl::readOFF(str,vV,vF,vN,vC); + if(!success) + { + // readOFF(str,vV,vF,vC) should have already printed an error + // message to stderr + return false; + } + bool V_rect = igl::list_to_matrix(vV,V); + if(!V_rect) + { + // igl::list_to_matrix(vV,V) already printed error message to std err + return false; + } + bool F_rect = igl::list_to_matrix(vF,F); + if(!F_rect) + { + // igl::list_to_matrix(vF,F) already printed error message to std err + return false; + } + + if (vN.size()) + { + bool N_rect = igl::list_to_matrix(vN,N); + if(!N_rect) + { + // igl::list_to_matrix(vN,N) already printed error message to std err + return false; + } + } + + //Warning: RGB colors will be returned in the N matrix + if (vC.size()) + { + bool C_rect = igl::list_to_matrix(vC,N); + if(!C_rect) + { + // igl::list_to_matrix(vC,N) already printed error message to std err + return false; + } + } + + return true; +} +#endif + + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template bool igl::readOFF(std::basic_string, std::allocator >, std::vector >, std::allocator > > >&, std::vector >, std::allocator > > >&, std::vector >, std::allocator > > >&, std::vector >, std::allocator > > >&); +// generated by autoexplicit.sh +template bool igl::readOFF, Eigen::Matrix >(std::basic_string, std::allocator >, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template bool igl::readOFF, Eigen::Matrix >(std::basic_string, std::allocator >, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template bool igl::readOFF, Eigen::Matrix >(std::basic_string, std::allocator >, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template bool igl::readOFF, Eigen::Matrix >(std::string, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template bool igl::readOFF, Eigen::Matrix >(std::basic_string, std::allocator >, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/readOFF.h b/src/external/libigl-2.3.0/include/igl/readOFF.h new file mode 100644 index 000000000..3d8c41fa5 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/readOFF.h @@ -0,0 +1,86 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_READOFF_H +#define IGL_READOFF_H +#include "igl_inline.h" +// History: +// return type changed from void to bool Alec 18 Sept 2011 + +#ifndef IGL_NO_EIGEN +# include +#endif +#include +#include +#include + +namespace igl +{ + + // Read a mesh from an ascii OFF file, filling in vertex positions, normals + // and texture coordinates. Mesh may have faces of any number of degree + // + // Templates: + // Scalar type for positions and vectors (will be read as double and cast + // to Scalar) + // Index type for indices (will be read as int and cast to Index) + // Inputs: + // str path to .obj file + // Outputs: + // V double matrix of vertex positions #V by 3 + // F #F list of face indices into vertex positions + // N list of vertex normals #V by 3 + // C list of rgb color values per vertex #V by 3 + // Returns true on success, false on errors + template + IGL_INLINE bool readOFF( + const std::string off_file_name, + std::vector > & V, + std::vector > & F, + std::vector > & N, + std::vector > & C); + // Inputs: + // off_file pointer to already opened .off file + // Outputs: + // off_file closed file + template + IGL_INLINE bool readOFF( + FILE * off_file, + std::vector > & V, + std::vector > & F, + std::vector > & N, + std::vector > & C); + + +#ifndef IGL_NO_EIGEN + // read mesh from a ascii off file + // Inputs: + // str path to .off file + // Outputs: + // V eigen double matrix #V by 3 + // F eigen int matrix #F by 3 + template + IGL_INLINE bool readOFF( + const std::string str, + Eigen::PlainObjectBase& V, + Eigen::PlainObjectBase& F); + + template + IGL_INLINE bool readOFF( + const std::string str, + Eigen::PlainObjectBase& V, + Eigen::PlainObjectBase& F, + Eigen::PlainObjectBase& N); +#endif + +} + +#ifndef IGL_STATIC_LIBRARY +# include "readOFF.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/readPLY.cpp b/src/external/libigl-2.3.0/include/igl/readPLY.cpp new file mode 100644 index 000000000..38c6e4a73 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/readPLY.cpp @@ -0,0 +1,641 @@ +#include "readPLY.h" +#include +#include +#include +#include +#include + +#include "tinyply.h" +#include "file_utils.h" + + +namespace igl +{ + +template +IGL_INLINE bool _tinyply_buffer_to_matrix( + tinyply::PlyData & D, + Eigen::PlainObjectBase & M, + size_t rows, + size_t cols ) +{ + Eigen::Map< Eigen::Matrix > + _map( reinterpret_cast( D.buffer.get()), rows, cols ); + + M = _map.template cast(); + return true; +} + + + +template +IGL_INLINE bool tinyply_buffer_to_matrix( + tinyply::PlyData & D, + Eigen::PlainObjectBase & M, + size_t rows, + size_t cols ) +{ + switch(D.t) + { + case tinyply::Type::INT8 : + return _tinyply_buffer_to_matrix(D, M,rows,cols); + case tinyply::Type::UINT8 : + return _tinyply_buffer_to_matrix(D, M,rows,cols); + case tinyply::Type::INT16 : + return _tinyply_buffer_to_matrix(D, M,rows,cols); + case tinyply::Type::UINT16 : + return _tinyply_buffer_to_matrix(D, M,rows,cols); + case tinyply::Type::INT32 : + return _tinyply_buffer_to_matrix(D, M,rows,cols); + case tinyply::Type::UINT32 : + return _tinyply_buffer_to_matrix(D, M,rows,cols); + case tinyply::Type::FLOAT32 : + return _tinyply_buffer_to_matrix(D, M,rows,cols); + case tinyply::Type::FLOAT64 : + return _tinyply_buffer_to_matrix(D, M,rows,cols); + default: + return false; + } +} + + +template +IGL_INLINE bool _tinyply_tristrips_to_trifaces( + tinyply::PlyData & D, + Eigen::PlainObjectBase & M, + size_t el, + size_t el_len ) +{ + + Eigen::Map< Eigen::Matrix > + _map( reinterpret_cast( D.buffer.get()), el, el_len ); + + // to make it more interesting, triangles in triangle strip can be separated by negative index elements + // 1. count all triangles + size_t triangles=0; + + // TODO: it's possible to optimize this , i suppose + for(size_t i=0; i=0 && _map(i,j+1)>=0 && _map(i,j+2)>=0) + triangles++; + } + + // 2. convert triangles to faces, skipping over the negative indeces, indicating separate strips + M.resize(triangles, 3); + size_t k=0; + for(size_t i=0; i=0 && _map(i,j+1)>=0 && _map(i,j+2)>=0) + { + // consequtive faces on the same strip have to be flip-flopped, to preserve orientation + M( k,0 ) = static_cast( _map(i, j ) ); + M( k,1 ) = static_cast( _map(i, j+1+flip ) ); + M( k,2 ) = static_cast( _map(i, j+1+(flip^1) ) ); + k++; + flip ^= 1; + } else { + // reset flip on new strip start + flip = 0; + } + } + } + assert(k==triangles); + return true; +} + +template +IGL_INLINE bool tinyply_tristrips_to_faces( + tinyply::PlyData & D, + Eigen::PlainObjectBase & M, + size_t el, + size_t el_len ) +{ + switch(D.t) + { + case tinyply::Type::INT8 : + return _tinyply_tristrips_to_trifaces(D, M,el,el_len); + case tinyply::Type::UINT8 : + return _tinyply_tristrips_to_trifaces(D, M,el,el_len); + case tinyply::Type::INT16 : + return _tinyply_tristrips_to_trifaces(D, M,el,el_len); + case tinyply::Type::UINT16 : + return _tinyply_tristrips_to_trifaces(D, M,el,el_len); + case tinyply::Type::INT32 : + return _tinyply_tristrips_to_trifaces(D, M,el,el_len); + case tinyply::Type::UINT32 : + return _tinyply_tristrips_to_trifaces(D, M,el,el_len); + case tinyply::Type::FLOAT32 : + return _tinyply_tristrips_to_trifaces(D, M,el,el_len); + case tinyply::Type::FLOAT64 : + return _tinyply_tristrips_to_trifaces(D, M,el,el_len); + default: + return false; + } +} + +template < + typename DerivedV, + typename DerivedF, + typename DerivedE, + typename DerivedN, + typename DerivedUV, + typename DerivedVD, + typename DerivedFD, + typename DerivedED + > +IGL_INLINE bool readPLY( + FILE *fp, + Eigen::PlainObjectBase & V, + Eigen::PlainObjectBase & F, + Eigen::PlainObjectBase & E, + Eigen::PlainObjectBase & N, + Eigen::PlainObjectBase & UV, + + Eigen::PlainObjectBase & VD, + std::vector & Vheader, + Eigen::PlainObjectBase & FD, + std::vector & Fheader, + Eigen::PlainObjectBase & ED, + std::vector & Eheader, + std::vector & comments + ) +{ + // buffer the whole file in memory + // then read from memory buffer + try + { + std::vector fileBufferBytes; + read_file_binary(fp,fileBufferBytes); + file_memory_stream stream((char*)fileBufferBytes.data(), fileBufferBytes.size()); + return readPLY(stream,V,F,E,N,UV,VD,Vheader,FD,Fheader,ED,Eheader,comments); + } + catch(const std::exception& e) + { + std::cerr << "ReadPLY error: " << e.what() << std::endl; + } + return false; +} + + + +template < + typename DerivedV, + typename DerivedF + > +IGL_INLINE bool readPLY( + FILE *fp, + Eigen::PlainObjectBase & V, + Eigen::PlainObjectBase & F + ) +{ + Eigen::MatrixXd N,UV,VD,FD,ED; + Eigen::MatrixXi E; + std::vector Vheader,Eheader,Fheader,comments; + return readPLY(fp,V,F,E,N,UV,VD,Vheader,FD,Fheader,ED,Eheader,comments); +} + +template < + typename DerivedV, + typename DerivedF, + typename DerivedE + > +IGL_INLINE bool readPLY( + FILE *fp, + Eigen::PlainObjectBase & V, + Eigen::PlainObjectBase & F, + Eigen::PlainObjectBase & E + ) +{ + Eigen::MatrixXd N,UV,VD,FD,ED; + std::vector Vheader,Eheader,Fheader,comments; + return readPLY(fp,V,F,E,N,UV,VD,Vheader,FD,Fheader,ED,Eheader,comments); +} + + +template < + typename DerivedV, + typename DerivedF, + typename DerivedE, + typename DerivedN, + typename DerivedUV, + typename DerivedVD, + typename DerivedFD, + typename DerivedED + > +IGL_INLINE bool readPLY( + std::istream & ply_stream, + Eigen::PlainObjectBase & V, + Eigen::PlainObjectBase & F, + Eigen::PlainObjectBase & E, + Eigen::PlainObjectBase & N, + Eigen::PlainObjectBase & UV, + + Eigen::PlainObjectBase & VD, + std::vector & Vheader, + Eigen::PlainObjectBase & FD, + std::vector & Fheader, + Eigen::PlainObjectBase & ED, + std::vector & Eheader, + std::vector & comments + ) +{ + tinyply::PlyFile file; + file.parse_header(ply_stream); + + std::set vertex_std{ "x","y","z", "nx","ny","nz", "u","v", "texture_u", "texture_v", "s", "t"}; + std::set face_std { "vertex_index", "vertex_indices"}; + std::set edge_std { "vertex1", "vertex2"}; //non-standard edge indexes + + // Tinyply treats parsed data as untyped byte buffers. + std::shared_ptr vertices, normals, faces, texcoords, edges; + + // Some ply files contain tristrips instead of faces + std::shared_ptr tristrips; + + std::shared_ptr _vertex_data; + std::vector _vertex_header; + + std::shared_ptr _face_data; + std::vector _face_header; + + std::shared_ptr _edge_data; + std::vector _edge_header; + + for (auto c : file.get_comments()) + comments.push_back(c); + + for (auto e : file.get_elements()) + { + if(e.name == "vertex" ) // found a vertex + { + for (auto p : e.properties) + { + if(vertex_std.find(p.name) == vertex_std.end()) + { + _vertex_header.push_back(p.name); + } + } + } + else if(e.name == "face" ) // found face + { + for (auto p : e.properties) + { + if(face_std.find(p.name) == face_std.end()) + { + _face_header.push_back(p.name); + } + } + } + else if(e.name == "edge" ) // found edge + { + for (auto p : e.properties) + { + if(edge_std.find(p.name) == edge_std.end()) + { + _edge_header.push_back(p.name); + } + } + } + // skip the unknown entries + } + + // The header information can be used to programmatically extract properties on elements + // known to exist in the header prior to reading the data. For brevity of this sample, properties + // like vertex position are hard-coded: + try { + vertices = file.request_properties_from_element("vertex", { "x", "y", "z" }); + } + catch (const std::exception & ) { } + + try { + normals = file.request_properties_from_element("vertex", { "nx", "ny", "nz" }); + } + catch (const std::exception & ) { } + + //Try texture coordinates with several names + try { + //texture_u texture_v are the names used by meshlab to store textures + texcoords = file.request_properties_from_element("vertex", { "texture_u", "texture_v" }); + } + catch (const std::exception & ) { } + if (!texcoords) + { + try { + //u v are the naive names + texcoords = file.request_properties_from_element("vertex", { "u", "v" }); + } + catch (const std::exception & ) { } + + } + if (!texcoords) + { + try { + //s t were the names used by blender and the previous libigl PLY reader. + texcoords = file.request_properties_from_element("vertex", { "s", "t" }); + } + catch (const std::exception & ) { } + + } + + // Providing a list size hint (the last argument) is a 2x performance improvement. If you have + // arbitrary ply files, it is best to leave this 0. + try { + faces = file.request_properties_from_element( "face", { "vertex_indices" }, 0); + } + catch (const std::exception & ) { } + + if (!faces) + { + try { + // alternative name of the elements + faces = file.request_properties_from_element( "face", { "vertex_index" },0); + } + catch (const std::exception & ) { } + } + + if (!faces) + { + try { + // try using tristrips + tristrips = file.request_properties_from_element( "tristrips", { "vertex_indices" }, 0); + } + catch (const std::exception & ) { } + + if (!tristrips) + { + try { + // alternative name of the elements + tristrips = file.request_properties_from_element( "tristrips", { "vertex_index" }, 0); + } + catch (const std::exception & ) { } + } + } + + + try { + edges = file.request_properties_from_element("edge", { "vertex1", "vertex2" }); + } + catch (const std::exception & ) { } + + if(! _vertex_header.empty()) + _vertex_data = file.request_properties_from_element( "vertex", _vertex_header); + if(! _face_header.empty()) + _face_data = file.request_properties_from_element( "face", _face_header); + if(! _edge_header.empty()) + _edge_data = file.request_properties_from_element( "edge", _edge_header); + + // Parse the geometry data + file.read(ply_stream); + + if (!vertices || !tinyply_buffer_to_matrix(*vertices,V,vertices->count,3) ) { + V.resize(0,0); + } + + if (!normals || !tinyply_buffer_to_matrix(*normals,N,normals->count,3) ) { + N.resize(0,0); + } + + if (!texcoords || !tinyply_buffer_to_matrix(*texcoords,UV,texcoords->count,2) ) { + UV.resize(0,0); + } + + //HACK: Unfortunately, tinyply doesn't store list size as a separate variable + if (!faces || !tinyply_buffer_to_matrix(*faces, F, faces->count, faces->buffer.size_bytes()/(tinyply::PropertyTable[faces->t].stride*faces->count) )) { + + if(tristrips) { // need to convert to faces + // code based on blender importer for ply + // converting triangle strips into triangles + // tinyply supports tristrips of the same length only + size_t el_count = tristrips->buffer.size_bytes()/(tinyply::PropertyTable[tristrips->t].stride*tristrips->count); + + // all strips should have tristrips->count elements + if(!tinyply_tristrips_to_faces(*tristrips, F , tristrips->count, el_count)) + F.resize(0,0); + + } else { + F.resize(0,0); + } + } + + if(!edges || !tinyply_buffer_to_matrix(*edges,E, edges->count,2)) { + E.resize(0,0); + } + + /// convert vertex data: + Vheader=_vertex_header; + if(_vertex_header.empty()) + { + VD.resize(0,0); + } + else + { + VD.resize(vertices->count,_vertex_header.size()); + tinyply_buffer_to_matrix(*_vertex_data, VD, vertices->count, _vertex_header.size()); + } + + /// convert face data: + Fheader=_face_header; + if(_face_header.empty()) + { + FD.resize(0,0); + } + else + { + FD.resize(faces->count, _face_header.size()); + tinyply_buffer_to_matrix(*_face_data, FD, faces->count, 1); + } + + /// convert edge data: + Eheader=_edge_header; + if(_edge_header.empty()) + { + ED.resize(0,0); + } + else + { + ED.resize(_edge_data->count, _edge_header.size()); + tinyply_buffer_to_matrix(*_edge_data, ED, _edge_data->count, _edge_header.size()); + } + return true; +} + + +template < + typename DerivedV, + typename DerivedF, + typename DerivedE, + typename DerivedN, + typename DerivedUV, + typename DerivedVD, + typename DerivedFD, + typename DerivedED + > +IGL_INLINE bool readPLY( + const std::string& ply_file, + Eigen::PlainObjectBase & V, + Eigen::PlainObjectBase & F, + Eigen::PlainObjectBase & E, + Eigen::PlainObjectBase & N, + Eigen::PlainObjectBase & UV, + + Eigen::PlainObjectBase & VD, + std::vector & VDheader, + + Eigen::PlainObjectBase & FD, + std::vector & FDheader, + + Eigen::PlainObjectBase & ED, + std::vector & EDheader, + std::vector & comments + ) +{ + + std::ifstream ply_stream(ply_file, std::ios::binary); + if (ply_stream.fail()) + { + std::cerr << "ReadPLY: Error opening file " << ply_file << std::endl; + return false; + } + try + { + return readPLY(ply_stream, V, F, E, N, UV, VD, VDheader, FD,FDheader, ED, EDheader, comments ); + } catch (const std::exception& e) { + std::cerr << "ReadPLY error: " << ply_file << e.what() << std::endl; + } + return false; +} + + +template < + typename DerivedV, + typename DerivedF, + typename DerivedE, + typename DerivedN, + typename DerivedUV, + typename DerivedD + > +IGL_INLINE bool readPLY( + const std::string & filename, + Eigen::PlainObjectBase & V, + Eigen::PlainObjectBase & F, + Eigen::PlainObjectBase & E, + Eigen::PlainObjectBase & N, + Eigen::PlainObjectBase & UV, + Eigen::PlainObjectBase & VD, + std::vector & Vheader + ) +{ + Eigen::MatrixXd FD,ED; + std::vector Fheader,Eheader; + std::vector comments; + return readPLY(filename,V,F,E,N,UV,VD,Vheader,FD,Fheader,ED,Eheader,comments); +} + +template < + typename DerivedV, + typename DerivedF, + typename DerivedE, + typename DerivedN, + typename DerivedUV + > +IGL_INLINE bool readPLY( + const std::string & filename, + Eigen::PlainObjectBase & V, + Eigen::PlainObjectBase & F, + Eigen::PlainObjectBase & E, + Eigen::PlainObjectBase & N, + Eigen::PlainObjectBase & UV + ) +{ + Eigen::MatrixXd VD,FD,ED; + std::vector Vheader,Fheader,Eheader; + std::vector comments; + return readPLY(filename,V,F,E, N,UV,VD,Vheader,FD,Fheader,ED,Eheader,comments); +} + +template < + typename DerivedV, + typename DerivedF, + typename DerivedN, + typename DerivedUV + > +IGL_INLINE bool readPLY( + const std::string & filename, + Eigen::PlainObjectBase & V, + Eigen::PlainObjectBase & F, + Eigen::PlainObjectBase & N, + Eigen::PlainObjectBase & UV + ) +{ + Eigen::MatrixXd VD,FD,ED; + Eigen::MatrixXi E; + std::vector Vheader,Fheader,Eheader; + std::vector comments; + return readPLY(filename,V,F,E, N,UV,VD,Vheader,FD,Fheader,ED,Eheader,comments); +} + +template < + typename DerivedV, + typename DerivedF + > +IGL_INLINE bool readPLY( + const std::string & filename, + Eigen::PlainObjectBase & V, + Eigen::PlainObjectBase & F + ) +{ + Eigen::MatrixXd N,UV; + Eigen::MatrixXd VD,FD,ED; + Eigen::MatrixXi E; + + std::vector Vheader,Fheader,Eheader; + std::vector comments; + return readPLY(filename,V,F,E,N,UV,VD,Vheader,FD,Fheader,ED,Eheader,comments); +} + +template < + typename DerivedV, + typename DerivedF, + typename DerivedE + > +IGL_INLINE bool readPLY( + const std::string & filename, + Eigen::PlainObjectBase & V, + Eigen::PlainObjectBase & F, + Eigen::PlainObjectBase & E + ) +{ + Eigen::MatrixXd N,UV; + Eigen::MatrixXd VD,FD,ED; + + std::vector Vheader,Fheader,Eheader; + std::vector comments; + return readPLY(filename,V,F,E,N,UV,VD,Vheader,FD,Fheader,ED,Eheader,comments); +} + + +} //igl namespace + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template bool igl::readPLY, Eigen::Matrix >(FILE*, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template bool igl::readPLY, Eigen::Matrix >(FILE*, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template bool igl::readPLY, Eigen::Matrix >(FILE*, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template bool igl::readPLY, Eigen::Matrix >(FILE*, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template bool igl::readPLY, Eigen::Matrix >(FILE*, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template bool igl::readPLY, Eigen::Matrix >(FILE*, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template bool igl::readPLY, Eigen::Matrix >(std::basic_string, std::allocator > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template bool igl::readPLY, Eigen::Matrix >(FILE*, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template bool igl::readPLY, Eigen::Matrix >(FILE*, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template bool igl::readPLY, Eigen::Matrix >(FILE*, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template bool igl::readPLY, Eigen::Matrix >(FILE*, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); + +template bool igl::readPLY, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(std::basic_string, std::allocator > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, std::vector, std::allocator >, std::allocator, std::allocator > > >&, Eigen::PlainObjectBase >&, std::vector, std::allocator >, std::allocator, std::allocator > > >&, Eigen::PlainObjectBase >&, std::vector, std::allocator >, std::allocator, std::allocator > > >&, std::vector, std::allocator >, std::allocator, std::allocator > > >&); +template bool igl::readPLY, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(std::basic_string, std::allocator > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, std::vector, std::allocator >, std::allocator, std::allocator > > >&, Eigen::PlainObjectBase >&, std::vector, std::allocator >, std::allocator, std::allocator > > >&, Eigen::PlainObjectBase >&, std::vector, std::allocator >, std::allocator, std::allocator > > >&, std::vector, std::allocator >, std::allocator, std::allocator > > >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/readPLY.h b/src/external/libigl-2.3.0/include/igl/readPLY.h new file mode 100644 index 000000000..ca57b0292 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/readPLY.h @@ -0,0 +1,221 @@ +#ifndef IGL_READPLY_H +#define IGL_READPLY_H +#include +#include +#include +#include +#include "tinyply.h" + +namespace igl +{ +template < + typename DerivedV, + typename DerivedF + > +IGL_INLINE bool readPLY( + FILE *fp, + Eigen::PlainObjectBase & V, + Eigen::PlainObjectBase & F + ); + + +// Read triangular mesh from ply file, filling in vertex positions, normals + // and texture coordinates, if available + // also read additional properties associated with vertex,faces and edges + // and file comments + // + // Templates: + // Derived from Eigen matrix parameters + // Inputs: + // ply_stream ply file input stream + // Outputs: + // V (#V,3) matrix of vertex positions + // F (#F,3) list of face indices into vertex positions + // E (#E,2) list of edge indices into vertex positions + // N (#V,3) list of normals + // UV (#V,2) list of texture coordinates + // VD (#V,*) additional vertex data + // Vheader (#V) list of vertex data headers + // FD (#F,*) additional face data + // Fheader (#F) list of face data headers + // ED (#E,*) additional edge data + // Eheader (#E) list of edge data headers + // comments (*) file comments + // Returns true on success, false on errors + template < + typename DerivedV, + typename DerivedF, + typename DerivedE, + typename DerivedN, + typename DerivedUV, + typename DerivedVD, + typename DerivedFD, + typename DerivedED + > + bool readPLY( + std::istream & ply_stream, + Eigen::PlainObjectBase & V, + Eigen::PlainObjectBase & F, + Eigen::PlainObjectBase & E, + Eigen::PlainObjectBase & N, + Eigen::PlainObjectBase & UV, + + Eigen::PlainObjectBase & VD, + std::vector & Vheader, + Eigen::PlainObjectBase & FD, + std::vector & Fheader, + Eigen::PlainObjectBase & ED, + std::vector & Eheader, + std::vector & comments + ); + + // Read triangular mesh from ply file, filling in vertex positions, normals + // and texture coordinates, if available + // also read additional properties associated with vertex,faces and edges + // and file comments + // + // Templates: + // Derived from Eigen matrix parameters + // Inputs: + // ply_file ply file name + // Outputs: + // V (#V,3) matrix of vertex positions + // F (#F,3) list of face indices into vertex positions + // E (#E,2) list of edge indices into vertex positions + // N (#V,3) list of normals + // UV (#V,2) list of texture coordinates + // VD (#V,*) additional vertex data + // Vheader (#V) list of vertex data headers + // FD (#F,*) additional face data + // Fheader (#F) list of face data headers + // ED (#E,*) additional edge data + // Eheader (#E) list of edge data headers + // comments (*) file comments + // Returns true on success, false on errors + template < + typename DerivedV, + typename DerivedF, + typename DerivedE, + typename DerivedN, + typename DerivedUV, + typename DerivedVD, + typename DerivedFD, + typename DerivedED + > + bool readPLY( + const std::string& ply_file, + Eigen::PlainObjectBase & V, + Eigen::PlainObjectBase & F, + Eigen::PlainObjectBase & E, + Eigen::PlainObjectBase & N, + Eigen::PlainObjectBase & UV, + + Eigen::PlainObjectBase & VD, + std::vector & VDheader, + + Eigen::PlainObjectBase & FD, + std::vector & FDheader, + + Eigen::PlainObjectBase & ED, + std::vector & EDheader, + std::vector & comments + ); + + + // Read triangular mesh from ply file, filling in vertex positions, normals + // and texture coordinates, if available + // also read additional properties associated with vertex,faces and edges + // and file comments + // + // Templates: + // Derived from Eigen matrix parameters + // Inputs: + // ply_file ply file name + // Outputs: + // V (#V,3) matrix of vertex positions + // F (#F,3) list of face indices into vertex positions + // N (#V,3) list of normals + // UV (#V,2) list of texture coordinates + // VD (#V,*) additional vertex data + // Vheader (#V) list of vertex data headers + // Returns true on success, false on errors + template < + typename DerivedV, + typename DerivedF, + typename DerivedN, + typename DerivedUV, + typename DerivedVD + > + bool readPLY( + const std::string & filename, + Eigen::PlainObjectBase & V, + Eigen::PlainObjectBase & F, + Eigen::PlainObjectBase & N, + Eigen::PlainObjectBase & UV, + Eigen::PlainObjectBase & VD, + std::vector & Vheader + ); + + // Read triangular mesh from ply file, filling in vertex positions, normals + // and texture coordinates, if available + // also read additional properties associated with vertex,faces and edges + // and file comments + // + // Templates: + // Derived from Eigen matrix parameters + // Inputs: + // ply_file ply file name + // Outputs: + // V (#V,3) matrix of vertex positions + // F (#F,3) list of face indices into vertex positions + // E (#E,2) list of edge indices into vertex positions + // N (#V,3) list of normals + // UV (#V,2) list of texture coordinates + // VD (#V,*) additional vertex data + // Vheader (#V) list of vertex data headers + // Returns true on success, false on errors + template < + typename DerivedV, + typename DerivedF, + typename DerivedE, + typename DerivedN, + typename DerivedUV + > + bool readPLY( + const std::string & filename, + Eigen::PlainObjectBase & V, + Eigen::PlainObjectBase & F, + Eigen::PlainObjectBase & E, + Eigen::PlainObjectBase & N, + Eigen::PlainObjectBase & UV + ); + + + template < + typename DerivedV, + typename DerivedF + > + bool readPLY( + const std::string & filename, + Eigen::PlainObjectBase & V, + Eigen::PlainObjectBase & F + ); + + template < + typename DerivedV, + typename DerivedF, + typename DerivedE + > + bool readPLY( + const std::string & filename, + Eigen::PlainObjectBase & V, + Eigen::PlainObjectBase & F, + Eigen::PlainObjectBase & E + ); + +} + +#ifndef IGL_STATIC_LIBRARY +# include "readPLY.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/readSTL.cpp b/src/external/libigl-2.3.0/include/igl/readSTL.cpp new file mode 100644 index 000000000..3275037bf --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/readSTL.cpp @@ -0,0 +1,326 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Alec Jacobson +// Copyright (C) 2018 Qingnan Zhou +// Copyright (C) 2020 Jérémie Dumas +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "readSTL.h" +#include "list_to_matrix.h" +#include "string_utils.h" +#include "file_utils.h" + +#include + +namespace igl { + +template +IGL_INLINE bool readSTL(std::istream &input, + Eigen::PlainObjectBase &V, + Eigen::PlainObjectBase &F, + Eigen::PlainObjectBase &N) { + std::vector> vV; + std::vector> vN; + std::vector> vF; + if (!readSTL(input, vV, vF, vN)) { + return false; + } + + if (!list_to_matrix(vV, V)) { + return false; + } + + if (!list_to_matrix(vF, F)) { + return false; + } + + if (!list_to_matrix(vN, N)) { + return false; + } + return true; +} + +IGL_INLINE bool is_stl_binary(std::istream &input) { + std::streampos start_pos = input.tellg(); + + constexpr size_t HEADER_SIZE = 80; + char header[HEADER_SIZE]; + input.read(header, HEADER_SIZE); + if (!starts_with(header, "solid")) { + input.seekg(start_pos); + return true; + } + if (!input.good()) { + input.seekg(start_pos); + return false; + } + + // Check if filesize matches the number of faces claimed. + char buf[4]; + input.read(buf, 4); + size_t num_faces = *reinterpret_cast(buf); + input.seekg(0, input.end); + size_t file_size = input.tellg(); + + input.seekg(start_pos); + + if (file_size == 80 + 4 + (4 * 12 + 2) * num_faces) { + return true; + } else { + return false; + } +} + +template +IGL_INLINE bool read_stl_ascii(std::istream &input, + std::vector> &V, + std::vector> &F, + std::vector> &N) { + constexpr size_t LINE_SIZE = 256; + char line[LINE_SIZE]; + bool success = true; + + if (!input) { + throw std::runtime_error("Failed to open file"); + } + + // skip header line. + input.getline(line, LINE_SIZE); + + auto parse_ascii_normal = [&N](const char *line) { + double x, y, z; + size_t n = sscanf(line, " facet normal %lf %lf %lf", &x, &y, &z); + assert(n == 3); + if (n != 3) { + return false; + } + + N.push_back({{static_cast(x), static_cast(y), + static_cast(z)}}); + return true; + }; + + auto parse_ascii_vertex = [&V](const char *line) { + double x, y, z; + size_t n = sscanf(line, " vertex %lf %lf %lf", &x, &y, &z); + assert(n == 3); + if (n != 3) { + return false; + } + + V.push_back({{static_cast(x), static_cast(y), + static_cast(z)}}); + return true; + }; + + auto parse_ascii_facet = [&parse_ascii_vertex, &parse_ascii_normal](std::istream &fin) { + constexpr size_t LINE_SIZE = 256; + constexpr size_t WORD_SIZE = 128; + char line[LINE_SIZE]; + char first_word[WORD_SIZE]; + const char *face_begin = "facet"; + const char *face_end = "endfacet"; + const char *loop_begin = "outer"; + const char *loop_end = "endloop"; + const char *vertex_flag = "vertex"; + + bool reading_facet = false; + bool reading_loop = false; + bool success = true; + size_t num_vts = 0; + while (!fin.eof()) { + fin.getline(line, LINE_SIZE); + size_t n = sscanf(line, " %s", first_word); + if (n == 0) + continue; + if (starts_with(first_word, face_begin)) { + success = parse_ascii_normal(line); + assert(success); + reading_facet = true; + } else if (starts_with(first_word, face_end)) { + assert(reading_facet); + reading_facet = false; + } else if (starts_with(first_word, loop_begin)) { + reading_loop = true; + } else if (starts_with(first_word, loop_end)) { + assert(reading_loop); + reading_loop = false; + } else if (starts_with(first_word, vertex_flag)) { + assert(reading_facet); + assert(reading_loop); + success = parse_ascii_vertex(line); + assert(success); + num_vts += 1; + } + if (!success) { + return false; + } + if (!reading_facet) { + break; + } + } + if (num_vts == 0) { + return true; + } + assert(num_vts == 3); + if (num_vts != 3) { + std::cerr << "Warning: mesh contain face made of " << num_vts + << " vertices" << std::endl; + return false; + } + return true; + }; + + while (!input.eof()) { + success = parse_ascii_facet(input); + if (!success) { + return false; + } + } + + F.resize(V.size() / 3); + for (size_t f = 0; f < F.size(); ++f) { + auto v = static_cast(f * 3); + F[f] = {{v, v + 1, v + 2}}; + } + return success; +} + +template +IGL_INLINE bool read_stl_binary(std::istream &input, + std::vector> &V, + std::vector> &F, + std::vector> &N) { + if (!input) { + throw std::runtime_error("Failed to open file"); + } + + constexpr size_t FLOAT_SIZE = sizeof(float); + static_assert(FLOAT_SIZE == 4, "float type is not 4 bytes"); + constexpr size_t LINE_SIZE = 256; + char buf[LINE_SIZE]; + + // 80 bytes header, no data significance. + input.read(buf, 80); + if (!input.good()) { + throw std::runtime_error("Unable to parse STL header."); + } + + input.read(buf, 4); + const size_t num_faces = *reinterpret_cast(buf); + if (!input.good()) { + throw std::runtime_error("Unable to parse STL number of faces."); + } + + for (size_t i = 0; i < num_faces; i++) { + // Parse normal + input.read(buf, FLOAT_SIZE * 3); + auto nx = static_cast(*reinterpret_cast(buf)); + auto ny = static_cast(*reinterpret_cast(buf + FLOAT_SIZE)); + auto nz = + static_cast(*reinterpret_cast(buf + FLOAT_SIZE * 2)); + assert(input.good()); + + // vertex 1 + input.read(buf, FLOAT_SIZE * 3); + auto v1x = static_cast(*reinterpret_cast(buf)); + auto v1y = static_cast(*reinterpret_cast(buf + FLOAT_SIZE)); + auto v1z = + static_cast(*reinterpret_cast(buf + FLOAT_SIZE * 2)); + assert(input.good()); + + // vertex 2 + input.read(buf, FLOAT_SIZE * 3); + auto v2x = static_cast(*reinterpret_cast(buf)); + auto v2y = static_cast(*reinterpret_cast(buf + FLOAT_SIZE)); + auto v2z = + static_cast(*reinterpret_cast(buf + FLOAT_SIZE * 2)); + assert(input.good()); + + // vertex 3 + input.read(buf, FLOAT_SIZE * 3); + auto v3x = static_cast(*reinterpret_cast(buf)); + auto v3y = static_cast(*reinterpret_cast(buf + FLOAT_SIZE)); + auto v3z = + static_cast(*reinterpret_cast(buf + FLOAT_SIZE * 2)); + assert(input.good()); + + // attribute (2 bytes), not sure what purpose they serve. + input.read(buf, 2); + + N.push_back({{nx, ny, nz}}); + V.push_back({{v1x, v1y, v1z}}); + V.push_back({{v2x, v2y, v2z}}); + V.push_back({{v3x, v3y, v3z}}); + + assert(input.good()); + if (!input.good()) { + std::stringstream err_msg; + err_msg << "Failed to parse face " << i << " from STL file"; + throw std::runtime_error(err_msg.str()); + } + } + std::for_each(V.begin(), V.end(), [](const std::array &v) { + for (auto x : v) { + if (!std::isfinite(x)) { + throw std::runtime_error("NaN or Inf detected in input file."); + } + } + }); + + if (!V.empty()) { + F.resize(V.size() / 3); + for (size_t f = 0; f < F.size(); ++f) { + auto v = static_cast(f * 3); + F[f] = {{v, v + 1, v + 2}}; + } + } + + return true; +} + +template +IGL_INLINE bool readSTL(std::istream &input, + std::vector> &V, + std::vector> &F, + std::vector> &N) { + bool success = false; + if (is_stl_binary(input)) { + success = read_stl_binary(input, V, F, N); + } else { + success = read_stl_ascii(input, V, F, N); + } + return success; +} + +template +IGL_INLINE bool readSTL( + FILE * fp, + Eigen::PlainObjectBase & V, + Eigen::PlainObjectBase & F, + Eigen::PlainObjectBase & N) +{ + std::vector fileBufferBytes; + read_file_binary(fp,fileBufferBytes); + file_memory_stream stream((char*)fileBufferBytes.data(), fileBufferBytes.size()); + return readSTL(stream, V, F, N); +} + +} // namespace igl + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template bool igl::readSTL, Eigen::Matrix, Eigen::Matrix >(FILE*, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template bool igl::readSTL, Eigen::Matrix, Eigen::Matrix >(FILE*, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template bool igl::readSTL, Eigen::Matrix, Eigen::Matrix >(FILE*, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template bool igl::readSTL, Eigen::Matrix, Eigen::Matrix >(FILE*, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template bool igl::readSTL, Eigen::Matrix, Eigen::Matrix >(FILE*, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template bool igl::readSTL, Eigen::Matrix, Eigen::Matrix >(FILE*, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template bool igl::readSTL, Eigen::Matrix, Eigen::Matrix >(FILE*, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template bool igl::readSTL, Eigen::Matrix, Eigen::Matrix >(FILE*, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template bool igl::readSTL, Eigen::Matrix, Eigen::Matrix >(FILE*, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template bool igl::readSTL, Eigen::Matrix, Eigen::Matrix >(FILE*, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/readSTL.h b/src/external/libigl-2.3.0/include/igl/readSTL.h new file mode 100644 index 000000000..cd39fd552 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/readSTL.h @@ -0,0 +1,68 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// Copyright (C) 2020 Jérémie Dumas +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_READSTL_H +#define IGL_READSTL_H +#include "igl_inline.h" + +#ifndef IGL_NO_EIGEN +# include +#endif +#include +#include +#include +#include + +namespace igl +{ + // Read a mesh from an ascii/binary stl file. + // + // Templates: + // Scalar type for positions and vectors (will be read as double and cast + // to Scalar) + // Inputs: + // filename path to .stl file + // Outputs: + // V double matrix of vertex positions #V*3 by 3 + // F index matrix of triangle indices #F by 3 + // N double matrix of surface normals #F by 3 + // Returns true on success, false on errors + // + // Example: + // bool success = readSTL(filename,temp_V,F,N); + // remove_duplicate_vertices(temp_V,0,V,SVI,SVJ); + // for_each(F.data(),F.data()+F.size(),[&SVJ](int & f){f=SVJ(f);}); + // writeOBJ("Downloads/cat.obj",V,F); + template + IGL_INLINE bool readSTL( + std::istream &input, + Eigen::PlainObjectBase & V, + Eigen::PlainObjectBase & F, + Eigen::PlainObjectBase & N); + + template + IGL_INLINE bool readSTL( + std::istream &input, + std::vector > & V, + std::vector > & F, + std::vector > & N); + + template + IGL_INLINE bool readSTL( + FILE * fp, + Eigen::PlainObjectBase & V, + Eigen::PlainObjectBase & F, + Eigen::PlainObjectBase & N); +} + +#ifndef IGL_STATIC_LIBRARY +# include "readSTL.cpp" +#endif + +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/readTGF.cpp b/src/external/libigl-2.3.0/include/igl/readTGF.cpp new file mode 100644 index 000000000..814395b30 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/readTGF.cpp @@ -0,0 +1,200 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "readTGF.h" + +#include + +IGL_INLINE bool igl::readTGF( + const std::string tgf_filename, + std::vector > & C, + std::vector > & E, + std::vector & P, + std::vector > & BE, + std::vector > & CE, + std::vector > & PE) +{ + using namespace std; + // clear output + C.clear(); + E.clear(); + P.clear(); + BE.clear(); + CE.clear(); + PE.clear(); + + FILE * tgf_file = fopen(tgf_filename.c_str(),"r"); + if(NULL==tgf_file) + { + printf("IOError: %s could not be opened\n",tgf_filename.c_str()); + return false; + } + + bool reading_vertices = true; + bool reading_edges = true; + const int MAX_LINE_LENGTH = 500; + char line[MAX_LINE_LENGTH]; + // read until seeing end of file + while(fgets(line,MAX_LINE_LENGTH,tgf_file)!=NULL) + { + // comment signifies end of vertices, next line is start of edges + if(line[0] == '#') + { + if(reading_vertices) + { + reading_vertices = false; + reading_edges = true; + }else if(reading_edges) + { + reading_edges = false; + } + // process vertex line + }else if(reading_vertices) + { + int index; + vector position(3); + int count = + sscanf(line,"%d %lg %lg %lg", + &index, + &position[0], + &position[1], + &position[2]); + if(count != 4) + { + fprintf(stderr,"Error: readTGF.h: bad format in vertex line\n"); + fclose(tgf_file); + return false; + } + // index is ignored since vertices must already be in order + C.push_back(position); + }else if(reading_edges) + { + vector edge(2); + int is_BE = 0; + int is_PE = 0; + int is_CE = 0; + int count = sscanf(line,"%d %d %d %d %d\n", + &edge[0], + &edge[1], + &is_BE, + &is_PE, + &is_CE); + if(count<2) + { + fprintf(stderr,"Error: readTGF.h: bad format in edge line\n"); + fclose(tgf_file); + return false; + } + // .tgf is one indexed + edge[0]--; + edge[1]--; + E.push_back(edge); + if(is_BE == 1) + { + BE.push_back(edge); + } + if(is_PE == 1) + { + // PE should index P + fprintf(stderr, + "Warning: readTGF.h found pseudo edges but does not support " + "them\n"); + } + if(is_CE == 1) + { + // CE should index P + fprintf(stderr, + "Warning: readTGF.h found cage edges but does not support them\n"); + } + }else + { + // ignore faces + } + } + fclose(tgf_file); + // Construct P, indices not in BE + for(int i = 0;i<(int)C.size();i++) + { + bool in_edge = false; + for(int j = 0;j<(int)BE.size();j++) + { + if(i == BE[j][0] || i == BE[j][1]) + { + in_edge = true; + break; + } + } + if(!in_edge) + { + P.push_back(i); + } + } + return true; +} + +#ifndef IGL_NO_EIGEN +#include "list_to_matrix.h" + +IGL_INLINE bool igl::readTGF( + const std::string tgf_filename, + Eigen::MatrixXd & C, + Eigen::MatrixXi & E, + Eigen::VectorXi & P, + Eigen::MatrixXi & BE, + Eigen::MatrixXi & CE, + Eigen::MatrixXi & PE) +{ + std::vector > vC; + std::vector > vE; + std::vector vP; + std::vector > vBE; + std::vector > vCE; + std::vector > vPE; + bool success = readTGF(tgf_filename,vC,vE,vP,vBE,vCE,vPE); + if(!success) + { + return false; + } + + if(!list_to_matrix(vC,C)) + { + return false; + } + if(!list_to_matrix(vE,E)) + { + return false; + } + if(!list_to_matrix(vP,P)) + { + return false; + } + if(!list_to_matrix(vBE,BE)) + { + return false; + } + if(!list_to_matrix(vCE,CE)) + { + return false; + } + if(!list_to_matrix(vPE,PE)) + { + return false; + } + + return true; +} + +IGL_INLINE bool igl::readTGF( + const std::string tgf_filename, + Eigen::MatrixXd & C, + Eigen::MatrixXi & E) +{ + Eigen::VectorXi P; + Eigen::MatrixXi BE,CE,PE; + return readTGF(tgf_filename,C,E,P,BE,CE,PE); +} +#endif diff --git a/src/external/libigl-2.3.0/include/igl/readTGF.h b/src/external/libigl-2.3.0/include/igl/readTGF.h new file mode 100644 index 000000000..68c5ddef8 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/readTGF.h @@ -0,0 +1,66 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_READTGF_H +#define IGL_READTGF_H +#include "igl_inline.h" + +#include +#include +#ifndef IGL_NO_EIGEN +#include +#endif + +namespace igl +{ + // READTGF + // + // [V,E,P,BE,CE,PE] = readTGF(filename) + // + // Read a graph from a .tgf file + // + // Input: + // filename .tgf file name + // Output: + // V # vertices by 3 list of vertex positions + // E # edges by 2 list of edge indices + // P # point-handles list of point handle indices + // BE # bone-edges by 2 list of bone-edge indices + // CE # cage-edges by 2 list of cage-edge indices + // PE # pseudo-edges by 2 list of pseudo-edge indices + // + // Assumes that graph vertices are 3 dimensional + IGL_INLINE bool readTGF( + const std::string tgf_filename, + std::vector > & C, + std::vector > & E, + std::vector & P, + std::vector > & BE, + std::vector > & CE, + std::vector > & PE); + + #ifndef IGL_NO_EIGEN + IGL_INLINE bool readTGF( + const std::string tgf_filename, + Eigen::MatrixXd & C, + Eigen::MatrixXi & E, + Eigen::VectorXi & P, + Eigen::MatrixXi & BE, + Eigen::MatrixXi & CE, + Eigen::MatrixXi & PE); + IGL_INLINE bool readTGF( + const std::string tgf_filename, + Eigen::MatrixXd & C, + Eigen::MatrixXi & E); + #endif +} + +#ifndef IGL_STATIC_LIBRARY +# include "readTGF.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/readWRL.cpp b/src/external/libigl-2.3.0/include/igl/readWRL.cpp new file mode 100644 index 000000000..ce6de3e73 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/readWRL.cpp @@ -0,0 +1,121 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "readWRL.h" +#include + +template +IGL_INLINE bool igl::readWRL( + const std::string wrl_file_name, + std::vector > & V, + std::vector > & F) +{ + using namespace std; + FILE * wrl_file = fopen(wrl_file_name.c_str(),"r"); + if(NULL==wrl_file) + { + printf("IOError: %s could not be opened...",wrl_file_name.c_str()); + return false; + } + return readWRL(wrl_file,V,F); +} + +template +IGL_INLINE bool igl::readWRL( + FILE * wrl_file, + std::vector > & V, + std::vector > & F) +{ + using namespace std; + + char line[1000]; + // Read lines until seeing "point [" + // treat other lines in file as "comments" + bool still_comments = true; + string needle("point ["); + string haystack; + while(still_comments) + { + if(fgets(line,1000,wrl_file) == NULL) + { + std::cerr<<"readWRL, reached EOF without finding \"point [\""< point; + point.resize(3); + point[0] = x; + point[1] = y; + point[2] = z; + V.push_back(point); + //printf("(%g, %g, %g)\n",x,y,z); + }else if(floats_read != 0) + { + printf("ERROR: unrecognized format...\n"); + return false; + } + } + // Read lines until seeing "coordIndex [" + // treat other lines in file as "comments" + still_comments = true; + needle = string("coordIndex ["); + while(still_comments) + { + fgets(line,1000,wrl_file); + haystack = string(line); + still_comments = string::npos == haystack.find(needle); + } + // read F + int ints_read = 1; + while(ints_read > 0) + { + // read new face indices (until hit -1) + vector face; + while(true) + { + // indices are 0-indexed + int i; + ints_read = fscanf(wrl_file," %d,",&i); + if(ints_read > 0) + { + if(i>=0) + { + face.push_back(i); + }else + { + F.push_back(face); + break; + } + }else + { + break; + } + } + } + + + + fclose(wrl_file); + return true; +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +template bool igl::readWRL(std::basic_string, std::allocator >, std::vector >, std::allocator > > >&, std::vector >, std::allocator > > >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/readWRL.h b/src/external/libigl-2.3.0/include/igl/readWRL.h new file mode 100644 index 000000000..45c1fa048 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/readWRL.h @@ -0,0 +1,53 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_READWRL_H +#define IGL_READWRL_H +#include "igl_inline.h" + +#include +#include +#include + +namespace igl +{ + // Read a mesh from an ascii wrl file, filling in vertex positions and face + // indices of the first model. Mesh may have faces of any number of degree + // + // Templates: + // Scalar type for positions and vectors (will be read as double and cast + // to Scalar) + // Index type for indices (will be read as int and cast to Index) + // Inputs: + // str path to .wrl file + // Outputs: + // V double matrix of vertex positions #V by 3 + // F #F list of face indices into vertex positions + // Returns true on success, false on errors + template + IGL_INLINE bool readWRL( + const std::string wrl_file_name, + std::vector > & V, + std::vector > & F); + // Inputs: + // wrl_file pointer to already opened .wrl file + // Outputs: + // wrl_file closed file + template + IGL_INLINE bool readWRL( + FILE * wrl_file, + std::vector > & V, + std::vector > & F); + +} + +#ifndef IGL_STATIC_LIBRARY +# include "readWRL.cpp" +#endif + +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/read_triangle_mesh.cpp b/src/external/libigl-2.3.0/include/igl/read_triangle_mesh.cpp new file mode 100644 index 000000000..f6180a345 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/read_triangle_mesh.cpp @@ -0,0 +1,225 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "read_triangle_mesh.h" + +#include "list_to_matrix.h" +#include "readMSH.h" +#include "readMESH.h" +#include "readOBJ.h" +#include "readOFF.h" +#include "readSTL.h" +#include "readPLY.h" +#include "readWRL.h" +#include "pathinfo.h" +#include "boundary_facets.h" +#include "polygon_corners.h" +#include "polygons_to_triangles.h" + +#include +#include + + +template +IGL_INLINE bool igl::read_triangle_mesh( + const std::string str, + std::vector > & V, + std::vector > & F) +{ + using namespace std; + // dirname, basename, extension and filename + string d,b,e,f; + pathinfo(str,d,b,e,f); + // Convert extension to lower case + std::transform(e.begin(), e.end(), e.begin(), ::tolower); + vector > TC, N, C; + vector > FTC, FN; + if(e == "obj") + { + // Annoyingly obj can store 4 coordinates, truncate to xyz for this generic + // read_triangle_mesh + bool success = readOBJ(str,V,TC,N,F,FTC,FN); + for(auto & v : V) + { + v.resize(std::min(v.size(),(size_t)3)); + } + return success; + }else if(e == "off") + { + return readOFF(str,V,F,N,C); + } + cerr<<"Error: "<<__FUNCTION__<<": "<< + str<<" is not a recognized mesh file format."< +IGL_INLINE bool igl::read_triangle_mesh( + const std::string str, + Eigen::PlainObjectBase& V, + Eigen::PlainObjectBase& F) +{ + std::string _1,_2,_3,_4; + return read_triangle_mesh(str,V,F,_1,_2,_3,_4); +} + +template +IGL_INLINE bool igl::read_triangle_mesh( + const std::string filename, + Eigen::PlainObjectBase& V, + Eigen::PlainObjectBase& F, + std::string & dir, + std::string & base, + std::string & ext, + std::string & name) +{ + using namespace std; + using namespace Eigen; + + // dirname, basename, extension and filename + pathinfo(filename,dir,base,ext,name); + // Convert extension to lower case + transform(ext.begin(), ext.end(), ext.begin(), ::tolower); + // readMSH requires filename + if(ext == "msh") + { + // readMSH is not properly templated + Eigen::MatrixXd mV; + Eigen::MatrixXi mF,T; + Eigen::VectorXi _1,_2; + // *TetWild doesn't use Tri field... + //bool res = readMSH(filename,mV,mF); + bool res = readMSH(filename,mV,mF,T,_1,_2); + V = mV.template cast(); + if(mF.rows() == 0 && T.rows() > 0) + { + boundary_facets(T,F); + // outward facing + F = F.rowwise().reverse().eval(); + }else + { + F = mF.template cast(); + } + return res; + }else + { + FILE * fp = fopen(filename.c_str(),"rb"); + if(NULL==fp) + { + fprintf(stderr,"IOError: %s could not be opened...\n", + filename.c_str()); + return false; + } + return read_triangle_mesh(ext,fp,V,F); + } +} + +template +IGL_INLINE bool igl::read_triangle_mesh( + const std::string & ext, + FILE * fp, + Eigen::PlainObjectBase& V, + Eigen::PlainObjectBase& F) +{ + using namespace std; + using namespace Eigen; + Eigen::MatrixXd N; + vector > vV,vN,vTC,vC; + vector > vF,vFTC,vFN; + vector> FM; + + if(ext == "mesh") + { + // Convert extension to lower case + MatrixXi T; + if(!readMESH(fp,V,T,F)) + { + return 1; + } + //if(F.size() > T.size() || F.size() == 0) + { + boundary_facets(T,F); + // outward facing + F = F.rowwise().reverse().eval(); + } + }else if(ext == "obj") + { + if(!readOBJ(fp,vV,vTC,vN,vF,vFTC,vFN,FM)) + { + return false; + } + // Annoyingly obj can store 4 coordinates, truncate to xyz for this generic + // read_triangle_mesh + for(auto & v : vV) + { + v.resize(std::min(v.size(),(size_t)3)); + } + }else if(ext == "off") + { + if(!readOFF(fp,vV,vF,vN,vC)) + { + return false; + } + }else if(ext == "ply") + { + return readPLY(fp, V, F); + + }else if(ext == "stl") + { + if(!readSTL(fp,V,F,N)) + { + return false; + } + }else if(ext == "wrl") + { + if(!readWRL(fp,vV,vF)) + { + return false; + } + }else + { + cerr<<"Error: unknown extension: "< 0) + { + if(!list_to_matrix(vV,V)) + { + return false; + } + { + Eigen::VectorXi I,C; + igl::polygon_corners(vF,I,C); + Eigen::VectorXi J; + igl::polygons_to_triangles(I,C,F,J); + } + } + return true; +} + +#endif + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template bool igl::read_triangle_mesh, Eigen::Matrix >(std::basic_string, std::allocator >, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template bool igl::read_triangle_mesh, Eigen::Matrix >(std::basic_string, std::allocator >, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template bool igl::read_triangle_mesh, Eigen::Matrix >(std::basic_string, std::allocator >, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, std::basic_string, std::allocator >&, std::basic_string, std::allocator >&, std::basic_string, std::allocator >&, std::basic_string, std::allocator >&); +template bool igl::read_triangle_mesh, Eigen::Matrix >(std::basic_string, std::allocator >, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template bool igl::read_triangle_mesh, Eigen::Matrix >(std::string, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template bool igl::read_triangle_mesh, Eigen::Matrix >(std::basic_string, std::allocator >, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template bool igl::read_triangle_mesh, Eigen::Matrix >(std::basic_string, std::allocator >, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, std::basic_string, std::allocator >&, std::basic_string, std::allocator >&, std::basic_string, std::allocator >&, std::basic_string, std::allocator >&); +template bool igl::read_triangle_mesh, Eigen::Matrix >(std::basic_string, std::allocator >, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template bool igl::read_triangle_mesh, Eigen::Matrix >(std::basic_string, std::allocator >, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template bool igl::read_triangle_mesh, Eigen::Matrix >(std::basic_string, std::allocator >, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template bool igl::read_triangle_mesh, Eigen::Matrix >(std::basic_string, std::allocator >, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template bool igl::read_triangle_mesh, Eigen::Matrix >(std::basic_string, std::allocator >, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template bool igl::read_triangle_mesh(std::basic_string, std::allocator >, std::vector >, std::allocator > > >&, std::vector >, std::allocator > > >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/read_triangle_mesh.h b/src/external/libigl-2.3.0/include/igl/read_triangle_mesh.h new file mode 100644 index 000000000..26b84c5f1 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/read_triangle_mesh.h @@ -0,0 +1,80 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_READ_TRIANGLE_MESH_H +#define IGL_READ_TRIANGLE_MESH_H +#include "igl_inline.h" + +#ifndef IGL_NO_EIGEN +# include +#endif +#include +#include +#include +// History: +// renamed read -> read_triangle_mesh Daniele 24 June 2014 +// return type changed from void to bool Alec 18 Sept 2011 + +namespace igl +{ + // read mesh from an ascii file with automatic detection of file format. + // supported: obj, off, stl, wrl, ply, mesh) + // + // Templates: + // Scalar type for positions and vectors (will be read as double and cast + // to Scalar) + // Index type for indices (will be read as int and cast to Index) + // Inputs: + // str path to file + // Outputs: + // V eigen double matrix #V by 3 + // F eigen int matrix #F by 3 + // Returns true iff success + template + IGL_INLINE bool read_triangle_mesh( + const std::string str, + std::vector > & V, + std::vector > & F); +#ifndef IGL_NO_EIGEN + template + IGL_INLINE bool read_triangle_mesh( + const std::string str, + Eigen::PlainObjectBase& V, + Eigen::PlainObjectBase& F); + // Outputs: + // dir directory path (see pathinfo.h) + // base base name (see pathinfo.h) + // ext extension (see pathinfo.h) + // name filename (see pathinfo.h) + template + IGL_INLINE bool read_triangle_mesh( + const std::string str, + Eigen::PlainObjectBase& V, + Eigen::PlainObjectBase& F, + std::string & dir, + std::string & base, + std::string & ext, + std::string & name); + // Inputs: + // ext file extension + // fp pointer to already opened .ext file + // Outputs: + // fp closed file + template + IGL_INLINE bool read_triangle_mesh( + const std::string & ext, + FILE * fp, + Eigen::PlainObjectBase& V, + Eigen::PlainObjectBase& F); +#endif +} + +#ifndef IGL_STATIC_LIBRARY +# include "read_triangle_mesh.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/redux.h b/src/external/libigl-2.3.0/include/igl/redux.h new file mode 100644 index 000000000..21356dab2 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/redux.h @@ -0,0 +1,70 @@ +#ifndef IGL_REDUX_H +#define IGL_REDUX_H +#include +#include +namespace igl +{ + // REDUX Perform reductions on the rows or columns of a SparseMatrix. This is + // _similar_ to DenseBase::redux, but different in two important ways: + // 1. (unstored) Zeros are **not** "visited", however if the first element + // in the column/row does not appear in the first row/column then the + // reduction is assumed to start with zero. In this way, "any", "all", + // "count"(non-zeros) work as expected. This means it is **not** possible + // to use this to count (implicit) zeros. + // 2. This redux is more powerful in the sense that A and B may have + // different types. This makes it possible to count the number of + // non-zeros in a SparseMatrix A into a VectorXi B. + // + // Inputs: + // A m by n sparse matrix + // dim dimension along which to sum (1 or 2) + // func function handle with the prototype `X(Y a, I i, J j, Z b)` where a + // is the running value, b is A(i,j) + // Output: + // S n-long sparse vector (if dim == 1) + // or + // S m-long sparse vector (if dim == 2) + template + inline void redux( + const Eigen::SparseMatrix & A, + const int dim, + const Func & func, + Eigen::PlainObjectBase & B); +} + +// Implementation + +#include "for_each.h" + +template +inline void igl::redux( + const Eigen::SparseMatrix & A, + const int dim, + const Func & func, + Eigen::PlainObjectBase & B) +{ + typedef typename Eigen::SparseMatrix::StorageIndex Index; + assert((dim == 1 || dim == 2) && "dim must be 2 or 1"); + // Get size of input + int m = A.rows(); + int n = A.cols(); + // resize output + B = DerivedB::Zero(dim==1?n:m); + const auto func_wrap = [&func,&B,&dim](const Index i, const Index j, const AType v) + { + if(dim == 1) + { + B(j) = i == 0? v : func(B(j),v); + }else + { + B(i) = j == 0? v : func(B(i),v); + } + }; + for_each(A,func_wrap); +} + + +//#ifndef IGL_STATIC_LIBRARY +//# include "redux.cpp" +//#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/remesh_along_isoline.cpp b/src/external/libigl-2.3.0/include/igl/remesh_along_isoline.cpp new file mode 100644 index 000000000..3c719ba99 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/remesh_along_isoline.cpp @@ -0,0 +1,167 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2018 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "remesh_along_isoline.h" +#include "list_to_matrix.h" +#include + +template < + typename DerivedV, + typename DerivedF, + typename DerivedS, + typename DerivedU, + typename DerivedG, + typename DerivedJ, + typename BCtype, + typename DerivedSU, + typename DerivedL> + IGL_INLINE void igl::remesh_along_isoline( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const Eigen::MatrixBase & S, + const typename DerivedS::Scalar val, + Eigen::PlainObjectBase & U, + Eigen::PlainObjectBase & G, + Eigen::PlainObjectBase & SU, + Eigen::PlainObjectBase & J, + Eigen::SparseMatrix & BC, + Eigen::PlainObjectBase & L) +{ + igl::remesh_along_isoline(V.rows(),F,S,val,G,SU,J,BC,L); + U = BC * V; +} + +template < + typename DerivedF, + typename DerivedS, + typename DerivedG, + typename DerivedJ, + typename BCtype, + typename DerivedSU, + typename DerivedL> + IGL_INLINE void igl::remesh_along_isoline( + const int num_vertices, + const Eigen::MatrixBase & F, + const Eigen::MatrixBase & S, + const typename DerivedS::Scalar val, + Eigen::PlainObjectBase & G, + Eigen::PlainObjectBase & SU, + Eigen::PlainObjectBase & J, + Eigen::SparseMatrix & BC, + Eigen::PlainObjectBase & L) +{ + // Lazy implementation using vectors + + //assert(val.size() == 1); + const int isoval_i = 0; + //auto isoval = val(isoval_i); + auto isoval = val; + std::vector > vG; + std::vector vJ; + std::vector vL; + std::vector > vBC; + int Ucount = 0; + for(int i = 0;i> edgeToBirthVert; + for(int f = 0;f isoval; + // Find crossings + const int n = (p+1)%3; + const bool nsign = S(F(f,n)) > isoval; + if(psign != nsign) + { + P[count] = p; + Psign[count] = psign; + // record crossing + count++; + } + } + + assert(count == 0 || count == 2); + switch(count) + { + case 0: + { + // Easy case + std::vector row = {F(f,0),F(f,1),F(f,2)}; + vG.push_back(row); + vJ.push_back(f); + vL.push_back( S(F(f,0))>isoval ? isoval_i+1 : isoval_i ); + break; + } + case 2: + { + // Cut case + // flip so that P[1] is the one-off vertex + if(P[0] == 0 && P[1] == 2) + { + std::swap(P[0],P[1]); + std::swap(Psign[0],Psign[1]); + } + assert(Psign[0] != Psign[1]); + // Create two new vertices + for(int i = 0;i<2;i++) + { + if ((edgeToBirthVert.find(F(f, P[i])) == edgeToBirthVert.end()) || (edgeToBirthVert.at(F(f, P[i])).find(F(f, (P[i] + 1) % 3)) == edgeToBirthVert.at(F(f, P[i])).end())) + { + const double bci = (isoval - S(F(f,(P[i]+1)%3)))/ + (S(F(f,P[i]))-S(F(f,(P[i]+1)%3))); + vBC.emplace_back(Ucount,F(f,P[i]),bci); + vBC.emplace_back(Ucount,F(f,(P[i]+1)%3),1.0-bci); + edgeToBirthVert[F(f, P[i])][F(f, (P[i] + 1) % 3)] = Ucount; + edgeToBirthVert[F(f, (P[i] + 1) % 3)][F(f, P[i])] = Ucount; + Ucount++; + } + } + const int v0 = F(f,P[0]); + assert(((P[0]+1)%3) == P[1]); + const int v1 = F(f,P[1]); + const int v2 = F(f,(P[1]+1)%3); + const int v01 = edgeToBirthVert[v0][v1]; + const int v12 = edgeToBirthVert[v1][v2]; + // v0 + // | \ + // | \ + // | \ + // v01 \ + // | \ + // | \ + // | \ + // v1--v12---v2 + typedef std::vector Row; + {Row row = {v01,v1,v12}; vG.push_back(row);vJ.push_back(f);vL.push_back(Psign[0]?isoval_i:isoval_i+1);} + {Row row = {v12,v2,v01}; vG.push_back(row);vJ.push_back(f);vL.push_back(Psign[1]?isoval_i:isoval_i+1);} + {Row row = {v2,v0,v01}; vG.push_back(row) ;vJ.push_back(f);vL.push_back(Psign[1]?isoval_i:isoval_i+1);} + break; + } + default: assert(false); + } + } + igl::list_to_matrix(vG,G); + igl::list_to_matrix(vJ,J); + igl::list_to_matrix(vL,L); + BC.resize(Ucount,num_vertices); + BC.setFromTriplets(vBC.begin(),vBC.end()); + SU = BC * S; +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +template void igl::remesh_along_isoline, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, double, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::Matrix::Scalar, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::SparseMatrix&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/remesh_along_isoline.h b/src/external/libigl-2.3.0/include/igl/remesh_along_isoline.h new file mode 100644 index 000000000..ea9ce0cda --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/remesh_along_isoline.h @@ -0,0 +1,81 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2018 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_REMESH_ALONG_ISOLINE_H +#define IGL_REMESH_ALONG_ISOLINE_H +#include "igl_inline.h" + +#include +#include + +namespace igl +{ + // Given a triangle mesh and a scalar field, remesh so that a given isovalue + // of the scalar field follows (new) edges of the output mesh. Effectively + // running "marching triangles" on mesh, but not in any coherent order. The + // output mesh should be as manifold as the input. + // + // Inputs: + // V #V by dim list of mesh vertex positions + // F #F by 3 list of mesh triangle indices into V + // S #V by 1 list of scalar field + // val value of S to remesh along + // Outputs: + // U #U by dim list of mesh vertex positions #U>=#V + // G #G by 3 list of mesh triangle indices into U, #G>=#F + // SU #U list of scalar field values over new mesh + // J #G list of indices into F revealing birth triangles + // BC #U by #V sparse matrix of barycentric coordinates so that U = BC*V + // L #G list of bools whether scalar field in triangle below or above val + template < + typename DerivedV, + typename DerivedF, + typename DerivedS, + typename DerivedU, + typename DerivedG, + typename DerivedJ, + typename BCtype, + typename DerivedSU, + typename DerivedL> + IGL_INLINE void remesh_along_isoline( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const Eigen::MatrixBase & S, + const typename DerivedS::Scalar val, + Eigen::PlainObjectBase & U, + Eigen::PlainObjectBase & G, + Eigen::PlainObjectBase & SU, + Eigen::PlainObjectBase & J, + Eigen::SparseMatrix & BC, + Eigen::PlainObjectBase & L); + // Input: + // n number of vertices (#V) + template < + typename DerivedF, + typename DerivedS, + typename DerivedG, + typename DerivedJ, + typename BCtype, + typename DerivedSU, + typename DerivedL> + IGL_INLINE void remesh_along_isoline( + const int n, + const Eigen::MatrixBase & F, + const Eigen::MatrixBase & S, + const typename DerivedS::Scalar val, + Eigen::PlainObjectBase & G, + Eigen::PlainObjectBase & SU, + Eigen::PlainObjectBase & J, + Eigen::SparseMatrix & BC, + Eigen::PlainObjectBase & L); +} + +#ifndef IGL_STATIC_LIBRARY +# include "remesh_along_isoline.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/remove_duplicate_vertices.cpp b/src/external/libigl-2.3.0/include/igl/remove_duplicate_vertices.cpp new file mode 100644 index 000000000..318f55c2c --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/remove_duplicate_vertices.cpp @@ -0,0 +1,87 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "remove_duplicate_vertices.h" +#include "round.h" +#include "unique_rows.h" +#include "colon.h" +#include "slice.h" +#include + +template < + typename DerivedV, + typename DerivedSV, + typename DerivedSVI, + typename DerivedSVJ> +IGL_INLINE void igl::remove_duplicate_vertices( + const Eigen::MatrixBase& V, + const double epsilon, + Eigen::PlainObjectBase& SV, + Eigen::PlainObjectBase& SVI, + Eigen::PlainObjectBase& SVJ) +{ + if(epsilon > 0) + { + DerivedV rV,rSV; + round((V/(epsilon)).eval(),rV); + unique_rows(rV,rSV,SVI,SVJ); + slice(V,SVI,colon(0,V.cols()-1),SV); + }else + { + unique_rows(V,SV,SVI,SVJ); + } +} + +template < + typename DerivedV, + typename DerivedF, + typename DerivedSV, + typename DerivedSVI, + typename DerivedSVJ, + typename DerivedSF> +IGL_INLINE void igl::remove_duplicate_vertices( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + const double epsilon, + Eigen::PlainObjectBase& SV, + Eigen::PlainObjectBase& SVI, + Eigen::PlainObjectBase& SVJ, + Eigen::PlainObjectBase& SF) +{ + using namespace Eigen; + using namespace std; + remove_duplicate_vertices(V,epsilon,SV,SVI,SVJ); + SF.resizeLike(F); + for(int f = 0;f, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, double, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::remove_duplicate_vertices, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, double, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::remove_duplicate_vertices, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, double, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::remove_duplicate_vertices, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, double, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::remove_duplicate_vertices, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, double, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::remove_duplicate_vertices, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, double, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::remove_duplicate_vertices, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, double, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::remove_duplicate_vertices, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, double, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::remove_duplicate_vertices, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, double, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::remove_duplicate_vertices, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, double, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::remove_duplicate_vertices, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, double, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/remove_duplicate_vertices.h b/src/external/libigl-2.3.0/include/igl/remove_duplicate_vertices.h new file mode 100644 index 000000000..ebffc09b0 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/remove_duplicate_vertices.h @@ -0,0 +1,65 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_REMOVE_DUPLICATE_VERTICES_H +#define IGL_REMOVE_DUPLICATE_VERTICES_H +#include "igl_inline.h" +#include +namespace igl +{ + // REMOVE_DUPLICATE_VERTICES Remove duplicate vertices upto a uniqueness + // tolerance (epsilon) + // + // Inputs: + // V #V by dim list of vertex positions + // epsilon uniqueness tolerance used coordinate-wise: 1e0 --> integer + // match, 1e-1 --> match up to first decimal, ... , 0 --> exact match. + // Outputs: + // SV #SV by dim new list of vertex positions + // SVI #SV by 1 list of indices so SV = V(SVI,:) + // SVJ #V by 1 list of indices so V = SV(SVJ,:) + // + // Example: + // % Mesh in (V,F) + // [SV,SVI,SVJ] = remove_duplicate_vertices(V,1e-7); + // % remap faces + // SF = SVJ(F); + // + template < + typename DerivedV, + typename DerivedSV, + typename DerivedSVI, + typename DerivedSVJ> + IGL_INLINE void remove_duplicate_vertices( + const Eigen::MatrixBase& V, + const double epsilon, + Eigen::PlainObjectBase& SV, + Eigen::PlainObjectBase& SVI, + Eigen::PlainObjectBase& SVJ); + // Wrapper that also remaps given faces (F) --> (SF) so that SF index SV + template < + typename DerivedV, + typename DerivedF, + typename DerivedSV, + typename DerivedSVI, + typename DerivedSVJ, + typename DerivedSF> + IGL_INLINE void remove_duplicate_vertices( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + const double epsilon, + Eigen::PlainObjectBase& SV, + Eigen::PlainObjectBase& SVI, + Eigen::PlainObjectBase& SVJ, + Eigen::PlainObjectBase& SF); +} + +#ifndef IGL_STATIC_LIBRARY +# include "remove_duplicate_vertices.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/remove_unreferenced.cpp b/src/external/libigl-2.3.0/include/igl/remove_unreferenced.cpp new file mode 100644 index 000000000..98ed8fcf5 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/remove_unreferenced.cpp @@ -0,0 +1,129 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "remove_unreferenced.h" +#include "slice.h" +#include + +template < + typename DerivedV, + typename DerivedF, + typename DerivedNV, + typename DerivedNF, + typename DerivedI> +IGL_INLINE void igl::remove_unreferenced( + const Eigen::MatrixBase &V, + const Eigen::MatrixBase &F, + Eigen::PlainObjectBase &NV, + Eigen::PlainObjectBase &NF, + Eigen::PlainObjectBase &I) +{ + Eigen::Matrix J; + remove_unreferenced(V,F,NV,NF,I,J); +} + +template < + typename DerivedV, + typename DerivedF, + typename DerivedNV, + typename DerivedNF, + typename DerivedI, + typename DerivedJ> +IGL_INLINE void igl::remove_unreferenced( + const Eigen::MatrixBase &V, + const Eigen::MatrixBase &F, + Eigen::PlainObjectBase &NV, + Eigen::PlainObjectBase &NF, + Eigen::PlainObjectBase &I, + Eigen::PlainObjectBase &J) +{ + using namespace std; + const size_t n = V.rows(); + remove_unreferenced(n,F,I,J); + NF = F; + std::for_each(NF.data(),NF.data()+NF.size(), + [&I](typename DerivedNF::Scalar & a){a=I(a);}); + slice(V,J,1,NV); +} + +template < + typename DerivedF, + typename DerivedI, + typename DerivedJ> +IGL_INLINE void igl::remove_unreferenced( + const size_t n, + const Eigen::MatrixBase &F, + Eigen::PlainObjectBase &I, + Eigen::PlainObjectBase &J) +{ + // Mark referenced vertices + typedef Eigen::Matrix MatrixXb; + MatrixXb mark = MatrixXb::Zero(n,1); + for(int i=0; i, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::remove_unreferenced, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::remove_unreferenced, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::remove_unreferenced, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +// generated by autoexplicit.sh +// generated by autoexplicit.sh +template void igl::remove_unreferenced, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::remove_unreferenced, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +//template void igl::remove_unreferenced, Eigen::Matrix, Eigen::Matrix >(unsigned long, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::remove_unreferenced, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::remove_unreferenced, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::remove_unreferenced, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::remove_unreferenced, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::remove_unreferenced, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::remove_unreferenced, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::remove_unreferenced, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::remove_unreferenced, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::remove_unreferenced, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::remove_unreferenced, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/remove_unreferenced.h b/src/external/libigl-2.3.0/include/igl/remove_unreferenced.h new file mode 100644 index 000000000..b0dfce0d7 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/remove_unreferenced.h @@ -0,0 +1,84 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +// +// remove_unreferenced.h +// Preview3D +// +// Created by Daniele Panozzo on 17/11/11. + +#ifndef IGL_REMOVE_UNREFERENCED_H +#define IGL_REMOVE_UNREFERENCED_H +#include "igl_inline.h" + +#include +namespace igl +{ + // Remove unreferenced vertices from V, updating F accordingly + // + // Input: + // V #V by dim list of mesh vertex positions + // F #F by ss list of simplices (Values of -1 are quitely skipped) + // Outputs: + // NV #NV by dim list of mesh vertex positions + // NF #NF by ss list of simplices + // I #V by 1 list of indices such that: NF = IM(F) and NT = IM(T) + // and V(find(IM<=size(NV,1)),:) = NV + // J #NV by 1 list, such that NV = V(J,:) + // + // + template < + typename DerivedV, + typename DerivedF, + typename DerivedNV, + typename DerivedNF, + typename DerivedI> + IGL_INLINE void remove_unreferenced( + const Eigen::MatrixBase &V, + const Eigen::MatrixBase &F, + Eigen::PlainObjectBase &NV, + Eigen::PlainObjectBase &NF, + Eigen::PlainObjectBase &I); + template < + typename DerivedV, + typename DerivedF, + typename DerivedNV, + typename DerivedNF, + typename DerivedI, + typename DerivedJ> + IGL_INLINE void remove_unreferenced( + const Eigen::MatrixBase &V, + const Eigen::MatrixBase &F, + Eigen::PlainObjectBase &NV, + Eigen::PlainObjectBase &NF, + Eigen::PlainObjectBase &I, + Eigen::PlainObjectBase &J); + // Inputs: + // n number of vertices (possibly greater than F.maxCoeff()+1) + // F #F by ss list of simplices + // Outputs: + // IM #V by 1 list of indices such that: NF = IM(F) and NT = IM(T) + // and V(find(IM<=size(NV,1)),:) = NV + // J #RV by 1 list, such that RV = V(J,:) + // + template < + typename DerivedF, + typename DerivedI, + typename DerivedJ> + IGL_INLINE void remove_unreferenced( + const size_t n, + const Eigen::MatrixBase &F, + Eigen::PlainObjectBase &I, + Eigen::PlainObjectBase &J); + +} + +#ifndef IGL_STATIC_LIBRARY +# include "remove_unreferenced.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/reorder.cpp b/src/external/libigl-2.3.0/include/igl/reorder.cpp new file mode 100644 index 000000000..c3dd9ba79 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/reorder.cpp @@ -0,0 +1,49 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "reorder.h" +#include "SortableRow.h" +#ifndef IGL_NO_EIGEN +#include +#endif + +// This implementation is O(n), but also uses O(n) extra memory +template< class T > +IGL_INLINE void igl::reorder( + const std::vector & unordered, + std::vector const & index_map, + std::vector & ordered) +{ + // copy for the reorder according to index_map, because unsorted may also be + // sorted + std::vector copy = unordered; + ordered.resize(index_map.size()); + for(int i = 0; i<(int)index_map.size();i++) + { + ordered[i] = copy[index_map[i]]; + } +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::reorder(std::vector > const&, std::vector > const&, std::vector >&); +// generated by autoexplicit.sh +template void igl::reorder(std::vector > const&, std::vector > const&, std::vector >&); +template void igl::reorder(std::vector > const&, std::vector > const&, std::vector >&); +template void igl::reorder(std::vector > const&, std::vector > const&, std::vector >&); +# ifndef IGL_NO_EIGEN + template void igl::reorder > >(std::vector >, std::allocator > > > const&, std::vector > const&, std::vector >, std::allocator > > >&); + template void igl::reorder > >(std::vector >, std::allocator > > > const&, std::vector > const&, std::vector >, std::allocator > > >&); +# endif +template void igl::reorder(std::vector > const&, std::vector > const&, std::vector >&); +#ifdef WIN32 +template void igl::reorder(class std::vector > const &,class std::vector > const &,class std::vector > &); +template void igl::reorder(class std::vector > const &,class std::vector > const &,class std::vector > &); +template void igl::reorder<__int64>(class std::vector<__int64,class std::allocator<__int64> > const &,class std::vector > const &,class std::vector<__int64,class std::allocator<__int64> > &); +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/reorder.h b/src/external/libigl-2.3.0/include/igl/reorder.h new file mode 100644 index 000000000..50f7d7b0f --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/reorder.h @@ -0,0 +1,34 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_REORDER_H +#define IGL_REORDER_H +#include "igl_inline.h" +#include +// For size_t +#include +#include + +namespace igl +{ + // Act like matlab's Y = X(I) for std vectors + // where I contains a vector of indices so that after, + // Y[j] = X[I[j]] for index j + // this implies that Y.size() == I.size() + // X and Y are allowed to be the same reference + template< class T > + IGL_INLINE void reorder( + const std::vector & unordered, + std::vector const & index_map, + std::vector & ordered); +} + +#ifndef IGL_STATIC_LIBRARY +# include "reorder.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/repdiag.cpp b/src/external/libigl-2.3.0/include/igl/repdiag.cpp new file mode 100644 index 000000000..e79576139 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/repdiag.cpp @@ -0,0 +1,96 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "repdiag.h" +#include + +template +IGL_INLINE void igl::repdiag( + const Eigen::SparseMatrix& A, + const int d, + Eigen::SparseMatrix& B) +{ + using namespace std; + using namespace Eigen; + int m = A.rows(); + int n = A.cols(); +#if false + vector > IJV; + IJV.reserve(A.nonZeros()*d); + // Loop outer level + for (int k=0; k::InnerIterator it(A,k); it; ++it) + { + for(int i = 0;i(i*m+it.row(),i*n+it.col(),it.value())); + } + } + } + B.resize(m*d,n*d); + B.setFromTriplets(IJV.begin(),IJV.end()); +#else + // This will not work for RowMajor + B.resize(m*d,n*d); + Eigen::VectorXi per_col = Eigen::VectorXi::Zero(n*d); + for (int k=0; k::InnerIterator it(A,k); it; ++it) + { + for(int r = 0;r::InnerIterator it(A,k); it; ++it) + { + B.insert(it.row()+mr,k+nr) = it.value(); + } + } + } + B.makeCompressed(); +#endif +} + +template +IGL_INLINE void igl::repdiag( + const Eigen::Matrix & A, + const int d, + Eigen::Matrix & B) +{ + int m = A.rows(); + int n = A.cols(); + B.setZero(m*d,n*d); + for(int i = 0;i +IGL_INLINE Mat igl::repdiag(const Mat & A, const int d) +{ + Mat B; + repdiag(A,d,B); + return B; +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::repdiag(Eigen::SparseMatrix const&, int, Eigen::SparseMatrix&); +// generated by autoexplicit.sh +template Eigen::SparseMatrix igl::repdiag >(Eigen::SparseMatrix const&, int); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/repdiag.h b/src/external/libigl-2.3.0/include/igl/repdiag.h new file mode 100644 index 000000000..779443374 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/repdiag.h @@ -0,0 +1,54 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_REPDIAG_H +#define IGL_REPDIAG_H +#include "igl_inline.h" + +#define EIGEN_YES_I_KNOW_SPARSE_MODULE_IS_NOT_STABLE_YET +#include +#include + +namespace igl +{ + // REPDIAG repeat a matrix along the diagonal a certain number of times, so + // that if A is a m by n matrix and we want to repeat along the diagonal d + // times, we get a m*d by n*d matrix B such that: + // B( (k*m+1):(k*m+1+m-1), (k*n+1):(k*n+1+n-1)) = A + // for k from 0 to d-1 + // + // Inputs: + // A m by n matrix we are repeating along the diagonal. May be dense or + // sparse + // d number of times to repeat A along the diagonal + // Outputs: + // B m*d by n*d matrix with A repeated d times along the diagonal, + // will be dense or sparse to match A + // + + // Sparse version + template + IGL_INLINE void repdiag( + const Eigen::SparseMatrix& A, + const int d, + Eigen::SparseMatrix& B); + // Dense version + template + IGL_INLINE void repdiag( + const Eigen::Matrix & A, + const int d, + Eigen::Matrix & B); + // Wrapper with B as output + template + IGL_INLINE Mat repdiag(const Mat & A, const int d); +} + +#ifndef IGL_STATIC_LIBRARY +# include "repdiag.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/repmat.cpp b/src/external/libigl-2.3.0/include/igl/repmat.cpp new file mode 100644 index 000000000..f79840444 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/repmat.cpp @@ -0,0 +1,67 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "repmat.h" + +template +IGL_INLINE void igl::repmat( + const Eigen::MatrixBase & A, + const int r, + const int c, + Eigen::PlainObjectBase & B) +{ + assert(r>0); + assert(c>0); + // Make room for output + B.resize(r*A.rows(),c*A.cols()); + + // copy tiled blocks + for(int i = 0;i +IGL_INLINE void igl::repmat( + const Eigen::SparseMatrix & A, + const int r, + const int c, + Eigen::SparseMatrix & B) +{ + assert(r>0); + assert(c>0); + B.resize(r*A.rows(),c*A.cols()); + B.reserve(r*c*A.nonZeros()); + for(int i = 0;i::InnerIterator it(A,k); it; ++it) + { + B.insert(i*A.rows()+it.row(),j*A.cols() + it.col()) = it.value(); + } + } + } + } + B.finalize(); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::repmat, Eigen::Matrix >(Eigen::MatrixBase > const&, int, int, Eigen::PlainObjectBase >&); +template void igl::repmat, Eigen::Matrix >(Eigen::MatrixBase > const&, int, int, Eigen::PlainObjectBase >&); +template void igl::repmat, Eigen::Matrix >(Eigen::MatrixBase > const&, int, int, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/repmat.h b/src/external/libigl-2.3.0/include/igl/repmat.h new file mode 100644 index 000000000..1509875aa --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/repmat.h @@ -0,0 +1,53 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_REPMAT_H +#define IGL_REPMAT_H +#include "igl_inline.h" + +#define EIGEN_YES_I_KNOW_SPARSE_MODULE_IS_NOT_STABLE_YET +#include +#include + +namespace igl +{ + // At least for Dense matrices this is replaced by `replicate` e.g., dst = src.replicate(n,m); + // http://forum.kde.org/viewtopic.php?f=74&t=90876#p173517 + + // Ideally this is a super overloaded function that behaves just like + // matlab's repmat + + // Replicate and tile a matrix + // + // Templates: + // T should be a eigen matrix primitive type like int or double + // Inputs: + // A m by n input matrix + // r number of row-direction copies + // c number of col-direction copies + // Outputs: + // B r*m by c*n output matrix + // + template + IGL_INLINE void repmat( + const Eigen::MatrixBase & A, + const int r, + const int c, + Eigen::PlainObjectBase & B); + template + IGL_INLINE void repmat( + const Eigen::SparseMatrix & A, + const int r, + const int c, + Eigen::SparseMatrix & B); +} + +#ifndef IGL_STATIC_LIBRARY +# include "repmat.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/resolve_duplicated_faces.cpp b/src/external/libigl-2.3.0/include/igl/resolve_duplicated_faces.cpp new file mode 100644 index 000000000..d55e01dd8 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/resolve_duplicated_faces.cpp @@ -0,0 +1,96 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Qingnan Zhou +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +// + +#include "resolve_duplicated_faces.h" + +#include "slice.h" +#include "unique_simplices.h" + +template< + typename DerivedF1, + typename DerivedF2, + typename DerivedJ > +IGL_INLINE void igl::resolve_duplicated_faces( + const Eigen::MatrixBase& F1, + Eigen::PlainObjectBase& F2, + Eigen::PlainObjectBase& J) { + + //typedef typename DerivedF1::Scalar Index; + Eigen::Matrix IA,IC; + DerivedF1 uF; + igl::unique_simplices(F1,uF,IA,IC); + + const size_t num_faces = F1.rows(); + const size_t num_unique_faces = uF.rows(); + assert((size_t) IA.rows() == num_unique_faces); + // faces on top of each unique face + std::vector > uF2F(num_unique_faces); + // signed counts + Eigen::VectorXi counts = Eigen::VectorXi::Zero(num_unique_faces); + Eigen::VectorXi ucounts = Eigen::VectorXi::Zero(num_unique_faces); + // loop over all faces + for (size_t i=0; i kept_faces; + for (size_t i=0; i 0) { + kept_faces.push_back(abs(fid)-1); + found = true; + break; + } + } + assert(found); + } else if (counts[i] == -1) { + bool found = false; + for (auto fid : uF2F[i]) { + if (fid < 0) { + kept_faces.push_back(abs(fid)-1); + found = true; + break; + } + } + assert(found); + } else { + assert(counts[i] == 0); + } + } + + const size_t num_kept = kept_faces.size(); + J.resize(num_kept, 1); + std::copy(kept_faces.begin(), kept_faces.end(), J.data()); + igl::slice(F1, J, 1, F2); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::resolve_duplicated_faces, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::resolve_duplicated_faces, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::resolve_duplicated_faces, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::resolve_duplicated_faces, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#ifdef WIN32 +template void igl::resolve_duplicated_faces, class Eigen::Matrix, class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>>(class Eigen::MatrixBase> const &, class Eigen::PlainObjectBase> &, class Eigen::PlainObjectBase> &); +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/resolve_duplicated_faces.h b/src/external/libigl-2.3.0/include/igl/resolve_duplicated_faces.h new file mode 100644 index 000000000..e3861fa8c --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/resolve_duplicated_faces.h @@ -0,0 +1,52 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Qingnan Zhou +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +// +#ifndef IGL_COPYLEFT_RESOLVE_DUPLICATED_FACES +#define IGL_COPYLEFT_RESOLVE_DUPLICATED_FACES + +#include "igl_inline.h" +#include + +namespace igl { + + // Resolve duplicated faces according to the following rules per unique face: + // + // 1. If the number of positively oriented faces equals the number of + // negatively oriented faces, remove all duplicated faces at this triangle. + // 2. If the number of positively oriented faces equals the number of + // negatively oriented faces plus 1, keeps one of the positively oriented + // face. + // 3. If the number of positively oriented faces equals the number of + // negatively oriented faces minus 1, keeps one of the negatively oriented + // face. + // 4. If the number of postively oriented faces differ with the number of + // negativley oriented faces by more than 1, the mesh is not orientable. + // An exception will be thrown. + // + // Inputs: + // F1 #F1 by 3 array of input faces. + // + // Outputs: + // F2 #F2 by 3 array of output faces without duplicated faces. + // J #F2 list of indices into F1. + template< + typename DerivedF1, + typename DerivedF2, + typename DerivedJ > + IGL_INLINE void resolve_duplicated_faces( + const Eigen::MatrixBase& F1, + Eigen::PlainObjectBase& F2, + Eigen::PlainObjectBase& J); + +} + +#ifndef IGL_STATIC_LIBRARY +# include "resolve_duplicated_faces.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/rgb_to_hsv.cpp b/src/external/libigl-2.3.0/include/igl/rgb_to_hsv.cpp new file mode 100644 index 000000000..fbf32bfec --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/rgb_to_hsv.cpp @@ -0,0 +1,102 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "rgb_to_hsv.h" + +template +IGL_INLINE void igl::rgb_to_hsv(const R * rgb, H * hsv) +{ + // http://en.literateprograms.org/RGB_to_HSV_color_space_conversion_%28C%29 + R rgb_max = 0.0; + R rgb_min = 1.0; + rgb_max = (rgb[0]>rgb_max?rgb[0]:rgb_max); + rgb_max = (rgb[1]>rgb_max?rgb[1]:rgb_max); + rgb_max = (rgb[2]>rgb_max?rgb[2]:rgb_max); + rgb_min = (rgb[0]rgb_max?rgb_n[0]:rgb_max); + rgb_max = (rgb_n[1]>rgb_max?rgb_n[1]:rgb_max); + rgb_max = (rgb_n[2]>rgb_max?rgb_n[2]:rgb_max); + rgb_min = 1; + rgb_min = (rgb_n[0]rgb_max?rgb_n[0]:rgb_max); + rgb_max = (rgb_n[1]>rgb_max?rgb_n[1]:rgb_max); + rgb_max = (rgb_n[2]>rgb_max?rgb_n[2]:rgb_max); + rgb_min = 1; + rgb_min = (rgb_n[0] +IGL_INLINE void igl::rgb_to_hsv( + const Eigen::PlainObjectBase & R, + Eigen::PlainObjectBase & H) +{ + assert(R.cols() == 3); + H.resizeLike(R); + for(typename DerivedR::Index r = 0;r(float const*, double*); +template void igl::rgb_to_hsv(double const*, double*); +template void igl::rgb_to_hsv, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&); +template void igl::rgb_to_hsv, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&); +template void igl::rgb_to_hsv, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/rgb_to_hsv.h b/src/external/libigl-2.3.0/include/igl/rgb_to_hsv.h new file mode 100644 index 000000000..ed695ad60 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/rgb_to_hsv.h @@ -0,0 +1,37 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_RGB_TO_HSV_H +#define IGL_RGB_TO_HSV_H +#include "igl_inline.h" +#include +namespace igl +{ + // Convert RGB to HSV + // + // Inputs: + // r red value ([0,1]) + // g green value ([0,1]) + // b blue value ([0,1]) + // Outputs: + // h hue value (degrees: [0,360]) + // s saturation value ([0,1]) + // v value value ([0,1]) + template + IGL_INLINE void rgb_to_hsv(const R * rgb, H * hsv); + template + IGL_INLINE void rgb_to_hsv( + const Eigen::PlainObjectBase & R, + Eigen::PlainObjectBase & H); +}; + +#ifndef IGL_STATIC_LIBRARY +# include "rgb_to_hsv.cpp" +#endif + +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/rigid_alignment.cpp b/src/external/libigl-2.3.0/include/igl/rigid_alignment.cpp new file mode 100644 index 000000000..fdff2ddc0 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/rigid_alignment.cpp @@ -0,0 +1,97 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2019 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "rigid_alignment.h" +#include "polar_svd.h" +#include +#include +#include +#include + +template < + typename DerivedX, + typename DerivedP, + typename DerivedN, + typename DerivedR, + typename Derivedt +> +IGL_INLINE void igl::rigid_alignment( + const Eigen::MatrixBase & _X, + const Eigen::MatrixBase & P, + const Eigen::MatrixBase & N, + Eigen::PlainObjectBase & R, + Eigen::PlainObjectBase & t) +{ + typedef typename DerivedX::Scalar Scalar; + typedef Eigen::Matrix MatrixXS; + typedef Eigen::Matrix VectorXS; + typedef Eigen::Matrix Matrix3S; + const int k = _X.rows(); + VectorXS Z = VectorXS::Zero(k,1); + VectorXS I = VectorXS::Ones(k,1); + + DerivedX X = _X; + R = DerivedR::Identity(3,3); + t = Derivedt::Zero(1,3); + // See gptoolbox, each iter could be O(1) instead of O(k) + const int max_iters = 5; + for(int iters = 0;iters > NNIJV; + for(int i = 0;i NN(k,k*3); + NN.setFromTriplets(NNIJV.begin(),NNIJV.end()); + A = (NN * A).eval(); + B = (NN * B).eval(); + VectorXS u = (A.transpose() * A).ldlt().solve(A.transpose() * B); + Derivedt ti = u.tail(3).transpose(); + + Matrix3S W; + W<< + 0, u(2),-u(1), + -u(2), 0, u(0), + u(1),-u(0), 0; + // strayed from a perfect rotation. Correct it. + const double x = u.head(3).stableNorm(); + DerivedR Ri; + if(x == 0) + { + Ri = DerivedR::Identity(3,3); + }else + { + Ri = + DerivedR::Identity(3,3) + + sin(x)/x*W + + (1.0-cos(x))/(x*x)*W*W; + } + + R = (R*Ri).eval(); + t = (t*Ri + ti).eval(); + X = ((_X*R).rowwise()+t).eval(); + } +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +template void igl::rigid_alignment, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/rigid_alignment.h b/src/external/libigl-2.3.0/include/igl/rigid_alignment.h new file mode 100644 index 000000000..6727b7433 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/rigid_alignment.h @@ -0,0 +1,50 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2019 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef RIGID_ALIGNMENT_H +#define RIGID_ALIGNMENT_H +#include "igl_inline.h" +#include + +namespace igl +{ + // Find the rigid transformation that best aligns the 3D points X to their + // corresponding points P with associated normals N. + // + // min ‖(X*R+t-P)'N‖² + // R∈SO(3) + // t∈R³ + // + // Inputs: + // X #X by 3 list of query points + // P #X by 3 list of corresponding (e.g., closest) points + // N #X by 3 list of unit normals for each row in P + // Outputs: + // R 3 by 3 rotation matrix + // t 1 by 3 translation vector + // + // See also: icp + template < + typename DerivedX, + typename DerivedP, + typename DerivedN, + typename DerivedR, + typename Derivedt + > + IGL_INLINE void rigid_alignment( + const Eigen::MatrixBase & X, + const Eigen::MatrixBase & P, + const Eigen::MatrixBase & N, + Eigen::PlainObjectBase & R, + Eigen::PlainObjectBase & t); +} + +#ifndef IGL_STATIC_LIBRARY +# include "rigid_alignment.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/rotate_by_quat.cpp b/src/external/libigl-2.3.0/include/igl/rotate_by_quat.cpp new file mode 100644 index 000000000..b77c812ea --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/rotate_by_quat.cpp @@ -0,0 +1,55 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "rotate_by_quat.h" + +#include "quat_conjugate.h" +#include "quat_mult.h" +#include "normalize_quat.h" +#include + +template +IGL_INLINE void igl::rotate_by_quat( + const Q_type *v, + const Q_type *q, + Q_type *out) +{ + // Quaternion form of v, copy data in v, (as a result out can be same pointer + // as v) + Q_type quat_v[4] = {v[0],v[1],v[2],0}; + + // normalize input + Q_type normalized_q[4]; + +#ifndef NDEBUG + bool normalized = +#endif + igl::normalize_quat(q,normalized_q); +#ifndef NDEBUG + assert(normalized); +#endif + + // Conjugate of q + Q_type q_conj[4]; + igl::quat_conjugate(normalized_q,q_conj); + + // Rotate of vector v by quaternion q is: + // q*v*conj(q) + // Compute q*v + Q_type q_mult_quat_v[4]; + igl::quat_mult(normalized_q,quat_v,q_mult_quat_v); + // Compute (q*v) * conj(q) + igl::quat_mult(q_mult_quat_v,q_conj,out); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::rotate_by_quat(double const*, double const*, double*); +// generated by autoexplicit.sh +template void igl::rotate_by_quat(float const*, float const*, float*); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/rotate_by_quat.h b/src/external/libigl-2.3.0/include/igl/rotate_by_quat.h new file mode 100644 index 000000000..b45204839 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/rotate_by_quat.h @@ -0,0 +1,33 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_ROTATE_BY_QUAT_H +#define IGL_ROTATE_BY_QUAT_H +#include "igl_inline.h" + +namespace igl +{ + // Compute rotation of a given vector/point by a quaternion + // A Quaternion, q, is defined here as an arrays of four scalars (x,y,z,w), + // such that q = x*i + y*j + z*k + w + // Inputs: + // v input 3d point/vector + // q input quaternion + // Outputs: + // out result of rotation, allowed to be same as v + template + IGL_INLINE void rotate_by_quat( + const Q_type *v, + const Q_type *q, + Q_type *out); +}; + +#ifndef IGL_STATIC_LIBRARY +# include "rotate_by_quat.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/rotate_vectors.cpp b/src/external/libigl-2.3.0/include/igl/rotate_vectors.cpp new file mode 100644 index 000000000..b236d79e6 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/rotate_vectors.cpp @@ -0,0 +1,37 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Daniele Panozzo +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +#include "rotate_vectors.h" +IGL_INLINE Eigen::MatrixXd igl::rotate_vectors( + const Eigen::MatrixXd& V, + const Eigen::VectorXd& A, + const Eigen::MatrixXd& B1, + const Eigen::MatrixXd& B2) +{ + Eigen::MatrixXd RV(V.rows(),V.cols()); + + for (unsigned i=0; i +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef IGL_ROTATE_VECTORS_H +#define IGL_ROTATE_VECTORS_H +#include "igl_inline.h" +#include +namespace igl +{ + // Rotate the vectors V by A radians on the tangent plane spanned by B1 and + // B2 + // + // Inputs: + // V #V by 3 eigen Matrix of vectors + // A #V eigen vector of rotation angles or a single angle to be applied + // to all vectors + // B1 #V by 3 eigen Matrix of base vector 1 + // B2 #V by 3 eigen Matrix of base vector 2 + // + // Output: + // Returns the rotated vectors + // + IGL_INLINE Eigen::MatrixXd rotate_vectors( + const Eigen::MatrixXd& V, + const Eigen::VectorXd& A, + const Eigen::MatrixXd& B1, + const Eigen::MatrixXd& B2); + +} + +#ifndef IGL_STATIC_LIBRARY +# include "rotate_vectors.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/rotation_matrix_from_directions.cpp b/src/external/libigl-2.3.0/include/igl/rotation_matrix_from_directions.cpp new file mode 100644 index 000000000..4ecc1a5d9 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/rotation_matrix_from_directions.cpp @@ -0,0 +1,63 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Daniele Panozzo , Olga Diamanti +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +#include "rotation_matrix_from_directions.h" +#include +#include + +template +IGL_INLINE Eigen::Matrix igl::rotation_matrix_from_directions( + const Eigen::Matrix v0, + const Eigen::Matrix v1) +{ + Eigen::Matrix rotM; + const double epsilon=1e-8; + Scalar dot=v0.normalized().dot(v1.normalized()); + ///control if there is no rotation + if ((v0-v1).norm()::Identity(); + return rotM; + } + if ((v0+v1).norm()::Identity(); + rotM(0,0) = 1.; + std::cerr<<"igl::rotation_matrix_from_directions: rotating around x axis by 180o"< axis; + axis=v0.cross(v1); + axis.normalize(); + + ///construct rotation matrix + Scalar u=axis(0); + Scalar v=axis(1); + Scalar w=axis(2); + Scalar phi=acos(dot); + Scalar rcos = cos(phi); + Scalar rsin = sin(phi); + + rotM(0,0) = rcos + u*u*(1-rcos); + rotM(1,0) = w * rsin + v*u*(1-rcos); + rotM(2,0) = -v * rsin + w*u*(1-rcos); + rotM(0,1) = -w * rsin + u*v*(1-rcos); + rotM(1,1) = rcos + v*v*(1-rcos); + rotM(2,1) = u * rsin + w*v*(1-rcos); + rotM(0,2) = v * rsin + u*w*(1-rcos); + rotM(1,2) = -u * rsin + v*w*(1-rcos); + rotM(2,2) = rcos + w*w*(1-rcos); + + return rotM; +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +template Eigen::Matrix igl::rotation_matrix_from_directions(const Eigen::Matrix, const Eigen::Matrix); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/rotation_matrix_from_directions.h b/src/external/libigl-2.3.0/include/igl/rotation_matrix_from_directions.h new file mode 100644 index 000000000..ca1397272 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/rotation_matrix_from_directions.h @@ -0,0 +1,34 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson, Daniele Panozzo, Olga Diamanti +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_ROTATION_MATRIX_FROM_DIRECTIONS_H +#define IGL_ROTATION_MATRIX_FROM_DIRECTIONS_H +#include "igl_inline.h" + +#include + +namespace igl +{ + // Given 2 vectors centered on origin calculate the rotation matrix from + // first to the second + // + // Inputs: + // v0 3D column vector + // v1 3D column vector + // Output: + // 3 by 3 rotation matrix that takes v0 to v1 + // + template + IGL_INLINE Eigen::Matrix rotation_matrix_from_directions( + const Eigen::Matrix v0, + const Eigen::Matrix v1); +} + +#ifndef IGL_STATIC_LIBRARY +#include "rotation_matrix_from_directions.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/round.cpp b/src/external/libigl-2.3.0/include/igl/round.cpp new file mode 100644 index 000000000..acde47316 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/round.cpp @@ -0,0 +1,49 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "round.h" +#include + + +// http://stackoverflow.com/a/485549 +template +IGL_INLINE DerivedX igl::round(const DerivedX r) +{ + return (r > 0.0) ? std::floor(r + 0.5) : std::ceil(r - 0.5); +} + +template < typename DerivedX, typename DerivedY> +IGL_INLINE void igl::round( + const Eigen::PlainObjectBase& X, + Eigen::PlainObjectBase& Y) +{ + Y.resizeLike(X); + // loop over rows + for(int i = 0;i, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::round, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::round, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::round, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&); +template void igl::round, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&); +template void igl::round, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&); +template void igl::round, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/round.h b/src/external/libigl-2.3.0/include/igl/round.h new file mode 100644 index 000000000..cdaac731b --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/round.h @@ -0,0 +1,37 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_ROUND_H +#define IGL_ROUND_H +#include "igl_inline.h" +#include +namespace igl +{ + // Round a scalar value + // + // Inputs: + // x number + // Returns x rounded to integer + template + DerivedX round(const DerivedX r); + // Round a given matrix to nearest integers + // + // Inputs: + // X m by n matrix of scalars + // Outputs: + // Y m by n matrix of rounded integers + template < typename DerivedX, typename DerivedY> + IGL_INLINE void round( + const Eigen::PlainObjectBase& X, + Eigen::PlainObjectBase& Y); +} + +#ifndef IGL_STATIC_LIBRARY +# include "round.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/rows_to_matrix.cpp b/src/external/libigl-2.3.0/include/igl/rows_to_matrix.cpp new file mode 100644 index 000000000..14c369e40 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/rows_to_matrix.cpp @@ -0,0 +1,54 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "rows_to_matrix.h" + +#include +#include + +#include "max_size.h" +#include "min_size.h" + +template +IGL_INLINE bool igl::rows_to_matrix(const std::vector & V,Mat & M) +{ + // number of columns + int m = V.size(); + if(m == 0) + { + fprintf(stderr,"Error: rows_to_matrix() list is empty()\n"); + return false; + } + // number of rows + int n = igl::min_size(V); + if(n != igl::max_size(V)) + { + fprintf(stderr,"Error: rows_to_matrix()" + " list elements are not all the same size\n"); + return false; + } + assert(n != -1); + // Resize output + M.resize(m,n); + + // Loop over rows + int i = 0; + typename std::vector::const_iterator iter = V.begin(); + while(iter != V.end()) + { + M.row(i) = V[i]; + // increment index and iterator + i++; + iter++; + } + + return true; +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +#endif diff --git a/src/external/libigl-2.3.0/include/igl/rows_to_matrix.h b/src/external/libigl-2.3.0/include/igl/rows_to_matrix.h new file mode 100644 index 000000000..8f62b5a2d --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/rows_to_matrix.h @@ -0,0 +1,34 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_ROWS_TO_MATRIX_H +#define IGL_ROWS_TO_MATRIX_H +#include "igl_inline.h" +#include +namespace igl +{ + // Convert a list (std::vector) of row vectors of the same length to a matrix + // Template: + // Row row vector type, must implement: + // .size() + // Mat Matrix type, must implement: + // .resize(m,n) + // .row(i) = Row + // Inputs: + // V a m-long list of vectors of size n + // Outputs: + // M an m by n matrix + // Returns true on success, false on errors + template + IGL_INLINE bool rows_to_matrix(const std::vector & V,Mat & M); +} + +#ifndef IGL_STATIC_LIBRARY +# include "rows_to_matrix.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/sample_edges.cpp b/src/external/libigl-2.3.0/include/igl/sample_edges.cpp new file mode 100644 index 000000000..a20df1426 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/sample_edges.cpp @@ -0,0 +1,33 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "sample_edges.h" + +IGL_INLINE void igl::sample_edges( + const Eigen::MatrixXd & V, + const Eigen::MatrixXi & E, + const int k, + Eigen::MatrixXd & S) +{ + using namespace Eigen; + // Resize output + S.resize(V.rows() + k * E.rows(),V.cols()); + // Copy V at front of S + S.block(0,0,V.rows(),V.cols()) = V; + + // loop over edges + for(int i = 0;i +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_SAMPLE_EDGES_H +#define IGL_SAMPLE_EDGES_H +#include "igl_inline.h" + +#include + +namespace igl +{ + // Compute samples_per_edge extra points along each edge in E defined over + // vertices of V. + // + // Inputs: + // V vertices over which edges are defined, # vertices by dim + // E edge list, # edges by 2 + // k number of extra samples to be computed along edge not + // including start and end points + // Output: + // S sampled vertices, size less than # edges * (2+k) by dim always begins + // with V so that E is also defined over S + IGL_INLINE void sample_edges( + const Eigen::MatrixXd & V, + const Eigen::MatrixXi & E, + const int k, + Eigen::MatrixXd & S); +} +#ifndef IGL_STATIC_LIBRARY +# include "sample_edges.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/scalar_to_cr_vector_gradient.cpp b/src/external/libigl-2.3.0/include/igl/scalar_to_cr_vector_gradient.cpp new file mode 100644 index 000000000..0b992ca3e --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/scalar_to_cr_vector_gradient.cpp @@ -0,0 +1,116 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2020 Oded Stein +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "scalar_to_cr_vector_gradient.h" + +#include "orient_halfedges.h" + +#include "doublearea.h" +#include "squared_edge_lengths.h" + + +template +IGL_INLINE void +igl::scalar_to_cr_vector_gradient( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + const Eigen::MatrixBase& E, + const Eigen::MatrixBase& oE, + Eigen::SparseMatrix& G) +{ + Eigen::Matrix + l_sq; + squared_edge_lengths(V, F, l_sq); + scalar_to_cr_vector_gradient_intrinsic(F, l_sq, E, oE, G); +} + +template +IGL_INLINE void +igl::scalar_to_cr_vector_gradient( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + Eigen::PlainObjectBase& E, + Eigen::PlainObjectBase& oE, + Eigen::SparseMatrix& G) +{ + if(E.rows()!=F.rows() || E.cols()!=F.cols() || oE.rows()!=F.rows() || + oE.cols()!=F.cols()) { + orient_halfedges(F, E, oE); + } + + const Eigen::PlainObjectBase& cE = E; + const Eigen::PlainObjectBase& coE = oE; + + scalar_to_cr_vector_gradient(V, F, cE, coE, G); +} + + +template +IGL_INLINE void +igl::scalar_to_cr_vector_gradient_intrinsic( + const Eigen::MatrixBase& F, + const Eigen::MatrixBase& l_sq, + const Eigen::MatrixBase& E, + const Eigen::MatrixBase& oE, + Eigen::SparseMatrix& G) +{ + Eigen::Matrix + dA; + DerivedL_sq l_sqrt = l_sq.array().sqrt().matrix(); + doublearea(l_sqrt, dA); + scalar_to_cr_vector_gradient_intrinsic(F, l_sq, dA, E, oE, G); +} + + +template +IGL_INLINE void +igl::scalar_to_cr_vector_gradient_intrinsic( + const Eigen::MatrixBase& F, + const Eigen::MatrixBase& l_sq, + const Eigen::MatrixBase& dA, + const Eigen::MatrixBase& E, + const Eigen::MatrixBase& oE, + Eigen::SparseMatrix& G) +{ + assert(F.cols()==3 && "Faces have three vertices"); + assert(E.rows()==F.rows() && E.cols()==F.cols() && oE.rows()==F.rows() && + oE.cols()==F.cols() && "Wrong dimension in edge vectors"); + + const Eigen::Index m = F.rows(); + const typename DerivedF::Scalar n = F.maxCoeff() + 1; + const typename DerivedE::Scalar nE = E.maxCoeff() + 1; + + std::vector > tripletList; + tripletList.reserve(5*3*m); + for(Eigen::Index f=0; f, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, double>(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::SparseMatrix&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/scalar_to_cr_vector_gradient.h b/src/external/libigl-2.3.0/include/igl/scalar_to_cr_vector_gradient.h new file mode 100644 index 000000000..4e9861c3c --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/scalar_to_cr_vector_gradient.h @@ -0,0 +1,100 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2020 Oded Stein +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_SCALAR_TO_CR_VECTOT_GRADIENT_H +#define IGL_SCALAR_TO_CR_VECTOT_GRADIENT_H + +#include "igl_inline.h" + +#include +#include + + +namespace igl +{ + // Computes the gradient matrix with hat functions on the right, and + // vector CR functions on the left. + // See Oded Stein, Max Wardetzky, Alec Jacobson, Eitan Grinspun, 2020. + // "A Simple Discretization of the Vector Dirichlet Energy" + // + // Inputs: + // V, F: input mesh + // E: a mapping from each halfedge to each edge, as computed with + // orient_halfedges. + // will be computed if not provided. + // oE: the orientation of each halfedge compared to the orientation of the + // actual edge, as computed with orient_halfedges. + // will be computed if not provided. + // + // Outputs: + // G: computed gradient matrix + // E, oE: these are computed if they are not present, as described above + + template + IGL_INLINE void + scalar_to_cr_vector_gradient( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + const Eigen::MatrixBase& E, + const Eigen::MatrixBase& oE, + Eigen::SparseMatrix& G); + + template + IGL_INLINE void + scalar_to_cr_vector_gradient( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + Eigen::PlainObjectBase& E, + Eigen::PlainObjectBase& oE, + Eigen::SparseMatrix& G); + + + // Version that uses intrinsic quantities as input + // + // Inputs: + // F: input mesh connectivity + // l_sq: squared edge lengths of each halfedge + // dA: double area of each face + // E: a mapping from each halfedge to each edge. + // oE: the orientation of each halfedge compared to the orientation of the + // actual edge. + // + // Outputs: + // G: computed gradient matrix + + template + IGL_INLINE void + scalar_to_cr_vector_gradient_intrinsic( + const Eigen::MatrixBase& F, + const Eigen::MatrixBase& l_sq, + const Eigen::MatrixBase& E, + const Eigen::MatrixBase& oE, + Eigen::SparseMatrix& G); + + template + IGL_INLINE void + scalar_to_cr_vector_gradient_intrinsic( + const Eigen::MatrixBase& F, + const Eigen::MatrixBase& l_sq, + const Eigen::MatrixBase& dA, + const Eigen::MatrixBase& E, + const Eigen::MatrixBase& oE, + Eigen::SparseMatrix& G); + + +} + + +#ifndef IGL_STATIC_LIBRARY +# include "scalar_to_cr_vector_gradient.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/screen_space_selection.cpp b/src/external/libigl-2.3.0/include/igl/screen_space_selection.cpp new file mode 100644 index 000000000..819ddfb92 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/screen_space_selection.cpp @@ -0,0 +1,100 @@ +#include "screen_space_selection.h" + +#include +#include +#include +#include +#include +#include + +template < + typename DerivedV, + typename DerivedF, + typename DerivedM, + typename DerivedN, + typename DerivedO, + typename Ltype, + typename DerivedW, + typename Deriveda> +IGL_INLINE void igl::screen_space_selection( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const igl::AABB & tree, + const Eigen::MatrixBase& model, + const Eigen::MatrixBase& proj, + const Eigen::MatrixBase& viewport, + const std::vector > & L, + Eigen::PlainObjectBase & W, + Eigen::PlainObjectBase & and_visible) +{ + typedef typename DerivedV::Scalar Scalar; + screen_space_selection(V,model,proj,viewport,L,W); + const Eigen::RowVector3d origin = + (model.inverse().col(3)).head(3).template cast(); + igl::parallel_for(V.rows(),[&](const int i) + { + // Skip unselected points + if(W(i)<0.5){ return; } + igl::Hit hit; + tree.intersect_ray(V,F,origin,V.row(i)-origin,hit); + and_visible(i) = !(hit.t>1e-5 && hit.t<(1-1e-5)); + }); +} + +template < + typename DerivedV, + typename DerivedM, + typename DerivedN, + typename DerivedO, + typename Ltype, + typename DerivedW> +IGL_INLINE void igl::screen_space_selection( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase& model, + const Eigen::MatrixBase& proj, + const Eigen::MatrixBase& viewport, + const std::vector > & L, + Eigen::PlainObjectBase & W) +{ + typedef typename DerivedV::Scalar Scalar; + Eigen::Matrix P(L.size(),2); + Eigen::Matrix E(L.size(),2); + for(int i = 0;i(); + E(i,0) = i; + E(i,1) = (i+1)%E.rows(); + } + return screen_space_selection(V,model,proj,viewport,P,E,W); +} + +template < + typename DerivedV, + typename DerivedM, + typename DerivedN, + typename DerivedO, + typename DerivedP, + typename DerivedE, + typename DerivedW> +IGL_INLINE void igl::screen_space_selection( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase& model, + const Eigen::MatrixBase& proj, + const Eigen::MatrixBase& viewport, + const Eigen::MatrixBase & P, + const Eigen::MatrixBase & E, + Eigen::PlainObjectBase & W) +{ + // project all mesh vertices to 2D + DerivedV V2; + igl::project(V,model,proj,viewport,V2); + // In 2D this uses O(N*M) naive algorithm. + igl::winding_number(P,E,V2,W); + W = W.array().abs().eval(); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +template void igl::screen_space_selection, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, float, Eigen::Matrix, Eigen::Array >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, igl::AABB, 3> const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, std::vector, std::allocator > > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::screen_space_selection, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, float, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, std::vector, std::allocator > > const&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/screen_space_selection.h b/src/external/libigl-2.3.0/include/igl/screen_space_selection.h new file mode 100644 index 000000000..cb7983887 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/screen_space_selection.h @@ -0,0 +1,105 @@ +#ifndef IGL_SCREEN_SPACE_SELECTION_H +#define IGL_SCREEN_SPACE_SELECTION_H + +#include "igl/igl_inline.h" +#include +#include +// Forward declaration +namespace igl { template class AABB; } + +namespace igl +{ + // Given a mesh, a camera determine which points are inside of a given 2D + // screen space polygon **culling points based on self-occlusion.** + // + // Inputs: + // V #V by 3 list of mesh vertex positions + // F #F by 3 list of mesh triangle indices into rows of V + // tree precomputed bounding volume heirarchy + // model 4 by 4 camera model-view matrix + // proj 4 by 4 camera projection matrix (perspective or orthoraphic) + // viewport 4-vector containing camera viewport + // L #L by 2 list of 2D polygon vertices (in order) + // Outputs: + // W #V by 1 list of winding numbers (|W|>0.5 indicates inside) + // and_visible #V by 1 list of visibility values (only correct for vertices + // with |W|>0.5) + template < + typename DerivedV, + typename DerivedF, + typename DerivedM, + typename DerivedN, + typename DerivedO, + typename Ltype, + typename DerivedW, + typename Deriveda> + IGL_INLINE void screen_space_selection( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const igl::AABB & tree, + const Eigen::MatrixBase& model, + const Eigen::MatrixBase& proj, + const Eigen::MatrixBase& viewport, + const std::vector > & L, + Eigen::PlainObjectBase & W, + Eigen::PlainObjectBase & and_visible); + // Given a mesh, a camera determine which points are inside of a given 2D + // screen space polygon + // + // Inputs: + // V #V by 3 list of mesh vertex positions + // model 4 by 4 camera model-view matrix + // proj 4 by 4 camera projection matrix (perspective or orthoraphic) + // viewport 4-vector containing camera viewport + // L #L by 2 list of 2D polygon vertices (in order) + // Outputs: + // W #V by 1 list of winding numbers (|W|>0.5 indicates inside) + template < + typename DerivedV, + typename DerivedM, + typename DerivedN, + typename DerivedO, + typename Ltype, + typename DerivedW> + IGL_INLINE void screen_space_selection( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase& model, + const Eigen::MatrixBase& proj, + const Eigen::MatrixBase& viewport, + const std::vector > & L, + Eigen::PlainObjectBase & W); + // Given a mesh, a camera determine which points are inside of a given 2D + // screen space polygon + // + // Inputs: + // V #V by 3 list of mesh vertex positions + // model 4 by 4 camera model-view matrix + // proj 4 by 4 camera projection matrix (perspective or orthoraphic) + // viewport 4-vector containing camera viewport + // P #P by 2 list of screen space polygon vertices + // E #E by 2 list of screen space edges as indices into rows of P + // Outputs: + // W #V by 1 list of winding numbers (|W|>0.5 indicates inside) + template < + typename DerivedV, + typename DerivedM, + typename DerivedN, + typename DerivedO, + typename DerivedP, + typename DerivedE, + typename DerivedW> + IGL_INLINE void screen_space_selection( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase& model, + const Eigen::MatrixBase& proj, + const Eigen::MatrixBase& viewport, + const Eigen::MatrixBase & P, + const Eigen::MatrixBase & E, + Eigen::PlainObjectBase & W); +} + +#ifndef IGL_STATIC_LIBRARY +#include "screen_space_selection.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/seam_edges.cpp b/src/external/libigl-2.3.0/include/igl/seam_edges.cpp new file mode 100644 index 000000000..8cbca143c --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/seam_edges.cpp @@ -0,0 +1,211 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Yotam Gingold +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +#include "seam_edges.h" +#include +#include +#include + +// Yotam has verified that this function produces the exact same output as +// `find_seam_fast.py` for `cow_triangled.obj`. +template < + typename DerivedV, + typename DerivedTC, + typename DerivedF, + typename DerivedFTC, + typename Derivedseams, + typename Derivedboundaries, + typename Derivedfoldovers> +IGL_INLINE void igl::seam_edges( + const Eigen::PlainObjectBase& V, + const Eigen::PlainObjectBase& TC, + const Eigen::PlainObjectBase& F, + const Eigen::PlainObjectBase& FTC, + Eigen::PlainObjectBase& seams, + Eigen::PlainObjectBase& boundaries, + Eigen::PlainObjectBase& foldovers) +{ + // Assume triangles. + assert( F.cols() == 3 ); + assert( F.cols() == FTC.cols() ); + assert( F.rows() == FTC.rows() ); + + // Assume 2D texture coordinates (foldovers tests). + assert( TC.cols() == 2 ); + typedef Eigen::Matrix< typename DerivedTC::Scalar, 2, 1 > Vector2S; + // Computes the orientation of `c` relative to the line between `a` and `b`. + // Assumes 2D vector input. + // Based on: https://www.cs.cmu.edu/~quake/robust.html + const auto& Orientation = []( + const Vector2S& a, + const Vector2S& b, + const Vector2S& c ) -> typename DerivedTC::Scalar + { + const Vector2S row0 = a - c; + const Vector2S row1 = b - c; + return row0(0)*row1(1) - row1(0)*row0(1); + }; + + seams .setZero( 3*F.rows(), 4 ); + boundaries.setZero( 3*F.rows(), 2 ); + foldovers .setZero( 3*F.rows(), 4 ); + + int num_seams = 0; + int num_boundaries = 0; + int num_foldovers = 0; + + // A map from a pair of vertex indices to the index (face and endpoints) + // into face_position_indices. + // The following should be true for every key, value pair: + // key == face_position_indices[ value ] + // This gives us a "reverse map" so that we can look up other face + // attributes based on position edges. + // The value are written in the format returned by numpy.where(), + // which stores multi-dimensional indices such as array[a0,b0], array[a1,b1] + // as ( (a0,a1), (b0,b1) ). + + // We need to make a hash function for our directed edges. + // We'll use i*V.rows() + j. + typedef std::pair< typename DerivedF::Scalar, typename DerivedF::Scalar > + directed_edge; + const int numV = V.rows(); + const int numF = F.rows(); + const auto& edge_hasher = + [numV]( directed_edge const& e ) { return e.first*numV + e.second; }; + // When we pass a hash function object, we also need to specify the number of + // buckets. The Euler characteristic says that the number of undirected edges + // is numV + numF -2*genus. + std::unordered_map,decltype(edge_hasher) > + directed_position_edge2face_position_index(2*( numV + numF ), edge_hasher); + for( int fi = 0; fi < F.rows(); ++fi ) + { + for( int i = 0; i < 3; ++i ) + { + const int j = ( i+1 ) % 3; + directed_position_edge2face_position_index[ + std::make_pair( F(fi,i), F(fi,j) ) ] = std::make_pair( fi, i ); + } + } + + // First find all undirected position edges (collect a canonical orientation + // of the directed edges). + std::unordered_set< directed_edge, decltype( edge_hasher ) > + undirected_position_edges( numV + numF, edge_hasher ); + for( const auto& el : directed_position_edge2face_position_index ) + { + // The canonical orientation is the one where the smaller of + // the two vertex indices is first. + undirected_position_edges.insert( std::make_pair( + std::min( el.first.first, el.first.second ), + std::max( el.first.first, el.first.second ) ) ); + } + + // Now we will iterate over all position edges. + // Seam edges are the edges whose two opposite directed edges have different + // texcoord indices (or one doesn't exist at all in the case of a mesh + // boundary). + for( const auto& vp_edge : undirected_position_edges ) + { + // We should only see canonical edges, + // where the first vertex index is smaller. + assert( vp_edge.first < vp_edge.second ); + + const auto vp_edge_reverse = std::make_pair(vp_edge.second, vp_edge.first); + // If it and its opposite exist as directed edges, check if their + // texture coordinate indices match. + if( directed_position_edge2face_position_index.count( vp_edge ) && + directed_position_edge2face_position_index.count( vp_edge_reverse ) ) + { + const auto forwards = + directed_position_edge2face_position_index[ vp_edge ]; + const auto backwards = + directed_position_edge2face_position_index[ vp_edge_reverse ]; + + // NOTE: They should never be equal. + assert( forwards != backwards ); + + // If the texcoord indices match (are similarly flipped), + // this edge is not a seam. It could be a foldover. + if( + std::make_pair( + FTC( forwards.first, forwards.second ), + FTC( forwards.first, ( forwards.second+1 ) % 3 ) ) + == + std::make_pair( + FTC( backwards.first, ( backwards.second+1 ) % 3 ), + FTC( backwards.first, backwards.second ) )) + { + // Check for foldovers in UV space. + // Get the edge (a,b) and the two opposite vertices's texture + // coordinates. + const Vector2S a = TC.row( FTC( forwards.first, forwards.second ) ); + const Vector2S b = + TC.row( FTC( forwards.first, (forwards.second+1) % 3 ) ); + const Vector2S c_forwards = + TC.row( FTC( forwards .first, (forwards .second+2) % 3 ) ); + const Vector2S c_backwards = + TC.row( FTC( backwards.first, (backwards.second+2) % 3 ) ); + // If the opposite vertices' texture coordinates fall on the same side + // of the edge, we have a UV-space foldover. + const auto orientation_forwards = Orientation( a, b, c_forwards ); + const auto orientation_backwards = Orientation( a, b, c_backwards ); + if( ( orientation_forwards > 0 && orientation_backwards > 0 ) || + ( orientation_forwards < 0 && orientation_backwards < 0 ) + ) { + foldovers( num_foldovers, 0 ) = forwards.first; + foldovers( num_foldovers, 1 ) = forwards.second; + foldovers( num_foldovers, 2 ) = backwards.first; + foldovers( num_foldovers, 3 ) = backwards.second; + num_foldovers += 1; + } + } + // Otherwise, we have a non-matching seam edge. + else + { + seams( num_seams, 0 ) = forwards.first; + seams( num_seams, 1 ) = forwards.second; + seams( num_seams, 2 ) = backwards.first; + seams( num_seams, 3 ) = backwards.second; + num_seams += 1; + } + } + // Otherwise, the edge and its opposite aren't both in the directed edges. + // One of them should be. + else if( directed_position_edge2face_position_index.count( vp_edge ) ) + { + const auto forwards = directed_position_edge2face_position_index[vp_edge]; + boundaries( num_boundaries, 0 ) = forwards.first; + boundaries( num_boundaries, 1 ) = forwards.second; + num_boundaries += 1; + } else if( + directed_position_edge2face_position_index.count( vp_edge_reverse ) ) + { + const auto backwards = + directed_position_edge2face_position_index[ vp_edge_reverse ]; + boundaries( num_boundaries, 0 ) = backwards.first; + boundaries( num_boundaries, 1 ) = backwards.second; + num_boundaries += 1; + } else { + // This should never happen! One of these two must have been seen. + assert( + directed_position_edge2face_position_index.count( vp_edge ) || + directed_position_edge2face_position_index.count( vp_edge_reverse ) + ); + } + } + + seams .conservativeResize( num_seams, Eigen::NoChange_t() ); + boundaries.conservativeResize( num_boundaries, Eigen::NoChange_t() ); + foldovers .conservativeResize( num_foldovers, Eigen::NoChange_t() ); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::seam_edges, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/seam_edges.h b/src/external/libigl-2.3.0/include/igl/seam_edges.h new file mode 100644 index 000000000..15c82826c --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/seam_edges.h @@ -0,0 +1,64 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Yotam Gingold +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_SEAM_EDGES_H +#define IGL_SEAM_EDGES_H +#include "igl_inline.h" +#include +namespace igl +{ + // Finds all UV-space boundaries of a mesh. + // + // Inputs: + // V #V by dim list of positions of the input mesh. + // TC #TC by 2 list of 2D texture coordinates of the input mesh + // F #F by 3 list of triange indices into V representing a + // manifold-with-boundary triangle mesh + // FTC #F by 3 list of indices into TC for each corner + // Outputs: + // seams Edges where the forwards and backwards directions have different + // texture coordinates, as a #seams-by-4 matrix of indices. Each row is + // organized as [ forward_face_index, forward_face_vertex_index, + // backwards_face_index, backwards_face_vertex_index ] such that one side + // of the seam is the edge: + // F[ seams( i, 0 ), seams( i, 1 ) ], F[ seams( i, 0 ), (seams( i, 1 ) + 1) % 3 ] + // and the other side is the edge: + // F[ seams( i, 2 ), seams( i, 3 ) ], F[ seams( i, 2 ), (seams( i, 3 ) + 1) % 3 ] + // boundaries Edges with only one incident triangle, as a #boundaries-by-2 + // matrix of indices. Each row is organized as + // [ face_index, face_vertex_index ] + // such that the edge is: + // F[ boundaries( i, 0 ), boundaries( i, 1 ) ], F[ boundaries( i, 0 ), (boundaries( i, 1 ) + 1) % 3 ] + // foldovers Edges where the two incident triangles fold over each other + // in UV-space, as a #foldovers-by-4 matrix of indices. + // Each row is organized as [ forward_face_index, forward_face_vertex_index, + // backwards_face_index, backwards_face_vertex_index ] + // such that one side of the foldover is the edge: + // F[ foldovers( i, 0 ), foldovers( i, 1 ) ], F[ foldovers( i, 0 ), (foldovers( i, 1 ) + 1) % 3 ] + // and the other side is the edge: + // F[ foldovers( i, 2 ), foldovers( i, 3 ) ], F[ foldovers( i, 2 ), (foldovers( i, 3 ) + 1) % 3 ] + template < + typename DerivedV, + typename DerivedTC, + typename DerivedF, + typename DerivedFTC, + typename Derivedseams, + typename Derivedboundaries, + typename Derivedfoldovers> + IGL_INLINE void seam_edges( + const Eigen::PlainObjectBase& V, + const Eigen::PlainObjectBase& TC, + const Eigen::PlainObjectBase& F, + const Eigen::PlainObjectBase& FTC, + Eigen::PlainObjectBase& seams, + Eigen::PlainObjectBase& boundaries, + Eigen::PlainObjectBase& foldovers); +} +#ifndef IGL_STATIC_LIBRARY +# include "seam_edges.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/segment_segment_intersect.cpp b/src/external/libigl-2.3.0/include/igl/segment_segment_intersect.cpp new file mode 100644 index 000000000..ebc2c6b9d --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/segment_segment_intersect.cpp @@ -0,0 +1,67 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Francisca Gil Ureta +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "segment_segment_intersect.h" + +#include + +template +IGL_INLINE bool igl::segment_segment_intersect( + const Eigen::MatrixBase &p, + const Eigen::MatrixBase &r, + const Eigen::MatrixBase &q, + const Eigen::MatrixBase &s, + double &a_t, + double &a_u, + double eps +) +{ + // http://stackoverflow.com/questions/563198/how-do-you-detect-where-two-line-segments-intersect + // Search intersection between two segments + // p + t*r : t \in [0,1] + // q + u*s : u \in [0,1] + + // p + t * r = q + u * s // x s + // t(r x s) = (q - p) x s + // t = (q - p) x s / (r x s) + + // (r x s) ~ 0 --> directions are parallel, they will never cross + Eigen::Matrix rxs = r.cross(s); + if (rxs.norm() <= eps) + return false; + + int sign; + + double u; + // u = (q − p) × r / (r × s) + Eigen::Matrix u1 = (q - p).cross(r); + sign = ((u1.dot(rxs)) > 0) ? 1 : -1; + u = u1.norm() / rxs.norm(); + u = u * sign; + + double t; + // t = (q - p) x s / (r x s) + Eigen::Matrix t1 = (q - p).cross(s); + sign = ((t1.dot(rxs)) > 0) ? 1 : -1; + t = t1.norm() / rxs.norm(); + t = t * sign; + + a_t = t; + a_u = u; + + if ((u - 1.) > eps || u < -eps) + return false; + + if ((t - 1.) > eps || t < -eps) + return false; + + return true; +}; + +#ifdef IGL_STATIC_LIBRARY +template bool igl::segment_segment_intersect, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, double&, double&, double); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/segment_segment_intersect.h b/src/external/libigl-2.3.0/include/igl/segment_segment_intersect.h new file mode 100644 index 000000000..77e89c320 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/segment_segment_intersect.h @@ -0,0 +1,46 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Francisca Gil Ureta +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef IGL_SEGMENT_SEGMENT_INTERSECT_H +#define IGL_SEGMENT_SEGMENT_INTERSECT_H + + +#include "igl_inline.h" +#include +namespace igl +{ + + // Determine whether two line segments A,B intersect + // A: p + t*r : t \in [0,1] + // B: q + u*s : u \in [0,1] + // Inputs: + // p 3-vector origin of segment A + // r 3-vector direction of segment A + // q 3-vector origin of segment B + // s 3-vector direction of segment B + // eps precision + // Outputs: + // t scalar point of intersection along segment A, t \in [0,1] + // u scalar point of intersection along segment B, u \in [0,1] + // Returns true if intersection + template + IGL_INLINE bool segment_segment_intersect( + const Eigen::MatrixBase &p, + const Eigen::MatrixBase &r, + const Eigen::MatrixBase &q, + const Eigen::MatrixBase &s, + double &t, + double &u, + double eps = 1e-6 + ); + +} +#ifndef IGL_STATIC_LIBRARY +# include "segment_segment_intersect.cpp" +#endif +#endif //IGL_SEGMENT_SEGMENT_INTERSECT_H diff --git a/src/external/libigl-2.3.0/include/igl/serialize.h b/src/external/libigl-2.3.0/include/igl/serialize.h new file mode 100644 index 000000000..498bd62c7 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/serialize.h @@ -0,0 +1,1295 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Christian Schüller +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_SERIALIZE_H +#define IGL_SERIALIZE_H + +// ----------------------------------------------------------------------------- +// Functions to save and load a serialization of fundamental c++ data types to +// and from a binary file. STL containers, Eigen matrix types and nested data +// structures are also supported. To serialize a user defined class implement +// the interface Serializable or SerializableBase. +// +// See also: xml/serialize_xml.h +// ----------------------------------------------------------------------------- +// TODOs: +// * arbitrary pointer graph structures +// ----------------------------------------------------------------------------- + +// Known issues: This is not written in libigl-style so it isn't (easily) +// "dualized" into the static library. +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "igl_inline.h" + +// non-intrusive serialization helper macros + +#define SERIALIZE_TYPE(Type,Params) \ +namespace igl { namespace serialization { \ + void _serialization(bool s,Type& obj,std::vector& buffer) {Params} \ + template<> inline void serialize(const Type& obj,std::vector& buffer) { \ + _serialization(true,const_cast(obj),buffer); \ + } \ + template<> inline void deserialize(Type& obj,const std::vector& buffer) { \ + _serialization(false,obj,const_cast&>(buffer)); \ + } \ +}} + +#define SERIALIZE_TYPE_SOURCE(Type,Params) \ +namespace igl { namespace serialization { \ + void _serialization(bool s,Type& obj,std::vector& buffer) {Params} \ + void _serialize(const Type& obj,std::vector& buffer) { \ + _serialization(true,const_cast(obj),buffer); \ + } \ + void _deserialize(Type& obj,const std::vector& buffer) { \ + _serialization(false,obj,const_cast&>(buffer)); \ + } \ +}} + +#define SERIALIZE_MEMBER(Object) igl::serializer(s,obj.Object,std::string(#Object),buffer); +#define SERIALIZE_MEMBER_NAME(Object,Name) igl::serializer(s,obj.Object,std::string(Name),buffer); + + +namespace igl +{ + struct IndexedPointerBase; + + // Serializes the given object either to a file or to a provided buffer + // Templates: + // T type of the object to serialize + // Inputs: + // obj object to serialize + // objectName unique object name,used for the identification + // overwrite set to true to overwrite an existing file + // filename name of the file containing the serialization + // Outputs: + // buffer binary serialization + // + template + inline bool serialize(const T& obj,const std::string& filename); + template + inline bool serialize(const T& obj,const std::string& objectName,const std::string& filename,bool overwrite = false); + template + inline bool serialize(const T& obj,const std::string& objectName,std::vector& buffer); + template + inline bool serialize(const T& obj,const std::string& objectName,std::vector& buffer); + + // Deserializes the given data from a file or buffer back to the provided object + // + // Templates: + // T type of the object to serialize + // Inputs: + // buffer binary serialization + // objectName unique object name, used for the identification + // filename name of the file containing the serialization + // Outputs: + // obj object to load back serialization to + // + template + inline bool deserialize(T& obj,const std::string& filename); + template + inline bool deserialize(T& obj,const std::string& objectName,const std::string& filename); + template + inline bool deserialize(T& obj,const std::string& objectName,const std::vector& buffer); + + // Wrapper to expose both, the de- and serialization as one function + // + template + inline bool serializer(bool serialize,T& obj,const std::string& filename); + template + inline bool serializer(bool serialize,T& obj,const std::string& objectName,const std::string& filename,bool overwrite = false); + template + inline bool serializer(bool serialize,T& obj,const std::string& objectName,std::vector& buffer); + + // User defined types have to either overload the function igl::serialization::serialize() + // and igl::serialization::deserialize() for their type (non-intrusive serialization): + // + // namespace igl { namespace serialization + // { + // template<> + // inline void serialize(const UserType& obj,std::vector& buffer) { + // ::igl::serialize(obj.var,"var",buffer); + // } + // + // template<> + // inline void deserialize(UserType& obj,const std::vector& buffer) { + // ::igl::deserialize(obj.var,"var",buffer); + // } + // }} + // + // or use this macro for convenience: + // + // SERIALIZE_TYPE(UserType, + // SERIALIZE_MEMBER(var) + // ) + // + // or to derive from the class Serializable and add their the members + // in InitSerialization like the following: + // + // class UserType : public igl::Serializable { + // + // int var; + // + // void InitSerialization() { + // this->Add(var,"var"); + // } + // }; + + // Base interface for user defined types + struct SerializableBase + { + virtual void Serialize(std::vector& buffer) const = 0; + virtual void Deserialize(const std::vector& buffer) = 0; + }; + + // Convenient interface for user defined types + class Serializable: public SerializableBase + { + private: + + template + struct SerializationObject : public SerializableBase + { + bool Binary; + std::string Name; + std::unique_ptr Object; + + void Serialize(std::vector& buffer) const override { + igl::serialize(*Object,Name,buffer); + } + + void Deserialize(const std::vector& buffer) override { + igl::deserialize(*Object,Name,buffer); + } + }; + + mutable bool initialized; + mutable std::vector objects; + + public: + + // You **MUST** Override this function to add your member variables which + // should be serialized + // + // http://stackoverflow.com/a/6634382/148668 + virtual void InitSerialization() = 0; + + // Following functions can be overridden to handle the specific events. + // Return false to prevent the de-/serialization of an object. + inline virtual bool PreSerialization() const; + inline virtual void PostSerialization() const; + inline virtual bool PreDeserialization(); + inline virtual void PostDeserialization(); + + // Default implementation of SerializableBase interface + inline void Serialize(std::vector& buffer) const override final; + inline void Deserialize(const std::vector& buffer) override final; + + // Default constructor, destructor, assignment and copy constructor + inline Serializable(); + inline Serializable(const Serializable& obj); + inline ~Serializable(); + inline Serializable& operator=(const Serializable& obj); + + // Use this function to add your variables which should be serialized + template + inline void Add(T& obj,std::string name,bool binary = false); + }; + + // structure for pointer handling + struct IndexedPointerBase + { + enum { BEGIN,END } Type; + size_t Index; + }; + template + struct IndexedPointer: public IndexedPointerBase + { + const T* Object; + }; + + // internal functions + namespace serialization + { + // compile time type checks + template + struct is_stl_container { static const bool value = false; }; + template + struct is_stl_container > { static const bool value = true; }; + template + struct is_stl_container > { static const bool value = true; }; + template + struct is_stl_container > { static const bool value = true; }; + template + struct is_stl_container > { static const bool value = true; }; + template + struct is_stl_container > { static const bool value = true; }; + + template + struct is_eigen_type { static const bool value = false; }; + template + struct is_eigen_type > { static const bool value = true; }; + template + struct is_eigen_type > { static const bool value = true; }; + template + struct is_eigen_type > { static const bool value = true; }; + + template + struct is_smart_ptr { static const bool value = false; }; + template + struct is_smart_ptr > { static const bool value = true; }; + template + struct is_smart_ptr > { static const bool value = true; }; + template + struct is_smart_ptr > { static const bool value = true; }; + + template + struct is_serializable { + static const bool value = std::is_fundamental::value || std::is_same::value || std::is_enum::value || std::is_base_of::value + || is_stl_container::value || is_eigen_type::value || std::is_pointer::value || serialization::is_smart_ptr::value; + }; + + // non serializable types + template + inline typename std::enable_if::value,size_t>::type getByteSize(const T& obj); + template + inline typename std::enable_if::value>::type serialize(const T& obj,std::vector& buffer,std::vector::iterator& iter); + template + inline typename std::enable_if::value>::type deserialize(T& obj,std::vector::const_iterator& iter); + + // fundamental types + template + inline typename std::enable_if::value,size_t>::type getByteSize(const T& obj); + template + inline typename std::enable_if::value>::type serialize(const T& obj,std::vector& buffer,std::vector::iterator& iter); + template + inline typename std::enable_if::value>::type deserialize(T& obj,std::vector::const_iterator& iter); + + // std::string + inline size_t getByteSize(const std::string& obj); + inline void serialize(const std::string& obj,std::vector& buffer,std::vector::iterator& iter); + inline void deserialize(std::string& obj,std::vector::const_iterator& iter); + + // enum types + template + inline typename std::enable_if::value,size_t>::type getByteSize(const T& obj); + template + inline typename std::enable_if::value>::type serialize(const T& obj,std::vector& buffer,std::vector::iterator& iter); + template + inline typename std::enable_if::value>::type deserialize(T& obj,std::vector::const_iterator& iter); + + // SerializableBase + template + inline typename std::enable_if::value,size_t>::type getByteSize(const T& obj); + template + inline typename std::enable_if::value>::type serialize(const T& obj,std::vector& buffer,std::vector::iterator& iter); + template + inline typename std::enable_if::value>::type deserialize(T& obj,std::vector::const_iterator& iter); + + // stl containers + // std::pair + template + inline size_t getByteSize(const std::pair& obj); + template + inline void serialize(const std::pair& obj,std::vector& buffer,std::vector::iterator& iter); + template + inline void deserialize(std::pair& obj,std::vector::const_iterator& iter); + + // std::vector + template + inline size_t getByteSize(const std::vector& obj); + template + inline void serialize(const std::vector& obj,std::vector& buffer,std::vector::iterator& iter); + template + inline void deserialize(std::vector& obj,std::vector::const_iterator& iter); + template + inline void deserialize(std::vector& obj,std::vector::const_iterator& iter); + + // std::set + template + inline size_t getByteSize(const std::set& obj); + template + inline void serialize(const std::set& obj,std::vector& buffer,std::vector::iterator& iter); + template + inline void deserialize(std::set& obj,std::vector::const_iterator& iter); + + // std::map + template + inline size_t getByteSize(const std::map& obj); + template + inline void serialize(const std::map& obj,std::vector& buffer,std::vector::iterator& iter); + template + inline void deserialize(std::map& obj,std::vector::const_iterator& iter); + + // std::list + template + inline size_t getByteSize(const std::list& obj); + template + inline void serialize(const std::list& obj, std::vector& buffer, std::vector::iterator& iter); + template + inline void deserialize(std::list& obj, std::vector::const_iterator& iter); + + // Eigen types + template + inline size_t getByteSize(const Eigen::Matrix& obj); + template + inline void serialize(const Eigen::Matrix& obj,std::vector& buffer,std::vector::iterator& iter); + template + inline void deserialize(Eigen::Matrix& obj,std::vector::const_iterator& iter); + + template + inline size_t getByteSize(const Eigen::Array& obj); + template + inline void serialize(const Eigen::Array& obj,std::vector& buffer,std::vector::iterator& iter); + template + inline void deserialize(Eigen::Array& obj,std::vector::const_iterator& iter); + + template + inline size_t getByteSize(const Eigen::SparseMatrix& obj); + template + inline void serialize(const Eigen::SparseMatrix& obj,std::vector& buffer,std::vector::iterator& iter); + template + inline void deserialize(Eigen::SparseMatrix& obj,std::vector::const_iterator& iter); + + template + inline size_t getByteSize(const Eigen::Quaternion& obj); + template + inline void serialize(const Eigen::Quaternion& obj,std::vector& buffer,std::vector::iterator& iter); + template + inline void deserialize(Eigen::Quaternion& obj,std::vector::const_iterator& iter); + + // raw pointers + template + inline typename std::enable_if::value,size_t>::type getByteSize(const T& obj); + template + inline typename std::enable_if::value>::type serialize(const T& obj,std::vector& buffer,std::vector::iterator& iter); + template + inline typename std::enable_if::value>::type deserialize(T& obj,std::vector::const_iterator& iter); + + // std::shared_ptr and std::unique_ptr + template + inline typename std::enable_if::value,size_t>::type getByteSize(const T& obj); + template + inline typename std::enable_if::value>::type serialize(const T& obj,std::vector& buffer,std::vector::iterator& iter); + template class T0, typename T1> + inline typename std::enable_if >::value>::type deserialize(T0& obj,std::vector::const_iterator& iter); + + // std::weak_ptr + template + inline size_t getByteSize(const std::weak_ptr& obj); + template + inline void serialize(const std::weak_ptr& obj,std::vector& buffer,std::vector::iterator& iter); + template + inline void deserialize(std::weak_ptr& obj,std::vector::const_iterator& iter); + + // functions to overload for non-intrusive serialization + template + inline void serialize(const T& obj,std::vector& buffer); + template + inline void deserialize(T& obj,const std::vector& buffer); + + // helper functions + template + inline void updateMemoryMap(T& obj,size_t size); + } +} + +// Always include inlines for these functions + +// IMPLEMENTATION + +namespace igl +{ + template + inline bool serialize(const T& obj,const std::string& filename) + { + return serialize(obj,"obj",filename,true); + } + + template + inline bool serialize(const T& obj,const std::string& objectName,const std::string& filename,bool overwrite) + { + bool success = false; + + std::vector buffer; + + std::ios_base::openmode mode = std::ios::out | std::ios::binary; + + if(overwrite) + mode |= std::ios::trunc; + else + mode |= std::ios::app; + + std::ofstream file(filename.c_str(),mode); + + if(file.is_open()) + { + serialize(obj,objectName,buffer); + + file.write(&buffer[0],buffer.size()); + + file.close(); + + success = true; + } + else + { + std::cerr << "serialization: file " << filename << " not found!" << std::endl; + } + + return success; + } + + template + inline bool serialize(const T& obj,const std::string& objectName,std::vector& buffer) + { + // serialize object data + size_t size = serialization::getByteSize(obj); + std::vector tmp(size); + auto it = tmp.begin(); + serialization::serialize(obj,tmp,it); + + std::string objectType(typeid(obj).name()); + size_t newObjectSize = tmp.size(); + size_t newHeaderSize = serialization::getByteSize(objectName) + serialization::getByteSize(objectType) + sizeof(size_t); + size_t curSize = buffer.size(); + size_t newSize = curSize + newHeaderSize + newObjectSize; + + buffer.resize(newSize); + + std::vector::iterator iter = buffer.begin()+curSize; + + // serialize object header (name/type/size) + serialization::serialize(objectName,buffer,iter); + serialization::serialize(objectType,buffer,iter); + serialization::serialize(newObjectSize,buffer,iter); + + // copy serialized data to buffer + iter = std::copy(tmp.begin(),tmp.end(),iter); + + return true; + } + + template + inline bool deserialize(T& obj,const std::string& filename) + { + return deserialize(obj,"obj",filename); + } + + template + inline bool deserialize(T& obj,const std::string& objectName,const std::string& filename) + { + bool success = false; + + std::ifstream file(filename.c_str(),std::ios::binary); + + if(file.is_open()) + { + file.seekg(0,std::ios::end); + std::streamoff size = file.tellg(); + file.seekg(0,std::ios::beg); + + std::vector buffer(size); + file.read(&buffer[0],size); + + success = deserialize(obj, objectName, buffer); + file.close(); + } + else + { + std::cerr << "serialization: file " << filename << " not found!" << std::endl; + } + + return success; + } + + template + inline bool deserialize(T& obj,const std::string& objectName,const std::vector& buffer) + { + bool success = false; + + // find suitable object header + auto objectIter = buffer.cend(); + auto iter = buffer.cbegin(); + while(iter != buffer.end()) + { + std::string name; + std::string type; + size_t size; + serialization::deserialize(name,iter); + serialization::deserialize(type,iter); + serialization::deserialize(size,iter); + + if(name == objectName && type == typeid(obj).name()) + { + objectIter = iter; + //break; // find first suitable object header + } + + iter+=size; + } + + if(objectIter != buffer.end()) + { + serialization::deserialize(obj,objectIter); + success = true; + } + else + { + obj = T(); + } + + return success; + } + + // Wrapper function which combines both, de- and serialization + template + inline bool serializer(bool s,T& obj,const std::string& filename) + { + return s ? serialize(obj,filename) : deserialize(obj,filename); + } + + template + inline bool serializer(bool s,T& obj,const std::string& objectName,const std::string& filename,bool overwrite) + { + return s ? serialize(obj,objectName,filename,overwrite) : deserialize(obj,objectName,filename); + } + + template + inline bool serializer(bool s,T& obj,const std::string& objectName,std::vector& buffer) + { + return s ? serialize(obj,objectName,buffer) : deserialize(obj,objectName,buffer); + } + + inline bool Serializable::PreSerialization() const + { + return true; + } + + inline void Serializable::PostSerialization() const + { + } + + inline bool Serializable::PreDeserialization() + { + return true; + } + + inline void Serializable::PostDeserialization() + { + } + + inline void Serializable::Serialize(std::vector& buffer) const + { + if(this->PreSerialization()) + { + if(initialized == false) + { + objects.clear(); + (const_cast(this))->InitSerialization(); + initialized = true; + } + + for(const auto& v : objects) + { + v->Serialize(buffer); + } + + this->PostSerialization(); + } + } + + inline void Serializable::Deserialize(const std::vector& buffer) + { + if(this->PreDeserialization()) + { + if(initialized == false) + { + objects.clear(); + (const_cast(this))->InitSerialization(); + initialized = true; + } + + for(auto& v : objects) + { + v->Deserialize(buffer); + } + + this->PostDeserialization(); + } + } + + inline Serializable::Serializable() + { + initialized = false; + } + + inline Serializable::Serializable(const Serializable& obj) + { + initialized = false; + objects.clear(); + } + + inline Serializable::~Serializable() + { + initialized = false; + objects.clear(); + } + + inline Serializable& Serializable::operator=(const Serializable& obj) + { + if(this != &obj) + { + if(initialized) + { + initialized = false; + objects.clear(); + } + } + return *this; + } + + template + inline void Serializable::Add(T& obj,const std::string name,bool binary) + { + auto object = new SerializationObject(); + object->Binary = binary; + object->Name = name; + object->Object = std::unique_ptr(&obj); + + objects.push_back(object); + } + + namespace serialization + { + template + inline typename std::enable_if::value,size_t>::type getByteSize(const T& obj) + { + return sizeof(std::vector::size_type); + } + + template + inline typename std::enable_if::value>::type serialize(const T& obj,std::vector& buffer,std::vector::iterator& iter) + { + // data + std::vector tmp; + serialize<>(obj,tmp); + + // size + size_t size = buffer.size(); + serialization::serialize(tmp.size(),buffer,iter); + size_t cur = iter - buffer.begin(); + + buffer.resize(size+tmp.size()); + iter = buffer.begin()+cur; + iter = std::copy(tmp.begin(),tmp.end(),iter); + } + + template + inline typename std::enable_if::value>::type deserialize(T& obj,std::vector::const_iterator& iter) + { + std::vector::size_type size; + serialization::deserialize<>(size,iter); + + std::vector tmp; + tmp.resize(size); + std::copy(iter,iter+size,tmp.begin()); + + deserialize<>(obj,tmp); + iter += size; + } + + // fundamental types + + template + inline typename std::enable_if::value,size_t>::type getByteSize(const T& obj) + { + return sizeof(T); + } + + template + inline typename std::enable_if::value>::type serialize(const T& obj,std::vector& buffer,std::vector::iterator& iter) + { + //serialization::updateMemoryMap(obj,sizeof(T)); + const uint8_t* ptr = reinterpret_cast(&obj); + iter = std::copy(ptr,ptr+sizeof(T),iter); + } + + template + inline typename std::enable_if::value>::type deserialize(T& obj,std::vector::const_iterator& iter) + { + uint8_t* ptr = reinterpret_cast(&obj); + std::copy(iter,iter+sizeof(T),ptr); + iter += sizeof(T); + } + + // std::string + + inline size_t getByteSize(const std::string& obj) + { + return getByteSize(obj.length())+obj.length()*sizeof(uint8_t); + } + + inline void serialize(const std::string& obj,std::vector& buffer,std::vector::iterator& iter) + { + serialization::serialize(obj.length(),buffer,iter); + for(const auto& cur : obj) + { + serialization::serialize(cur,buffer,iter); + } + } + + inline void deserialize(std::string& obj,std::vector::const_iterator& iter) + { + size_t size; + serialization::deserialize(size,iter); + + std::string str(size,'\0'); + for(size_t i=0; i + inline typename std::enable_if::value,size_t>::type getByteSize(const T& obj) + { + return sizeof(T); + } + + template + inline typename std::enable_if::value>::type serialize(const T& obj,std::vector& buffer,std::vector::iterator& iter) + { + const uint8_t* ptr = reinterpret_cast(&obj); + iter = std::copy(ptr,ptr+sizeof(T),iter); + } + + template + inline typename std::enable_if::value>::type deserialize(T& obj,std::vector::const_iterator& iter) + { + uint8_t* ptr = reinterpret_cast(&obj); + std::copy(iter,iter+sizeof(T),ptr); + iter += sizeof(T); + } + + // SerializableBase + + template + inline typename std::enable_if::value,size_t>::type getByteSize(const T& obj) + { + return sizeof(std::vector::size_type); + } + + template + inline typename std::enable_if::value>::type serialize(const T& obj,std::vector& buffer,std::vector::iterator& iter) + { + // data + std::vector tmp; + obj.Serialize(tmp); + + // size + size_t size = buffer.size(); + serialization::serialize(tmp.size(),buffer,iter); + size_t cur = iter - buffer.begin(); + + buffer.resize(size+tmp.size()); + iter = buffer.begin()+cur; + iter = std::copy(tmp.begin(),tmp.end(),iter); + } + + template + inline typename std::enable_if::value>::type deserialize(T& obj,std::vector::const_iterator& iter) + { + std::vector::size_type size; + serialization::deserialize(size,iter); + + std::vector tmp; + tmp.resize(size); + std::copy(iter,iter+size,tmp.begin()); + + obj.Deserialize(tmp); + iter += size; + } + + // STL containers + + // std::pair + + template + inline size_t getByteSize(const std::pair& obj) + { + return getByteSize(obj.first)+getByteSize(obj.second); + } + + template + inline void serialize(const std::pair& obj,std::vector& buffer,std::vector::iterator& iter) + { + serialization::serialize(obj.first,buffer,iter); + serialization::serialize(obj.second,buffer,iter); + } + + template + inline void deserialize(std::pair& obj,std::vector::const_iterator& iter) + { + serialization::deserialize(obj.first,iter); + serialization::deserialize(obj.second,iter); + } + + // std::vector + + template + inline size_t getByteSize(const std::vector& obj) + { + return std::accumulate(obj.begin(),obj.end(),sizeof(size_t),[](const size_t& acc,const T1& cur) { return acc+getByteSize(cur); }); + } + + template + inline void serialize(const std::vector& obj,std::vector& buffer,std::vector::iterator& iter) + { + size_t size = obj.size(); + serialization::serialize(size,buffer,iter); + for(const T1& cur : obj) + { + serialization::serialize(cur,buffer,iter); + } + } + + template + inline void deserialize(std::vector& obj,std::vector::const_iterator& iter) + { + size_t size; + serialization::deserialize(size,iter); + + obj.resize(size); + for(T1& v : obj) + { + serialization::deserialize(v,iter); + } + } + + template + inline void deserialize(std::vector& obj,std::vector::const_iterator& iter) + { + size_t size; + serialization::deserialize(size,iter); + + obj.resize(size); + for(int i=0;i + inline size_t getByteSize(const std::set& obj) + { + return std::accumulate(obj.begin(),obj.end(),getByteSize(obj.size()),[](const size_t& acc,const T& cur) { return acc+getByteSize(cur); }); + } + + template + inline void serialize(const std::set& obj,std::vector& buffer,std::vector::iterator& iter) + { + serialization::serialize(obj.size(),buffer,iter); + for(const T& cur : obj) + { + serialization::serialize(cur,buffer,iter); + } + } + + template + inline void deserialize(std::set& obj,std::vector::const_iterator& iter) + { + size_t size; + serialization::deserialize(size,iter); + + obj.clear(); + for(size_t i=0; i + inline size_t getByteSize(const std::map& obj) + { + return std::accumulate(obj.begin(),obj.end(),sizeof(size_t),[](const size_t& acc,const std::pair& cur) { return acc+getByteSize(cur); }); + } + + template + inline void serialize(const std::map& obj,std::vector& buffer,std::vector::iterator& iter) + { + serialization::serialize(obj.size(),buffer,iter); + for(const auto& cur : obj) + { + serialization::serialize(cur,buffer,iter); + } + } + + template + inline void deserialize(std::map& obj,std::vector::const_iterator& iter) + { + size_t size; + serialization::deserialize(size,iter); + + obj.clear(); + for(size_t i=0; i pair; + serialization::deserialize(pair,iter); + obj.insert(pair); + } + } + + //std::list + + template + inline size_t getByteSize(const std::list& obj) + { + return std::accumulate(obj.begin(), obj.end(), getByteSize(obj.size()), [](const size_t& acc, const T& cur) { return acc + getByteSize(cur); }); + } + + template + inline void serialize(const std::list& obj, std::vector& buffer, std::vector::iterator& iter) + { + serialization::serialize(obj.size(), buffer, iter); + for (const T& cur : obj) + { + serialization::serialize(cur, buffer, iter); + } + } + + template + inline void deserialize(std::list& obj, std::vector::const_iterator& iter) + { + size_t size; + serialization::deserialize(size, iter); + + obj.clear(); + for (size_t i = 0; i < size; ++i) + { + T val; + serialization::deserialize(val, iter); + obj.emplace_back(val); + } + } + + + // Eigen types + template + inline size_t getByteSize(const Eigen::Matrix& obj) + { + // space for numbers of rows,cols and data + return 2*sizeof(typename Eigen::Matrix::Index)+sizeof(T)*obj.rows()*obj.cols(); + } + + template + inline void serialize(const Eigen::Matrix& obj,std::vector& buffer,std::vector::iterator& iter) + { + serialization::serialize(obj.rows(),buffer,iter); + serialization::serialize(obj.cols(),buffer,iter); + size_t size = sizeof(T)*obj.rows()*obj.cols(); + auto ptr = reinterpret_cast(obj.data()); + iter = std::copy(ptr,ptr+size,iter); + } + + template + inline void deserialize(Eigen::Matrix& obj,std::vector::const_iterator& iter) + { + typename Eigen::Matrix::Index rows,cols; + serialization::deserialize(rows,iter); + serialization::deserialize(cols,iter); + size_t size = sizeof(T)*rows*cols; + obj.resize(rows,cols); + auto ptr = reinterpret_cast(obj.data()); + std::copy(iter,iter+size,ptr); + iter+=size; + } + + template + inline size_t getByteSize(const Eigen::Array& obj) + { + // space for numbers of rows,cols and data + return 2*sizeof(typename Eigen::Array::Index)+sizeof(T)*obj.rows()*obj.cols(); + } + + template + inline void serialize(const Eigen::Array& obj,std::vector& buffer,std::vector::iterator& iter) + { + serialization::serialize(obj.rows(),buffer,iter); + serialization::serialize(obj.cols(),buffer,iter); + size_t size = sizeof(T)*obj.rows()*obj.cols(); + auto ptr = reinterpret_cast(obj.data()); + iter = std::copy(ptr,ptr+size,iter); + } + + template + inline void deserialize(Eigen::Array& obj,std::vector::const_iterator& iter) + { + typename Eigen::Array::Index rows,cols; + serialization::deserialize(rows,iter); + serialization::deserialize(cols,iter); + size_t size = sizeof(T)*rows*cols; + obj.resize(rows,cols); + auto ptr = reinterpret_cast(obj.data()); + std::copy(iter,iter+size,ptr); + iter+=size; + } + + template + inline size_t getByteSize(const Eigen::SparseMatrix& obj) + { + // space for numbers of rows,cols,nonZeros and tripplets with data (rowIdx,colIdx,value) + size_t size = sizeof(typename Eigen::SparseMatrix::Index); + return 3*size+(sizeof(T)+2*size)*obj.nonZeros(); + } + + template + inline void serialize(const Eigen::SparseMatrix& obj,std::vector& buffer,std::vector::iterator& iter) + { + serialization::serialize(obj.rows(),buffer,iter); + serialization::serialize(obj.cols(),buffer,iter); + serialization::serialize(obj.nonZeros(),buffer,iter); + + for(int k=0;k::InnerIterator it(obj,k);it;++it) + { + serialization::serialize(it.row(),buffer,iter); + serialization::serialize(it.col(),buffer,iter); + serialization::serialize(it.value(),buffer,iter); + } + } + } + + template + inline void deserialize(Eigen::SparseMatrix& obj,std::vector::const_iterator& iter) + { + typename Eigen::SparseMatrix::Index rows,cols,nonZeros; + serialization::deserialize(rows,iter); + serialization::deserialize(cols,iter); + serialization::deserialize(nonZeros,iter); + + obj.resize(rows,cols); + obj.setZero(); + + std::vector > triplets; + for(int i=0;i::Index rowId,colId; + serialization::deserialize(rowId,iter); + serialization::deserialize(colId,iter); + T value; + serialization::deserialize(value,iter); + triplets.push_back(Eigen::Triplet(rowId,colId,value)); + } + obj.setFromTriplets(triplets.begin(),triplets.end()); + } + + template + inline size_t getByteSize(const Eigen::Quaternion& obj) + { + return sizeof(T)*4; + } + + template + inline void serialize(const Eigen::Quaternion& obj,std::vector& buffer,std::vector::iterator& iter) + { + serialization::serialize(obj.w(),buffer,iter); + serialization::serialize(obj.x(),buffer,iter); + serialization::serialize(obj.y(),buffer,iter); + serialization::serialize(obj.z(),buffer,iter); + } + + template + inline void deserialize(Eigen::Quaternion& obj,std::vector::const_iterator& iter) + { + serialization::deserialize(obj.w(),iter); + serialization::deserialize(obj.x(),iter); + serialization::deserialize(obj.y(),iter); + serialization::deserialize(obj.z(),iter); + } + + // pointers + + template + inline typename std::enable_if::value,size_t>::type getByteSize(const T& obj) + { + size_t size = sizeof(bool); + + if(obj) + size += getByteSize(*obj); + + return size; + } + + template + inline typename std::enable_if::value>::type serialize(const T& obj,std::vector& buffer,std::vector::iterator& iter) + { + serialization::serialize(obj == nullptr,buffer,iter); + + if(obj) + serialization::serialize(*obj,buffer,iter); + } + + template + inline typename std::enable_if::value>::type deserialize(T& obj,std::vector::const_iterator& iter) + { + bool isNullPtr; + serialization::deserialize(isNullPtr,iter); + + if(isNullPtr) + { + if(obj) + { + std::cout << "serialization: possible memory leak in serialization for '" << typeid(obj).name() << "'" << std::endl; + obj = nullptr; + } + } + else + { + if(obj) + { + std::cout << "serialization: possible memory corruption in deserialization for '" << typeid(obj).name() << "'" << std::endl; + } + else + { + obj = new typename std::remove_pointer::type(); + } + serialization::deserialize(*obj,iter); + } + } + + // std::shared_ptr and std::unique_ptr + + template + inline typename std::enable_if::value,size_t>::type getByteSize(const T& obj) + { + return getByteSize(obj.get()); + } + + template + inline typename std::enable_if::value>::type serialize(const T& obj,std::vector& buffer,std::vector::iterator& iter) + { + serialize(obj.get(),buffer,iter); + } + + template class T0,typename T1> + inline typename std::enable_if >::value>::type deserialize(T0& obj,std::vector::const_iterator& iter) + { + bool isNullPtr; + serialization::deserialize(isNullPtr,iter); + + if(isNullPtr) + { + obj.reset(); + } + else + { + obj = T0(new T1()); + serialization::deserialize(*obj,iter); + } + } + + // std::weak_ptr + + template + inline size_t getByteSize(const std::weak_ptr& obj) + { + return sizeof(size_t); + } + + template + inline void serialize(const std::weak_ptr& obj,std::vector& buffer,std::vector::iterator& iter) + { + + } + + template + inline void deserialize(std::weak_ptr& obj,std::vector::const_iterator& iter) + { + + } + + // functions to overload for non-intrusive serialization + template + inline void serialize(const T& obj,std::vector& buffer) + { + std::cerr << typeid(obj).name() << " is not serializable: derive from igl::Serializable or spezialize the template function igl::serialization::serialize(const T& obj,std::vector& buffer)" << std::endl; + } + + template + inline void deserialize(T& obj,const std::vector& buffer) + { + std::cerr << typeid(obj).name() << " is not deserializable: derive from igl::Serializable or spezialize the template function igl::serialization::deserialize(T& obj, const std::vector& buffer)" << std::endl; + } + + // helper functions + + template + inline void updateMemoryMap(T& obj,size_t size,std::map& memoryMap) + { + // check if object is already serialized + auto startPtr = new IndexedPointer(); + startPtr->Object = &obj; + auto startBasePtr = static_cast(startPtr); + startBasePtr->Type = IndexedPointerBase::BEGIN; + auto startAddress = reinterpret_cast(&obj); + auto p = std::pair(startAddress,startBasePtr); + + auto el = memoryMap.insert(p); + auto iter = ++el.first; // next elememt + if(el.second && (iter == memoryMap.end() || iter->second->Type != IndexedPointerBase::END)) + { + // not yet serialized + auto endPtr = new IndexedPointer(); + auto endBasePtr = static_cast(endPtr); + endBasePtr->Type = IndexedPointerBase::END; + auto endAddress = reinterpret_cast(&obj) + size - 1; + auto p = std::pair(endAddress,endBasePtr); + + // insert end address + memoryMap.insert(el.first,p); + } + else + { + // already serialized + + // remove inserted address + memoryMap.erase(el.first); + } + } + } +} + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/setdiff.cpp b/src/external/libigl-2.3.0/include/igl/setdiff.cpp new file mode 100644 index 000000000..0d5980c62 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/setdiff.cpp @@ -0,0 +1,84 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "setdiff.h" +#include "LinSpaced.h" +#include "list_to_matrix.h" +#include "sort.h" +#include "unique.h" + +template < + typename DerivedA, + typename DerivedB, + typename DerivedC, + typename DerivedIA> +IGL_INLINE void igl::setdiff( + const Eigen::MatrixBase & A, + const Eigen::MatrixBase & B, + Eigen::PlainObjectBase & C, + Eigen::PlainObjectBase & IA) +{ + using namespace Eigen; + using namespace std; + // boring base cases + if(A.size() == 0) + { + C.resize(0,1); + IA.resize(0,1); + return; + } + + // Get rid of any duplicates + typedef Matrix VectorA; + typedef Matrix VectorB; + VectorA uA; + VectorB uB; + typedef DerivedIA IAType; + IAType uIA,uIuA,uIB,uIuB; + unique(A,uA,uIA,uIuA); + unique(B,uB,uIB,uIuB); + + // Sort both + VectorA sA; + VectorB sB; + IAType sIA,sIB; + sort(uA,1,true,sA,sIA); + sort(uB,1,true,sB,sIB); + + vector vC; + vector vIA; + int bi = 0; + // loop over sA + bool past = false; + bool sBempty = sB.size()==0; + for(int a = 0;asB(bi)) + { + bi++; + past = bi>=sB.size(); + } + if(sBempty || past || sA(a), Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::setdiff, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::setdiff, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::setdiff, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::setdiff, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/setdiff.h b/src/external/libigl-2.3.0/include/igl/setdiff.h new file mode 100644 index 000000000..a8f9e0775 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/setdiff.h @@ -0,0 +1,38 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_SETDIFF_H +#define IGL_SETDIFF_H +#include "igl_inline.h" +#include +namespace igl +{ + // Set difference of elements of matrices + // + // Inputs: + // A m-long vector of indices + // B n-long vector of indices + // Outputs: + // C (k<=m)-long vector of unique elements appearing in A but not in B + // IA (k<=m)-long list of indices into A so that C = A(IA) + // + template < + typename DerivedA, + typename DerivedB, + typename DerivedC, + typename DerivedIA> + IGL_INLINE void setdiff( + const Eigen::MatrixBase & A, + const Eigen::MatrixBase & B, + Eigen::PlainObjectBase & C, + Eigen::PlainObjectBase & IA); +} + +#ifndef IGL_STATIC_LIBRARY +# include "setdiff.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/setunion.cpp b/src/external/libigl-2.3.0/include/igl/setunion.cpp new file mode 100644 index 000000000..eb0e721d8 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/setunion.cpp @@ -0,0 +1,74 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "setunion.h" +#include "unique.h" + +template < + typename DerivedA, + typename DerivedB, + typename DerivedC, + typename DerivedIA, + typename DerivedIB> +IGL_INLINE void igl::setunion( + const Eigen::DenseBase & A, + const Eigen::DenseBase & B, + Eigen::PlainObjectBase & C, + Eigen::PlainObjectBase & IA, + Eigen::PlainObjectBase & IB) +{ + DerivedC CS(A.size()+B.size(),1); + { + int k = 0; + for(int j = 0;j, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::DenseBase > const&, Eigen::DenseBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/setunion.h b/src/external/libigl-2.3.0/include/igl/setunion.h new file mode 100644 index 000000000..f28bff653 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/setunion.h @@ -0,0 +1,43 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_SETUNION_H +#define IGL_SETUNION_H +#include "igl_inline.h" +#include +namespace igl +{ + // Union of elements of matrices (like matlab's `union`) + // + // Inputs: + // A m-long vector of indices + // B n-long vector of indices + // Outputs: + // C (k>=m)-long vector of unique elements appearing in A and/or B + // IA (=m)-long list of indices into A so that C = sort([A(IA);B(IB)]) + // IB (=m)-long list of indices into B so that C = sort([A(IA);B(IB)]) + // + template < + typename DerivedA, + typename DerivedB, + typename DerivedC, + typename DerivedIA, + typename DerivedIB> + IGL_INLINE void setunion( + const Eigen::DenseBase & A, + const Eigen::DenseBase & B, + Eigen::PlainObjectBase & C, + Eigen::PlainObjectBase & IA, + Eigen::PlainObjectBase & IB); +} + +#ifndef IGL_STATIC_LIBRARY +# include "setunion.cpp" +#endif +#endif + + diff --git a/src/external/libigl-2.3.0/include/igl/setxor.cpp b/src/external/libigl-2.3.0/include/igl/setxor.cpp new file mode 100644 index 000000000..dde66f207 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/setxor.cpp @@ -0,0 +1,33 @@ +#include "setxor.h" +#include "setdiff.h" +#include "setunion.h" +#include "slice.h" + +template < + typename DerivedA, + typename DerivedB, + typename DerivedC, + typename DerivedIA, + typename DerivedIB> +IGL_INLINE void igl::setxor( + const Eigen::MatrixBase & A, + const Eigen::MatrixBase & B, + Eigen::PlainObjectBase & C, + Eigen::PlainObjectBase & IA, + Eigen::PlainObjectBase & IB) +{ + DerivedC AB,BA; + DerivedIA IAB,IBA; + setdiff(A,B,AB,IAB); + setdiff(B,A,BA,IBA); + setunion(AB,BA,C,IA,IB); + slice(IAB,DerivedIA(IA),IA); + slice(IBA,DerivedIB(IB),IB); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::setxor, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::setxor, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/setxor.h b/src/external/libigl-2.3.0/include/igl/setxor.h new file mode 100644 index 000000000..0abc13156 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/setxor.h @@ -0,0 +1,43 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_SETXOR_H +#define IGL_SETXOR_H +#include "igl_inline.h" +#include +namespace igl +{ + // Set xor of elements of matrices + // + // Inputs: + // A m-long vector of indices + // B n-long vector of indices + // Outputs: + // C (k<=m)-long vector of unique elements appearing in A but not in B or + // B but not in A + // IA ( + IGL_INLINE void setxor( + const Eigen::MatrixBase & A, + const Eigen::MatrixBase & B, + Eigen::PlainObjectBase & C, + Eigen::PlainObjectBase & IA, + Eigen::PlainObjectBase & IB); +} + +#ifndef IGL_STATIC_LIBRARY +# include "setxor.cpp" +#endif +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/shape_diameter_function.cpp b/src/external/libigl-2.3.0/include/igl/shape_diameter_function.cpp new file mode 100644 index 000000000..4c611fb94 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/shape_diameter_function.cpp @@ -0,0 +1,182 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2017 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "shape_diameter_function.h" +#include "random_dir.h" +#include "barycenter.h" +#include "ray_mesh_intersect.h" +#include "per_vertex_normals.h" +#include "per_face_normals.h" +#include "EPS.h" +#include "Hit.h" +#include "parallel_for.h" +#include +#include +#include + +template < + typename DerivedP, + typename DerivedN, + typename DerivedS > +IGL_INLINE void igl::shape_diameter_function( + const std::function< + double( + const Eigen::Vector3f&, + const Eigen::Vector3f&) + > & shoot_ray, + const Eigen::MatrixBase & P, + const Eigen::MatrixBase & N, + const int num_samples, + Eigen::PlainObjectBase & S) +{ + using namespace Eigen; + const int n = P.rows(); + // Resize output + S.resize(n,1); + // Embree seems to be parallel when constructing but not when tracing rays + const MatrixXf D = random_dir_stratified(num_samples).cast(); + + const auto & inner = [&P,&N,&num_samples,&D,&S,&shoot_ray](const int p) + { + const Vector3f origin = P.row(p).template cast(); + const Vector3f normal = N.row(p).template cast(); + int num_hits = 0; + double total_distance = 0; + for(int s = 0;s 0) + { + // reverse ray + d *= -1; + } + const double dist = shoot_ray(origin,d); + if(std::isfinite(dist)) + { + total_distance += dist; + num_hits++; + } + } + S(p) = total_distance/(double)num_hits; + }; + parallel_for(n,inner,1000); +} + +template < + typename DerivedV, + int DIM, + typename DerivedF, + typename DerivedP, + typename DerivedN, + typename DerivedS > +IGL_INLINE void igl::shape_diameter_function( + const igl::AABB & aabb, + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const Eigen::MatrixBase & P, + const Eigen::MatrixBase & N, + const int num_samples, + Eigen::PlainObjectBase & S) +{ + const auto & shoot_ray = [&aabb,&V,&F]( + const Eigen::Vector3f& _s, + const Eigen::Vector3f& dir)->double + { + Eigen::Vector3f s = _s+1e-4*dir; + igl::Hit hit; + if(aabb.intersect_ray( + V, + F, + s .cast().eval(), + dir.cast().eval(), + hit)) + { + return hit.t; + }else + { + return std::numeric_limits::infinity(); + } + }; + return shape_diameter_function(shoot_ray,P,N,num_samples,S); + +} + +template < + typename DerivedV, + typename DerivedF, + typename DerivedP, + typename DerivedN, + typename DerivedS > +IGL_INLINE void igl::shape_diameter_function( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const Eigen::MatrixBase & P, + const Eigen::MatrixBase & N, + const int num_samples, + Eigen::PlainObjectBase & S) +{ + if(F.rows() < 100) + { + // Super naive + const auto & shoot_ray = [&V,&F]( + const Eigen::Vector3f& _s, + const Eigen::Vector3f& dir)->double + { + Eigen::Vector3f s = _s+1e-4*dir; + igl::Hit hit; + if(ray_mesh_intersect(s,dir,V,F,hit)) + { + return hit.t; + }else + { + return std::numeric_limits::infinity(); + } + }; + return shape_diameter_function(shoot_ray,P,N,num_samples,S); + } + AABB aabb; + aabb.init(V,F); + return shape_diameter_function(aabb,V,F,P,N,num_samples,S); +} + +template < + typename DerivedV, + typename DerivedF, + typename DerivedS> +IGL_INLINE void igl::shape_diameter_function( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const bool per_face, + const int num_samples, + Eigen::PlainObjectBase & S) +{ + if (per_face) + { + DerivedV N; + igl::per_face_normals(V, F, N); + DerivedV P; + igl::barycenter(V, F, P); + return igl::shape_diameter_function(V, F, P, N, num_samples, S); + } + else + { + DerivedV N; + igl::per_vertex_normals(V, F, N); + return igl::shape_diameter_function(V, F, V, N, num_samples, S); + } +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +template void igl::shape_diameter_function, Eigen::Matrix, Eigen::Matrix >(std::function const&, Eigen::Matrix const&)> const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, int, Eigen::PlainObjectBase >&); +template void igl::shape_diameter_function, Eigen::Matrix, Eigen::Matrix >(std::function const&, Eigen::Matrix const&)> const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, int, Eigen::PlainObjectBase >&); +template void igl::shape_diameter_function, Eigen::Matrix, Eigen::Matrix >(std::function const&, Eigen::Matrix const&)> const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, int, Eigen::PlainObjectBase >&); +template void igl::shape_diameter_function, Eigen::Matrix, Eigen::Matrix >(std::function const&, Eigen::Matrix const&)> const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, int, Eigen::PlainObjectBase >&); +template void igl::shape_diameter_function, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, bool, int, Eigen::PlainObjectBase >&); +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/shape_diameter_function.h b/src/external/libigl-2.3.0/include/igl/shape_diameter_function.h new file mode 100644 index 000000000..01e5c5b7a --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/shape_diameter_function.h @@ -0,0 +1,95 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2017 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_SHAPE_DIAMETER_FUNCTION_H +#define IGL_SHAPE_DIAMETER_FUNCTION_H +#include "igl_inline.h" +#include "AABB.h" +#include +#include +namespace igl +{ + // Compute shape diamater function per given point. In the parlence of the + // paper "Consistent Mesh Partitioning and Skeletonisation using the Shape + // Diameter Function" [Shapiro et al. 2008], this implementation uses a 180° + // cone and a _uniform_ average (_not_ a average weighted by inverse angles). + // + // Inputs: + // shoot_ray function handle that outputs hits of a given ray against a + // mesh (embedded in function handles as captured variable/data) + // P #P by 3 list of origin points + // N #P by 3 list of origin normals + // Outputs: + // S #P list of shape diamater function values between bounding box + // diagonal (perfect sphere) and 0 (perfect needle hook) + // + template < + typename DerivedP, + typename DerivedN, + typename DerivedS > + IGL_INLINE void shape_diameter_function( + const std::function< + double( + const Eigen::Vector3f&, + const Eigen::Vector3f&) + > & shoot_ray, + const Eigen::MatrixBase & P, + const Eigen::MatrixBase & N, + const int num_samples, + Eigen::PlainObjectBase & S); + // Inputs: + // AABB axis-aligned bounding box hierarchy around (V,F) + template < + typename DerivedV, + int DIM, + typename DerivedF, + typename DerivedP, + typename DerivedN, + typename DerivedS > + IGL_INLINE void shape_diameter_function( + const igl::AABB & aabb, + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const Eigen::MatrixBase & P, + const Eigen::MatrixBase & N, + const int num_samples, + Eigen::PlainObjectBase & S); + // Inputs: + // V #V by 3 list of mesh vertex positions + // F #F by 3 list of mesh face indices into V + template < + typename DerivedV, + typename DerivedF, + typename DerivedP, + typename DerivedN, + typename DerivedS > + IGL_INLINE void shape_diameter_function( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const Eigen::MatrixBase & P, + const Eigen::MatrixBase & N, + const int num_samples, + Eigen::PlainObjectBase & S); + // per_face whether to compute per face (S is #F by 1) or per vertex (S is + // #V by 1) + template < + typename DerivedV, + typename DerivedF, + typename DerivedS> + IGL_INLINE void shape_diameter_function( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const bool per_face, + const int num_samples, + Eigen::PlainObjectBase & S); +}; +#ifndef IGL_STATIC_LIBRARY +# include "shape_diameter_function.cpp" +#endif + +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/shapeup.cpp b/src/external/libigl-2.3.0/include/igl/shapeup.cpp new file mode 100644 index 000000000..f352d22bf --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/shapeup.cpp @@ -0,0 +1,238 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2017 Amir Vaxman +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace igl +{ + + //This projection does nothing but render points into projP. Mostly used for "echoing" the global step + IGL_INLINE bool shapeup_identity_projection(const Eigen::PlainObjectBase& P, const Eigen::PlainObjectBase& SC, const Eigen::PlainObjectBase& S, Eigen::PlainObjectBase& projP){ + projP.conservativeResize(SC.rows(), 3*SC.maxCoeff()); + for (int i=0;i& P, const Eigen::PlainObjectBase& SC, const Eigen::PlainObjectBase& S, Eigen::PlainObjectBase& projP){ + projP.conservativeResize(SC.rows(), 3*SC.maxCoeff()); + for (int currRow=0;currRow svd(corrMat, Eigen::ComputeFullU | Eigen::ComputeFullV); + Eigen::MatrixXd R=svd.matrixU()*svd.matrixV().transpose(); + //getting scale by edge length change average. TODO: by singular values + Eigen::VectorXd sourceEdgeLengths(N); + Eigen::VectorXd targetEdgeLengths(N); + for (int j=0;j + IGL_INLINE bool shapeup_precomputation(const Eigen::PlainObjectBase& P, + const Eigen::PlainObjectBase& SC, + const Eigen::PlainObjectBase& S, + const Eigen::PlainObjectBase& E, + const Eigen::PlainObjectBase& b, + const Eigen::PlainObjectBase& wShape, + const Eigen::PlainObjectBase& wSmooth, + ShapeupData & sudata) + { + using namespace std; + using namespace Eigen; + sudata.P=P; + sudata.SC=SC; + sudata.S=S; + sudata.b=b; + typedef typename DerivedP::Scalar Scalar; + + //checking for consistency of the input + assert(SC.rows()==S.rows()); + assert(SC.rows()==wShape.rows()); + assert(E.rows()==wSmooth.rows()); + assert(b.rows()!=0); //would lead to matrix becoming SPD + + sudata.DShape.conservativeResize(SC.sum(), P.rows()); //Shape matrix (integration); + sudata.DClose.conservativeResize(b.rows(), P.rows()); //Closeness matrix for positional constraints + sudata.DSmooth.conservativeResize(E.rows(), P.rows()); //smoothness matrix + + //Building shape matrix + std::vector > DShapeTriplets; + int currRow=0; + for (int i=0;i(currRow+j, S(i,k), (1.0-avgCoeff))); + else + DShapeTriplets.push_back(Triplet(currRow+j, S(i,k), (-avgCoeff))); + } + } + currRow+=SC(i); + + } + + sudata.DShape.setFromTriplets(DShapeTriplets.begin(), DShapeTriplets.end()); + + //Building closeness matrix + std::vector > DCloseTriplets; + for (int i=0;i(i,b(i), 1.0)); + + sudata.DClose.setFromTriplets(DCloseTriplets.begin(), DCloseTriplets.end()); + + //Building smoothness matrix + std::vector > DSmoothTriplets; + for (int i=0; i(i, E(i, 0), -1)); + DSmoothTriplets.push_back(Triplet(i, E(i, 1), 1)); + } + + SparseMatrix tempMat; + igl::cat(1, sudata.DShape, sudata.DClose, tempMat); + igl::cat(1, tempMat, sudata.DSmooth, sudata.A); + + //weight matrix + vector > WTriplets; + + //one weight per set in S. + currRow=0; + for (int i=0;i(currRow+j,currRow+j,sudata.shapeCoeff*wShape(i))); + currRow+=SC(i); + } + + for (int i=0;i(SC.sum()+i, SC.sum()+i, sudata.closeCoeff)); + + for (int i=0;i(SC.sum()+b.size()+i, SC.sum()+b.size()+i, sudata.smoothCoeff*wSmooth(i))); + + sudata.W.conservativeResize(SC.sum()+b.size()+E.rows(), SC.sum()+b.size()+E.rows()); + sudata.W.setFromTriplets(WTriplets.begin(), WTriplets.end()); + + sudata.At=sudata.A.transpose(); //for efficieny, as we use the transpose a lot in the iteration + sudata.Q=sudata.At*sudata.W*sudata.A; + + return min_quad_with_fixed_precompute(sudata.Q,VectorXi(),SparseMatrix(),true,sudata.solver_data); + } + + + template < + typename DerivedP, + typename DerivedSC, + typename DerivedS> + IGL_INLINE bool shapeup_solve(const Eigen::PlainObjectBase& bc, + const std::function&, const Eigen::PlainObjectBase&, const Eigen::PlainObjectBase&, Eigen::PlainObjectBase&)>& local_projection, + const Eigen::PlainObjectBase& P0, + const ShapeupData & sudata, + const bool quietIterations, + Eigen::PlainObjectBase& P) + { + using namespace Eigen; + using namespace std; + MatrixXd currP=P0; + MatrixXd prevP=P0; + MatrixXd projP; + + assert(bc.rows()==sudata.b.rows()); + + MatrixXd rhs(sudata.A.rows(), 3); rhs.setZero(); + rhs.block(sudata.DShape.rows(), 0, sudata.b.rows(),3)=bc; //this stays constant throughout the iterations + + if (!quietIterations){ + cout<<"Shapeup Iterations, "<(); + if (!quietIterations) + cout << "Iteration "<, typename Eigen::Matrix, typename Eigen::Matrix, typename Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, igl::ShapeupData&); + +template bool igl::shapeup_solve, typename Eigen::Matrix, typename Eigen::Matrix >(const Eigen::PlainObjectBase >& bc, const std::function >&, const Eigen::PlainObjectBase >&, const Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >& ) >& local_projection, const Eigen::PlainObjectBase >& P0, const igl::ShapeupData & sudata, const bool quietIterations, Eigen::PlainObjectBase >& P); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/shapeup.h b/src/external/libigl-2.3.0/include/igl/shapeup.h new file mode 100644 index 000000000..7230a8dc7 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/shapeup.h @@ -0,0 +1,128 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2017 Amir Vaxman +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_SHAPEUP_H +#define IGL_SHAPEUP_H + +#include +#include +#include +#include +#include +#include +#include + + +//This file implements the following algorithm: + +//Boaziz et al. +//Shape-Up: Shaping Discrete Geometry with Projections +//Computer Graphics Forum (Proc. SGP) 31(5), 2012 + +namespace igl +{ + struct ShapeupData{ + //input data + Eigen::MatrixXd P; + Eigen::VectorXi SC; + Eigen::MatrixXi S; + Eigen::VectorXi b; + int maxIterations; //referring to number of local-global pairs. + double pTolerance; //algorithm stops when max(|P_k-P_{k-1}|) DShape, DClose, DSmooth, Q, A, At, W; + + min_quad_with_fixed_data solver_data; + + ShapeupData(): + maxIterations(50), + pTolerance(10e-6), + shapeCoeff(1.0), + closeCoeff(100.0), + smoothCoeff(0.0){} + }; + + //Every function here defines a local projection for ShapeUp, and must have the following structure to qualify: + //Input: + // P #P by 3 the set of points, either the initial solution, or from previous iteration. + // SC #Set by 1 cardinalities of sets in S + // S #Sets by max(SC) independent sets where the local projection applies. Values beyond column SC(i)-1 in row S(i,:) are "don't care" + //Output: + // projP #S by 3*max(SC) in format xyzxyzxyz, where the projected points correspond to each set in S in the same order. + typedef std::function&, const Eigen::PlainObjectBase&, const Eigen::PlainObjectBase&, Eigen::PlainObjectBase&)> shapeup_projection_function; + + + //This projection does nothing but render points into projP. Mostly used for "echoing" the global step + IGL_INLINE bool shapeup_identity_projection(const Eigen::PlainObjectBase& P, const Eigen::PlainObjectBase& SC, const Eigen::PlainObjectBase& S, Eigen::PlainObjectBase& projP); + + //the projection assumes that the sets are vertices of polygons in cyclic order + IGL_INLINE bool shapeup_regular_face_projection(const Eigen::PlainObjectBase& P, const Eigen::PlainObjectBase& SC, const Eigen::PlainObjectBase& S, Eigen::PlainObjectBase& projP); + + + //This function precomputation the necessary matrices for the ShapeUp process, and prefactorizes them. + + //input: + // P #P by 3 point positions + // SC #Set by 1 cardinalities of sets in S + // S #Sets by max(SC) independent sets where the local projection applies. Values beyond column SC(i)-1 in row S(i,:) are "don't care" + // E #E by 2 the "edges" of the set P; used for the smoothness energy. + // b #b by 1 boundary (fixed) vertices from P. + // wShape, #Set by 1 + // wSmooth #b by 1 weights for constraints from S and positional constraints (used in the global step) + + // Output: + // sudata struct ShapeupData the data necessary to solve the system in shapeup_solve + + template < + typename DerivedP, + typename DerivedSC, + typename DerivedS, + typename Derivedw> + IGL_INLINE bool shapeup_precomputation(const Eigen::PlainObjectBase& P, + const Eigen::PlainObjectBase& SC, + const Eigen::PlainObjectBase& S, + const Eigen::PlainObjectBase& E, + const Eigen::PlainObjectBase& b, + const Eigen::PlainObjectBase& wShape, + const Eigen::PlainObjectBase& wSmooth, + ShapeupData & sudata); + + + + //This function solve the shapeup project optimization. shapeup_precompute must be called before with the same sudata, or results are unpredictable + + //Input: + //bc #b by 3 fixed point values corresonding to "b" in sudata + //local_projection function pointer taking (P,SC,S,projP), + // where the first three parameters are as defined, and "projP" is the output, as a #S by 3*max(SC) function in format xyzxyzxyz, and where it returns the projected points corresponding to each set in S in the same order. + //NOTE: the input values in P0 don't need to correspond to prescribed values in bc; the iterations will project them automatically (by design). + //P0 #P by 3 initial solution (point positions) + //sudata the ShapeUpData structure computed in shapeup_precomputation() + //quietIterations flagging if to output iteration information. + + //Output: + //P the solution to the problem, indices corresponding to P0. + template < + typename DerivedP, + typename DerivedSC, + typename DerivedS> + IGL_INLINE bool shapeup_solve(const Eigen::PlainObjectBase& bc, + const std::function&, const Eigen::PlainObjectBase&, const Eigen::PlainObjectBase&, Eigen::PlainObjectBase&)>& local_projection, + const Eigen::PlainObjectBase& P0, + const ShapeupData & sudata, + const bool quietIterations, + Eigen::PlainObjectBase& P); + +} + +#ifndef IGL_STATIC_LIBRARY +#include "shapeup.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/sharp_edges.cpp b/src/external/libigl-2.3.0/include/igl/sharp_edges.cpp new file mode 100644 index 000000000..8f1c053f7 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/sharp_edges.cpp @@ -0,0 +1,112 @@ +#include "sharp_edges.h" +#include +#include +#include +#include + +template < + typename DerivedV, + typename DerivedF, + typename DerivedSE, + typename DerivedE, + typename DeriveduE, + typename DerivedEMAP, + typename uE2Etype, + typename sharptype> +IGL_INLINE void igl::sharp_edges( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const typename DerivedV::Scalar angle, + Eigen::PlainObjectBase & SE, + Eigen::PlainObjectBase & E, + Eigen::PlainObjectBase & uE, + Eigen::PlainObjectBase & EMAP, + std::vector > & uE2E, + std::vector< sharptype > & sharp) +{ + typedef typename DerivedSE::Scalar Index; + typedef typename DerivedV::Scalar Scalar; + typedef Eigen::Matrix MatrixX2I; + typedef Eigen::Matrix MatrixX3S; + typedef Eigen::Matrix RowVector3S; + typedef Eigen::Matrix VectorXI; + + unique_edge_map(F,E,uE,EMAP,uE2E); + MatrixX3S N; + per_face_normals(V,F,N); + // number of faces + const Index m = F.rows(); + // Dihedral angles + //std::vector > DIJV; + sharp.clear(); + // Loop over each unique edge + for(int u = 0;u angle) + { + u_is_sharp = true; + } + } + if(u_is_sharp) + { + sharp.push_back(u); + } + } + SE.resize(sharp.size(),2); + for(int i = 0;i +IGL_INLINE void igl::sharp_edges( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const typename DerivedV::Scalar angle, + Eigen::PlainObjectBase & SE + ) +{ + typedef typename DerivedSE::Scalar Index; + typedef typename DerivedV::Scalar Scalar; + typedef Eigen::Matrix MatrixX2I; + typedef Eigen::Matrix MatrixX3S; + typedef Eigen::Matrix RowVector3S; + typedef Eigen::Matrix VectorXI; + MatrixX2I E,uE; + VectorXI EMAP; + std::vector > uE2E; + std::vector sharp; + return sharp_edges(V,F,angle,SE,E,uE,EMAP,uE2E,sharp); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +template void igl::sharp_edges, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::Matrix::Scalar, Eigen::PlainObjectBase >&); +template void igl::sharp_edges, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, int, int>(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::Matrix::Scalar, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, std::vector >, std::allocator > > >&, std::vector >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/sharp_edges.h b/src/external/libigl-2.3.0/include/igl/sharp_edges.h new file mode 100644 index 000000000..6f939bfc2 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/sharp_edges.h @@ -0,0 +1,61 @@ +#ifndef IGL_SHARP_EDGES_H +#define IGL_SHARP_EDGES_H + +#include +#include +#include + +namespace igl +{ + // SHARP_EDGES Given a mesh, compute sharp edges. + // + // Inputs: + // V #V by 3 list of vertex positions + // F #F by 3 list of triangle mesh indices into V + // angle dihedral angle considered to sharp (e.g., igl::PI * 0.11) + // Outputs: + // SE #SE by 2 list of edge indices into V + // uE #uE by 2 list of unique undirected edges + // EMAP #F*3 list of indices into uE, mapping each directed edge to unique + // undirected edge so that uE(EMAP(f+#F*c)) is the unique edge + // corresponding to E.row(f+#F*c) + // uE2E #uE list of lists of indices into E of coexisting edges, so that + // E.row(uE2E[i][j]) corresponds to uE.row(i) for all j in + // 0..uE2E[i].size()-1. + // sharp #SE list of indices into uE revealing sharp undirected edges + template < + typename DerivedV, + typename DerivedF, + typename DerivedSE, + typename DerivedE, + typename DeriveduE, + typename DerivedEMAP, + typename uE2Etype, + typename sharptype> + IGL_INLINE void sharp_edges( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const typename DerivedV::Scalar angle, + Eigen::PlainObjectBase & SE, + Eigen::PlainObjectBase & E, + Eigen::PlainObjectBase & uE, + Eigen::PlainObjectBase & EMAP, + std::vector > & uE2E, + std::vector< sharptype > & sharp); + template < + typename DerivedV, + typename DerivedF, + typename DerivedSE> + IGL_INLINE void sharp_edges( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const typename DerivedV::Scalar angle, + Eigen::PlainObjectBase & SE + ); +} + +#ifndef IGL_STATIC_LIBRARY +# include "sharp_edges.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/shortest_edge_and_midpoint.cpp b/src/external/libigl-2.3.0/include/igl/shortest_edge_and_midpoint.cpp new file mode 100644 index 000000000..db5338d0d --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/shortest_edge_and_midpoint.cpp @@ -0,0 +1,23 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "shortest_edge_and_midpoint.h" + +IGL_INLINE void igl::shortest_edge_and_midpoint( + const int e, + const Eigen::MatrixXd & V, + const Eigen::MatrixXi & /*F*/, + const Eigen::MatrixXi & E, + const Eigen::VectorXi & /*EMAP*/, + const Eigen::MatrixXi & /*EF*/, + const Eigen::MatrixXi & /*EI*/, + double & cost, + Eigen::RowVectorXd & p) +{ + cost = (V.row(E(e,0))-V.row(E(e,1))).norm(); + p = 0.5*(V.row(E(e,0))+V.row(E(e,1))); +} diff --git a/src/external/libigl-2.3.0/include/igl/shortest_edge_and_midpoint.h b/src/external/libigl-2.3.0/include/igl/shortest_edge_and_midpoint.h new file mode 100644 index 000000000..45a4a2abf --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/shortest_edge_and_midpoint.h @@ -0,0 +1,48 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_SHORTEST_EDGE_AND_MIDPOINT_H +#define IGL_SHORTEST_EDGE_AND_MIDPOINT_H +#include "igl_inline.h" +#include +#include +namespace igl +{ + // Cost and placement function compatible with igl::decimate. The cost of + // collapsing an edge is its length (prefer to collapse short edges) and the + // placement strategy for the new vertex is the midpoint of the collapsed + // edge. + // + // Inputs: + // e index into E of edge to be considered for collapse + // V #V by dim list of vertex positions + // F #F by 3 list of faces (ignored) + // E #E by 2 list of edge indices into V + // EMAP #F*3 list of half-edges indices into E (ignored) + // EF #E by 2 list of edge-face flaps into F (ignored) + // EI #E by 2 list of edge-face opposite corners (ignored) + // Outputs: + // cost set to edge length + // p placed point set to edge midpoint + IGL_INLINE void shortest_edge_and_midpoint( + const int e, + const Eigen::MatrixXd & V, + const Eigen::MatrixXi & /*F*/, + const Eigen::MatrixXi & E, + const Eigen::VectorXi & /*EMAP*/, + const Eigen::MatrixXi & /*EF*/, + const Eigen::MatrixXi & /*EI*/, + double & cost, + Eigen::RowVectorXd & p); +} + +#ifndef IGL_STATIC_LIBRARY +# include "shortest_edge_and_midpoint.cpp" +#endif +#endif + + diff --git a/src/external/libigl-2.3.0/include/igl/signed_angle.cpp b/src/external/libigl-2.3.0/include/igl/signed_angle.cpp new file mode 100644 index 000000000..c851122e2 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/signed_angle.cpp @@ -0,0 +1,67 @@ +#include "signed_angle.h" +#include "PI.h" +#include + +template < + typename DerivedA, + typename DerivedB, + typename DerivedP> +IGL_INLINE typename DerivedA::Scalar igl::signed_angle( + const Eigen::MatrixBase & A, + const Eigen::MatrixBase & B, + const Eigen::MatrixBase & P) +{ + typedef typename DerivedA::Scalar SType; + // Gather vectors to source and destination + SType o2A[2]; + SType o2B[2]; + // and lengths + SType o2Al = 0; + SType o2Bl = 0; + for(int i = 0;i<2;i++) + { + o2A[i] = P(i) - A(i); + o2B[i] = P(i) - B(i); + o2Al += o2A[i]*o2A[i]; + o2Bl += o2B[i]*o2B[i]; + } + o2Al = sqrt(o2Al); + o2Bl = sqrt(o2Bl); + // Normalize + for(int i = 0;i<2;i++) + { + // Matlab crashes on NaN + if(o2Al!=0) + { + o2A[i] /= o2Al; + } + if(o2Bl!=0) + { + o2B[i] /= o2Bl; + } + } + return + -atan2(o2B[0]*o2A[1]-o2B[1]*o2A[0],o2B[0]*o2A[0]+o2B[1]*o2A[1])/ + (2.*igl::PI); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +template Eigen::Block const, 1, 2, false>::Scalar igl::signed_angle const, 1, 2, false>, Eigen::Block const, 1, 2, false>, Eigen::Matrix >(Eigen::MatrixBase const, 1, 2, false> > const&, Eigen::MatrixBase const, 1, 2, false> > const&, Eigen::MatrixBase > const&); +template Eigen::Block const, 1, 2, false>::Scalar igl::signed_angle const, 1, 2, false>, Eigen::Block const, 1, 2, false>, Eigen::Block const, 1, -1, false> >(Eigen::MatrixBase const, 1, 2, false> > const&, Eigen::MatrixBase const, 1, 2, false> > const&, Eigen::MatrixBase const, 1, -1, false> > const&); +template Eigen::Block const, 1, 3, true>::Scalar igl::signed_angle const, 1, 3, true>, Eigen::Block const, 1, 3, true>, Eigen::Matrix >(Eigen::MatrixBase const, 1, 3, true> > const&, Eigen::MatrixBase const, 1, 3, true> > const&, Eigen::MatrixBase > const&); +template Eigen::Block const, 1, 3, true>::Scalar igl::signed_angle const, 1, 3, true>, Eigen::Block const, 1, 3, true>, Eigen::Matrix >(Eigen::MatrixBase const, 1, 3, true> > const&, Eigen::MatrixBase const, 1, 3, true> > const&, Eigen::MatrixBase > const&); +template Eigen::Block const, 1, -1, false>::Scalar igl::signed_angle const, 1, -1, false>, Eigen::Block const, 1, -1, false>, Eigen::Matrix >(Eigen::MatrixBase const, 1, -1, false> > const&, Eigen::MatrixBase const, 1, -1, false> > const&, Eigen::MatrixBase > const&); +template Eigen::Block const, 1, 3, true>::Scalar igl::signed_angle const, 1, 3, true>, Eigen::Block const, 1, 3, true>, Eigen::Matrix >(Eigen::MatrixBase const, 1, 3, true> > const&, Eigen::MatrixBase const, 1, 3, true> > const&, Eigen::MatrixBase > const&); +template Eigen::Block const, 1, 3, false>::Scalar igl::signed_angle const, 1, 3, false>, Eigen::Block const, 1, 3, false>, Eigen::Matrix >(Eigen::MatrixBase const, 1, 3, false> > const&, Eigen::MatrixBase const, 1, 3, false> > const&, Eigen::MatrixBase > const&); +template Eigen::Block const, 1, -1, false>::Scalar igl::signed_angle const, 1, -1, false>, Eigen::Block const, 1, -1, false>, Eigen::Block const, 1, -1, false> >(Eigen::MatrixBase const, 1, -1, false> > const&, Eigen::MatrixBase const, 1, -1, false> > const&, Eigen::MatrixBase const, 1, -1, false> > const&); +template Eigen::Block const, 1, -1, false>::Scalar igl::signed_angle const, 1, -1, false>, Eigen::Block const, 1, -1, false>, Eigen::Matrix >(Eigen::MatrixBase const, 1, -1, false> > const&, Eigen::MatrixBase const, 1, -1, false> > const&, Eigen::MatrixBase > const&); +template Eigen::Block const, 1, -1, false>::Scalar igl::signed_angle const, 1, -1, false>, Eigen::Block const, 1, -1, false>, Eigen::Matrix >(Eigen::MatrixBase const, 1, -1, false> > const&, Eigen::MatrixBase const, 1, -1, false> > const&, Eigen::MatrixBase > const&); +template Eigen::Block const, 1, -1, false>::Scalar igl::signed_angle const, 1, -1, false>, Eigen::Block const, 1, -1, false>, Eigen::Matrix >(Eigen::MatrixBase const, 1, -1, false> > const&, Eigen::MatrixBase const, 1, -1, false> > const&, Eigen::MatrixBase > const&); +template Eigen::Block const, 1, 3, false>::Scalar igl::signed_angle const, 1, 3, false>, Eigen::Block const, 1, 3, false>, Eigen::Matrix >(Eigen::MatrixBase const, 1, 3, false> > const&, Eigen::MatrixBase const, 1, 3, false> > const&, Eigen::MatrixBase > const&); +template Eigen::Block const, 1, 3, true>::Scalar igl::signed_angle const, 1, 3, true>, Eigen::Block const, 1, 3, true>, Eigen::Matrix >(Eigen::MatrixBase const, 1, 3, true> > const&, Eigen::MatrixBase const, 1, 3, true> > const&, Eigen::MatrixBase > const&); +#ifdef WIN32 +template float igl::signed_angle const ,1,3,1>,class Eigen::Block const ,1,3,1>,class Eigen::Matrix >(class Eigen::MatrixBase const ,1,3,1> > const &,class Eigen::MatrixBase const ,1,3,1> > const &,class Eigen::MatrixBase > const &); +template float igl::signed_angle const ,1,3,0>,class Eigen::Block const ,1,3,0>,class Eigen::Matrix >(class Eigen::MatrixBase const ,1,3,0> > const &,class Eigen::MatrixBase const ,1,3,0> > const &,class Eigen::MatrixBase > const &); +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/signed_angle.h b/src/external/libigl-2.3.0/include/igl/signed_angle.h new file mode 100644 index 000000000..547ba00a4 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/signed_angle.h @@ -0,0 +1,27 @@ +#ifndef IGL_SIGNED_ANGLE_H +#define IGL_SIGNED_ANGLE_H +#include "igl_inline.h" +#include +namespace igl +{ + // Compute the signed angle subtended by the oriented 3d triangle (A,B,C) at some point P + // + // Inputs: + // A 2D position of corner + // B 2D position of corner + // P 2D position of query point + // returns signed angle + template < + typename DerivedA, + typename DerivedB, + typename DerivedP> + IGL_INLINE typename DerivedA::Scalar signed_angle( + const Eigen::MatrixBase & A, + const Eigen::MatrixBase & B, + const Eigen::MatrixBase & P); +} +#ifndef IGL_STATIC_LIBRARY +# include "signed_angle.cpp" +#endif +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/signed_distance.cpp b/src/external/libigl-2.3.0/include/igl/signed_distance.cpp new file mode 100644 index 000000000..d9cc42b61 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/signed_distance.cpp @@ -0,0 +1,538 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "signed_distance.h" +#include "get_seconds.h" +#include "per_edge_normals.h" +#include "parallel_for.h" +#include "per_face_normals.h" +#include "per_vertex_normals.h" +#include "point_mesh_squared_distance.h" +#include "pseudonormal_test.h" +#include "fast_winding_number.h" + + +template < + typename DerivedP, + typename DerivedV, + typename DerivedF, + typename DerivedS, + typename DerivedI, + typename DerivedC, + typename DerivedN> +IGL_INLINE void igl::signed_distance( + const Eigen::MatrixBase & P, + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const SignedDistanceType sign_type, + const typename DerivedV::Scalar lower_bound, + const typename DerivedV::Scalar upper_bound, + Eigen::PlainObjectBase & S, + Eigen::PlainObjectBase & I, + Eigen::PlainObjectBase & C, + Eigen::PlainObjectBase & N) +{ + using namespace Eigen; + using namespace std; + + const int dim = V.cols(); + + assert((V.cols() == 3||V.cols() == 2) && "V should have 3d or 2d positions"); + assert((P.cols() == 3||P.cols() == 2) && "P should have 3d or 2d positions"); + assert(V.cols() == P.cols() && "V should have same dimension as P"); + + if (sign_type == SIGNED_DISTANCE_TYPE_FAST_WINDING_NUMBER){ + assert(V.cols() == 3 && "V should be 3D for fast winding number"); + } + + // Only unsigned distance is supported for non-triangles + if(sign_type != SIGNED_DISTANCE_TYPE_UNSIGNED) + { + assert(F.cols() == dim && "F should have co-dimension 0 simplices"); + } + typedef Eigen::Matrix RowVector3S; + + // Prepare distance computation + AABB tree3; + AABB tree2; + switch(dim) + { + default: + case 3: + tree3.init(V,F); + break; + case 2: + tree2.init(V,F); + break; + } + + // Need to be Dynamic columns to work with both 2d and 3d + Eigen::Matrix FN,VN,EN; + Eigen::Matrix E; + Eigen::Matrix EMAP; + WindingNumberAABB hier3; + igl::FastWindingNumberBVH fwn_bvh; + Eigen::VectorXf W; + + switch(sign_type) + { + default: + assert(false && "Unknown SignedDistanceType"); + case SIGNED_DISTANCE_TYPE_UNSIGNED: + // do nothing + break; + case SIGNED_DISTANCE_TYPE_DEFAULT: + case SIGNED_DISTANCE_TYPE_WINDING_NUMBER: + switch(dim) + { + default: + case 3: + hier3.set_mesh(V,F); + hier3.grow(); + break; + case 2: + // no precomp, no hierarchy + break; + } + break; + case SIGNED_DISTANCE_TYPE_FAST_WINDING_NUMBER: + // assert above ensures dim == 3 + igl::fast_winding_number(V.template cast().eval(), F, 2, fwn_bvh); + + case SIGNED_DISTANCE_TYPE_PSEUDONORMAL: + switch(dim) + { + default: + case 3: + // "Signed Distance Computation Using the Angle Weighted Pseudonormal" + // [Bærentzen & Aanæs 2005] + per_face_normals(V,F,FN); + per_vertex_normals(V,F,PER_VERTEX_NORMALS_WEIGHTING_TYPE_ANGLE,FN,VN); + per_edge_normals( + V,F,PER_EDGE_NORMALS_WEIGHTING_TYPE_UNIFORM,FN,EN,E,EMAP); + break; + case 2: + FN.resize(F.rows(),2); + VN = DerivedV::Zero(V.rows(),2); + for(int e = 0;e q2; + switch(P.cols()) + { + default: + case 3: + q3.head(P.row(p).size()) = P.row(p); + break; + case 2: + q2 = P.row(p).head(2); + break; + } + typename DerivedV::Scalar s=1,sqrd=0; + Eigen::Matrix c; + Eigen::Matrix c3; + Eigen::Matrix c2; + int i=-1; + // in all cases compute squared unsiged distances + sqrd = dim==3? + tree3.squared_distance(V,F,q3,low_sqr_d,up_sqr_d,i,c3): + tree2.squared_distance(V,F,q2,low_sqr_d,up_sqr_d,i,c2); + if(sqrd >= up_sqr_d || sqrd < low_sqr_d) + { + // Out of bounds gets a nan (nans on grids can be flood filled later using + // igl::flood_fill) + S(p) = std::numeric_limits::quiet_NaN(); + I(p) = F.rows()+1; + C.row(p).setConstant(0); + }else + { + // Determine sign + switch(sign_type) + { + default: + assert(false && "Unknown SignedDistanceType"); + case SIGNED_DISTANCE_TYPE_UNSIGNED: + break; + case SIGNED_DISTANCE_TYPE_DEFAULT: + case SIGNED_DISTANCE_TYPE_WINDING_NUMBER: + { + Scalar w = 0; + if(dim == 3) + { + s = 1.-2.*hier3.winding_number(q3.transpose()); + }else + { + assert(!V.derived().IsRowMajor); + assert(!F.derived().IsRowMajor); + s = 1.-2.*winding_number(V,F,q2); + } + break; + } + case SIGNED_DISTANCE_TYPE_FAST_WINDING_NUMBER: + { + //assert above ensured 3D + Scalar w = fast_winding_number(fwn_bvh, 2, q3.template cast().eval()); + s = 1.-2.*std::abs(w); + + break; + } + case SIGNED_DISTANCE_TYPE_PSEUDONORMAL: + { + RowVector3S n3; + Eigen::Matrix n2; + dim==3 ? + pseudonormal_test(V,F,FN,VN,EN,EMAP,q3,i,c3,s,n3): + // This should use (V,F,FN), not (V,E,EN) since E is auxiliary for + // 3D case, not the input "F"acets. + pseudonormal_test(V,F,FN,VN,q2,i,c2,s,n2); + Eigen::Matrix n; + (dim==3 ? n = n3.template cast() : n = n2.template cast()); + N.row(p) = n.template cast(); + break; + } + } + I(p) = i; + S(p) = s*sqrt(sqrd); + C.row(p) = (dim==3 ? c=c3 : c=c2).template cast(); + } + } + ,10000); +} + +template < + typename DerivedP, + typename DerivedV, + typename DerivedF, + typename DerivedS, + typename DerivedI, + typename DerivedC, + typename DerivedN> +IGL_INLINE void igl::signed_distance( + const Eigen::MatrixBase & P, + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const SignedDistanceType sign_type, + Eigen::PlainObjectBase & S, + Eigen::PlainObjectBase & I, + Eigen::PlainObjectBase & C, + Eigen::PlainObjectBase & N) +{ + typedef typename DerivedV::Scalar Scalar; + Scalar lower = std::numeric_limits::min(); + Scalar upper = std::numeric_limits::max(); + return signed_distance(P,V,F,sign_type,lower,upper,S,I,C,N); +} + + +template < + typename DerivedV, + typename DerivedF, + typename DerivedFN, + typename DerivedVN, + typename DerivedEN, + typename DerivedEMAP, + typename Derivedq> +IGL_INLINE typename DerivedV::Scalar igl::signed_distance_pseudonormal( + const AABB & tree, + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const Eigen::MatrixBase & FN, + const Eigen::MatrixBase & VN, + const Eigen::MatrixBase & EN, + const Eigen::MatrixBase & EMAP, + const Eigen::MatrixBase & q) +{ + typename DerivedV::Scalar s,sqrd; + Eigen::Matrix n,c; + int i = -1; + signed_distance_pseudonormal(tree,V,F,FN,VN,EN,EMAP,q,s,sqrd,i,c,n); + return s*sqrt(sqrd); +} + +template < + typename DerivedP, + typename DerivedV, + typename DerivedF, + typename DerivedFN, + typename DerivedVN, + typename DerivedEN, + typename DerivedEMAP, + typename DerivedS, + typename DerivedI, + typename DerivedC, + typename DerivedN> +IGL_INLINE void igl::signed_distance_pseudonormal( + const Eigen::MatrixBase & P, + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const AABB & tree, + const Eigen::MatrixBase & FN, + const Eigen::MatrixBase & VN, + const Eigen::MatrixBase & EN, + const Eigen::MatrixBase & EMAP, + Eigen::PlainObjectBase & S, + Eigen::PlainObjectBase & I, + Eigen::PlainObjectBase & C, + Eigen::PlainObjectBase & N) +{ + using namespace Eigen; + const size_t np = P.rows(); + S.resize(np,1); + I.resize(np,1); + N.resize(np,3); + C.resize(np,3); + typedef typename AABB::RowVectorDIMS RowVector3S; +# pragma omp parallel for if(np>1000) + for(std::ptrdiff_t p = 0;p +IGL_INLINE void igl::signed_distance_pseudonormal( + const AABB & tree, + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const Eigen::MatrixBase & FN, + const Eigen::MatrixBase & VN, + const Eigen::MatrixBase & EN, + const Eigen::MatrixBase & EMAP, + const Eigen::MatrixBase & q, + Scalar & s, + Scalar & sqrd, + int & i, + Eigen::PlainObjectBase & c, + Eigen::PlainObjectBase & n) +{ + using namespace Eigen; + using namespace std; + //typedef Eigen::Matrix RowVector3S; + // Alec: Why was this constructor around q necessary? + //sqrd = tree.squared_distance(V,F,RowVector3S(q),i,(RowVector3S&)c); + // Alec: Why was this constructor around c necessary? + //sqrd = tree.squared_distance(V,F,q,i,(RowVector3S&)c); + sqrd = tree.squared_distance(V,F,q,i,c); + pseudonormal_test(V,F,FN,VN,EN,EMAP,q,i,c,s,n); +} + +template < + typename DerivedV, + typename DerivedE, + typename DerivedEN, + typename DerivedVN, + typename Derivedq, + typename Scalar, + typename Derivedc, + typename Derivedn> +IGL_INLINE void igl::signed_distance_pseudonormal( + const AABB & tree, + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & E, + const Eigen::MatrixBase & EN, + const Eigen::MatrixBase & VN, + const Eigen::MatrixBase & q, + Scalar & s, + Scalar & sqrd, + int & i, + Eigen::PlainObjectBase & c, + Eigen::PlainObjectBase & n) +{ + using namespace Eigen; + using namespace std; + typedef Eigen::Matrix RowVector2S; + sqrd = tree.squared_distance(V,E,RowVector2S(q),i,(RowVector2S&)c); + pseudonormal_test(V,E,EN,VN,q,i,c,s,n); +} + +template < + typename DerivedV, + typename DerivedF, + typename Derivedq> +IGL_INLINE typename DerivedV::Scalar igl::signed_distance_winding_number( + const AABB & tree, + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const igl::WindingNumberAABB & hier, + const Eigen::MatrixBase & q) +{ + typedef typename DerivedV::Scalar Scalar; + Scalar s,sqrd; + Eigen::Matrix c; + int i=-1; + signed_distance_winding_number(tree,V,F,hier,q,s,sqrd,i,c); + return s*sqrt(sqrd); +} + + +template < + typename DerivedV, + typename DerivedF, + typename Derivedq, + typename Scalar, + typename Derivedc> +IGL_INLINE void igl::signed_distance_winding_number( + const AABB & tree, + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const igl::WindingNumberAABB & hier, + const Eigen::MatrixBase & q, + Scalar & s, + Scalar & sqrd, + int & i, + Eigen::PlainObjectBase & c) +{ + using namespace Eigen; + using namespace std; + typedef Eigen::Matrix RowVector3S; + sqrd = tree.squared_distance(V,F,RowVector3S(q),i,(RowVector3S&)c); + const Scalar w = hier.winding_number(q.transpose()); + s = 1.-2.*w; +} + +template < + typename DerivedV, + typename DerivedF, + typename Derivedq, + typename Scalar, + typename Derivedc> +IGL_INLINE void igl::signed_distance_winding_number( + const AABB & tree, + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const Eigen::MatrixBase & q, + Scalar & s, + Scalar & sqrd, + int & i, + Eigen::PlainObjectBase & c) +{ + using namespace Eigen; + using namespace std; + typedef Eigen::Matrix RowVector2S; + sqrd = tree.squared_distance(V,F,RowVector2S(q),i,(RowVector2S&)c); + // TODO: using .data() like this is very dangerous... This is assuming + // colmajor order + assert(!V.derived().IsRowMajor); + assert(!F.derived().IsRowMajor); + s = 1.-2.*winding_number(V,F,q); +} + +//Multi point by parrallel for on single point +template < + typename DerivedP, + typename DerivedV, + typename DerivedF, + typename DerivedS> +IGL_INLINE void igl::signed_distance_fast_winding_number( + const Eigen::MatrixBase & P, + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const AABB & tree, + const igl::FastWindingNumberBVH & fwn_bvh, + Eigen::PlainObjectBase & S) + { + typedef Eigen::Matrix RowVector3S; + S.resize(P.rows(),1); + int min_parallel = 10000; + parallel_for(P.rows(), [&](const int p) + { + RowVector3S q; + q.head(P.row(p).size()) = P.row(p); + // get sdf for single point, update result matrix + S(p) = signed_distance_fast_winding_number(q, V, F, tree,fwn_bvh); + } + ,min_parallel); + } + +//Single Point +template < + typename Derivedq, + typename DerivedV, + typename DerivedF> +IGL_INLINE typename DerivedV::Scalar igl::signed_distance_fast_winding_number( + const Eigen::MatrixBase & q, + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const AABB & tree, + const igl::FastWindingNumberBVH & fwn_bvh) + { + typedef typename DerivedV::Scalar Scalar; + Scalar s,sqrd; + Eigen::Matrix c; + int i = -1; + sqrd = tree.squared_distance(V,F,q,i,c); + Scalar w = fast_winding_number(fwn_bvh,2,q.template cast()); + //0.5 is on surface + return sqrt(sqrd)*(1.-2.*std::abs(w)); + } + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::signed_distance, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, igl::SignedDistanceType, Eigen::Matrix::Scalar, Eigen::Matrix::Scalar, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::signed_distance, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, igl::SignedDistanceType, Eigen::Matrix::Scalar, Eigen::Matrix::Scalar, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::signed_distance, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, igl::SignedDistanceType, Eigen::Matrix::Scalar, Eigen::Matrix::Scalar, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::signed_distance, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, igl::SignedDistanceType, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::signed_distance_pseudonormal, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, double, Eigen::Matrix, Eigen::Matrix >(igl::AABB, 3> const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, double&, double&, int&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::signed_distance, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, igl::SignedDistanceType, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template Eigen::Matrix::Scalar igl::signed_distance_pseudonormal, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(igl::AABB, 3> const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&); +template void igl::signed_distance_pseudonormal, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, igl::AABB, 3> const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::signed_distance, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, igl::SignedDistanceType, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::signed_distance_winding_number, Eigen::Matrix, Eigen::Matrix, double, Eigen::Matrix >(igl::AABB, 3> const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, igl::WindingNumberAABB, Eigen::Matrix, Eigen::Matrix > const&, Eigen::MatrixBase > const&, double&, double&, int&, Eigen::PlainObjectBase >&); +template Eigen::Matrix::Scalar igl::signed_distance_winding_number, Eigen::Matrix, Eigen::Matrix >(igl::AABB, 3> const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, igl::WindingNumberAABB, Eigen::Matrix, Eigen::Matrix > const&, Eigen::MatrixBase > const&); +template void igl::signed_distance_fast_winding_number, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, igl::AABB, 3> const&, igl::FastWindingNumberBVH const&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/signed_distance.h b/src/external/libigl-2.3.0/include/igl/signed_distance.h new file mode 100644 index 000000000..ae54eb3ad --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/signed_distance.h @@ -0,0 +1,321 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_SIGNED_DISTANCE_H +#define IGL_SIGNED_DISTANCE_H + +#include "igl_inline.h" +#include "AABB.h" +#include "WindingNumberAABB.h" +#include "fast_winding_number.h" +#include +#include +namespace igl +{ + enum SignedDistanceType + { + // Use fast pseudo-normal test [Bærentzen & Aanæs 2005] + SIGNED_DISTANCE_TYPE_PSEUDONORMAL = 0, + // Use winding number [Jacobson, Kavan Sorking-Hornug 2013] + SIGNED_DISTANCE_TYPE_WINDING_NUMBER = 1, + SIGNED_DISTANCE_TYPE_DEFAULT = 2, + SIGNED_DISTANCE_TYPE_UNSIGNED = 3, + // Use Fast winding number [Barill, Dickson, Schmidt, Levin, Jacobson 2018] + SIGNED_DISTANCE_TYPE_FAST_WINDING_NUMBER = 4, + NUM_SIGNED_DISTANCE_TYPE = 5 + }; + // Computes signed distance to a mesh + // + // Inputs: + // P #P by 3 list of query point positions + // V #V by 3 list of vertex positions + // F #F by ss list of triangle indices, ss should be 3 unless sign_type == + // SIGNED_DISTANCE_TYPE_UNSIGNED + // sign_type method for computing distance _sign_ S + // lower_bound lower bound of distances needed {std::numeric_limits::min} + // upper_bound lower bound of distances needed {std::numeric_limits::max} + // Outputs: + // S #P list of smallest signed distances + // I #P list of facet indices corresponding to smallest distances + // C #P by 3 list of closest points + // N #P by 3 list of closest normals (only set if + // sign_type=SIGNED_DISTANCE_TYPE_PSEUDONORMAL) + // + // Known bugs: This only computes distances to triangles. So unreferenced + // vertices and degenerate triangles are ignored. + template < + typename DerivedP, + typename DerivedV, + typename DerivedF, + typename DerivedS, + typename DerivedI, + typename DerivedC, + typename DerivedN> + IGL_INLINE void signed_distance( + const Eigen::MatrixBase & P, + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const SignedDistanceType sign_type, + const typename DerivedV::Scalar lower_bound, + const typename DerivedV::Scalar upper_bound, + Eigen::PlainObjectBase & S, + Eigen::PlainObjectBase & I, + Eigen::PlainObjectBase & C, + Eigen::PlainObjectBase & N); + // Computes signed distance to a mesh, with default bounds + // + // Inputs: + // P #P by 3 list of query point positions + // V #V by 3 list of vertex positions + // F #F by ss list of triangle indices, ss should be 3 unless sign_type == + // SIGNED_DISTANCE_TYPE_UNSIGNED + // sign_type method for computing distance _sign_ S + // lower_bound lower bound of distances needed {std::numeric_limits::min} + // upper_bound lower bound of distances needed {std::numeric_limits::max} + // Outputs: + // S #P list of smallest signed distances + // I #P list of facet indices corresponding to smallest distances + // C #P by 3 list of closest points + // N #P by 3 list of closest normals (only set if + // sign_type=SIGNED_DISTANCE_TYPE_PSEUDONORMAL) + template < + typename DerivedP, + typename DerivedV, + typename DerivedF, + typename DerivedS, + typename DerivedI, + typename DerivedC, + typename DerivedN> + IGL_INLINE void signed_distance( + const Eigen::MatrixBase & P, + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const SignedDistanceType sign_type, + Eigen::PlainObjectBase & S, + Eigen::PlainObjectBase & I, + Eigen::PlainObjectBase & C, + Eigen::PlainObjectBase & N); + // Computes signed distance to mesh using pseudonormal with precomputed AABB tree and edge/vertice normals + // + // Inputs: + // tree AABB acceleration tree (see AABB.h) + // F #F by 3 list of triangle indices + // FN #F by 3 list of triangle normals + // VN #V by 3 list of vertex normals (ANGLE WEIGHTING) + // EN #E by 3 list of edge normals (UNIFORM WEIGHTING) + // EMAP #F*3 mapping edges in F to E + // q Query point + // Returns signed distance to mesh + // + template < + typename DerivedV, + typename DerivedF, + typename DerivedFN, + typename DerivedVN, + typename DerivedEN, + typename DerivedEMAP, + typename Derivedq> + IGL_INLINE typename DerivedV::Scalar signed_distance_pseudonormal( + const AABB & tree, + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const Eigen::MatrixBase & FN, + const Eigen::MatrixBase & VN, + const Eigen::MatrixBase & EN, + const Eigen::MatrixBase & EMAP, + const Eigen::MatrixBase & q); + template < + typename DerivedP, + typename DerivedV, + typename DerivedF, + typename DerivedFN, + typename DerivedVN, + typename DerivedEN, + typename DerivedEMAP, + typename DerivedS, + typename DerivedI, + typename DerivedC, + typename DerivedN> + IGL_INLINE void signed_distance_pseudonormal( + const Eigen::MatrixBase & P, + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const AABB & tree, + const Eigen::MatrixBase & FN, + const Eigen::MatrixBase & VN, + const Eigen::MatrixBase & EN, + const Eigen::MatrixBase & EMAP, + Eigen::PlainObjectBase & S, + Eigen::PlainObjectBase & I, + Eigen::PlainObjectBase & C, + Eigen::PlainObjectBase & N); + // Outputs: + // s sign + // sqrd squared distance + // i closest primitive + // c closest point + // n normal + template < + typename DerivedV, + typename DerivedF, + typename DerivedFN, + typename DerivedVN, + typename DerivedEN, + typename DerivedEMAP, + typename Derivedq, + typename Scalar, + typename Derivedc, + typename Derivedn> + IGL_INLINE void signed_distance_pseudonormal( + const AABB & tree, + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const Eigen::MatrixBase & FN, + const Eigen::MatrixBase & VN, + const Eigen::MatrixBase & EN, + const Eigen::MatrixBase & EMAP, + const Eigen::MatrixBase & q, + Scalar & s, + Scalar & sqrd, + int & i, + Eigen::PlainObjectBase & c, + Eigen::PlainObjectBase & n); + template < + typename DerivedV, + typename DerivedE, + typename DerivedEN, + typename DerivedVN, + typename Derivedq, + typename Scalar, + typename Derivedc, + typename Derivedn> + IGL_INLINE void signed_distance_pseudonormal( + const AABB & tree, + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & E, + const Eigen::MatrixBase & EN, + const Eigen::MatrixBase & VN, + const Eigen::MatrixBase & q, + Scalar & s, + Scalar & sqrd, + int & i, + Eigen::PlainObjectBase & c, + Eigen::PlainObjectBase & n); + // Inputs: + // tree AABB acceleration tree (see cgal/point_mesh_squared_distance.h) + // hier Winding number evaluation hierarchy + // q Query point + // Returns signed distance to mesh + template < + typename DerivedV, + typename DerivedF, + typename Derivedq> + IGL_INLINE typename DerivedV::Scalar signed_distance_winding_number( + const AABB & tree, + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const igl::WindingNumberAABB & hier, + const Eigen::MatrixBase & q); + // Outputs: + // s sign + // sqrd squared distance + // pp closest point and primitve + template < + typename DerivedV, + typename DerivedF, + typename Derivedq, + typename Scalar, + typename Derivedc> + IGL_INLINE void signed_distance_winding_number( + const AABB & tree, + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const igl::WindingNumberAABB & hier, + const Eigen::MatrixBase & q, + Scalar & s, + Scalar & sqrd, + int & i, + Eigen::PlainObjectBase & c); + template < + typename DerivedV, + typename DerivedF, + typename Derivedq, + typename Scalar, + typename Derivedc> + IGL_INLINE void signed_distance_winding_number( + const AABB & tree, + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const Eigen::MatrixBase & q, + Scalar & s, + Scalar & sqrd, + int & i, + Eigen::PlainObjectBase & c); + + + // Calculates signed distance at query points P, using fast winding number + // for sign. + // + // Usage: + // VectorXd S; + // VectorXd V, P; //where V is mesh vertices, P are query points + // VectorXi F; + // igl::FastWindingNumberBVH fwn_bvh; + // igl::fast_winding_number(V.cast(), F, 2, fwn_bvh); + // igl::signed_distance_fast_winding_number(P,V,F,tree,fwn_bvh,S); + // + // Inputs: + // P #P by 3 list of query point positions + // V #V by 3 list of triangle indices + // F #F by 3 list of triangle normals + // tree AABB acceleration tree (see AABB.h) + // bvh fast winding precomputation (see Fast_Winding_Number.h) + // Outputs: + // S #P list of signed distances of each point in P + template < + typename DerivedP, + typename DerivedV, + typename DerivedF, + typename DerivedS> + IGL_INLINE void signed_distance_fast_winding_number( + const Eigen::MatrixBase & P, + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const AABB & tree, + const igl::FastWindingNumberBVH & fwn_bvh, + Eigen::PlainObjectBase & S + ); + + // Calculates signed distance at query point q, using fast winding number + // for sign. + // + // Inputs: + // tree AABB acceleration tree (see AABB.h) + // V #V by 3 list of triangle indices + // F #F by 3 list of triangle normals + // bvh fast winding precomputation (see Fast_Winding_Number.h) + // q 1 by 3 list of query point positions + // Outputs: + // S #P list of signed distances of each point in P + template < + typename Derivedq, + typename DerivedV, + typename DerivedF> + IGL_INLINE typename DerivedV::Scalar signed_distance_fast_winding_number( + const Eigen::MatrixBase & q, + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const AABB & tree, + const igl::FastWindingNumberBVH & fwn_bvh + ); +} + +#ifndef IGL_STATIC_LIBRARY +# include "signed_distance.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/simplify_polyhedron.cpp b/src/external/libigl-2.3.0/include/igl/simplify_polyhedron.cpp new file mode 100644 index 000000000..6accbb20d --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/simplify_polyhedron.cpp @@ -0,0 +1,107 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "simplify_polyhedron.h" +#include "decimate.h" +#include "circulation.h" +#include "per_face_normals.h" +#include "infinite_cost_stopping_condition.h" +#include + +IGL_INLINE void igl::simplify_polyhedron( + const Eigen::MatrixXd & OV, + const Eigen::MatrixXi & OF, + Eigen::MatrixXd & V, + Eigen::MatrixXi & F, + Eigen::VectorXi & J) +{ + // TODO: to generalize to open meshes, 0-cost should keep all incident + // boundary edges on their original lines. (for non-manifold meshes, + // igl::decimate needs to be generalized) + + Eigen::MatrixXd N; + // Function for computing cost of collapsing edge (0 if at least one + // direction doesn't change pointset, inf otherwise) and placement (in lowest + // cost direction). + const auto & perfect= [&N]( + const int e, + const Eigen::MatrixXd & V, + const Eigen::MatrixXi & F, + const Eigen::MatrixXi & E, + const Eigen::VectorXi & EMAP, + const Eigen::MatrixXi & EF, + const Eigen::MatrixXi & EI, + double & cost, + Eigen::RowVectorXd & p) + { + // Function for ocmputing cost (0 or inf) of collapsing edge by placing + // vertex at `positive` end of edge. + const auto & perfect_directed = [&N]( + const int e, + const bool positive, + const Eigen::MatrixXd & V, + const Eigen::MatrixXi & F, + const Eigen::MatrixXi & E, + const Eigen::VectorXi & EMAP, + const Eigen::MatrixXi & EF, + const Eigen::MatrixXi & EI, + double & cost, + Eigen::RowVectorXd & p) + { + const auto vi = E(e,positive); + const auto vj = E(e,!positive); + p = V.row(vj); + std::vector faces = igl::circulation(e,positive,EMAP,EF,EI); + cost = 0; + for(auto f : faces) + { + // Skip the faces being collapsed + if(f == EF(e,0) || f == EF(e,1)) + { + continue; + } + const Eigen::RowVectorXd nbefore = N.row(f); + // Face with vi replaced with vj + const Eigen::RowVector3i fafter( + F(f,0) == vi ? vj : F(f,0), + F(f,1) == vi ? vj : F(f,1), + F(f,2) == vi ? vj : F(f,2)); + Eigen::RowVectorXd nafter; + igl::per_face_normals(V,fafter,nafter); + const double epsilon = 1e-10; + // if normal changed then not feasible, break + if((nbefore-nafter).norm() > epsilon) + { + cost = std::numeric_limits::infinity(); + break; + } + } + }; + p.resize(3); + double cost0, cost1; + Eigen::RowVectorXd p0, p1; + perfect_directed(e,false,V,F,E,EMAP,EF,EI,cost0,p0); + perfect_directed(e,true,V,F,E,EMAP,EF,EI,cost1,p1); + if(cost0 < cost1) + { + cost = cost0; + p = p0; + }else + { + cost = cost1; + p = p1; + } + }; + igl::per_face_normals(OV,OF,N); + Eigen::VectorXi I; + igl::decimate( + OV,OF, + perfect, + igl::infinite_cost_stopping_condition(perfect), + V,F,J,I); +} + diff --git a/src/external/libigl-2.3.0/include/igl/simplify_polyhedron.h b/src/external/libigl-2.3.0/include/igl/simplify_polyhedron.h new file mode 100644 index 000000000..5b5018192 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/simplify_polyhedron.h @@ -0,0 +1,37 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_SIMPLIFY_POLYHEDRON_H +#define IGL_SIMPLIFY_POLYHEDRON_H +#include "igl_inline.h" +#include +namespace igl +{ + // Simplify a polyhedron represented as a triangle mesh (OV,OF) by collapsing + // any edge that doesn't contribute to defining surface's pointset. This + // _would_ also make sense for open and non-manifold meshes, but the current + // implementation only works with closed manifold surfaces with well defined + // triangle normals. + // + // Inputs: + // OV #OV by 3 list of input mesh vertex positions + // OF #OF by 3 list of input mesh triangle indices into OV + // Outputs: + // V #V by 3 list of output mesh vertex positions + // F #F by 3 list of input mesh triangle indices into V + // J #F list of indices into OF of birth parents + IGL_INLINE void simplify_polyhedron( + const Eigen::MatrixXd & OV, + const Eigen::MatrixXi & OF, + Eigen::MatrixXd & V, + Eigen::MatrixXi & F, + Eigen::VectorXi & J); +} +#ifndef IGL_STATIC_LIBRARY +# include "simplify_polyhedron.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/slice.cpp b/src/external/libigl-2.3.0/include/igl/slice.cpp new file mode 100644 index 000000000..fd8ad590b --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/slice.cpp @@ -0,0 +1,264 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "slice.h" +#include "colon.h" + +#include + +template < + typename TX, + typename TY, + typename DerivedR, + typename DerivedC> +IGL_INLINE void igl::slice( + const Eigen::SparseMatrix &X, + const Eigen::DenseBase &R, + const Eigen::DenseBase &C, + Eigen::SparseMatrix &Y) +{ + int xm = X.rows(); + int xn = X.cols(); + int ym = R.size(); + int yn = C.size(); + + // special case when R or C is empty + if (ym == 0 || yn == 0) + { + Y.resize(ym, yn); + return; + } + + assert(R.minCoeff() >= 0); + assert(R.maxCoeff() < xm); + assert(C.minCoeff() >= 0); + assert(C.maxCoeff() < xn); + + // Build reindexing maps for columns and rows + std::vector> RI; + RI.resize(xm); + for (int i = 0; i < ym; i++) + { + RI[R(i)].push_back(i); + } + std::vector> CI; + CI.resize(xn); + for (int i = 0; i < yn; i++) + { + CI[C(i)].push_back(i); + } + + // Take a guess at the number of nonzeros (this assumes uniform distribution + // not banded or heavily diagonal) + std::vector> entries; + entries.reserve((X.nonZeros()/(X.rows()*X.cols())) * (ym*yn)); + + // Iterate over outside + for (int k = 0; k < X.outerSize(); ++k) + { + // Iterate over inside + for (typename Eigen::SparseMatrix::InnerIterator it(X, k); it; ++it) + { + for (auto rit = RI[it.row()].begin(); rit != RI[it.row()].end(); rit++) + { + for (auto cit = CI[it.col()].begin(); cit != CI[it.col()].end(); cit++) + { + entries.emplace_back(*rit, *cit, it.value()); + } + } + } + } + Y.resize(ym, yn); + Y.setFromTriplets(entries.begin(), entries.end()); +} + +template +IGL_INLINE void igl::slice( + const MatX &X, + const Eigen::DenseBase &R, + const int dim, + MatY &Y) +{ + Eigen::Matrix C; + switch (dim) + { + case 1: + // boring base case + if (X.cols() == 0) + { + Y.resize(R.size(), 0); + return; + } + igl::colon(0, X.cols() - 1, C); + return slice(X, R, C, Y); + case 2: + // boring base case + if (X.rows() == 0) + { + Y.resize(0, R.size()); + return; + } + igl::colon(0, X.rows() - 1, C); + return slice(X, C, R, Y); + default: + assert(false && "Unsupported dimension"); + return; + } +} + +template < + typename DerivedX, + typename DerivedR, + typename DerivedC, + typename DerivedY> +IGL_INLINE void igl::slice( + const Eigen::DenseBase &X, + const Eigen::DenseBase &R, + const Eigen::DenseBase &C, + Eigen::PlainObjectBase &Y) +{ +#ifndef NDEBUG + int xm = X.rows(); + int xn = X.cols(); +#endif + int ym = R.size(); + int yn = C.size(); + + // special case when R or C is empty + if (ym == 0 || yn == 0) + { + Y.resize(ym, yn); + return; + } + + assert(R.minCoeff() >= 0); + assert(R.maxCoeff() < xm); + assert(C.minCoeff() >= 0); + assert(C.maxCoeff() < xn); + + // Resize output + Y.resize(ym, yn); + // loop over output rows, then columns + for (int i = 0; i < ym; i++) + { + for (int j = 0; j < yn; j++) + { + Y(i, j) = X(R(i, 0), C(j, 0)); + } + } +} + +template +IGL_INLINE void igl::slice( + const Eigen::DenseBase &X, + const Eigen::DenseBase &R, + Eigen::PlainObjectBase &Y) +{ + // phony column indices + Eigen::Matrix C; + C.resize(1); + C(0) = 0; + return igl::slice(X, R, C, Y); +} + +template +IGL_INLINE DerivedX igl::slice( + const Eigen::DenseBase &X, + const Eigen::DenseBase &R) +{ + DerivedX Y; + igl::slice(X, R, Y); + return Y; +} + +template +IGL_INLINE DerivedX igl::slice( + const Eigen::DenseBase &X, + const Eigen::DenseBase &R, + const int dim) +{ + DerivedX Y; + igl::slice(X, R, dim, Y); + return Y; +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::slice, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::DenseBase > const&, Eigen::DenseBase > const&, Eigen::DenseBase > const&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::slice, Eigen::Matrix, Eigen::Matrix >(Eigen::Matrix const&, Eigen::DenseBase > const&, int, Eigen::Matrix&); +// generated by autoexplicit.sh +template void igl::slice, Eigen::Block, -1, 1, true>, Eigen::Matrix >(Eigen::Matrix const&, Eigen::DenseBase, -1, 1, true> > const&, int, Eigen::Matrix&); +// generated by autoexplicit.sh +template void igl::slice const, -1>, Eigen::Block, -1, 1, true>, Eigen::Matrix >(Eigen::VectorBlock const, -1> const&, Eigen::DenseBase, -1, 1, true> > const&, int, Eigen::Matrix&); +// generated by autoexplicit.sh +template void igl::slice, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::DenseBase > const&, Eigen::DenseBase > const&, Eigen::DenseBase > const&, Eigen::PlainObjectBase >&); +template Eigen::Matrix igl::slice, Eigen::Matrix>(Eigen::DenseBase> const &, Eigen::DenseBase> const &, int); +template Eigen::Matrix igl::slice, Eigen::Matrix>(Eigen::DenseBase> const &, Eigen::DenseBase> const &); +template Eigen::Matrix igl::slice, Eigen::Matrix >(Eigen::DenseBase > const&, Eigen::DenseBase > const&, int); +template void igl::slice, Eigen::Matrix, Eigen::Array >(Eigen::Array const&, Eigen::DenseBase > const&, int, Eigen::Array&); +template void igl::slice, Eigen::Matrix, Eigen::Matrix>(Eigen::DenseBase> const &, Eigen::DenseBase> const &, Eigen::PlainObjectBase> &); +template void igl::slice, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix>(Eigen::DenseBase> const &, Eigen::DenseBase> const &, Eigen::DenseBase> const &, Eigen::PlainObjectBase> &); +template void igl::slice, Eigen::Matrix, Eigen::Matrix>(Eigen::Matrix const &, Eigen::DenseBase> const &, int, Eigen::Matrix &); +template void igl::slice, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix>(Eigen::DenseBase> const &, Eigen::DenseBase> const &, Eigen::DenseBase> const &, Eigen::PlainObjectBase> &); +template void igl::slice, Eigen::Matrix, Eigen::PlainObjectBase>>(Eigen::Matrix const &, Eigen::DenseBase> const &, int, Eigen::PlainObjectBase> &); +template void igl::slice, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix>(Eigen::DenseBase> const &, Eigen::DenseBase> const &, Eigen::DenseBase> const &, Eigen::PlainObjectBase> &); +template void igl::slice, Eigen::Matrix, Eigen::Matrix>(Eigen::DenseBase> const &, Eigen::DenseBase> const &, Eigen::PlainObjectBase> &); +template void igl::slice, Eigen::Matrix, Eigen::Matrix >(Eigen::Matrix const&, Eigen::DenseBase > const&, int, Eigen::Matrix&); +template void igl::slice, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::DenseBase > const&, Eigen::DenseBase > const&, Eigen::DenseBase > const&, Eigen::PlainObjectBase >&); +template void igl::slice, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix>(Eigen::DenseBase> const &, Eigen::DenseBase> const &, Eigen::DenseBase> const &, Eigen::PlainObjectBase> &); +template void igl::slice, Eigen::Matrix, Eigen::Matrix >(Eigen::Matrix const&, Eigen::DenseBase > const&, int, Eigen::Matrix&); +template void igl::slice, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix>(Eigen::DenseBase> const &, Eigen::DenseBase> const &, Eigen::DenseBase> const &, Eigen::PlainObjectBase> &); +template void igl::slice, Eigen::Matrix, Eigen::Matrix>(Eigen::DenseBase> const &, Eigen::DenseBase> const &, Eigen::PlainObjectBase> &); +template void igl::slice, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix>(Eigen::DenseBase> const &, Eigen::DenseBase> const &, Eigen::DenseBase> const &, Eigen::PlainObjectBase> &); +template void igl::slice, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix>(Eigen::DenseBase> const &, Eigen::DenseBase> const &, Eigen::DenseBase> const &, Eigen::PlainObjectBase> &); +template void igl::slice, Eigen::Matrix, Eigen::Matrix >(Eigen::Matrix const&, Eigen::DenseBase > const&, int, Eigen::Matrix&); +template void igl::slice, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix>(Eigen::DenseBase> const &, Eigen::DenseBase> const &, Eigen::DenseBase> const &, Eigen::PlainObjectBase> &); +template void igl::slice, Eigen::Matrix, Eigen::PlainObjectBase>>(Eigen::Matrix const &, Eigen::DenseBase> const &, int, Eigen::PlainObjectBase> &); +template void igl::slice, Eigen::Matrix, Eigen::Block const, -1, 1, true>>(Eigen::DenseBase> const &, Eigen::DenseBase const, -1, 1, true>> const &, Eigen::PlainObjectBase> &); +template void igl::slice, Eigen::Matrix, Eigen::Matrix>(Eigen::DenseBase> const &, Eigen::DenseBase> const &, Eigen::PlainObjectBase> &); +template void igl::slice, Eigen::Matrix, Eigen::Matrix>(Eigen::Matrix const &, Eigen::DenseBase> const &, int, Eigen::Matrix &); +template void igl::slice, Eigen::Matrix, Eigen::PlainObjectBase>>(Eigen::Matrix const &, Eigen::DenseBase> const &, int, Eigen::PlainObjectBase> &); +template void igl::slice, Eigen::Matrix, Eigen::PlainObjectBase>>(Eigen::Matrix const &, Eigen::DenseBase> const &, int, Eigen::PlainObjectBase> &); +template void igl::slice >, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::DenseBase > const&, int, Eigen::Matrix&); +template void igl::slice >, Eigen::Matrix, Eigen::PlainObjectBase > >(Eigen::MatrixBase > const&, Eigen::DenseBase > const&, int, Eigen::PlainObjectBase >&); +template void igl::slice >, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::DenseBase > const&, int, Eigen::Matrix&); +template void igl::slice >, Eigen::Matrix, Eigen::PlainObjectBase > >(Eigen::MatrixBase > const&, Eigen::DenseBase > const&, int, Eigen::PlainObjectBase >&); +template void igl::slice >, Eigen::Matrix, Eigen::PlainObjectBase > >(Eigen::MatrixBase > const&, Eigen::DenseBase > const&, int, Eigen::PlainObjectBase >&); +template void igl::slice >, Eigen::Matrix, Eigen::PlainObjectBase > >(Eigen::MatrixBase > const&, Eigen::DenseBase > const&, int, Eigen::PlainObjectBase >&); +template void igl::slice >, Eigen::Matrix, Eigen::PlainObjectBase > >(Eigen::MatrixBase > const&, Eigen::DenseBase > const&, int, Eigen::PlainObjectBase >&); +template void igl::slice >, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::DenseBase > const&, int, Eigen::Matrix&); +template void igl::slice >, Eigen::Matrix, Eigen::PlainObjectBase > >(Eigen::MatrixBase > const&, Eigen::DenseBase > const&, int, Eigen::PlainObjectBase >&); +template void igl::slice >, Eigen::Matrix, Eigen::PlainObjectBase > >(Eigen::MatrixBase > const&, Eigen::DenseBase > const&, int, Eigen::PlainObjectBase >&); +template void igl::slice >, Eigen::Matrix, Eigen::PlainObjectBase > >(Eigen::MatrixBase > const&, Eigen::DenseBase > const&, int, Eigen::PlainObjectBase >&); +template void igl::slice >, Eigen::Matrix, Eigen::PlainObjectBase > >(Eigen::MatrixBase > const&, Eigen::DenseBase > const&, int, Eigen::PlainObjectBase >&); +template void igl::slice >, Eigen::Matrix, Eigen::PlainObjectBase > >(Eigen::MatrixBase > const&, Eigen::DenseBase > const&, int, Eigen::PlainObjectBase >&); +template void igl::slice >, Eigen::Matrix, Eigen::PlainObjectBase > >(Eigen::MatrixBase > const&, Eigen::DenseBase > const&, int, Eigen::PlainObjectBase >&); +template void igl::slice >, Eigen::Matrix, Eigen::PlainObjectBase > >(Eigen::MatrixBase > const&, Eigen::DenseBase > const&, int, Eigen::PlainObjectBase >&); +template void igl::slice >, Eigen::Matrix, Eigen::PlainObjectBase > >(Eigen::MatrixBase > const&, Eigen::DenseBase > const&, int, Eigen::PlainObjectBase >&); +template void igl::slice >, Eigen::Matrix, Eigen::PlainObjectBase > >(Eigen::MatrixBase > const&, Eigen::DenseBase > const&, int, Eigen::PlainObjectBase >&); +template void igl::slice >, Eigen::Matrix, Eigen::PlainObjectBase > >(Eigen::MatrixBase > const&, Eigen::DenseBase > const&, int, Eigen::PlainObjectBase >&); +template void igl::slice >, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::DenseBase > const&, int, Eigen::Matrix&); +template void igl::slice>, Eigen::Matrix, Eigen::PlainObjectBase>>(Eigen::PlainObjectBase> const &, Eigen::DenseBase> const &, int, Eigen::PlainObjectBase> &); +template void igl::slice>, Eigen::Matrix, Eigen::PlainObjectBase>>(Eigen::PlainObjectBase> const &, Eigen::DenseBase> const &, int, Eigen::PlainObjectBase> &); +template void igl::slice>, Eigen::Matrix, Eigen::PlainObjectBase>>(Eigen::PlainObjectBase> const &, Eigen::DenseBase> const &, int, Eigen::PlainObjectBase> &); +template void igl::slice>, Eigen::Matrix, Eigen::PlainObjectBase>>(Eigen::PlainObjectBase> const &, Eigen::DenseBase> const &, int, Eigen::PlainObjectBase> &); +template void igl::slice, Eigen::Matrix, Eigen::SparseMatrix>(Eigen::SparseMatrix const &, Eigen::DenseBase> const &, int, Eigen::SparseMatrix &); +template void igl::slice, Eigen::Array, Eigen::SparseMatrix >(Eigen::SparseMatrix const&, Eigen::DenseBase > const&, int, Eigen::SparseMatrix&); +template void igl::slice, Eigen::Matrix, Eigen::SparseMatrix>(Eigen::SparseMatrix const &, Eigen::DenseBase> const &, int, Eigen::SparseMatrix &); +template void igl::slice, Eigen::Matrix, Eigen::SparseMatrix>(Eigen::SparseMatrix const &, Eigen::DenseBase> const &, int, Eigen::SparseMatrix &); +template void igl::slice, Eigen::Matrix, Eigen::SparseMatrix>(Eigen::SparseMatrix const &, Eigen::DenseBase> const &, int, Eigen::SparseMatrix &); + +#ifdef WIN32 +template void igl::slice >,class Eigen::Matrix<__int64,-1,1,0,-1,1>,class Eigen::PlainObjectBase > >(class Eigen::DenseBase > const &,class Eigen::DenseBase > const &,int,class Eigen::PlainObjectBase > &); +template void igl::slice >,class Eigen::Matrix<__int64,-1,1,0,-1,1>,class Eigen::PlainObjectBase > >(class Eigen::MatrixBase > const &,class Eigen::DenseBase > const &,int,class Eigen::PlainObjectBase > &); +template void igl::slice, Eigen::Matrix<__int64, -1, 1, 0, -1, 1>, Eigen::PlainObjectBase>>(Eigen::Matrix<__int64, -1, 1, 0, -1, 1> const &, Eigen::DenseBase> const &, int, Eigen::PlainObjectBase> &); +template void igl::slice>, Eigen::Matrix<__int64, -1, 1, 0, -1, 1>, Eigen::PlainObjectBase>>(Eigen::PlainObjectBase> const &, Eigen::DenseBase> const &, int, Eigen::PlainObjectBase> &); +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/slice.h b/src/external/libigl-2.3.0/include/igl/slice.h new file mode 100644 index 000000000..542fafd17 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/slice.h @@ -0,0 +1,93 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_SLICE_H +#define IGL_SLICE_H +#include "igl_inline.h" + +#include +namespace igl +{ + // Act like the matlab X(row_indices,col_indices) operator, where + // row_indices, col_indices are non-negative integer indices. + // + // Inputs: + // X m by n matrix + // R list of row indices + // C list of column indices + // Output: + // Y #R by #C matrix + // + // See also: slice_mask, and Eigen's unaryExpr + // https://stackoverflow.com/a/49411587/148668 + template < + typename TX, + typename TY, + typename DerivedR, + typename DerivedC> + IGL_INLINE void slice( + const Eigen::SparseMatrix& X, + const Eigen::DenseBase & R, + const Eigen::DenseBase & C, + Eigen::SparseMatrix& Y); + + // Wrapper to only slice in one direction + // + // Inputs: + // dim dimension to slice in 1 or 2, dim=1 --> X(R,:), dim=2 --> X(:,R) + // + // Note: For now this is just a cheap wrapper. + template < + typename MatX, + typename DerivedR, + typename MatY> + IGL_INLINE void slice( + const MatX& X, + const Eigen::DenseBase & R, + const int dim, + MatY& Y); + + template < + typename DerivedX, + typename DerivedR, + typename DerivedC, + typename DerivedY> + IGL_INLINE void slice( + const Eigen::DenseBase & X, + const Eigen::DenseBase & R, + const Eigen::DenseBase & C, + Eigen::PlainObjectBase & Y); + + template + IGL_INLINE void slice( + const Eigen::DenseBase & X, + const Eigen::DenseBase & R, + Eigen::PlainObjectBase & Y); + + // VectorXi Y = slice(X,R); + // + // This templating is bad because the return type might not have the same + // size as `DerivedX`. This will probably only work if DerivedX has Dynamic + // as it's non-trivial sizes or if the number of rows in R happens to equal + // the number of rows in `DerivedX`. + template + IGL_INLINE DerivedX slice( + const Eigen::DenseBase & X, + const Eigen::DenseBase & R); + template + IGL_INLINE DerivedX slice( + const Eigen::DenseBase& X, + const Eigen::DenseBase & R, + const int dim); + +} + +#ifndef IGL_STATIC_LIBRARY +# include "slice.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/slice_cached.cpp b/src/external/libigl-2.3.0/include/igl/slice_cached.cpp new file mode 100644 index 000000000..e0f13d804 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/slice_cached.cpp @@ -0,0 +1,57 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2017 Daniele Panozzo +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "slice_cached.h" + +#include +#include +#include +#include "slice.h" + +template +IGL_INLINE void igl::slice_cached_precompute( + const Eigen::SparseMatrix& X, + const Eigen::Matrix & R, + const Eigen::Matrix & C, + Eigen::MatrixBase& data, + Eigen::SparseMatrix& Y + ) +{ + // Create a sparse matrix whose entries are the ids + Eigen::SparseMatrix TS = X.template cast(); + + TS.makeCompressed(); + for (unsigned i=0;i TS_sliced; + igl::slice(TS,R,C,TS_sliced); + Y = TS_sliced.cast(); + + data.resize(TS_sliced.nonZeros()); + for (unsigned i=0;i +IGL_INLINE void igl::slice_cached( + const Eigen::SparseMatrix& X, + const Eigen::MatrixBase& data, + Eigen::SparseMatrix& Y + ) +{ + for (unsigned i=0; i >(Eigen::SparseMatrix const&, Eigen::MatrixBase > const&, Eigen::SparseMatrix&); +template void igl::slice_cached_precompute >(Eigen::SparseMatrix const&, Eigen::Matrix const&, Eigen::Matrix const&, Eigen::MatrixBase >&, Eigen::SparseMatrix&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/slice_cached.h b/src/external/libigl-2.3.0/include/igl/slice_cached.h new file mode 100644 index 000000000..84ced8dc9 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/slice_cached.h @@ -0,0 +1,69 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2017 Daniele Panozzo +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_SLICE_CACHED_H +#define IGL_SLICE_CACHED_H +#include "igl_inline.h" +#define EIGEN_YES_I_KNOW_SPARSE_MODULE_IS_NOT_STABLE_YET +#include +#include +namespace igl +{ + + // Act like the matlab X(row_indices,col_indices) operator, where row_indices, + // col_indices are non-negative integer indices. This is a fast version of + // igl::slice that can analyze and store the sparsity structure. It is slower + // at the irst evaluation (slice_cached_precompute), but faster on the + // subsequent ones. + // + // Inputs: + // X m by n matrix + // R list of row indices + // C list of column indices + // + // Output: + // Y #R by #C matrix + // data Temporary data used by slice_cached to repeat this operation + // + // Usage: + // + // // Construct and slice up Laplacian + // SparseMatrix L,L_sliced; + // igl::cotmatrix(V,F,L); + + // // Normal igl::slice call + // igl::slice(L,in,in,L_in_in); + + // // Fast version + // static VectorXi data; // static or saved in a global state + // if (data.size() == 0) + // igl::slice_cached_precompute(L,in,in,data,L_sliced); + // else + // igl::slice_cached(L,data,L_sliced); + +template +IGL_INLINE void slice_cached_precompute( + const Eigen::SparseMatrix& X, + const Eigen::Matrix & R, + const Eigen::Matrix & C, + Eigen::MatrixBase& data, + Eigen::SparseMatrix& Y + ); + +template +IGL_INLINE void slice_cached( + const Eigen::SparseMatrix& X, + const Eigen::MatrixBase& data, + Eigen::SparseMatrix& Y + ); +} + +#ifndef IGL_STATIC_LIBRARY +# include "slice_cached.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/slice_into.cpp b/src/external/libigl-2.3.0/include/igl/slice_into.cpp new file mode 100644 index 000000000..733ef67d3 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/slice_into.cpp @@ -0,0 +1,141 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "slice_into.h" +#include "colon.h" + +// Bug in unsupported/Eigen/SparseExtra needs iostream first +#include +#include + +template +IGL_INLINE void igl::slice_into( + const Eigen::SparseMatrix& X, + const Eigen::MatrixBase & R, + const Eigen::MatrixBase & C, + Eigen::SparseMatrix& Y) +{ + +#ifndef NDEBUG + int xm = X.rows(); + int xn = X.cols(); + assert(R.size() == xm); + assert(C.size() == xn); + int ym = Y.rows(); + int yn = Y.cols(); + assert(R.minCoeff() >= 0); + assert(R.maxCoeff() < ym); + assert(C.minCoeff() >= 0); + assert(C.maxCoeff() < yn); +#endif + + // create temporary dynamic sparse matrix + Eigen::DynamicSparseMatrix dyn_Y(Y); + // Iterate over outside + for(int k=0; k::InnerIterator it (X,k); it; ++it) + { + dyn_Y.coeffRef(R(it.row()),C(it.col())) = it.value(); + } + } + Y = Eigen::SparseMatrix(dyn_Y); +} + +template +IGL_INLINE void igl::slice_into( + const Eigen::MatrixBase & X, + const Eigen::MatrixBase & R, + const Eigen::MatrixBase & C, + Eigen::PlainObjectBase & Y) +{ + + int xm = X.rows(); + int xn = X.cols(); +#ifndef NDEBUG + assert(R.size() == xm); + assert(C.size() == xn); + int ym = Y.rows(); + int yn = Y.cols(); + assert(R.minCoeff() >= 0); + assert(R.maxCoeff() < ym); + assert(C.minCoeff() >= 0); + assert(C.maxCoeff() < yn); +#endif + + // Build reindexing maps for columns and rows, -1 means not in map + Eigen::Matrix RI; + RI.resize(xm); + for(int i = 0;i +IGL_INLINE void igl::slice_into( + const MatX & X, + const Eigen::MatrixBase & R, + const int dim, + MatY& Y) +{ + Eigen::Matrix C; + switch(dim) + { + case 1: + assert(R.size() == X.rows()); + // boring base case + if(X.cols() == 0) + { + return; + } + igl::colon(0,X.cols()-1,C); + return slice_into(X,R,C,Y); + case 2: + assert(R.size() == X.cols()); + // boring base case + if(X.rows() == 0) + { + return; + } + igl::colon(0,X.rows()-1,C); + return slice_into(X,C,R,Y); + default: + assert(false && "Unsupported dimension"); + return; + } +} + +template +IGL_INLINE void igl::slice_into( + const Eigen::MatrixBase & X, + const Eigen::MatrixBase & R, + Eigen::PlainObjectBase & Y) +{ + // phony column indices + Eigen::Matrix C; + C.resize(1); + C(0) = 0; + return igl::slice_into(X,R,C,Y); +} + +#ifdef IGL_STATIC_LIBRARY +template void igl::slice_into, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::slice_into, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::slice_into >(Eigen::SparseMatrix const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::SparseMatrix&); +template void igl::slice_into, Eigen::PlainObjectBase >, Eigen::Matrix >(Eigen::Matrix const&, Eigen::MatrixBase > const&, int, Eigen::PlainObjectBase >&); +template void igl::slice_into, Eigen::PlainObjectBase >, Eigen::Matrix >(Eigen::Matrix const&, Eigen::MatrixBase > const&, int, Eigen::PlainObjectBase >&); +template void igl::slice_into, Eigen::Matrix, Eigen::Matrix >(Eigen::Matrix const&, Eigen::MatrixBase > const&, int, Eigen::Matrix&); +template void igl::slice_into, Eigen::Matrix, Eigen::Matrix >(Eigen::Matrix const&, Eigen::MatrixBase > const&, int, Eigen::Matrix&); +template void igl::slice_into, Eigen::SparseMatrix, Eigen::Matrix >(Eigen::SparseMatrix const&, Eigen::MatrixBase > const&, int, Eigen::SparseMatrix&); +template void igl::slice_into, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::slice_into, Eigen::Matrix, Eigen::MatrixWrapper > >(Eigen::Matrix const&, Eigen::MatrixBase > > const&, int, Eigen::Matrix&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/slice_into.h b/src/external/libigl-2.3.0/include/igl/slice_into.h new file mode 100644 index 000000000..5971d97ee --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/slice_into.h @@ -0,0 +1,63 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_SLICE_INTO_H +#define IGL_SLICE_INTO_H +#include "igl_inline.h" + +#define EIGEN_YES_I_KNOW_SPARSE_MODULE_IS_NOT_STABLE_YET +#include +#include +namespace igl +{ + // Act like the matlab Y(row_indices,col_indices) = X + // + // Inputs: + // X xm by xn rhs matrix + // R list of row indices + // C list of column indices + // Y ym by yn lhs matrix + // Output: + // Y ym by yn lhs matrix, same as input but Y(R,C) = X + template + IGL_INLINE void slice_into( + const Eigen::SparseMatrix& X, + const Eigen::MatrixBase & R, + const Eigen::MatrixBase & C, + Eigen::SparseMatrix& Y); + + template + IGL_INLINE void slice_into( + const Eigen::MatrixBase & X, + const Eigen::MatrixBase & R, + const Eigen::MatrixBase & C, + Eigen::PlainObjectBase & Y); + // Wrapper to only slice in one direction + // + // Inputs: + // dim dimension to slice in 1 or 2, dim=1 --> X(R,:), dim=2 --> X(:,R) + // + // Note: For now this is just a cheap wrapper. + template + IGL_INLINE void slice_into( + const MatX & X, + const Eigen::MatrixBase & R, + const int dim, + MatY& Y); + + template + IGL_INLINE void slice_into( + const Eigen::MatrixBase& X, + const Eigen::MatrixBase& R, + Eigen::PlainObjectBase& Y); +} + +#ifndef IGL_STATIC_LIBRARY +# include "slice_into.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/slice_mask.cpp b/src/external/libigl-2.3.0/include/igl/slice_mask.cpp new file mode 100644 index 000000000..ceb91e63d --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/slice_mask.cpp @@ -0,0 +1,182 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "slice_mask.h" +#include "slice.h" +#include "slice_sorted.h" +#include "find.h" +#include + +template +IGL_INLINE void igl::slice_mask( + const Eigen::DenseBase & X, + const Eigen::Array & R, + const Eigen::Array & C, + Eigen::PlainObjectBase & Y) +{ + int xm = X.rows(); + int xn = X.cols(); + int ym = R.count(); + int yn = C.count(); + assert(R.size() == X.rows() && "R.size() should match X.rows()"); + assert(C.size() == X.cols() && "C.size() should match X.cols()"); + Y.resize(ym,yn); + { + int yi = 0; + for(int i = 0;i +IGL_INLINE void igl::slice_mask( + const Eigen::DenseBase & X, + const Eigen::Array & R, + const int dim, + Eigen::PlainObjectBase & Y) +{ + switch(dim) + { + case 1: + { + const int ym = R.count(); + assert(X.rows() == R.size() && "X.rows() should match R.size()"); + Y.resize(ym,X.cols()); + { + int yi = 0; + for(int i = 0;i +IGL_INLINE DerivedX igl::slice_mask( + const Eigen::DenseBase & X, + const Eigen::Array & R, + const Eigen::Array & C) +{ + DerivedX Y; + igl::slice_mask(X,R,C,Y); + return Y; +} + +template +IGL_INLINE DerivedX igl::slice_mask( + const Eigen::DenseBase& X, + const Eigen::Array & R, + const int dim) +{ + DerivedX Y; + igl::slice_mask(X,R,dim,Y); + return Y; +} + + +template +IGL_INLINE void igl::slice_mask( + const Eigen::SparseMatrix & X, + const Eigen::Array & R, + const int dim, + Eigen::SparseMatrix & Y) +{ + // Cheapskate solution + Eigen::VectorXi Ri; + find(R,Ri); + return slice(X,Ri,dim,Y); +} + +template +IGL_INLINE void igl::slice_mask( + const Eigen::SparseMatrix & X, + const Eigen::Array & R, + const Eigen::Array & C, + Eigen::SparseMatrix & Y) +{ + // Cheapskate solution + Eigen::VectorXi Ri; + find(R,Ri); + Eigen::VectorXi Ci; + find(C,Ci); + return slice_sorted(X,Ri,Ci,Y); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +template void igl::slice_mask, Eigen::Matrix >(Eigen::DenseBase > const&, Eigen::Array const&, int, Eigen::PlainObjectBase >&); +template void igl::slice_mask, Eigen::Matrix >(Eigen::DenseBase > const&, Eigen::Array const&, Eigen::Array const&, Eigen::PlainObjectBase >&); +template void igl::slice_mask, Eigen::Matrix >(Eigen::DenseBase > const&, Eigen::Array const&, int, Eigen::PlainObjectBase >&); +template void igl::slice_mask, Eigen::Matrix >(Eigen::DenseBase > const&, Eigen::Array const&, int, Eigen::PlainObjectBase >&); +template void igl::slice_mask, Eigen::Matrix >(Eigen::DenseBase > const&, Eigen::Array const&, int, Eigen::PlainObjectBase >&); +template void igl::slice_mask, Eigen::Matrix >(Eigen::DenseBase > const&, Eigen::Array const&, Eigen::Array const&, Eigen::PlainObjectBase >&); +template Eigen::Array igl::slice_mask >(Eigen::DenseBase > const&, Eigen::Array const&, int); +template Eigen::Matrix igl::slice_mask >(Eigen::DenseBase > const&, Eigen::Array const&, int); +template Eigen::Matrix igl::slice_mask >(Eigen::DenseBase > const&, Eigen::Array const&, int); +template Eigen::Array igl::slice_mask >(Eigen::DenseBase > const&, Eigen::Array const&, int); +template void igl::slice_mask(Eigen::SparseMatrix const&, Eigen::Array const&, int, Eigen::SparseMatrix&); +template void igl::slice_mask, Eigen::Matrix >(Eigen::DenseBase > const&, Eigen::Array const&, int, Eigen::PlainObjectBase >&); +template void igl::slice_mask, Eigen::Matrix >(Eigen::DenseBase > const&, Eigen::Array const&, int, Eigen::PlainObjectBase >&); +template void igl::slice_mask, Eigen::Matrix >(Eigen::DenseBase > const&, Eigen::Array const&, int, Eigen::PlainObjectBase >&); +template void igl::slice_mask, Eigen::Array >(Eigen::DenseBase > const&, Eigen::Array const&, int, Eigen::PlainObjectBase >&); +template void igl::slice_mask >(Eigen::DenseBase > const&, Eigen::Array const&, int, Eigen::PlainObjectBase >&); +template void igl::slice_mask >(Eigen::DenseBase > const&, Eigen::Array const&, Eigen::Array const&, Eigen::PlainObjectBase >&); +template void igl::slice_mask >(Eigen::DenseBase > const&, Eigen::Array const&, int, Eigen::PlainObjectBase >&); +template void igl::slice_mask >(Eigen::DenseBase > const&, Eigen::Array const&, Eigen::Array const&, Eigen::PlainObjectBase >&); +template void igl::slice_mask >(Eigen::DenseBase > const&, Eigen::Array const&, int, Eigen::PlainObjectBase >&); +template void igl::slice_mask, Eigen::Matrix >(Eigen::DenseBase > const&, Eigen::Array const&, int, Eigen::PlainObjectBase >&); +template Eigen::Matrix igl::slice_mask >(Eigen::DenseBase > const&, Eigen::Array const&, int); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/slice_mask.h b/src/external/libigl-2.3.0/include/igl/slice_mask.h new file mode 100644 index 000000000..0a0dcda7c --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/slice_mask.h @@ -0,0 +1,74 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_SLICE_MASK_H +#define IGL_SLICE_MASK_H +#include "igl_inline.h" + +#include +#include +namespace igl +{ + // Act like the matlab X(row_mask,col_mask) operator, where + // row_mask, col_mask are non-negative integer indices. + // + // Inputs: + // X m by n matrix + // R m list of row bools + // C n list of column bools + // Output: + // Y #trues-in-R by #trues-in-C matrix + // + // See also: slice_mask + + template + IGL_INLINE void slice_mask( + const Eigen::DenseBase & X, + const Eigen::Array & R, + const Eigen::Array & C, + Eigen::PlainObjectBase & Y); + template + IGL_INLINE void slice_mask( + const Eigen::DenseBase & X, + const Eigen::Array & R, + const int dim, + Eigen::PlainObjectBase & Y); + // + // This templating is bad because the return type might not have the same + // size as `DerivedX`. This will probably only work if DerivedX has Dynamic + // as it's non-trivial sizes or if the number of rows in R happens to equal + // the number of rows in `DerivedX`. + template + IGL_INLINE DerivedX slice_mask( + const Eigen::DenseBase & X, + const Eigen::Array & R, + const Eigen::Array & C); + template + IGL_INLINE DerivedX slice_mask( + const Eigen::DenseBase & X, + const Eigen::Array & R, + const int dim); + template + IGL_INLINE void slice_mask( + const Eigen::SparseMatrix & X, + const Eigen::Array & R, + const int dim, + Eigen::SparseMatrix & Y); + template + IGL_INLINE void slice_mask( + const Eigen::SparseMatrix & X, + const Eigen::Array & R, + const Eigen::Array & C, + Eigen::SparseMatrix & Y); +} + + +#ifndef IGL_STATIC_LIBRARY +# include "slice_mask.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/slice_sorted.cpp b/src/external/libigl-2.3.0/include/igl/slice_sorted.cpp new file mode 100644 index 000000000..000a20aa9 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/slice_sorted.cpp @@ -0,0 +1,88 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "slice_sorted.h" + +#include + +// TODO: Write a version that works for row-major sparse matrices as well. +template +IGL_INLINE void igl::slice_sorted(const Eigen::SparseMatrix &X, + const Eigen::DenseBase &R, + const Eigen::DenseBase &C, + Eigen::SparseMatrix &Y) +{ + int xm = X.rows(); + int xn = X.cols(); + int ym = R.size(); + int yn = C.size(); + + // Special case when R or C is empty + if (ym == 0 || yn == 0) + { + Y.resize(ym, yn); + return; + } + + assert(R.minCoeff() >= 0); + assert(R.maxCoeff() < xm); + assert(C.minCoeff() >= 0); + assert(C.maxCoeff() < xn); + + // Multiplicity count for each row/col + using RowIndexType = typename DerivedR::Scalar; + using ColIndexType = typename DerivedC::Scalar; + std::vector slicedRowStart(xm); + std::vector rowRepeat(xm, 0); + for (int i = 0; i < ym; ++i) + { + if (rowRepeat[R(i)] == 0) + { + slicedRowStart[R(i)] = i; + } + rowRepeat[R(i)]++; + } + std::vector columnRepeat(xn, 0); + for (int i = 0; i < yn; i++) + { + columnRepeat[C(i)]++; + } + // Count number of nnz per outer row/col + Eigen::VectorXi nnz(yn); + for (int k = 0, c = 0; k < X.outerSize(); ++k) + { + int cnt = 0; + for (typename Eigen::SparseMatrix::InnerIterator it(X, k); it; ++it) + { + cnt += rowRepeat[it.row()]; + } + for (int i = 0; i < columnRepeat[k]; ++i, ++c) + { + nnz(c) = cnt; + } + } + Y.resize(ym, yn); + Y.reserve(nnz); + // Insert values + for (int k = 0, c = 0; k < X.outerSize(); ++k) + { + for (int i = 0; i < columnRepeat[k]; ++i, ++c) + { + for (typename Eigen::SparseMatrix::InnerIterator it(X, k); it; ++it) + { + for (int j = 0, r = slicedRowStart[it.row()]; j < rowRepeat[it.row()]; ++j, ++r) + { + Y.insert(r, c) = it.value(); + } + } + } + } +} + +#ifdef IGL_STATIC_LIBRARY +template void igl::slice_sorted, Eigen::Matrix >(Eigen::SparseMatrix const&, Eigen::DenseBase > const&, Eigen::DenseBase > const&, Eigen::SparseMatrix&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/slice_sorted.h b/src/external/libigl-2.3.0/include/igl/slice_sorted.h new file mode 100644 index 000000000..47826b927 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/slice_sorted.h @@ -0,0 +1,42 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2019 Jérémie Dumas +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef IGL_SLICE_SORTED_H +#define IGL_SLICE_SORTED_H + +#include "igl_inline.h" +#include +#include + +namespace igl +{ + // Act like the matlab X(row_indices,col_indices) operator, where row_indices, + // col_indices are non-negative integer indices. This version is about 2x faster + // than igl::slice, but it assumes that the indices to slice with are already sorted. + // + // Inputs: + // X m by n matrix + // R list of row indices + // C list of column indices + // + // Output: + // Y #R by #C matrix + // + template + IGL_INLINE void slice_sorted(const Eigen::SparseMatrix &X, + const Eigen::DenseBase &R, + const Eigen::DenseBase &C, + Eigen::SparseMatrix &Y); + +} // namespace igl + +#ifndef IGL_STATIC_LIBRARY +#include "slice_sorted.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/slim.cpp b/src/external/libigl-2.3.0/include/igl/slim.cpp new file mode 100644 index 000000000..ed779eadf --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/slim.cpp @@ -0,0 +1,811 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Michael Rabinovich +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "slim.h" + +#include "boundary_loop.h" +#include "cotmatrix.h" +#include "edge_lengths.h" +#include "grad.h" +#include "local_basis.h" +#include "repdiag.h" +#include "vector_area_matrix.h" +#include "arap.h" +#include "cat.h" +#include "doublearea.h" +#include "grad.h" +#include "local_basis.h" +#include "per_face_normals.h" +#include "slice_into.h" +#include "volume.h" +#include "polar_svd.h" +#include "flip_avoiding_line_search.h" +#include "mapping_energy_with_jacobians.h" + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "Timer.h" +#include "sparse_cached.h" +#include "AtA_cached.h" + +#ifdef CHOLMOD +#include +#endif + +namespace igl +{ + namespace slim + { + // Definitions of internal functions + IGL_INLINE void buildRhs(igl::SLIMData& s, const Eigen::SparseMatrix &A); + IGL_INLINE void add_soft_constraints(igl::SLIMData& s, Eigen::SparseMatrix &L); + IGL_INLINE double compute_energy(igl::SLIMData& s, const Eigen::MatrixXd &V_new); + IGL_INLINE double compute_soft_const_energy(igl::SLIMData& s, + const Eigen::MatrixXd &V, + const Eigen::MatrixXi &F, + const Eigen::MatrixXd &V_o); + + IGL_INLINE void solve_weighted_arap(igl::SLIMData& s, + const Eigen::MatrixXd &V, + const Eigen::MatrixXi &F, + Eigen::MatrixXd &uv, + Eigen::VectorXi &soft_b_p, + Eigen::MatrixXd &soft_bc_p); + IGL_INLINE void update_weights_and_closest_rotations( igl::SLIMData& s, + Eigen::MatrixXd &uv); + IGL_INLINE void compute_jacobians(igl::SLIMData& s, const Eigen::MatrixXd &uv); + IGL_INLINE void build_linear_system(igl::SLIMData& s, Eigen::SparseMatrix &L); + IGL_INLINE void pre_calc(igl::SLIMData& s); + + // Implementation + + IGL_INLINE void compute_jacobians(igl::SLIMData& s, const Eigen::MatrixXd &uv) + { + if (s.F.cols() == 3) + { + // Ji=[D1*u,D2*u,D1*v,D2*v]; + s.Ji.col(0) = s.Dx * uv.col(0); + s.Ji.col(1) = s.Dy * uv.col(0); + s.Ji.col(2) = s.Dx * uv.col(1); + s.Ji.col(3) = s.Dy * uv.col(1); + } + else /*tet mesh*/{ + // Ji=[D1*u,D2*u,D3*u, D1*v,D2*v, D3*v, D1*w,D2*w,D3*w]; + s.Ji.col(0) = s.Dx * uv.col(0); + s.Ji.col(1) = s.Dy * uv.col(0); + s.Ji.col(2) = s.Dz * uv.col(0); + s.Ji.col(3) = s.Dx * uv.col(1); + s.Ji.col(4) = s.Dy * uv.col(1); + s.Ji.col(5) = s.Dz * uv.col(1); + s.Ji.col(6) = s.Dx * uv.col(2); + s.Ji.col(7) = s.Dy * uv.col(2); + s.Ji.col(8) = s.Dz * uv.col(2); + } + } + + IGL_INLINE void update_weights_and_closest_rotations(igl::SLIMData& s, Eigen::MatrixXd &uv) + { + compute_jacobians(s, uv); + slim_update_weights_and_closest_rotations_with_jacobians(s.Ji, s.slim_energy, s.exp_factor, s.W, s.Ri); + } + + + + + IGL_INLINE void solve_weighted_arap(igl::SLIMData& s, + const Eigen::MatrixXd &V, + const Eigen::MatrixXi &F, + Eigen::MatrixXd &uv, + Eigen::VectorXi &soft_b_p, + Eigen::MatrixXd &soft_bc_p) + { + using namespace Eigen; + + Eigen::SparseMatrix L; + build_linear_system(s,L); + + igl::Timer t; + + //t.start(); + // solve + Eigen::VectorXd Uc; +#ifndef CHOLMOD + if (s.dim == 2) + { + SimplicialLDLT > solver; + Uc = solver.compute(L).solve(s.rhs); + } + else + { // seems like CG performs much worse for 2D and way better for 3D + Eigen::VectorXd guess(uv.rows() * s.dim); + for (int i = 0; i < s.v_num; i++) for (int j = 0; j < s.dim; j++) guess(uv.rows() * j + i) = uv(i, j); // flatten vector + ConjugateGradient, Lower | Upper> cg; + cg.setTolerance(1e-8); + cg.compute(L); + Uc = cg.solveWithGuess(s.rhs, guess); + } +#else + CholmodSimplicialLDLT > solver; + Uc = solver.compute(L).solve(s.rhs); +#endif + for (int i = 0; i < s.dim; i++) + uv.col(i) = Uc.block(i * s.v_n, 0, s.v_n, 1); + + // t.stop(); + // std::cerr << "solve: " << t.getElapsedTime() << std::endl; + + } + + + IGL_INLINE void pre_calc(igl::SLIMData& s) + { + if (!s.has_pre_calc) + { + s.v_n = s.v_num; + s.f_n = s.f_num; + + if (s.F.cols() == 3) + { + s.dim = 2; + Eigen::MatrixXd F1, F2, F3; + igl::local_basis(s.V, s.F, F1, F2, F3); + Eigen::SparseMatrix G; + igl::grad(s.V, s.F, G); + Eigen::SparseMatrix Face_Proj; + + auto face_proj = [](Eigen::MatrixXd& F){ + std::vector >IJV; + int f_num = F.rows(); + for(int i=0; i(i, i, F(i,0))); + IJV.push_back(Eigen::Triplet(i, i+f_num, F(i,1))); + IJV.push_back(Eigen::Triplet(i, i+2*f_num, F(i,2))); + } + Eigen::SparseMatrix P(f_num, 3*f_num); + P.setFromTriplets(IJV.begin(), IJV.end()); + return P; + }; + + s.Dx = face_proj(F1) * G; + s.Dy = face_proj(F2) * G; + } + else + { + s.dim = 3; + Eigen::SparseMatrix G; + igl::grad(s.V, s.F, G, + s.mesh_improvement_3d /*use normal gradient, or one from a "regular" tet*/); + s.Dx = G.block(0, 0, s.F.rows(), s.V.rows()); + s.Dy = G.block(s.F.rows(), 0, s.F.rows(), s.V.rows()); + s.Dz = G.block(2 * s.F.rows(), 0, s.F.rows(), s.V.rows()); + } + + s.W.resize(s.f_n, s.dim * s.dim); + s.Dx.makeCompressed(); + s.Dy.makeCompressed(); + s.Dz.makeCompressed(); + s.Ri.resize(s.f_n, s.dim * s.dim); + s.Ji.resize(s.f_n, s.dim * s.dim); + s.rhs.resize(s.dim * s.v_num); + + // flattened weight matrix + s.WGL_M.resize(s.dim * s.dim * s.f_n); + for (int i = 0; i < s.dim * s.dim; i++) + for (int j = 0; j < s.f_n; j++) + s.WGL_M(i * s.f_n + j) = s.M(j); + + s.first_solve = true; + s.has_pre_calc = true; + } + } + + IGL_INLINE void build_linear_system(igl::SLIMData& s, Eigen::SparseMatrix &L) + { + // formula (35) in paper + std::vector > IJV; + + #ifdef SLIM_CACHED + slim_buildA(s.Dx, s.Dy, s.Dz, s.W, IJV); + if (s.A.rows() == 0) + { + s.A = Eigen::SparseMatrix(s.dim * s.dim * s.f_n, s.dim * s.v_n); + igl::sparse_cached_precompute(IJV,s.A_data,s.A); + } + else + igl::sparse_cached(IJV,s.A_data,s.A); + #else + Eigen::SparseMatrix A(s.dim * s.dim * s.f_n, s.dim * s.v_n); + slim_buildA(s.Dx, s.Dy, s.Dz, s.W, IJV); + A.setFromTriplets(IJV.begin(),IJV.end()); + A.makeCompressed(); + #endif + + #ifdef SLIM_CACHED + #else + Eigen::SparseMatrix At = A.transpose(); + At.makeCompressed(); + #endif + + #ifdef SLIM_CACHED + Eigen::SparseMatrix id_m(s.A.cols(), s.A.cols()); + #else + Eigen::SparseMatrix id_m(A.cols(), A.cols()); + #endif + + id_m.setIdentity(); + + // add proximal penalty + #ifdef SLIM_CACHED + s.AtA_data.W = s.WGL_M; + if (s.AtA.rows() == 0) + igl::AtA_cached_precompute(s.A,s.AtA_data,s.AtA); + else + igl::AtA_cached(s.A,s.AtA_data,s.AtA); + + L = s.AtA + s.proximal_p * id_m; //add also a proximal + L.makeCompressed(); + + #else + L = At * s.WGL_M.asDiagonal() * A + s.proximal_p * id_m; //add also a proximal term + L.makeCompressed(); + #endif + + #ifdef SLIM_CACHED + buildRhs(s, s.A); + #else + buildRhs(s, A); + #endif + + Eigen::SparseMatrix OldL = L; + add_soft_constraints(s,L); + L.makeCompressed(); + } + + IGL_INLINE void add_soft_constraints(igl::SLIMData& s, Eigen::SparseMatrix &L) + { + int v_n = s.v_num; + for (int d = 0; d < s.dim; d++) + { + for (int i = 0; i < s.b.rows(); i++) + { + int v_idx = s.b(i); + s.rhs(d * v_n + v_idx) += s.soft_const_p * s.bc(i, d); // rhs + L.coeffRef(d * v_n + v_idx, d * v_n + v_idx) += s.soft_const_p; // diagonal of matrix + } + } + } + + IGL_INLINE double compute_energy(igl::SLIMData& s, const Eigen::MatrixXd &V_new) + { + compute_jacobians(s,V_new); + return mapping_energy_with_jacobians(s.Ji, s.M, s.slim_energy, s.exp_factor) + + compute_soft_const_energy(s, s.V, s.F, V_new); + } + + IGL_INLINE double compute_soft_const_energy(igl::SLIMData& s, + const Eigen::MatrixXd &V, + const Eigen::MatrixXi &F, + const Eigen::MatrixXd &V_o) + { + double e = 0; + for (int i = 0; i < s.b.rows(); i++) + { + e += s.soft_const_p * (s.bc.row(i) - V_o.row(s.b(i))).squaredNorm(); + } + return e; + } + + + + IGL_INLINE void buildRhs(igl::SLIMData& s, const Eigen::SparseMatrix &A) + { + Eigen::VectorXd f_rhs(s.dim * s.dim * s.f_n); + f_rhs.setZero(); + if (s.dim == 2) + { + /*b = [W11*R11 + W12*R21; (formula (36)) + W11*R12 + W12*R22; + W21*R11 + W22*R21; + W21*R12 + W22*R22];*/ + for (int i = 0; i < s.f_n; i++) + { + f_rhs(i + 0 * s.f_n) = s.W(i, 0) * s.Ri(i, 0) + s.W(i, 1) * s.Ri(i, 1); + f_rhs(i + 1 * s.f_n) = s.W(i, 0) * s.Ri(i, 2) + s.W(i, 1) * s.Ri(i, 3); + f_rhs(i + 2 * s.f_n) = s.W(i, 2) * s.Ri(i, 0) + s.W(i, 3) * s.Ri(i, 1); + f_rhs(i + 3 * s.f_n) = s.W(i, 2) * s.Ri(i, 2) + s.W(i, 3) * s.Ri(i, 3); + } + } + else + { + /*b = [W11*R11 + W12*R21 + W13*R31; + W11*R12 + W12*R22 + W13*R32; + W11*R13 + W12*R23 + W13*R33; + W21*R11 + W22*R21 + W23*R31; + W21*R12 + W22*R22 + W23*R32; + W21*R13 + W22*R23 + W23*R33; + W31*R11 + W32*R21 + W33*R31; + W31*R12 + W32*R22 + W33*R32; + W31*R13 + W32*R23 + W33*R33;];*/ + for (int i = 0; i < s.f_n; i++) + { + f_rhs(i + 0 * s.f_n) = s.W(i, 0) * s.Ri(i, 0) + s.W(i, 1) * s.Ri(i, 1) + s.W(i, 2) * s.Ri(i, 2); + f_rhs(i + 1 * s.f_n) = s.W(i, 0) * s.Ri(i, 3) + s.W(i, 1) * s.Ri(i, 4) + s.W(i, 2) * s.Ri(i, 5); + f_rhs(i + 2 * s.f_n) = s.W(i, 0) * s.Ri(i, 6) + s.W(i, 1) * s.Ri(i, 7) + s.W(i, 2) * s.Ri(i, 8); + f_rhs(i + 3 * s.f_n) = s.W(i, 3) * s.Ri(i, 0) + s.W(i, 4) * s.Ri(i, 1) + s.W(i, 5) * s.Ri(i, 2); + f_rhs(i + 4 * s.f_n) = s.W(i, 3) * s.Ri(i, 3) + s.W(i, 4) * s.Ri(i, 4) + s.W(i, 5) * s.Ri(i, 5); + f_rhs(i + 5 * s.f_n) = s.W(i, 3) * s.Ri(i, 6) + s.W(i, 4) * s.Ri(i, 7) + s.W(i, 5) * s.Ri(i, 8); + f_rhs(i + 6 * s.f_n) = s.W(i, 6) * s.Ri(i, 0) + s.W(i, 7) * s.Ri(i, 1) + s.W(i, 8) * s.Ri(i, 2); + f_rhs(i + 7 * s.f_n) = s.W(i, 6) * s.Ri(i, 3) + s.W(i, 7) * s.Ri(i, 4) + s.W(i, 8) * s.Ri(i, 5); + f_rhs(i + 8 * s.f_n) = s.W(i, 6) * s.Ri(i, 6) + s.W(i, 7) * s.Ri(i, 7) + s.W(i, 8) * s.Ri(i, 8); + } + } + Eigen::VectorXd uv_flat(s.dim *s.v_n); + for (int i = 0; i < s.dim; i++) + for (int j = 0; j < s.v_n; j++) + uv_flat(s.v_n * i + j) = s.V_o(j, i); + + s.rhs = (f_rhs.transpose() * s.WGL_M.asDiagonal() * A).transpose() + s.proximal_p * uv_flat; + } + + } +} + +IGL_INLINE void igl::slim_update_weights_and_closest_rotations_with_jacobians(const Eigen::MatrixXd &Ji, + igl::MappingEnergyType slim_energy, + double exp_factor, + Eigen::MatrixXd &W, + Eigen::MatrixXd &Ri) +{ + const double eps = 1e-8; + double exp_f = exp_factor; + const int dim = (Ji.cols()==4? 2:3); + + if (dim == 2) + { + for (int i = 0; i < Ji.rows(); ++i) + { + typedef Eigen::Matrix2d Mat2; + typedef Eigen::Matrix RMat2; + typedef Eigen::Vector2d Vec2; + Mat2 ji, ri, ti, ui, vi; + Vec2 sing; + Vec2 closest_sing_vec; + RMat2 mat_W; + Vec2 m_sing_new; + double s1, s2; + + ji(0, 0) = Ji(i, 0); + ji(0, 1) = Ji(i, 1); + ji(1, 0) = Ji(i, 2); + ji(1, 1) = Ji(i, 3); + + igl::polar_svd(ji, ri, ti, ui, sing, vi); + + s1 = sing(0); + s2 = sing(1); + + // Update Weights according to energy + switch (slim_energy) + { + case igl::MappingEnergyType::ARAP: + { + m_sing_new << 1, 1; + break; + } + case igl::MappingEnergyType::SYMMETRIC_DIRICHLET: + { + double s1_g = 2 * (s1 - pow(s1, -3)); + double s2_g = 2 * (s2 - pow(s2, -3)); + m_sing_new << sqrt(s1_g / (2 * (s1 - 1))), sqrt(s2_g / (2 * (s2 - 1))); + break; + } + case igl::MappingEnergyType::LOG_ARAP: + { + double s1_g = 2 * (log(s1) / s1); + double s2_g = 2 * (log(s2) / s2); + m_sing_new << sqrt(s1_g / (2 * (s1 - 1))), sqrt(s2_g / (2 * (s2 - 1))); + break; + } + case igl::MappingEnergyType::CONFORMAL: + { + double s1_g = 1 / (2 * s2) - s2 / (2 * pow(s1, 2)); + double s2_g = 1 / (2 * s1) - s1 / (2 * pow(s2, 2)); + + double geo_avg = sqrt(s1 * s2); + double s1_min = geo_avg; + double s2_min = geo_avg; + + m_sing_new << sqrt(s1_g / (2 * (s1 - s1_min))), sqrt(s2_g / (2 * (s2 - s2_min))); + + // change local step + closest_sing_vec << s1_min, s2_min; + ri = ui * closest_sing_vec.asDiagonal() * vi.transpose(); + break; + } + case igl::MappingEnergyType::EXP_CONFORMAL: + { + double s1_g = 2 * (s1 - pow(s1, -3)); + double s2_g = 2 * (s2 - pow(s2, -3)); + + double geo_avg = sqrt(s1 * s2); + double s1_min = geo_avg; + double s2_min = geo_avg; + + double in_exp = exp_f * ((pow(s1, 2) + pow(s2, 2)) / (2 * s1 * s2)); + double exp_thing = exp(in_exp); + + s1_g *= exp_thing * exp_f; + s2_g *= exp_thing * exp_f; + + m_sing_new << sqrt(s1_g / (2 * (s1 - 1))), sqrt(s2_g / (2 * (s2 - 1))); + break; + } + case igl::MappingEnergyType::EXP_SYMMETRIC_DIRICHLET: + { + double s1_g = 2 * (s1 - pow(s1, -3)); + double s2_g = 2 * (s2 - pow(s2, -3)); + + double in_exp = exp_f * (pow(s1, 2) + pow(s1, -2) + pow(s2, 2) + pow(s2, -2)); + double exp_thing = exp(in_exp); + + s1_g *= exp_thing * exp_f; + s2_g *= exp_thing * exp_f; + + m_sing_new << sqrt(s1_g / (2 * (s1 - 1))), sqrt(s2_g / (2 * (s2 - 1))); + break; + } + default: assert(false); + } + + if (std::abs(s1 - 1) < eps) m_sing_new(0) = 1; + if (std::abs(s2 - 1) < eps) m_sing_new(1) = 1; + mat_W = ui * m_sing_new.asDiagonal() * ui.transpose(); + + W.row(i) = Eigen::Map>(mat_W.data()); + // 2) Update local step (doesn't have to be a rotation, for instance in case of conformal energy) + Ri.row(i) = Eigen::Map>(ri.data()); + } + } + else + { + typedef Eigen::Matrix Vec3; + typedef Eigen::Matrix Mat3; + typedef Eigen::Matrix RMat3; + Mat3 ji; + Vec3 m_sing_new; + Vec3 closest_sing_vec; + const double sqrt_2 = sqrt(2); + for (int i = 0; i < Ji.rows(); ++i) + { + ji << Ji(i,0), Ji(i,1), Ji(i,2), + Ji(i,3), Ji(i,4), Ji(i,5), + Ji(i,6), Ji(i,7), Ji(i,8); + + Mat3 ri, ti, ui, vi; + Vec3 sing; + igl::polar_svd(ji, ri, ti, ui, sing, vi); + + double s1 = sing(0); + double s2 = sing(1); + double s3 = sing(2); + + // 1) Update Weights + switch (slim_energy) + { + case igl::MappingEnergyType::ARAP: + { + m_sing_new << 1, 1, 1; + break; + } + case igl::MappingEnergyType::LOG_ARAP: + { + double s1_g = 2 * (log(s1) / s1); + double s2_g = 2 * (log(s2) / s2); + double s3_g = 2 * (log(s3) / s3); + m_sing_new << sqrt(s1_g / (2 * (s1 - 1))), sqrt(s2_g / (2 * (s2 - 1))), sqrt(s3_g / (2 * (s3 - 1))); + break; + } + case igl::MappingEnergyType::SYMMETRIC_DIRICHLET: + { + double s1_g = 2 * (s1 - pow(s1, -3)); + double s2_g = 2 * (s2 - pow(s2, -3)); + double s3_g = 2 * (s3 - pow(s3, -3)); + m_sing_new << sqrt(s1_g / (2 * (s1 - 1))), sqrt(s2_g / (2 * (s2 - 1))), sqrt(s3_g / (2 * (s3 - 1))); + break; + } + case igl::MappingEnergyType::EXP_SYMMETRIC_DIRICHLET: + { + double s1_g = 2 * (s1 - pow(s1, -3)); + double s2_g = 2 * (s2 - pow(s2, -3)); + double s3_g = 2 * (s3 - pow(s3, -3)); + m_sing_new << sqrt(s1_g / (2 * (s1 - 1))), sqrt(s2_g / (2 * (s2 - 1))), sqrt(s3_g / (2 * (s3 - 1))); + + double in_exp = exp_f * (pow(s1, 2) + pow(s1, -2) + pow(s2, 2) + pow(s2, -2) + pow(s3, 2) + pow(s3, -2)); + double exp_thing = exp(in_exp); + + s1_g *= exp_thing * exp_f; + s2_g *= exp_thing * exp_f; + s3_g *= exp_thing * exp_f; + + m_sing_new << sqrt(s1_g / (2 * (s1 - 1))), sqrt(s2_g / (2 * (s2 - 1))), sqrt(s3_g / (2 * (s3 - 1))); + + break; + } + case igl::MappingEnergyType::CONFORMAL: + { + double common_div = 9 * (pow(s1 * s2 * s3, 5. / 3.)); + + double s1_g = (-2 * s2 * s3 * (pow(s2, 2) + pow(s3, 2) - 2 * pow(s1, 2))) / common_div; + double s2_g = (-2 * s1 * s3 * (pow(s1, 2) + pow(s3, 2) - 2 * pow(s2, 2))) / common_div; + double s3_g = (-2 * s1 * s2 * (pow(s1, 2) + pow(s2, 2) - 2 * pow(s3, 2))) / common_div; + + double closest_s = sqrt(pow(s1, 2) + pow(s3, 2)) / sqrt_2; + double s1_min = closest_s; + double s2_min = closest_s; + double s3_min = closest_s; + + m_sing_new << sqrt(s1_g / (2 * (s1 - s1_min))), sqrt(s2_g / (2 * (s2 - s2_min))), sqrt( + s3_g / (2 * (s3 - s3_min))); + + // change local step + closest_sing_vec << s1_min, s2_min, s3_min; + ri = ui * closest_sing_vec.asDiagonal() * vi.transpose(); + break; + } + case igl::MappingEnergyType::EXP_CONFORMAL: + { + // E_conf = (s1^2 + s2^2 + s3^2)/(3*(s1*s2*s3)^(2/3) ) + // dE_conf/ds1 = (-2*(s2*s3)*(s2^2+s3^2 -2*s1^2) ) / (9*(s1*s2*s3)^(5/3)) + // Argmin E_conf(s1): s1 = sqrt(s1^2+s2^2)/sqrt(2) + double common_div = 9 * (pow(s1 * s2 * s3, 5. / 3.)); + + double s1_g = (-2 * s2 * s3 * (pow(s2, 2) + pow(s3, 2) - 2 * pow(s1, 2))) / common_div; + double s2_g = (-2 * s1 * s3 * (pow(s1, 2) + pow(s3, 2) - 2 * pow(s2, 2))) / common_div; + double s3_g = (-2 * s1 * s2 * (pow(s1, 2) + pow(s2, 2) - 2 * pow(s3, 2))) / common_div; + + double in_exp = exp_f * ((pow(s1, 2) + pow(s2, 2) + pow(s3, 2)) / (3 * pow((s1 * s2 * s3), 2. / 3)));; + double exp_thing = exp(in_exp); + + double closest_s = sqrt(pow(s1, 2) + pow(s3, 2)) / sqrt_2; + double s1_min = closest_s; + double s2_min = closest_s; + double s3_min = closest_s; + + s1_g *= exp_thing * exp_f; + s2_g *= exp_thing * exp_f; + s3_g *= exp_thing * exp_f; + + m_sing_new << sqrt(s1_g / (2 * (s1 - s1_min))), sqrt(s2_g / (2 * (s2 - s2_min))), sqrt( + s3_g / (2 * (s3 - s3_min))); + + // change local step + closest_sing_vec << s1_min, s2_min, s3_min; + ri = ui * closest_sing_vec.asDiagonal() * vi.transpose(); + break; + } + default: assert(false); + } + if (std::abs(s1 - 1) < eps) m_sing_new(0) = 1; + if (std::abs(s2 - 1) < eps) m_sing_new(1) = 1; + if (std::abs(s3 - 1) < eps) m_sing_new(2) = 1; + RMat3 mat_W; + mat_W = ui * m_sing_new.asDiagonal() * ui.transpose(); + + W.row(i) = Eigen::Map>(mat_W.data()); + // 2) Update closest rotations (not rotations in case of conformal energy) + Ri.row(i) = Eigen::Map>(ri.data()); + } // for loop end + + } // if dim end + +} + +IGL_INLINE void igl::slim_buildA(const Eigen::SparseMatrix &Dx, + const Eigen::SparseMatrix &Dy, + const Eigen::SparseMatrix &Dz, + const Eigen::MatrixXd &W, +std::vector > & IJV) +{ + const int dim = (W.cols() == 4) ? 2 : 3; + const int f_n = W.rows(); + const int v_n = Dx.cols(); + + // formula (35) in paper + if (dim == 2) + { + IJV.reserve(4 * (Dx.outerSize() + Dy.outerSize())); + + /*A = [W11*Dx, W12*Dx; + W11*Dy, W12*Dy; + W21*Dx, W22*Dx; + W21*Dy, W22*Dy];*/ + for (int k = 0; k < Dx.outerSize(); ++k) + { + for (Eigen::SparseMatrix::InnerIterator it(Dx, k); it; ++it) + { + int dx_r = it.row(); + int dx_c = it.col(); + double val = it.value(); + + IJV.push_back(Eigen::Triplet(dx_r, dx_c, val * W(dx_r, 0))); + IJV.push_back(Eigen::Triplet(dx_r, v_n + dx_c, val * W(dx_r, 1))); + + IJV.push_back(Eigen::Triplet(2 * f_n + dx_r, dx_c, val * W(dx_r, 2))); + IJV.push_back(Eigen::Triplet(2 * f_n + dx_r, v_n + dx_c, val * W(dx_r, 3))); + } + } + + for (int k = 0; k < Dy.outerSize(); ++k) + { + for (Eigen::SparseMatrix::InnerIterator it(Dy, k); it; ++it) + { + int dy_r = it.row(); + int dy_c = it.col(); + double val = it.value(); + + IJV.push_back(Eigen::Triplet(f_n + dy_r, dy_c, val * W(dy_r, 0))); + IJV.push_back(Eigen::Triplet(f_n + dy_r, v_n + dy_c, val * W(dy_r, 1))); + + IJV.push_back(Eigen::Triplet(3 * f_n + dy_r, dy_c, val * W(dy_r, 2))); + IJV.push_back(Eigen::Triplet(3 * f_n + dy_r, v_n + dy_c, val * W(dy_r, 3))); + } + } + } + else + { + + /*A = [W11*Dx, W12*Dx, W13*Dx; + W11*Dy, W12*Dy, W13*Dy; + W11*Dz, W12*Dz, W13*Dz; + W21*Dx, W22*Dx, W23*Dx; + W21*Dy, W22*Dy, W23*Dy; + W21*Dz, W22*Dz, W23*Dz; + W31*Dx, W32*Dx, W33*Dx; + W31*Dy, W32*Dy, W33*Dy; + W31*Dz, W32*Dz, W33*Dz;];*/ + IJV.reserve(9 * (Dx.outerSize() + Dy.outerSize() + Dz.outerSize())); + for (int k = 0; k < Dx.outerSize(); k++) + { + for (Eigen::SparseMatrix::InnerIterator it(Dx, k); it; ++it) + { + int dx_r = it.row(); + int dx_c = it.col(); + double val = it.value(); + + IJV.push_back(Eigen::Triplet(dx_r, dx_c, val * W(dx_r, 0))); + IJV.push_back(Eigen::Triplet(dx_r, v_n + dx_c, val * W(dx_r, 1))); + IJV.push_back(Eigen::Triplet(dx_r, 2 * v_n + dx_c, val * W(dx_r, 2))); + + IJV.push_back(Eigen::Triplet(3 * f_n + dx_r, dx_c, val * W(dx_r, 3))); + IJV.push_back(Eigen::Triplet(3 * f_n + dx_r, v_n + dx_c, val * W(dx_r, 4))); + IJV.push_back(Eigen::Triplet(3 * f_n + dx_r, 2 * v_n + dx_c, val * W(dx_r, 5))); + + IJV.push_back(Eigen::Triplet(6 * f_n + dx_r, dx_c, val * W(dx_r, 6))); + IJV.push_back(Eigen::Triplet(6 * f_n + dx_r, v_n + dx_c, val * W(dx_r, 7))); + IJV.push_back(Eigen::Triplet(6 * f_n + dx_r, 2 * v_n + dx_c, val * W(dx_r, 8))); + } + } + + for (int k = 0; k < Dy.outerSize(); k++) + { + for (Eigen::SparseMatrix::InnerIterator it(Dy, k); it; ++it) + { + int dy_r = it.row(); + int dy_c = it.col(); + double val = it.value(); + + IJV.push_back(Eigen::Triplet(f_n + dy_r, dy_c, val * W(dy_r, 0))); + IJV.push_back(Eigen::Triplet(f_n + dy_r, v_n + dy_c, val * W(dy_r, 1))); + IJV.push_back(Eigen::Triplet(f_n + dy_r, 2 * v_n + dy_c, val * W(dy_r, 2))); + + IJV.push_back(Eigen::Triplet(4 * f_n + dy_r, dy_c, val * W(dy_r, 3))); + IJV.push_back(Eigen::Triplet(4 * f_n + dy_r, v_n + dy_c, val * W(dy_r, 4))); + IJV.push_back(Eigen::Triplet(4 * f_n + dy_r, 2 * v_n + dy_c, val * W(dy_r, 5))); + + IJV.push_back(Eigen::Triplet(7 * f_n + dy_r, dy_c, val * W(dy_r, 6))); + IJV.push_back(Eigen::Triplet(7 * f_n + dy_r, v_n + dy_c, val * W(dy_r, 7))); + IJV.push_back(Eigen::Triplet(7 * f_n + dy_r, 2 * v_n + dy_c, val * W(dy_r, 8))); + } + } + + for (int k = 0; k < Dz.outerSize(); k++) + { + for (Eigen::SparseMatrix::InnerIterator it(Dz, k); it; ++it) + { + int dz_r = it.row(); + int dz_c = it.col(); + double val = it.value(); + + IJV.push_back(Eigen::Triplet(2 * f_n + dz_r, dz_c, val * W(dz_r, 0))); + IJV.push_back(Eigen::Triplet(2 * f_n + dz_r, v_n + dz_c, val * W(dz_r, 1))); + IJV.push_back(Eigen::Triplet(2 * f_n + dz_r, 2 * v_n + dz_c, val * W(dz_r, 2))); + + IJV.push_back(Eigen::Triplet(5 * f_n + dz_r, dz_c, val * W(dz_r, 3))); + IJV.push_back(Eigen::Triplet(5 * f_n + dz_r, v_n + dz_c, val * W(dz_r, 4))); + IJV.push_back(Eigen::Triplet(5 * f_n + dz_r, 2 * v_n + dz_c, val * W(dz_r, 5))); + + IJV.push_back(Eigen::Triplet(8 * f_n + dz_r, dz_c, val * W(dz_r, 6))); + IJV.push_back(Eigen::Triplet(8 * f_n + dz_r, v_n + dz_c, val * W(dz_r, 7))); + IJV.push_back(Eigen::Triplet(8 * f_n + dz_r, 2 * v_n + dz_c, val * W(dz_r, 8))); + } + } + } +} +/// Slim Implementation + +IGL_INLINE void igl::slim_precompute( + const Eigen::MatrixXd &V, + const Eigen::MatrixXi &F, + const Eigen::MatrixXd &V_init, + igl::SLIMData &data, + igl::MappingEnergyType slim_energy, + const Eigen::VectorXi &b, + const Eigen::MatrixXd &bc, + double soft_p) +{ + + data.V = V; + data.F = F; + data.V_o = V_init; + + data.v_num = V.rows(); + data.f_num = F.rows(); + + data.slim_energy = slim_energy; + + data.b = b; + data.bc = bc; + data.soft_const_p = soft_p; + + data.proximal_p = 0.0001; + + igl::doublearea(V, F, data.M); + data.M /= 2.; + data.mesh_area = data.M.sum(); + data.mesh_improvement_3d = false; // whether to use a jacobian derived from a real mesh or an abstract regular mesh (used for mesh improvement) + data.exp_factor = 1.0; // param used only for exponential energies (e.g exponential symmetric dirichlet) + + assert (F.cols() == 3 || F.cols() == 4); + + igl::slim::pre_calc(data); + data.energy = igl::slim::compute_energy(data,data.V_o) / data.mesh_area; +} + +IGL_INLINE Eigen::MatrixXd igl::slim_solve(igl::SLIMData &data, int iter_num) +{ + for (int i = 0; i < iter_num; i++) + { + Eigen::MatrixXd dest_res; + dest_res = data.V_o; + + // Solve Weighted Proxy + igl::slim::update_weights_and_closest_rotations(data, dest_res); + igl::slim::solve_weighted_arap(data,data.V, data.F, dest_res, data.b, data.bc); + + double old_energy = data.energy; + + std::function compute_energy = [&]( + Eigen::MatrixXd &aaa) { return igl::slim::compute_energy(data,aaa); }; + + data.energy = igl::flip_avoiding_line_search(data.F, data.V_o, dest_res, compute_energy, + data.energy * data.mesh_area) / data.mesh_area; + } + return data.V_o; +} + + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +#endif diff --git a/src/external/libigl-2.3.0/include/igl/slim.h b/src/external/libigl-2.3.0/include/igl/slim.h new file mode 100644 index 000000000..5661ec63a --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/slim.h @@ -0,0 +1,115 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Michael Rabinovich +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef SLIM_H +#define SLIM_H + +#include "igl_inline.h" +#include "MappingEnergyType.h" +#include +#include + +// This option makes the iterations faster (all except the first) by caching the +// sparsity pattern of the matrix involved in the assembly. It should be on if you plan to do many iterations, off if you have to change the matrix structure at every iteration. +#define SLIM_CACHED + +#ifdef SLIM_CACHED +#include +#endif + +namespace igl +{ + +// Compute a SLIM map as derived in "Scalable Locally Injective Maps" [Rabinovich et al. 2016]. +struct SLIMData +{ + // Input + Eigen::MatrixXd V; // #V by 3 list of mesh vertex positions + Eigen::MatrixXi F; // #F by 3/3 list of mesh faces (triangles/tets) + MappingEnergyType slim_energy; + + // Optional Input + // soft constraints + Eigen::VectorXi b; + Eigen::MatrixXd bc; + double soft_const_p; + + double exp_factor; // used for exponential energies, ignored otherwise + bool mesh_improvement_3d; // only supported for 3d + + // Output + Eigen::MatrixXd V_o; // #V by dim list of mesh vertex positions (dim = 2 for parametrization, 3 otherwise) + double energy; // objective value + + // INTERNAL + Eigen::VectorXd M; + double mesh_area; + double avg_edge_length; + int v_num; + int f_num; + double proximal_p; + + Eigen::VectorXd WGL_M; + Eigen::VectorXd rhs; + Eigen::MatrixXd Ri,Ji; + Eigen::MatrixXd W; + Eigen::SparseMatrix Dx,Dy,Dz; + int f_n,v_n; + bool first_solve; + bool has_pre_calc = false; + int dim; + + #ifdef SLIM_CACHED + Eigen::SparseMatrix A; + Eigen::VectorXi A_data; + Eigen::SparseMatrix AtA; + igl::AtA_cached_data AtA_data; + #endif +}; + +// Compute necessary information to start using SLIM +// Inputs: +// V #V by 3 list of mesh vertex positions +// F #F by 3/3 list of mesh faces (triangles/tets) +// b list of boundary indices into V +// bc #b by dim list of boundary conditions +// soft_p Soft penalty factor (can be zero) +// slim_energy Energy to minimize +IGL_INLINE void slim_precompute( + const Eigen::MatrixXd& V, + const Eigen::MatrixXi& F, + const Eigen::MatrixXd& V_init, + SLIMData& data, + MappingEnergyType slim_energy, + const Eigen::VectorXi& b, + const Eigen::MatrixXd& bc, + double soft_p); + +// Run iter_num iterations of SLIM +// Outputs: +// V_o (in SLIMData): #V by dim list of mesh vertex positions +IGL_INLINE Eigen::MatrixXd slim_solve(SLIMData& data, int iter_num); + +// Internal Routine. Exposed for Integration with SCAF +IGL_INLINE void slim_update_weights_and_closest_rotations_with_jacobians(const Eigen::MatrixXd &Ji, + igl::MappingEnergyType slim_energy, + double exp_factor, + Eigen::MatrixXd &W, + Eigen::MatrixXd &Ri); + +IGL_INLINE void slim_buildA(const Eigen::SparseMatrix &Dx, + const Eigen::SparseMatrix &Dy, + const Eigen::SparseMatrix &Dz, + const Eigen::MatrixXd &W, + std::vector > & IJV); +} // END NAMESPACE + +#ifndef IGL_STATIC_LIBRARY +# include "slim.cpp" +#endif + +#endif // SLIM_H diff --git a/src/external/libigl-2.3.0/include/igl/snap_points.cpp b/src/external/libigl-2.3.0/include/igl/snap_points.cpp new file mode 100644 index 000000000..3e586aa00 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/snap_points.cpp @@ -0,0 +1,90 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "snap_points.h" +#include +#include + +template < + typename DerivedC, + typename DerivedV, + typename DerivedI, + typename DerivedminD, + typename DerivedVI> +IGL_INLINE void igl::snap_points( + const Eigen::MatrixBase & C, + const Eigen::MatrixBase & V, + Eigen::PlainObjectBase & I, + Eigen::PlainObjectBase & minD, + Eigen::PlainObjectBase & VI) +{ + snap_points(C,V,I,minD); + const int m = C.rows(); + VI.resize(m,V.cols()); + for(int c = 0;c +IGL_INLINE void igl::snap_points( + const Eigen::MatrixBase & C, + const Eigen::MatrixBase & V, + Eigen::PlainObjectBase & I, + Eigen::PlainObjectBase & minD) +{ + using namespace std; + const int n = V.rows(); + const int m = C.rows(); + assert(V.cols() == C.cols() && "Dimensions should match"); + // O(m*n) + // + // I believe there should be a way to do this in O(m*log(n) + n) assuming + // reasonably distubed points. + I.resize(m,1); + typedef typename DerivedV::Scalar Scalar; + minD.setConstant(m,1,numeric_limits::max()); + for(int v = 0;v +IGL_INLINE void igl::snap_points( + const Eigen::MatrixBase & C, + const Eigen::MatrixBase & V, + Eigen::PlainObjectBase & I) +{ + Eigen::Matrix minD; + return igl::snap_points(C,V,I,minD); +} + + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +template void igl::snap_points, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::snap_points, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::snap_points, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/snap_points.h b/src/external/libigl-2.3.0/include/igl/snap_points.h new file mode 100644 index 000000000..21ad448b5 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/snap_points.h @@ -0,0 +1,67 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_SNAP_POINTS_H +#define IGL_SNAP_POINTS_H + +#include "igl_inline.h" +#include + +namespace igl +{ + // SNAP_POINTS snap list of points C to closest of another list of points V + // + // [I,minD,VI] = snap_points(C,V) + // + // Inputs: + // C #C by dim list of query point positions + // V #V by dim list of data point positions + // Outputs: + // I #C list of indices into V of closest points to C + // minD #C list of squared (^p) distances to closest points + // VI #C by dim list of new point positions, VI = V(I,:) + template < + typename DerivedC, + typename DerivedV, + typename DerivedI, + typename DerivedminD, + typename DerivedVI> + IGL_INLINE void snap_points( + const Eigen::MatrixBase & C, + const Eigen::MatrixBase & V, + Eigen::PlainObjectBase & I, + Eigen::PlainObjectBase & minD, + Eigen::PlainObjectBase & VI); + template < + typename DerivedC, + typename DerivedV, + typename DerivedI, + typename DerivedminD> + IGL_INLINE void snap_points( + const Eigen::MatrixBase & C, + const Eigen::MatrixBase & V, + Eigen::PlainObjectBase & I, + Eigen::PlainObjectBase & minD); + template < + typename DerivedC, + typename DerivedV, + typename DerivedI > + IGL_INLINE void snap_points( + const Eigen::MatrixBase & C, + const Eigen::MatrixBase & V, + Eigen::PlainObjectBase & I); +} + +#ifndef IGL_STATIC_LIBRARY +# include "snap_points.cpp" +#endif + +#endif + + + + diff --git a/src/external/libigl-2.3.0/include/igl/snap_to_canonical_view_quat.cpp b/src/external/libigl-2.3.0/include/igl/snap_to_canonical_view_quat.cpp new file mode 100644 index 000000000..9fb01724c --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/snap_to_canonical_view_quat.cpp @@ -0,0 +1,117 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "snap_to_canonical_view_quat.h" + +#include "canonical_quaternions.h" +#include "normalize_quat.h" + +#include +#include + +// Note: For the canonical view quaternions it should be completely possible to +// determine this anaylitcally. That is the max_distance should be a +// theoretical known value +// Also: I'm not sure it matters in this case, but. We are dealing with +// quaternions on the 4d unit sphere, but measuring distance in general 4d +// space (i.e. not geodesics on the sphere). Probably something with angles +// would be better. +template +IGL_INLINE bool igl::snap_to_canonical_view_quat( + const Q_type* q, + const Q_type threshold, + Q_type* s) +{ + // Copy input into output + // CANNOT use std::copy here according to: + // http://www.cplusplus.com/reference/algorithm/copy/ + s[0] = q[0]; + s[1] = q[1]; + s[2] = q[2]; + s[3] = q[3]; + + // Normalize input quaternion + Q_type qn[4]; + bool valid_len = + igl::normalize_quat(q,qn); + // If normalizing valid then don't bother + if(!valid_len) + { + return false; + } + + // 0.290019 + const Q_type MAX_DISTANCE = 0.4; + Q_type min_distance = 2*MAX_DISTANCE; + int min_index = -1; + double min_sign = 0; + // loop over canonical view quaternions + for(double sign = -1;sign<=1;sign+=2) + { + for(int i = 0; i(i,j))* + (qn[j]-sign*igl::CANONICAL_VIEW_QUAT(i,j)); + } + if(min_distance > distance) + { + min_distance = distance; + min_index = i; + min_sign = sign; + } + } + } + + if(MAX_DISTANCE < min_distance) + { + fprintf( + stderr, + "ERROR: found new max MIN_DISTANCE: %g\n" + "PLEASE update snap_to_canonical_quat()", + min_distance); + } + + assert(min_distance < MAX_DISTANCE); + assert(min_index >= 0); + + if( min_distance/MAX_DISTANCE <= threshold) + { + // loop over coordinates + for(int j = 0;j<4;j++) + { + s[j] = min_sign*igl::CANONICAL_VIEW_QUAT(min_index,j); + } + return true; + } + return false; +} + +template +IGL_INLINE bool igl::snap_to_canonical_view_quat( + const Eigen::Quaternion & q, + const double threshold, + Eigen::Quaternion & s) +{ + return snap_to_canonical_view_quat( + q.coeffs().data(),threshold,s.coeffs().data()); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template bool igl::snap_to_canonical_view_quat(const double*, double, double*); +// generated by autoexplicit.sh +template bool igl::snap_to_canonical_view_quat(const float*, float, float*); +template bool igl::snap_to_canonical_view_quat(Eigen::Quaternion const&, double, Eigen::Quaternion&); +template bool igl::snap_to_canonical_view_quat(Eigen::Quaternion const&, double, Eigen::Quaternion&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/snap_to_canonical_view_quat.h b/src/external/libigl-2.3.0/include/igl/snap_to_canonical_view_quat.h new file mode 100644 index 000000000..79bc3e024 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/snap_to_canonical_view_quat.h @@ -0,0 +1,44 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_SNAP_TO_CANONICAL_VIEW_QUAT_H +#define IGL_SNAP_TO_CANONICAL_VIEW_QUAT_H +#include "igl_inline.h" +#include +// A Quaternion, q, is defined here as an arrays of four scalars (x,y,z,w), +// such that q = x*i + y*j + z*k + w +namespace igl +{ + // Snap the quaternion q to the nearest canonical view quaternion + // Input: + // q quaternion to be snapped (also see Outputs) + // threshold (optional) threshold: + // 1.0 --> snap any input + // 0.5 --> snap inputs somewhat close to canonical views + // 0.0 --> snap no input + // Output: + // q quaternion possibly set to nearest canonical view + // Return: + // true only if q was snapped to the nearest canonical view + template + IGL_INLINE bool snap_to_canonical_view_quat( + const Q_type* q, + const Q_type threshold, + Q_type* s); + + template + IGL_INLINE bool snap_to_canonical_view_quat( + const Eigen::Quaternion & q, + const double threshold, + Eigen::Quaternion & s); +} + +#ifndef IGL_STATIC_LIBRARY +# include "snap_to_canonical_view_quat.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/snap_to_fixed_up.cpp b/src/external/libigl-2.3.0/include/igl/snap_to_fixed_up.cpp new file mode 100644 index 000000000..f0fdd7de8 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/snap_to_fixed_up.cpp @@ -0,0 +1,33 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "snap_to_fixed_up.h" + +template +IGL_INLINE void igl::snap_to_fixed_up( + const Eigen::Quaternion & q, + Eigen::Quaternion & s) +{ + using namespace Eigen; + typedef Eigen::Matrix Vector3Q; + const Vector3Q up = q.matrix() * Vector3Q(0,1,0); + Vector3Q proj_up(0,up(1),up(2)); + if(proj_up.norm() == 0) + { + proj_up = Vector3Q(0,1,0); + } + proj_up.normalize(); + Quaternion dq; + dq = Quaternion::FromTwoVectors(up,proj_up); + s = dq * q; +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiations +template void igl::snap_to_fixed_up(Eigen::Quaternion const&, Eigen::Quaternion&); +template void igl::snap_to_fixed_up(Eigen::Quaternion const&, Eigen::Quaternion&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/snap_to_fixed_up.h b/src/external/libigl-2.3.0/include/igl/snap_to_fixed_up.h new file mode 100644 index 000000000..4276fa79c --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/snap_to_fixed_up.h @@ -0,0 +1,39 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_SNAP_TO_FIXED_UP_H +#define IGL_SNAP_TO_FIXED_UP_H + +#include "igl_inline.h" +#include +#include + +namespace igl +{ + // Snap an arbitrary rotation to a rotation resulting from a rotation about + // the y-axis then the x-axis (maintaining fixed up like + // two_axis_valuator_fixed_up.) + // + // Inputs: + // q General rotation as quaternion + // Outputs: + // s the resulting rotation (as quaternion) + // + // See also: two_axis_valuator_fixed_up + template + IGL_INLINE void snap_to_fixed_up( + const Eigen::Quaternion & q, + Eigen::Quaternion & s); +} + +#ifndef IGL_STATIC_LIBRARY +# include "snap_to_fixed_up.cpp" +#endif + +#endif + + diff --git a/src/external/libigl-2.3.0/include/igl/solid_angle.cpp b/src/external/libigl-2.3.0/include/igl/solid_angle.cpp new file mode 100644 index 000000000..d0b296a70 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/solid_angle.cpp @@ -0,0 +1,85 @@ +#include "solid_angle.h" +#include "PI.h" +#include + +template < + typename DerivedA, + typename DerivedB, + typename DerivedC, + typename DerivedP> +IGL_INLINE typename DerivedA::Scalar igl::solid_angle( + const Eigen::MatrixBase & A, + const Eigen::MatrixBase & B, + const Eigen::MatrixBase & C, + const Eigen::MatrixBase & P) +{ + typedef typename DerivedA::Scalar SType; + // Gather vectors to corners + Eigen::Matrix v; + // Don't use this since it will freak out for templates with != 3 size + //v<< (A-P),(B-P),(C-P); + for(int d = 0;d<3;d++) + { + v(0,d) = A(d)-P(d); + v(1,d) = B(d)-P(d); + v(2,d) = C(d)-P(d); + } + Eigen::Matrix vl = v.rowwise().norm(); + //printf("\n"); + // Compute determinant + SType detf = + v(0,0)*v(1,1)*v(2,2)+ + v(1,0)*v(2,1)*v(0,2)+ + v(2,0)*v(0,1)*v(1,2)- + v(2,0)*v(1,1)*v(0,2)- + v(1,0)*v(0,1)*v(2,2)- + v(0,0)*v(2,1)*v(1,2); + // Compute pairwise dotproducts + Eigen::Matrix dp; + dp(0) = v(1,0)*v(2,0); + dp(0) += v(1,1)*v(2,1); + dp(0) += v(1,2)*v(2,2); + dp(1) = v(2,0)*v(0,0); + dp(1) += v(2,1)*v(0,1); + dp(1) += v(2,2)*v(0,2); + dp(2) = v(0,0)*v(1,0); + dp(2) += v(0,1)*v(1,1); + dp(2) += v(0,2)*v(1,2); + // Compute winding number + // Only divide by TWO_PI instead of 4*pi because there was a 2 out front + return atan2(detf, + vl(0)*vl(1)*vl(2) + + dp(0)*vl(0) + + dp(1)*vl(1) + + dp(2)*vl(2)) / (2.*igl::PI); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template Eigen::Block const, 1, 2, false>::Scalar igl::solid_angle const, 1, 2, false>, Eigen::Block const, 1, 2, false>, Eigen::Block const, 1, 2, false>, Eigen::Matrix >(Eigen::MatrixBase const, 1, 2, false> > const&, Eigen::MatrixBase const, 1, 2, false> > const&, Eigen::MatrixBase const, 1, 2, false> > const&, Eigen::MatrixBase > const&); +// generated by autoexplicit.sh +template Eigen::Block const, 1, 2, false>::Scalar igl::solid_angle const, 1, 2, false>, Eigen::Block const, 1, 2, false>, Eigen::Block const, 1, 2, false>, Eigen::Block const, 1, -1, false> >(Eigen::MatrixBase const, 1, 2, false> > const&, Eigen::MatrixBase const, 1, 2, false> > const&, Eigen::MatrixBase const, 1, 2, false> > const&, Eigen::MatrixBase const, 1, -1, false> > const&); +// generated by autoexplicit.sh +template Eigen::Block const, 1, 3, true>::Scalar igl::solid_angle const, 1, 3, true>, Eigen::Block const, 1, 3, true>, Eigen::Block const, 1, 3, true>, Eigen::Matrix >(Eigen::MatrixBase const, 1, 3, true> > const&, Eigen::MatrixBase const, 1, 3, true> > const&, Eigen::MatrixBase const, 1, 3, true> > const&, Eigen::MatrixBase > const&); +// generated by autoexplicit.sh +template Eigen::Block const, 1, 3, true>::Scalar igl::solid_angle const, 1, 3, true>, Eigen::Block const, 1, 3, true>, Eigen::Block const, 1, 3, true>, Eigen::Matrix >(Eigen::MatrixBase const, 1, 3, true> > const&, Eigen::MatrixBase const, 1, 3, true> > const&, Eigen::MatrixBase const, 1, 3, true> > const&, Eigen::MatrixBase > const&); +// generated by autoexplicit.sh +template Eigen::Block const, 1, -1, false>::Scalar igl::solid_angle const, 1, -1, false>, Eigen::Block const, 1, -1, false>, Eigen::Block const, 1, -1, false>, Eigen::Matrix >(Eigen::MatrixBase const, 1, -1, false> > const&, Eigen::MatrixBase const, 1, -1, false> > const&, Eigen::MatrixBase const, 1, -1, false> > const&, Eigen::MatrixBase > const&); +// generated by autoexplicit.sh +template Eigen::Block const, 1, 3, true>::Scalar igl::solid_angle const, 1, 3, true>, Eigen::Block const, 1, 3, true>, Eigen::Block const, 1, 3, true>, Eigen::Matrix >(Eigen::MatrixBase const, 1, 3, true> > const&, Eigen::MatrixBase const, 1, 3, true> > const&, Eigen::MatrixBase const, 1, 3, true> > const&, Eigen::MatrixBase > const&); +// generated by autoexplicit.sh +template Eigen::Block const, 1, 3, true>::Scalar igl::solid_angle const, 1, 3, true>, Eigen::Block const, 1, 3, true>, Eigen::Block const, 1, 3, true>, Eigen::Matrix >(Eigen::MatrixBase const, 1, 3, true> > const&, Eigen::MatrixBase const, 1, 3, true> > const&, Eigen::MatrixBase const, 1, 3, true> > const&, Eigen::MatrixBase > const&); +// generated by autoexplicit.sh +template Eigen::Block const, 1, 3, false>::Scalar igl::solid_angle const, 1, 3, false>, Eigen::Block const, 1, 3, false>, Eigen::Block const, 1, 3, false>, Eigen::Matrix >(Eigen::MatrixBase const, 1, 3, false> > const&, Eigen::MatrixBase const, 1, 3, false> > const&, Eigen::MatrixBase const, 1, 3, false> > const&, Eigen::MatrixBase > const&); +// generated by autoexplicit.sh +template Eigen::Block const, 1, 3, false>::Scalar igl::solid_angle const, 1, 3, false>, Eigen::Block const, 1, 3, false>, Eigen::Block const, 1, 3, false>, Eigen::Matrix >(Eigen::MatrixBase const, 1, 3, false> > const&, Eigen::MatrixBase const, 1, 3, false> > const&, Eigen::MatrixBase const, 1, 3, false> > const&, Eigen::MatrixBase > const&); +// generated by autoexplicit.sh +template Eigen::Block const, 1, -1, false>::Scalar igl::solid_angle const, 1, -1, false>, Eigen::Block const, 1, -1, false>, Eigen::Block const, 1, -1, false>, Eigen::Block const, 1, -1, false> >(Eigen::MatrixBase const, 1, -1, false> > const&, Eigen::MatrixBase const, 1, -1, false> > const&, Eigen::MatrixBase const, 1, -1, false> > const&, Eigen::MatrixBase const, 1, -1, false> > const&); +// generated by autoexplicit.sh +template Eigen::Block const, 1, -1, false>::Scalar igl::solid_angle const, 1, -1, false>, Eigen::Block const, 1, -1, false>, Eigen::Block const, 1, -1, false>, Eigen::Matrix >(Eigen::MatrixBase const, 1, -1, false> > const&, Eigen::MatrixBase const, 1, -1, false> > const&, Eigen::MatrixBase const, 1, -1, false> > const&, Eigen::MatrixBase > const&); +// generated by autoexplicit.sh +template Eigen::Block const, 1, -1, false>::Scalar igl::solid_angle const, 1, -1, false>, Eigen::Block const, 1, -1, false>, Eigen::Block const, 1, -1, false>, Eigen::Matrix >(Eigen::MatrixBase const, 1, -1, false> > const&, Eigen::MatrixBase const, 1, -1, false> > const&, Eigen::MatrixBase const, 1, -1, false> > const&, Eigen::MatrixBase > const&); +// generated by autoexplicit.sh +template Eigen::Block const, 1, -1, false>::Scalar igl::solid_angle const, 1, -1, false>, Eigen::Block const, 1, -1, false>, Eigen::Block const, 1, -1, false>, Eigen::Matrix >(Eigen::MatrixBase const, 1, -1, false> > const&, Eigen::MatrixBase const, 1, -1, false> > const&, Eigen::MatrixBase const, 1, -1, false> > const&, Eigen::MatrixBase > const&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/solid_angle.h b/src/external/libigl-2.3.0/include/igl/solid_angle.h new file mode 100644 index 000000000..2ee98a247 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/solid_angle.h @@ -0,0 +1,29 @@ +#ifndef IGL_SOLID_ANGLE_H +#define IGL_SOLID_ANGLE_H +#include "igl_inline.h" +#include +namespace igl +{ + // Compute the signed solid angle subtended by the oriented 3d triangle (A,B,C) at some point P + // + // Inputs: + // A 3D position of corner + // B 3D position of corner + // C 3D position of corner + // P 3D position of query point + // Returns signed solid angle + template < + typename DerivedA, + typename DerivedB, + typename DerivedC, + typename DerivedP> + IGL_INLINE typename DerivedA::Scalar solid_angle( + const Eigen::MatrixBase & A, + const Eigen::MatrixBase & B, + const Eigen::MatrixBase & C, + const Eigen::MatrixBase & P); +} +#ifndef IGL_STATIC_LIBRARY +# include "solid_angle.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/sort.cpp b/src/external/libigl-2.3.0/include/igl/sort.cpp new file mode 100644 index 000000000..13c407fc1 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/sort.cpp @@ -0,0 +1,384 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "sort.h" + +#include "SortableRow.h" +#include "reorder.h" +#include "IndexComparison.h" +#include "colon.h" +#include "parallel_for.h" + +#include +#include +#include + +template +IGL_INLINE void igl::sort( + const Eigen::DenseBase& X, + const int dim, + const bool ascending, + Eigen::PlainObjectBase& Y, + Eigen::PlainObjectBase& IX) +{ + typedef typename DerivedX::Scalar Scalar; + // get number of rows (or columns) + int num_inner = (dim == 1 ? X.rows() : X.cols() ); + // Special case for swapping + switch(num_inner) + { + default: + break; + case 2: + return igl::sort2(X,dim,ascending,Y,IX); + case 3: + return igl::sort3(X,dim,ascending,Y,IX); + } + using namespace Eigen; + // get number of columns (or rows) + int num_outer = (dim == 1 ? X.cols() : X.rows() ); + // dim must be 2 or 1 + assert(dim == 1 || dim == 2); + // Resize output + Y.resizeLike(X); + IX.resizeLike(X); + // idea is to process each column (or row) as a std vector + // loop over columns (or rows) + for(int i = 0; i index_map(num_inner); + std::vector data(num_inner); + for(int j = 0;j +IGL_INLINE void igl::sort( + const Eigen::DenseBase& X, + const int dim, + const bool ascending, + Eigen::PlainObjectBase& Y) +{ + Eigen::Matrix< int, DerivedX::RowsAtCompileTime, DerivedX::ColsAtCompileTime > IX; + return sort(X,dim,ascending,Y,IX); +} + +template +IGL_INLINE void igl::sort_new( + const Eigen::DenseBase& X, + const int dim, + const bool ascending, + Eigen::PlainObjectBase& Y, + Eigen::PlainObjectBase& IX) +{ + // get number of rows (or columns) + int num_inner = (dim == 1 ? X.rows() : X.cols() ); + // Special case for swapping + switch(num_inner) + { + default: + break; + case 2: + return igl::sort2(X,dim,ascending,Y,IX); + case 3: + return igl::sort3(X,dim,ascending,Y,IX); + } + using namespace Eigen; + // get number of columns (or rows) + int num_outer = (dim == 1 ? X.cols() : X.rows() ); + // dim must be 2 or 1 + assert(dim == 1 || dim == 2); + // Resize output + Y.resizeLike(X); + IX.resizeLike(X); + // idea is to process each column (or row) as a std vector + // loop over columns (or rows) + for(int i = 0; i(X.col(i))); + }else + { + std::sort( + ix.data(), + ix.data()+ix.size(), + igl::IndexVectorLessThan(X.row(i))); + } + // if not ascending then reverse + if(!ascending) + { + std::reverse(ix.data(),ix.data()+ix.size()); + } + for(int j = 0;j +IGL_INLINE void igl::sort2( + const Eigen::DenseBase& X, + const int dim, + const bool ascending, + Eigen::PlainObjectBase& Y, + Eigen::PlainObjectBase& IX) +{ + using namespace Eigen; + using namespace std; + typedef typename DerivedY::Scalar YScalar; + Y = X.derived().template cast(); + + + // get number of columns (or rows) + int num_outer = (dim == 1 ? X.cols() : X.rows() ); + // get number of rows (or columns) + int num_inner = (dim == 1 ? X.rows() : X.cols() ); + assert(num_inner == 2);(void)num_inner; + typedef typename DerivedIX::Scalar Index; + IX.resizeLike(X); + if(dim==1) + { + IX.row(0).setConstant(0);// = DerivedIX::Zero(1,IX.cols()); + IX.row(1).setConstant(1);// = DerivedIX::Ones (1,IX.cols()); + }else + { + IX.col(0).setConstant(0);// = DerivedIX::Zero(IX.rows(),1); + IX.col(1).setConstant(1);// = DerivedIX::Ones (IX.rows(),1); + } + // loop over columns (or rows) + for(int i = 0;ib) || (!ascending && a +IGL_INLINE void igl::sort3( + const Eigen::DenseBase& X, + const int dim, + const bool ascending, + Eigen::PlainObjectBase& Y, + Eigen::PlainObjectBase& IX) +{ + using namespace Eigen; + using namespace std; + typedef typename DerivedY::Scalar YScalar; + Y = X.derived().template cast(); + Y.resizeLike(X); + for(int j=0;j b) + { + std::swap(a,b); + std::swap(ai,bi); + } + // 123 132 123 231 132 231 + if(b > c) + { + std::swap(b,c); + std::swap(bi,ci); + // 123 123 123 213 123 213 + if(a > b) + { + std::swap(a,b); + std::swap(ai,bi); + } + // 123 123 123 123 123 123 + } + }else + { + // 123 132 213 231 312 321 + if(a < b) + { + std::swap(a,b); + std::swap(ai,bi); + } + // 213 312 213 321 312 321 + if(b < c) + { + std::swap(b,c); + std::swap(bi,ci); + // 231 321 231 321 321 321 + if(a < b) + { + std::swap(a,b); + std::swap(ai,bi); + } + // 321 321 321 321 321 321 + } + } + }; + parallel_for(num_outer,inner,16000); +} + +template +IGL_INLINE void igl::sort( +const std::vector & unsorted, +const bool ascending, +std::vector & sorted, +std::vector & index_map) +{ +// Original unsorted index map +index_map.resize(unsorted.size()); +for(size_t i=0;i& >(unsorted)); + +// if not ascending then reverse +if(!ascending) +{ + std::reverse(index_map.begin(),index_map.end()); +} + // make space for output without clobbering + sorted.resize(unsorted.size()); + // reorder unsorted into sorted using index map + igl::reorder(unsorted,index_map,sorted); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::sort, Eigen::Matrix >(Eigen::DenseBase > const&, int, bool, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::sort, Eigen::Matrix, Eigen::Matrix >(Eigen::DenseBase > const&, int, bool, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::sort, Eigen::Matrix, Eigen::Matrix >(Eigen::DenseBase > const&, int, bool, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::sort, Eigen::Matrix >(Eigen::DenseBase > const&, int, bool, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::sort, 1, -1, false>, Eigen::Matrix >(Eigen::DenseBase, 1, -1, false> > const&, int, bool, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::sort, Eigen::Matrix >(Eigen::DenseBase > const&, int, bool, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::sort, Eigen::Matrix >(Eigen::DenseBase > const&, int, bool, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::sort, Eigen::Matrix >(Eigen::DenseBase > const&, int, bool, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::sort, Eigen::Matrix >(Eigen::DenseBase > const&, int, bool, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::sort, Eigen::Matrix, Eigen::Matrix >(Eigen::DenseBase > const&, int, bool, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::sort, Eigen::Matrix, Eigen::Matrix >(Eigen::DenseBase > const&, int, bool, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::sort, Eigen::Matrix, Eigen::Matrix >(Eigen::DenseBase > const&, int, bool, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::sort, Eigen::Matrix, Eigen::Matrix >(Eigen::DenseBase > const&, int, bool, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::sort, Eigen::Matrix, Eigen::Matrix >(Eigen::DenseBase > const&, int, bool, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::sort(std::vector > const&, bool, std::vector >&, std::vector > &); +template void igl::sort, Eigen::Matrix, Eigen::Matrix >(Eigen::DenseBase > const&, int, bool, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::sort, Eigen::Matrix, Eigen::Matrix >(Eigen::DenseBase > const&, int, bool, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::sort, Eigen::Matrix, Eigen::Matrix >(Eigen::DenseBase > const&, int, bool, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::sort, Eigen::Matrix, Eigen::Matrix >(Eigen::DenseBase > const&, int, bool, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::sort, Eigen::Matrix >(Eigen::DenseBase > const&, int, bool, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::sort, Eigen::Matrix, Eigen::Matrix >(Eigen::DenseBase > const&, int, bool, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::sort_new, Eigen::Matrix, Eigen::Matrix >(Eigen::DenseBase > const&, int, bool, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::sort, Eigen::Matrix >(Eigen::DenseBase > const&, int, bool, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::sort, Eigen::Matrix, Eigen::Matrix >(Eigen::DenseBase > const&, int, bool, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::sort, Eigen::Matrix, Eigen::Matrix >(Eigen::DenseBase > const&, int, bool, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::sort(std::vector > const&, bool, std::vector >&, std::vector >&); +template void igl::sort, Eigen::Matrix, Eigen::Matrix >(Eigen::DenseBase > const&, int, bool, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::sort, Eigen::Matrix, Eigen::Matrix >(Eigen::DenseBase > const&, int, bool, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::sort, Eigen::Matrix, Eigen::Matrix >(Eigen::DenseBase > const&, int, bool, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::sort, Eigen::Matrix, Eigen::Matrix >(Eigen::DenseBase > const&, int, bool, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::sort, Eigen::Matrix, Eigen::Matrix >(Eigen::DenseBase > const&, int, bool, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::sort, Eigen::Matrix, Eigen::Matrix >(Eigen::DenseBase > const&, int, bool, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::sort, Eigen::Matrix >(Eigen::DenseBase > const&, int, bool, Eigen::PlainObjectBase >&); +template void igl::sort, Eigen::Matrix, Eigen::Matrix >(Eigen::DenseBase > const&, int, bool, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::sort, Eigen::Matrix, Eigen::Matrix >(Eigen::DenseBase > const&, int, bool, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::sort, Eigen::Matrix, Eigen::Matrix >(Eigen::DenseBase > const&, int, bool, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::sort, Eigen::Matrix, Eigen::Matrix >(Eigen::DenseBase > const&, int, bool, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#ifdef WIN32 +template void igl::sort,class Eigen::Matrix,class Eigen::Matrix<__int64,-1,1,0,-1,1> >(class Eigen::DenseBase > const &,int,bool,class Eigen::PlainObjectBase > &,class Eigen::PlainObjectBase > &); +template void igl::sort<__int64>(class std::vector<__int64,class std::allocator<__int64> > const &,bool,class std::vector<__int64,class std::allocator<__int64> > &,class std::vector > &); +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/sort.h b/src/external/libigl-2.3.0/include/igl/sort.h new file mode 100644 index 000000000..a7d3e7ad9 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/sort.h @@ -0,0 +1,94 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_SORT_H +#define IGL_SORT_H +#include "igl_inline.h" + +#include +#include +namespace igl +{ + + // Sort the elements of a matrix X along a given dimension like matlabs sort + // function + // + // Templates: + // DerivedX derived scalar type, e.g. MatrixXi or MatrixXd + // DerivedIX derived integer type, e.g. MatrixXi + // Inputs: + // X m by n matrix whose entries are to be sorted + // dim dimensional along which to sort: + // 1 sort each column (matlab default) + // 2 sort each row + // ascending sort ascending (true, matlab default) or descending (false) + // Outputs: + // Y m by n matrix whose entries are sorted + // IX m by n matrix of indices so that if dim = 1, then in matlab notation + // for j = 1:n, Y(:,j) = X(I(:,j),j); end + template + IGL_INLINE void sort( + const Eigen::DenseBase& X, + const int dim, + const bool ascending, + Eigen::PlainObjectBase& Y, + Eigen::PlainObjectBase& IX); + template + IGL_INLINE void sort( + const Eigen::DenseBase& X, + const int dim, + const bool ascending, + Eigen::PlainObjectBase& Y); + template + // Only better if size(X,dim) is small + IGL_INLINE void sort_new( + const Eigen::DenseBase& X, + const int dim, + const bool ascending, + Eigen::PlainObjectBase& Y, + Eigen::PlainObjectBase& IX); + // Special case if size(X,dim) == 2 + template + IGL_INLINE void sort2( + const Eigen::DenseBase& X, + const int dim, + const bool ascending, + Eigen::PlainObjectBase& Y, + Eigen::PlainObjectBase& IX); + // Special case if size(X,dim) == 3 + template + IGL_INLINE void sort3( + const Eigen::DenseBase& X, + const int dim, + const bool ascending, + Eigen::PlainObjectBase& Y, + Eigen::PlainObjectBase& IX); + + + // Act like matlab's [Y,I] = SORT(X) for std library vectors + // Templates: + // T should be a class that implements the '<' comparator operator + // Input: + // unsorted unsorted vector + // ascending sort ascending (true, matlab default) or descending (false) + // Output: + // sorted sorted vector, allowed to be same as unsorted + // index_map an index map such that sorted[i] = unsorted[index_map[i]] + template + IGL_INLINE void sort( + const std::vector &unsorted, + const bool ascending, + std::vector &sorted, + std::vector &index_map); + +} + +#ifndef IGL_STATIC_LIBRARY +# include "sort.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/sort_angles.cpp b/src/external/libigl-2.3.0/include/igl/sort_angles.cpp new file mode 100644 index 000000000..a030eb006 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/sort_angles.cpp @@ -0,0 +1,114 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "sort_angles.h" +#include "LinSpaced.h" +#include + +template +IGL_INLINE void igl::sort_angles( + const Eigen::MatrixBase& M, + Eigen::PlainObjectBase& R) { + const size_t num_rows = M.rows(); + const size_t num_cols = M.cols(); + assert(num_cols >= 2); + + R.resize(num_rows); + // Have to use << instead of = because Eigen's PlainObjectBase is annoying + R << igl::LinSpaced< + Eigen::Matrix > + (num_rows, 0, num_rows-1); + + // | + // (pi/2, pi) | (0, pi/2) + // | + // -------------+-------------- + // | + // (-pi, -pi/2) | (-pi/2, 0) + // | + auto comp = [&](size_t i, size_t j) { + auto yi = M(i, 0); + auto xi = M(i, 1); + auto yj = M(j, 0); + auto xj = M(j, 1); + + if (xi == xj && yi == yj) { + for (size_t idx=2; idx= 0 && yi >= 0) { + if (xj >=0 && yj >= 0) { + if (xi != xj) { + return xi > xj; + } else { + return yi < yj; + } + } else if (xj < 0 && yj >= 0) { + return true; + } else if (xj < 0 && yj < 0) { + return false; + } else { + return false; + } + } else if (xi < 0 && yi >= 0) { + if (xj >= 0 && yj >= 0) { + return false; + } else if (xj < 0 && yj >= 0) { + if (xi != xj) { + return xi > xj; + } else { + return yi > yj; + } + } else if (xj < 0 && yj < 0) { + return false; + } else { + return false; + } + } else if (xi < 0 && yi < 0) { + if (xj >= 0 && yj >= 0) { + return true; + } else if (xj < 0 && yj >= 0) { + return true; + } else if (xj < 0 && yj < 0) { + if (xi != xj) { + return xi < xj; + } else { + return yi > yj; + } + } else { + return true; + } + } else { + if (xj >= 0 && yj >= 0) { + return true; + } else if (xj < 0 && yj >= 0) { + return true; + } else if (xj < 0 && yj < 0) { + return false; + } else { + if (xi != xj) { + return xi < xj; + } else { + return yi < yj; + } + } + } + }; + std::sort(R.data(), R.data() + num_rows, comp); +} + +#ifdef IGL_STATIC_LIBRARY +template void igl::sort_angles, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/sort_angles.h b/src/external/libigl-2.3.0/include/igl/sort_angles.h new file mode 100644 index 000000000..d7e6e3c4d --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/sort_angles.h @@ -0,0 +1,35 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef SORT_ANGLES_H +#define SORT_ANGLES_H + +#include "igl_inline.h" +#include + +namespace igl { + // Sort angles in ascending order in a numerically robust way. + // + // Instead of computing angles using atan2(y, x), sort directly on (y, x). + // + // Inputs: + // M: m by n matrix of scalars. (n >= 2). Assuming the first column of M + // contains values for y, and the second column is x. Using the rest + // of the columns as tie-breaker. + // R: an array of m indices. M.row(R[i]) contains the i-th smallest + // angle. + template + IGL_INLINE void sort_angles( + const Eigen::MatrixBase& M, + Eigen::PlainObjectBase& R); +} + +#ifndef IGL_STATIC_LIBRARY +#include "sort_angles.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/sort_triangles.cpp b/src/external/libigl-2.3.0/include/igl/sort_triangles.cpp new file mode 100644 index 000000000..5f2cc2304 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/sort_triangles.cpp @@ -0,0 +1,57 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "sort_triangles.h" +#include "barycenter.h" +#include "sort.h" +#include "sortrows.h" +#include "slice.h" +#include "round.h" +#include "colon.h" + +#include + +template < + typename DerivedV, + typename DerivedF, + typename DerivedMV, + typename DerivedP, + typename DerivedFF, + typename DerivedI> +IGL_INLINE void igl::sort_triangles( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const Eigen::MatrixBase & MV, + const Eigen::MatrixBase & P, + Eigen::PlainObjectBase & FF, + Eigen::PlainObjectBase & I) +{ + using namespace Eigen; + using namespace std; + + + typedef typename DerivedV::Scalar Scalar; + // Barycenter, centroid + Eigen::Matrix D,sD; + Eigen::Matrix BC; + barycenter(V,F,BC); + Eigen::Matrix BC4(BC.rows(),4); + BC4.leftCols(3) = BC; + BC4.col(3).setConstant(1); + D = BC4*( + MV.template cast().transpose()* + P.template cast().transpose().eval().col(2)); + sort(D,1,false,sD,I); + slice(F,I,1,FF); +} + + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +template void igl::sort_triangles, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::sort_triangles, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/sort_triangles.h b/src/external/libigl-2.3.0/include/igl/sort_triangles.h new file mode 100644 index 000000000..57678a22b --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/sort_triangles.h @@ -0,0 +1,44 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_SORT_TRIANGLES_H +#define IGL_SORT_TRIANGLES_H + +#include "igl_inline.h" +#include + +namespace igl +{ + // Inputs: + // V #V by **4** list of homogeneous vertex positions + // F #F by 3 list of triangle indices + // MV 4 by 4 model view matrix + // P 4 by 4 projection matrix + // Outputs: + // FF #F by 3 list of sorted triangles indices + // I #F list of sorted indices + template < + typename DerivedV, + typename DerivedF, + typename DerivedMV, + typename DerivedP, + typename DerivedFF, + typename DerivedI> + IGL_INLINE void sort_triangles( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const Eigen::MatrixBase & MV, + const Eigen::MatrixBase & P, + Eigen::PlainObjectBase & FF, + Eigen::PlainObjectBase & I); +} + +#ifndef IGL_STATIC_LIBRARY +# include "sort_triangles.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/sort_vectors_ccw.cpp b/src/external/libigl-2.3.0/include/igl/sort_vectors_ccw.cpp new file mode 100644 index 000000000..ea613c51b --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/sort_vectors_ccw.cpp @@ -0,0 +1,103 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include +#include +#include + +template +IGL_INLINE void igl::sort_vectors_ccw( + const Eigen::PlainObjectBase& P, + const Eigen::PlainObjectBase& N, + Eigen::PlainObjectBase &order) +{ + int half_degree = P.cols()/3; + //local frame + Eigen::Matrix e1 = P.head(3).normalized(); + Eigen::Matrix e3 = N.normalized(); + Eigen::Matrix e2 = e3.cross(e1); + + Eigen::Matrix F; F< angles(half_degree,1); + for (int i=0; i Pl = F.colPivHouseholderQr().solve(P.segment(i*3,3).transpose()).transpose(); +// assert(fabs(Pl(2))/Pl.cwiseAbs().maxCoeff() <1e-5); + angles[i] = atan2(Pl(1),Pl(0)); + } + + igl::sort( angles, 1, true, angles, order); + //make sure that the first element is always at the top + while (order[0] != 0) + { + //do a circshift + int temp = order[0]; + for (int i =0; i< half_degree-1; ++i) + order[i] = order[i+1]; + order(half_degree-1) = temp; + } +} + +template +IGL_INLINE void igl::sort_vectors_ccw( + const Eigen::PlainObjectBase& P, + const Eigen::PlainObjectBase& N, + Eigen::PlainObjectBase &order, + Eigen::PlainObjectBase &sorted) + { + int half_degree = P.cols()/3; + igl::sort_vectors_ccw(P,N,order); + sorted.resize(1,half_degree*3); + for (int i=0; i +IGL_INLINE void igl::sort_vectors_ccw( + const Eigen::PlainObjectBase& P, + const Eigen::PlainObjectBase& N, + Eigen::PlainObjectBase &order, + Eigen::PlainObjectBase &inv_order) + { + int half_degree = P.cols()/3; + igl::sort_vectors_ccw(P,N,order); + inv_order.resize(half_degree,1); + for (int i=0; i +IGL_INLINE void igl::sort_vectors_ccw( + const Eigen::PlainObjectBase& P, + const Eigen::PlainObjectBase& N, + Eigen::PlainObjectBase &order, + Eigen::PlainObjectBase &sorted, + Eigen::PlainObjectBase &inv_order) +{ + int half_degree = P.cols()/3; + + igl::sort_vectors_ccw(P,N,order,inv_order); + + sorted.resize(1,half_degree*3); + for (int i=0; i, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&); +template void igl::sort_vectors_ccw, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/sort_vectors_ccw.h b/src/external/libigl-2.3.0/include/igl/sort_vectors_ccw.h new file mode 100644 index 000000000..73c2f6fba --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/sort_vectors_ccw.h @@ -0,0 +1,68 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Olga Diamanti +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef IGL_SORT_VECTORS_CCW +#define IGL_SORT_VECTORS_CCW +#include "igl_inline.h" + +#include + +namespace igl { + // Sorts a set of N coplanar vectors in a ccw order, and returns their order. + // Optionally it also returns a copy of the ordered vector set, or the indices, + // in the original unordered set, of the vectors in the ordered set (called here + // the "inverse" set of indices). + + // Inputs: + // P 1 by 3N row vector of the vectors to be sorted, stacked horizontally + // N #1 by 3 normal of the plane where the vectors lie + // Output: + // order N by 1 order of the vectors (indices of the unordered vectors into + // the ordered vector set) + // sorted 1 by 3N row vector of the ordered vectors, stacked horizontally + // inv_order N by 1 "inverse" order of the vectors (the indices of the ordered + // vectors into the unordered vector set) + // + template + IGL_INLINE void sort_vectors_ccw( + const Eigen::PlainObjectBase& P, + const Eigen::PlainObjectBase& N, + Eigen::PlainObjectBase &order, + Eigen::PlainObjectBase &sorted, + Eigen::PlainObjectBase &inv_order); + + template + IGL_INLINE void sort_vectors_ccw( + const Eigen::PlainObjectBase& P, + const Eigen::PlainObjectBase& N, + Eigen::PlainObjectBase &order, + Eigen::PlainObjectBase &sorted); + + template + IGL_INLINE void sort_vectors_ccw( + const Eigen::PlainObjectBase& P, + const Eigen::PlainObjectBase& N, + Eigen::PlainObjectBase &order, + Eigen::PlainObjectBase &inv_order); + + + template + IGL_INLINE void sort_vectors_ccw( + const Eigen::PlainObjectBase& P, + const Eigen::PlainObjectBase& N, + Eigen::PlainObjectBase &order); + +}; + + +#ifndef IGL_STATIC_LIBRARY +#include "sort_vectors_ccw.cpp" +#endif + + +#endif /* defined(IGL_FIELD_LOCAL_GLOBAL_CONVERSIONS) */ diff --git a/src/external/libigl-2.3.0/include/igl/sortrows.cpp b/src/external/libigl-2.3.0/include/igl/sortrows.cpp new file mode 100644 index 000000000..f48005d5e --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/sortrows.cpp @@ -0,0 +1,163 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "sortrows.h" +#include "get_seconds.h" + +#include "SortableRow.h" +#include "sort.h" +#include "colon.h" +#include "IndexComparison.h" + +#include + +// Obsolete slower version converst to vector +//template +//IGL_INLINE void igl::sortrows( +// const Eigen::DenseBase& X, +// const bool ascending, +// Eigen::PlainObjectBase& Y, +// Eigen::PlainObjectBase& IX) +//{ +// using namespace std; +// using namespace Eigen; +// typedef Eigen::Matrix RowVector; +// vector > rows; +// rows.resize(X.rows()); +// // Loop over rows +// for(int i = 0;i(ri); +// } +// vector > sorted; +// std::vector index_map; +// // Perform sort on rows +// igl::sort(rows,ascending,sorted,index_map); +// // Resize output +// Y.resizeLike(X); +// IX.resize(X.rows(),1); +// // Convert to eigen +// for(int i = 0;i +IGL_INLINE void igl::sortrows( + const Eigen::DenseBase& X, + const bool ascending, + Eigen::PlainObjectBase& Y, + Eigen::PlainObjectBase& IX) +{ + // This is already 2x faster than matlab's builtin `sortrows`. I have tried + // implementing a "multiple-pass" sort on each column, but see no performance + // improvement. + using namespace std; + using namespace Eigen; + // Resize output + const size_t num_rows = X.rows(); + const size_t num_cols = X.cols(); + Y.resize(num_rows,num_cols); + IX.resize(num_rows,1); + for(int i = 0;i X.coeff(j, c)) return true; + else if (X.coeff(j,c) > X.coeff(i,c)) return false; + } + return false; + }; + std::sort( + IX.data(), + IX.data()+IX.size(), + index_greater_than + ); + } + for (size_t j=0; j +IGL_INLINE void igl::sortrows( + const Eigen::DenseBase& X, + const bool ascending, + Eigen::PlainObjectBase& Y) +{ + Eigen::Matrix I; + return igl::sortrows(X,ascending,Y,I); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::sortrows, Eigen::Matrix >(Eigen::DenseBase > const&, bool, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::sortrows, Eigen::Matrix >(Eigen::DenseBase > const&, bool, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::sortrows, Eigen::Matrix >(Eigen::DenseBase > const&, bool, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::sortrows, Eigen::Matrix >(Eigen::DenseBase > const&, bool, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::sortrows, Eigen::Matrix >(Eigen::DenseBase > const&, bool, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::sortrows, Eigen::Matrix >(Eigen::DenseBase > const&, bool, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::sortrows, Eigen::Matrix >(Eigen::DenseBase > const&, bool, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::sortrows, Eigen::Matrix >(Eigen::DenseBase > const&, bool, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::sortrows, Eigen::Matrix >(Eigen::DenseBase > const&, bool, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::sortrows, Eigen::Matrix >(Eigen::DenseBase > const&, bool, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::sortrows, Eigen::Matrix >(Eigen::DenseBase > const&, bool, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::sortrows, Eigen::Matrix >(Eigen::DenseBase > const&, bool, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::sortrows, Eigen::Matrix >(Eigen::DenseBase > const&, bool, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::sortrows, Eigen::Matrix >(Eigen::DenseBase > const&, bool, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::sortrows, Eigen::Matrix >(Eigen::DenseBase > const&, bool, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::sortrows, Eigen::Matrix >(Eigen::DenseBase > const&, bool, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::sortrows, Eigen::Matrix >(Eigen::DenseBase > const&, bool, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::sortrows, Eigen::Matrix >(Eigen::DenseBase > const&, bool, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::sortrows, Eigen::Matrix >(Eigen::DenseBase > const&, bool, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::sortrows, Eigen::Matrix >(Eigen::DenseBase > const&, bool, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::sortrows, Eigen::Matrix >(Eigen::DenseBase > const&, bool, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::sortrows, Eigen::Matrix >(Eigen::DenseBase > const&, bool, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::sortrows, Eigen::Matrix >(Eigen::DenseBase > const&, bool, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::sortrows, Eigen::Matrix >(Eigen::DenseBase > const&, bool, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::sortrows, Eigen::Matrix >(Eigen::DenseBase > const&, bool, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::sortrows, Eigen::Matrix >(Eigen::DenseBase > const&, bool, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::sortrows >(Eigen::DenseBase > const&, bool, Eigen::PlainObjectBase >&); +#ifdef WIN32 +template void igl::sortrows,class Eigen::Matrix<__int64,-1,1,0,-1,1> >(class Eigen::DenseBase > const &,bool,class Eigen::PlainObjectBase > &,class Eigen::PlainObjectBase > &); +template void igl::sortrows,class Eigen::Matrix<__int64,-1,1,0,-1,1> >(class Eigen::DenseBase > const &,bool,class Eigen::PlainObjectBase > &,class Eigen::PlainObjectBase > &); +template void igl::sortrows,class Eigen::Matrix<__int64,-1,1,0,-1,1> >(class Eigen::DenseBase > const &,bool,class Eigen::PlainObjectBase > &,class Eigen::PlainObjectBase > &); +template void igl::sortrows,class Eigen::Matrix<__int64,-1,1,0,-1,1> >(class Eigen::DenseBase > const &,bool,class Eigen::PlainObjectBase > &,class Eigen::PlainObjectBase > &); +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/sortrows.h b/src/external/libigl-2.3.0/include/igl/sortrows.h new file mode 100644 index 000000000..a1e5db77f --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/sortrows.h @@ -0,0 +1,47 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_SORTROWS_H +#define IGL_SORTROWS_H +#include "igl_inline.h" + +#include +#include +namespace igl +{ + // Act like matlab's [Y,I] = sortrows(X) + // + // Templates: + // DerivedX derived scalar type, e.g. MatrixXi or MatrixXd + // DerivedI derived integer type, e.g. MatrixXi + // Inputs: + // X m by n matrix whose entries are to be sorted + // ascending sort ascending (true, matlab default) or descending (false) + // Outputs: + // Y m by n matrix whose entries are sorted (**should not** be same + // reference as X) + // I m list of indices so that + // Y = X(I,:); + template + IGL_INLINE void sortrows( + const Eigen::DenseBase& X, + const bool ascending, + Eigen::PlainObjectBase& Y, + Eigen::PlainObjectBase& I); + template + IGL_INLINE void sortrows( + const Eigen::DenseBase& X, + const bool ascending, + Eigen::PlainObjectBase& Y); +} + +#ifndef IGL_STATIC_LIBRARY +# include "sortrows.cpp" +#endif + +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/sparse.cpp b/src/external/libigl-2.3.0/include/igl/sparse.cpp new file mode 100644 index 000000000..ed9cd4a49 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/sparse.cpp @@ -0,0 +1,123 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "sparse.h" + +#include +#include + +template +IGL_INLINE void igl::sparse( + const IndexVector & I, + const IndexVector & J, + const ValueVector & V, + Eigen::SparseMatrix& X) +{ + size_t m = (size_t)I.maxCoeff()+1; + size_t n = (size_t)J.maxCoeff()+1; + return igl::sparse(I,J,V,m,n,X); +} + +#include "verbose.h" +template < + class IndexVectorI, + class IndexVectorJ, + class ValueVector, + typename T> +IGL_INLINE void igl::sparse( + const IndexVectorI & I, + const IndexVectorJ & J, + const ValueVector & V, + const size_t m, + const size_t n, + Eigen::SparseMatrix& X) +{ + using namespace std; + using namespace Eigen; + assert((int)I.maxCoeff() < (int)m); + assert((int)I.minCoeff() >= 0); + assert((int)J.maxCoeff() < (int)n); + assert((int)J.minCoeff() >= 0); + assert(I.size() == J.size()); + assert(J.size() == V.size()); + // Really we just need .size() to be the same, but this is safer + assert(I.rows() == J.rows()); + assert(J.rows() == V.rows()); + assert(I.cols() == J.cols()); + assert(J.cols() == V.cols()); + //// number of values + //int nv = V.size(); + + //Eigen::DynamicSparseMatrix dyn_X(m,n); + //// over estimate the number of entries + //dyn_X.reserve(I.size()); + //for(int i = 0;i < nv;i++) + //{ + // dyn_X.coeffRef((int)I(i),(int)J(i)) += (T)V(i); + //} + //X = Eigen::SparseMatrix(dyn_X); + vector > IJV; + IJV.reserve(I.size()); + for(int x = 0;x(I(x),J(x),V(x))); + } + X.resize(m,n); + X.setFromTriplets(IJV.begin(),IJV.end()); +} + +template +IGL_INLINE void igl::sparse( + const Eigen::PlainObjectBase& D, + Eigen::SparseMatrix& X) +{ + assert(false && "Obsolete. Just call D.sparseView() directly"); + using namespace std; + using namespace Eigen; + vector > DIJV; + const int m = D.rows(); + const int n = D.cols(); + for(int i = 0;i(i,j,D(i,j))); + } + } + } + X.resize(m,n); + X.setFromTriplets(DIJV.begin(),DIJV.end()); +} + +template +IGL_INLINE Eigen::SparseMatrix igl::sparse( + const Eigen::PlainObjectBase& D) +{ + assert(false && "Obsolete. Just call D.sparseView() directly"); + Eigen::SparseMatrix X; + igl::sparse(D,X); + return X; +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +#ifndef WIN32 +//template void igl::sparse >, Eigen::Matrix, Eigen::CwiseNullaryOp, Eigen::Array >, bool>(Eigen::PlainObjectBase > const&, Eigen::Matrix const&, Eigen::CwiseNullaryOp, Eigen::Array > const&, unsigned long, unsigned long, Eigen::SparseMatrix&); +//template void igl::sparse >, Eigen::MatrixBase >, Eigen::CwiseNullaryOp, Eigen::Array >, bool>(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::CwiseNullaryOp, Eigen::Array > const&, unsigned long, unsigned long, Eigen::SparseMatrix&); +#if EIGEN_VERSION_AT_LEAST(3,3,0) +#else +//template void igl::sparse, Eigen::Matrix >, Eigen::Matrix, Eigen::CwiseNullaryOp, Eigen::Array >, bool>(Eigen::CwiseNullaryOp, Eigen::Matrix > const&, Eigen::Matrix const&, Eigen::CwiseNullaryOp, Eigen::Array > const&, unsigned long, unsigned long, Eigen::SparseMatrix&); +#endif +#endif + +template void igl::sparse, Eigen::Matrix, Eigen::Matrix, std::complex >(Eigen::Matrix const&, Eigen::Matrix const&, Eigen::Matrix const&, size_t, size_t, Eigen::SparseMatrix, 0, int>&); +template void igl::sparse, Eigen::Matrix, double>(Eigen::Matrix const&, Eigen::Matrix const&, Eigen::Matrix const&, Eigen::SparseMatrix&); +template void igl::sparse, Eigen::Matrix, Eigen::Matrix, double>(Eigen::Matrix const&, Eigen::Matrix const&, Eigen::Matrix const&, size_t, size_t, Eigen::SparseMatrix&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/sparse.h b/src/external/libigl-2.3.0/include/igl/sparse.h new file mode 100644 index 000000000..a947978ab --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/sparse.h @@ -0,0 +1,78 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_SPARSE_H +#define IGL_SPARSE_H +#include "igl_inline.h" +#define EIGEN_YES_I_KNOW_SPARSE_MODULE_IS_NOT_STABLE_YET +#include +#include +namespace igl +{ + // Build a sparse matrix from list of indices and values (I,J,V), functions + // like the sparse function in matlab + // + // Templates: + // IndexVector list of indices, value should be non-negative and should + // expect to be cast to an index. Must implement operator(i) to retrieve + // ith element + // ValueVector list of values, value should be expect to be cast to type + // T. Must implement operator(i) to retrieve ith element + // T should be a eigen sparse matrix primitive type like int or double + // Input: + // I nnz vector of row indices of non zeros entries in X + // J nnz vector of column indices of non zeros entries in X + // V nnz vector of non-zeros entries in X + // Optional: + // m number of rows + // n number of cols + // Outputs: + // X m by n matrix of type T whose entries are to be found + // + template + IGL_INLINE void sparse( + const IndexVector & I, + const IndexVector & J, + const ValueVector & V, + Eigen::SparseMatrix& X); + template < + class IndexVectorI, + class IndexVectorJ, + class ValueVector, + typename T> + IGL_INLINE void sparse( + const IndexVectorI & I, + const IndexVectorJ & J, + const ValueVector & V, + const size_t m, + const size_t n, + Eigen::SparseMatrix& X); + // THIS MAY BE SUPERSEDED BY EIGEN'S .sparseView Indeed it is. + // Convert a full, dense matrix to a sparse one + // + // Templates: + // T should be a eigen sparse matrix primitive type like int or double + // Input: + // D m by n full, dense matrix + // Output: + // X m by n sparse matrix + template + IGL_INLINE void sparse( + const Eigen::PlainObjectBase& D, + Eigen::SparseMatrix& X); + // Wrapper with return + template + IGL_INLINE Eigen::SparseMatrix sparse( + const Eigen::PlainObjectBase& D); + +} + +#ifndef IGL_STATIC_LIBRARY +# include "sparse.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/sparse_cached.cpp b/src/external/libigl-2.3.0/include/igl/sparse_cached.cpp new file mode 100644 index 000000000..ddd65aadf --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/sparse_cached.cpp @@ -0,0 +1,127 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2017 Daniele Panozzo +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "sparse_cached.h" + +#include +#include +#include +#include +#include +#include + +template +IGL_INLINE void igl::sparse_cached_precompute( + const Eigen::MatrixBase & I, + const Eigen::MatrixBase & J, + Eigen::VectorXi& data, + Eigen::SparseMatrix& X) +{ + // Generates the triplets + std::vector > t(I.size()); + for (unsigned i = 0; i(I[i],J[i],1); + + // Call the triplets version + sparse_cached_precompute(t,X,data); +} + +template +IGL_INLINE void igl::sparse_cached_precompute( + const std::vector >& triplets, + Eigen::VectorXi& data, + Eigen::SparseMatrix& X) +{ + // Construct an empty sparse matrix + X.setFromTriplets(triplets.begin(),triplets.end()); + X.makeCompressed(); + + std::vector > T(triplets.size()); + for (unsigned i=0; i= 0); + assert(row < X.rows()); + assert(row >= 0); + assert(value_index >= 0); + assert(value_index < X.nonZeros()); + + std::pair p_m = std::make_pair(row,col); + + while (t +IGL_INLINE void igl::sparse_cached( + const std::vector >& triplets, + const Eigen::VectorXi& data, + Eigen::SparseMatrix& X) +{ + assert(triplets.size() == data.size()); + + // Clear it first + for (unsigned i = 0; i +IGL_INLINE void igl::sparse_cached( + const Eigen::MatrixBase& V, + const Eigen::VectorXi& data, + Eigen::SparseMatrix& X) +{ + assert(V.size() == data.size()); + + // Clear it first + for (unsigned i = 0; i(std::vector::StorageIndex>, std::allocator::StorageIndex> > > const&, Eigen::Matrix const&, Eigen::SparseMatrix&); + template void igl::sparse_cached_precompute(std::vector::StorageIndex>, std::allocator::StorageIndex> > > const&, Eigen::Matrix&, Eigen::SparseMatrix&); +#else + template void igl::sparse_cached(std::vector::Index>, std::allocator::Index> > > const&, Eigen::Matrix const&, Eigen::SparseMatrix&); + template void igl::sparse_cached_precompute(std::vector::Index>, std::allocator::Index> > > const&, Eigen::Matrix&, Eigen::SparseMatrix&); +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/sparse_cached.h b/src/external/libigl-2.3.0/include/igl/sparse_cached.h new file mode 100644 index 000000000..c5a66c99f --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/sparse_cached.h @@ -0,0 +1,85 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2017 Daniele Panozzo +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_SPARSE_CACHED_H +#define IGL_SPARSE_CACHED_H +#include "igl_inline.h" +#define EIGEN_YES_I_KNOW_SPARSE_MODULE_IS_NOT_STABLE_YET +#include +#include +namespace igl +{ + // Build a sparse matrix from list of indices and values (I,J,V), similarly to + // the sparse function in matlab. Divides the construction in two phases, one + // for fixing the sparsity pattern, and one to populate it with values. Compared to + // igl::sparse, this version is slower for the first time (since it requires a + // precomputation), but faster to the subsequent evaluations. + // + // Templates: + // IndexVector list of indices, value should be non-negative and should + // expect to be cast to an index. Must implement operator(i) to retrieve + // ith element + // ValueVector list of values, value should be expect to be cast to type + // T. Must implement operator(i) to retrieve ith element + // T should be a eigen sparse matrix primitive type like int or double + // Input: + // I nnz vector of row indices of non zeros entries in X + // J nnz vector of column indices of non zeros entries in X + // V nnz vector of non-zeros entries in X + // Optional: + // m number of rows + // n number of cols + // Outputs: + // X m by n matrix of type T whose entries are to be found + // + // Example: + // Eigen::SparseMatrix A; + // std::vector > IJV; + // slim_buildA(IJV); + // if (A.rows() == 0) + // { + // A = Eigen::SparseMatrix(rows,cols); + // igl::sparse_cached_precompute(IJV,A,A_data); + // } + // else + // igl::sparse_cached(IJV,s.A,s.A_data); + + template + IGL_INLINE void sparse_cached_precompute( + const Eigen::MatrixBase & I, + const Eigen::MatrixBase & J, + Eigen::VectorXi& data, + Eigen::SparseMatrix& X + ); + + template + IGL_INLINE void sparse_cached_precompute( + const std::vector >& triplets, + Eigen::VectorXi& data, + Eigen::SparseMatrix& X + ); + + template + IGL_INLINE void sparse_cached( + const std::vector >& triplets, + const Eigen::VectorXi& data, + Eigen::SparseMatrix& X); + + template + IGL_INLINE void sparse_cached( + const Eigen::MatrixBase& V, + const Eigen::VectorXi& data, + Eigen::SparseMatrix& X + ); + +} + +#ifndef IGL_STATIC_LIBRARY +# include "sparse_cached.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/sparse_voxel_grid.cpp b/src/external/libigl-2.3.0/include/igl/sparse_voxel_grid.cpp new file mode 100644 index 000000000..c88883ad8 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/sparse_voxel_grid.cpp @@ -0,0 +1,202 @@ +#include "sparse_voxel_grid.h" + +#include +#include +#include + + +template +IGL_INLINE void igl::sparse_voxel_grid(const Eigen::MatrixBase& p0, + const Func& scalarFunc, + const double eps, + const int expected_number_of_cubes, + Eigen::PlainObjectBase& CS, + Eigen::PlainObjectBase& CV, + Eigen::PlainObjectBase& CI) +{ + typedef typename DerivedV::Scalar ScalarV; + typedef typename DerivedS::Scalar ScalarS; + typedef typename DerivedI::Scalar ScalarI; + typedef Eigen::Matrix VertexRowVector; + typedef Eigen::Matrix IndexRowVector; + + + struct IndexRowVectorHash { + std::size_t operator()(const Eigen::RowVector3i& key) const { + std::size_t seed = 0; + std::hash hasher; + for (int i = 0; i < 3; i++) { + seed ^= hasher(key[i]) + 0x9e3779b9 + (seed<<6) + (seed>>2); // Copied from boost::hash_combine + } + return seed; + } + }; + + auto sgn = [](ScalarS val) -> int { + return (ScalarS(0) < val) - (val < ScalarS(0)); + }; + + ScalarV half_eps = 0.5 * eps; + + std::vector CI_vector; + std::vector CV_vector; + std::vector CS_vector; + CI_vector.reserve(expected_number_of_cubes); + CV_vector.reserve(8 * expected_number_of_cubes); + CS_vector.reserve(8 * expected_number_of_cubes); + + // Track visisted neighbors + std::unordered_map visited; + visited.reserve(6 * expected_number_of_cubes); + visited.max_load_factor(0.5); + + // BFS Queue + std::vector queue; + queue.reserve(expected_number_of_cubes * 8); + queue.push_back(Eigen::RowVector3i(0, 0, 0)); + + while (queue.size() > 0) + { + Eigen::RowVector3i pi = queue.back(); + queue.pop_back(); + if(visited.count(pi)){ continue; } + + VertexRowVector ctr = p0 + eps*pi.cast(); // R^3 center of this cube + + // X, Y, Z basis vectors, and array of neighbor offsets used to construct cubes + const Eigen::RowVector3i bx(1, 0, 0), by(0, 1, 0), bz(0, 0, -1); + const std::array neighbors = { + bx, -bx, by, -by, bz, -bz, + by-bz, -by+bz, // 1-2 4-7 + bx+by, -bx-by, // 0-1 7-6 + by+bz, -by-bz, // 0-3 6-5 + by-bx, -by+bx, // 2-3 5-4 + bx-bz, -bx+bz, // 1-5 3-7 + bx+bz, -bx-bz, // 0-4 2-6 + -bx+by+bz, bx-by-bz, // 3 5 + bx+by+bz, -bx-by-bz, // 0 6 + bx+by-bz, -bx-by+bz, //1 7 + -bx+by-bz, bx-by+bz, // 2 4, + }; + + // Compute the position of the cube corners and the scalar values at those corners + // + // Cube corners are ordered y-x-z, so their xyz offsets are: + // + // +++ + // ++- + // -+- + // -++ + // +-+ + // +-- + // --- + // --+ + std::array cubeCorners = { + ctr+half_eps*(bx+by+bz).cast(), ctr+half_eps*(bx+by-bz).cast(), ctr+half_eps*(-bx+by-bz).cast(), ctr+half_eps*(-bx+by+bz).cast(), + ctr+half_eps*(bx-by+bz).cast(), ctr+half_eps*(bx-by-bz).cast(), ctr+half_eps*(-bx-by-bz).cast(), ctr+half_eps*(-bx-by+bz).cast() + }; + std::array cubeScalars; + for (int i = 0; i < 8; i++) { cubeScalars[i] = scalarFunc(cubeCorners[i]); } + + // If this cube doesn't intersect the surface, disregard it + bool validCube = false; + int sign = sgn(cubeScalars[0]); + for (int i = 1; i < 8; i++) { + if (sign != sgn(cubeScalars[i])) { + validCube = true; + break; + } + } + if (!validCube) { + continue; + } + + // Add the cube vertices and indices to the output arrays if they are not there already + IndexRowVector cube; + uint8_t vertexAlreadyAdded = 0; // This is a bimask. If a bit is 1, it has been visited already by the BFS + constexpr std::array zv = { + (1 << 0) | (1 << 1) | (1 << 4) | (1 << 5), + (1 << 2) | (1 << 3) | (1 << 6) | (1 << 7), + (1 << 0) | (1 << 1) | (1 << 2) | (1 << 3), + (1 << 4) | (1 << 5) | (1 << 6) | (1 << 7), + (1 << 0) | (1 << 3) | (1 << 4) | (1 << 7), + (1 << 1) | (1 << 2) | (1 << 5) | (1 << 6), + (1 << 1) | (1 << 2), + (1 << 4) | (1 << 7), + (1 << 0) | (1 << 1), + (1 << 6) | (1 << 7), + (1 << 0) | (1 << 3), + (1 << 5) | (1 << 6), + (1 << 2) | (1 << 3), + (1 << 4) | (1 << 5), + (1 << 1) | (1 << 5), + (1 << 3) | (1 << 7), + (1 << 0) | (1 << 4), + (1 << 2) | (1 << 6), + (1 << 3), (1 << 5), // diagonals + (1 << 0), (1 << 6), + (1 << 1), (1 << 7), + (1 << 2), (1 << 4), + }; + constexpr std::array, 26> zvv {{ + {{0, 1, 4, 5}}, {{3, 2, 7, 6}}, {{0, 1, 2, 3}}, + {{4, 5, 6, 7}}, {{0, 3, 4, 7}}, {{1, 2, 5, 6}}, + {{-1,-1,1,2}}, {{-1,-1,4,7}}, {{-1,-1,0,1}},{{-1,-1,7,6}}, + {{-1,-1,0,3}}, {{-1,-1,5,6}}, {{-1,-1,2,3}}, {{-1,-1,5,4}}, + {{-1,-1,1,5}}, {{-1,-1,3,7}}, {{-1,-1,0,4}}, {{-1,-1,2,6}}, + {{-1,-1,-1,3}}, {{-1,-1,-1,5}}, {{-1,-1,-1,0}}, {{-1,-1,-1,6}}, + {{-1,-1,-1,1}}, {{-1,-1,-1,7}}, {{-1,-1,-1,2}}, {{-1,-1,-1,4}} }}; + + for (int n = 0; n < 26; n++) { // For each neighbor, check the hash table to see if its been added before + Eigen::RowVector3i nkey = pi + neighbors[n]; + auto nbr = visited.find(nkey); + if (nbr != visited.end()) { // We've already visited this neighbor, use references to its vertices instead of duplicating them + vertexAlreadyAdded |= zv[n]; + for (int i = 0; i < 4; i++) + { + if (zvv[n][i]!=-1) + { + cube[zvv[n][i]] = CI_vector[nbr->second][zvv[n % 2 == 0 ? n + 1 : n - 1][i]]; + } + } + } else { + queue.push_back(nkey); // Otherwise, we have not visited the neighbor, put it in the BFS queue + } + } + + for (int i = 0; i < 8; i++) { // Add new, non-visited,2 vertices to the arrays + if (0 == ((1 << i) & vertexAlreadyAdded)) { + cube[i] = CS_vector.size(); + CV_vector.push_back(cubeCorners[i]); + CS_vector.push_back(cubeScalars[i]); + } + } + + visited[pi] = CI_vector.size(); + CI_vector.push_back(cube); + } + + CV.conservativeResize(CV_vector.size(), 3); + CS.conservativeResize(CS_vector.size(), 1); + CI.conservativeResize(CI_vector.size(), 8); + // If you pass in column-major matrices, this is going to be slooooowwwww + for (int i = 0; i < CV_vector.size(); i++) { + CV.row(i) = CV_vector[i]; + } + for (int i = 0; i < CS_vector.size(); i++) { + CS(i) = CS_vector[i]; + } + for (int i = 0; i < CI_vector.size(); i++) { + CI.row(i) = CI_vector[i]; + } +} + + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::sparse_voxel_grid, std::function const&)>, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, std::function const&)> const&, double, int, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::sparse_voxel_grid, class std::function const &)>, class Eigen::Matrix, class Eigen::Matrix, class Eigen::Matrix >(class Eigen::MatrixBase > const &, class std::function const &)> const &, double, int, class Eigen::PlainObjectBase > &, class Eigen::PlainObjectBase > &, class Eigen::PlainObjectBase > &); +template void igl::sparse_voxel_grid, std::function const&)>, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, std::function const&)> const&, double, int, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::sparse_voxel_grid, std::function const&)>, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, std::function const&)> const&, double, int, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/sparse_voxel_grid.h b/src/external/libigl-2.3.0/include/igl/sparse_voxel_grid.h new file mode 100644 index 000000000..34640d919 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/sparse_voxel_grid.h @@ -0,0 +1,55 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2018 Francis Williams +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_SPARSE_VOXEL_GRID_H +#define IGL_SPARSE_VOXEL_GRID_H + +#include "igl_inline.h" +#include + +namespace igl +{ + // sparse_voxel_grid( p0, scalarFunc, eps, CV, CS, CI ) + // + // Given a point, p0, on an isosurface, construct a shell of epsilon sized cubes surrounding the surface. + // These cubes can be used as the input to marching cubes. + // + // Input: + // p0 A 3D point on the isosurface surface defined by scalarFunc(x) = 0 + // scalarFunc A scalar function from R^3 to R -- points which map to 0 lie + // on the surface, points which are negative lie inside the surface, + // and points which are positive lie outside the surface + // eps The edge length of the cubes surrounding the surface + // expected_number_of_cubes This pre-allocates internal data structures to speed things up + // Output: + // CS #CV by 1 list of scalar values at the cube vertices + // CV #CV by 3 list of cube vertex positions + // CI #CI by 8 list of cube indices into rows of CS and CV. Each row + // represents 8 corners of cube in y-x-z binary counting order. + // + template < + typename DerivedP0, + typename Func, + typename DerivedS, + typename DerivedV, + typename DerivedI> + IGL_INLINE void sparse_voxel_grid( + const Eigen::MatrixBase& p0, + const Func& scalarFunc, + const double eps, + const int expected_number_of_cubes, + Eigen::PlainObjectBase& CS, + Eigen::PlainObjectBase& CV, + Eigen::PlainObjectBase& CI); + +} + +#ifndef IGL_STATIC_LIBRARY +# include "sparse_voxel_grid.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/speye.cpp b/src/external/libigl-2.3.0/include/igl/speye.cpp new file mode 100644 index 000000000..54af00c71 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/speye.cpp @@ -0,0 +1,35 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "speye.h" + +template +IGL_INLINE void igl::speye(const int m, const int n, Eigen::SparseMatrix & I) +{ + // size of diagonal + int d = (m(m,n); + I.reserve(d); + for(int i = 0;i +IGL_INLINE void igl::speye(const int n, Eigen::SparseMatrix & I) +{ + return igl::speye(n,n,I); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::speye(int, Eigen::SparseMatrix&); +template void igl::speye >(int, int, Eigen::SparseMatrix, 0, int>&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/speye.h b/src/external/libigl-2.3.0/include/igl/speye.h new file mode 100644 index 000000000..4c2425571 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/speye.h @@ -0,0 +1,42 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_SPEYE_H +#define IGL_SPEYE_H +#include "igl_inline.h" + +#define EIGEN_YES_I_KNOW_SPARSE_MODULE_IS_NOT_STABLE_YET +#include + +namespace igl +{ + // Builds an m by n sparse identity matrix like matlab's speye function + // Templates: + // T should be a eigen sparse matrix primitive type like int or double + // Inputs: + // m number of rows + // n number of cols + // Outputs: + // I m by n sparse matrix with 1's on the main diagonal + template + IGL_INLINE void speye(const int n,const int m, Eigen::SparseMatrix & I); + // Builds an n by n sparse identity matrix like matlab's speye function + // Templates: + // T should be a eigen sparse matrix primitive type like int or double + // Inputs: + // n number of rows and cols + // Outputs: + // I n by n sparse matrix with 1's on the main diagonal + template + IGL_INLINE void speye(const int n, Eigen::SparseMatrix & I); +} + +#ifndef IGL_STATIC_LIBRARY +# include "speye.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/squared_edge_lengths.cpp b/src/external/libigl-2.3.0/include/igl/squared_edge_lengths.cpp new file mode 100644 index 000000000..f916a0dcd --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/squared_edge_lengths.cpp @@ -0,0 +1,113 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "squared_edge_lengths.h" +#include "parallel_for.h" +#include + +template +IGL_INLINE void igl::squared_edge_lengths( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + Eigen::PlainObjectBase& L) +{ + using namespace std; + const int m = F.rows(); + switch(F.cols()) + { + case 2: + { + L.resize(F.rows(),1); + for(int i = 0;i, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::squared_edge_lengths, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::squared_edge_lengths, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::squared_edge_lengths, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::squared_edge_lengths, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::squared_edge_lengths, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::squared_edge_lengths, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::squared_edge_lengths, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::squared_edge_lengths, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::squared_edge_lengths, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::squared_edge_lengths, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::squared_edge_lengths, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::squared_edge_lengths, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::squared_edge_lengths, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::squared_edge_lengths, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::squared_edge_lengths, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::squared_edge_lengths, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::squared_edge_lengths, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::squared_edge_lengths, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::squared_edge_lengths, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::squared_edge_lengths, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::squared_edge_lengths, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::squared_edge_lengths, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::squared_edge_lengths, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::squared_edge_lengths, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::squared_edge_lengths, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::squared_edge_lengths, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::squared_edge_lengths, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::squared_edge_lengths, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::squared_edge_lengths, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::squared_edge_lengths, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/squared_edge_lengths.h b/src/external/libigl-2.3.0/include/igl/squared_edge_lengths.h new file mode 100644 index 000000000..2f374d6c3 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/squared_edge_lengths.h @@ -0,0 +1,49 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_SQUARED_EDGE_LENGTHS_H +#define IGL_SQUARED_EDGE_LENGTHS_H +#include "igl_inline.h" + +#include + +namespace igl +{ + // Constructs a list of squared lengths of edges opposite each index in a face + // (triangle/tet) list + // + // Templates: + // DerivedV derived from vertex positions matrix type: i.e. MatrixXd + // DerivedF derived from face indices matrix type: i.e. MatrixXi + // DerivedL derived from edge lengths matrix type: i.e. MatrixXd + // Inputs: + // V eigen matrix #V by 3 + // F #F by 2 list of mesh edges + // or + // F #F by 3 list of mesh faces (must be triangles) + // or + // T #T by 4 list of mesh elements (must be tets) + // Outputs: + // L #F by {1|3|6} list of edge lengths squared + // for edges, column of lengths + // for triangles, columns correspond to edges [1,2],[2,0],[0,1] + // for tets, columns correspond to edges + // [3 0],[3 1],[3 2],[1 2],[2 0],[0 1] + // + template + IGL_INLINE void squared_edge_lengths( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + Eigen::PlainObjectBase& L); +} + +#ifndef IGL_STATIC_LIBRARY +# include "squared_edge_lengths.cpp" +#endif + +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/stdin_to_temp.cpp b/src/external/libigl-2.3.0/include/igl/stdin_to_temp.cpp new file mode 100644 index 000000000..a7a7fbd70 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/stdin_to_temp.cpp @@ -0,0 +1,38 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "stdin_to_temp.h" + +#include + +IGL_INLINE bool igl::stdin_to_temp(FILE ** temp_file) +{ + // get a temporary file + *temp_file = tmpfile(); + if(*temp_file == NULL) + { + fprintf(stderr,"IOError: temp file could not be created.\n"); + return false; + } + char c; + // c++'s cin handles the stdind input in a reasonable way + while (std::cin.good()) + { + c = std::cin.get(); + if(std::cin.good()) + { + if(1 != fwrite(&c,sizeof(char),1,*temp_file)) + { + fprintf(stderr,"IOError: error writing to tempfile.\n"); + return false; + } + } + } + // rewind file getting it ready to read from + rewind(*temp_file); + return true; +} diff --git a/src/external/libigl-2.3.0/include/igl/stdin_to_temp.h b/src/external/libigl-2.3.0/include/igl/stdin_to_temp.h new file mode 100644 index 000000000..ae35219ea --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/stdin_to_temp.h @@ -0,0 +1,36 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_STDIN_TO_TEMP_H +#define IGL_STDIN_TO_TEMP_H +#include "igl_inline.h" +#include +namespace igl +{ + // Write stdin/piped input to a temporary file which can than be preprocessed as it + // is (a normal file). This is often useful if you want to process stdin/piped + // with library functions that expect to be able to fseek(), rewind() etc.. + // + // If your application is not using fseek(), rewind(), etc. but just reading + // from stdin then this will likely cause a bottle neck as it defeats the whole + // purpose of piping. + // + // Outputs: + // temp_file pointer to temp file pointer, rewound to beginning of file so + // its ready to be read + // Return true only if no errors were found + // + // Note: Caller is responsible for closing the file (tmpfile() automatically + // unlinks the file so there is no need to remove/delete/unlink the file) + IGL_INLINE bool stdin_to_temp(FILE ** temp_file); +} + +#ifndef IGL_STATIC_LIBRARY +# include "stdin_to_temp.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/straighten_seams.cpp b/src/external/libigl-2.3.0/include/igl/straighten_seams.cpp new file mode 100644 index 000000000..d15f1b634 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/straighten_seams.cpp @@ -0,0 +1,370 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2017 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "straighten_seams.h" +#include "LinSpaced.h" +#include "on_boundary.h" +#include "sparse.h" +#include "max.h" +#include "count.h" +#include "any.h" +#include "slice_mask.h" +#include "slice_into.h" +#include "unique_simplices.h" +#include "adjacency_matrix.h" +#include "setxor.h" +#include "edges_to_path.h" +#include "ramer_douglas_peucker.h" +#include "vertex_components.h" +#include "list_to_matrix.h" +#include "ears.h" +#include "slice.h" +#include "sum.h" +#include "find.h" +#include + +template < + typename DerivedV, + typename DerivedF, + typename DerivedVT, + typename DerivedFT, + typename Scalar, + typename DerivedUE, + typename DerivedUT, + typename DerivedOT> +IGL_INLINE void igl::straighten_seams( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const Eigen::MatrixBase & VT, + const Eigen::MatrixBase & FT, + const Scalar tol, + Eigen::PlainObjectBase & UE, + Eigen::PlainObjectBase & UT, + Eigen::PlainObjectBase & OT) +{ + using namespace Eigen; + // number of faces + assert(FT.rows() == F.rows() && "#FT must == #F"); + assert(F.cols() == 3 && "F should contain triangles"); + assert(FT.cols() == 3 && "FT should contain triangles"); + const int m = F.rows(); + // Boundary edges of the texture map and 3d meshes + Array _; + Array BT,BF; + on_boundary(FT,_,BT); + on_boundary(F,_,BF); + assert((!((BF && (BT!=true)).any())) && + "Not dealing with boundaries of mesh that get 'stitched' in texture mesh"); + typedef Matrix MatrixX2I; + const MatrixX2I ET = (MatrixX2I(FT.rows()*3,2) + <vBT = Map >(BT.data(),BT.size(),1); + ArrayvBF = Map >(BF.data(),BF.size(),1); + MatrixX2I OF; + slice_mask(ET,vBT,1,OT); + slice_mask(EF,vBT,1,OF); + VectorXi OFMAP; + slice_mask(EFMAP,vBT,1,OFMAP); + // Two boundary edges on the texture-mapping are "equivalent" to each other on + // the 3D-mesh if their 3D-mesh vertex indices match + SparseMatrix OEQ; + { + SparseMatrix OEQR; + sparse( + igl::LinSpaced(OT.rows(),0,OT.rows()-1), + OFMAP, + Array::Ones(OT.rows(),1), + OT.rows(), + m*3, + OEQR); + OEQ = OEQR * OEQR.transpose(); + // Remove diagonal + OEQ.prune([](const int r, const int c, const bool)->bool{return r!=c;}); + } + // For each edge in OT, for each endpoint, how many _other_ texture-vertices + // are images of all the 3d-mesh vertices in F who map from "corners" in F/FT + // mapping to this endpoint. + // + // Adjacency matrix between 3d-vertices and texture-vertices + SparseMatrix V2VT; + sparse( + F, + FT, + Array::Ones(F.rows(),F.cols()), + V.rows(), + VT.rows(), + V2VT); + // For each 3d-vertex count how many different texture-coordinates its getting + // from different incident corners + VectorXi DV; + count(V2VT,2,DV); + VectorXi M,I; + max(V2VT,1,M,I); + assert( (M.array() == 1).all() ); + VectorXi DT; + // Map counts onto texture-vertices + slice(DV,I,1,DT); + // Boundary in 3D && UV + Array BTF; + slice_mask(vBF, vBT, 1, BTF); + // Texture-vertex is "sharp" if incident on "half-"edge that is not a + // boundary in the 3D mesh but is a boundary in the texture-mesh AND is not + // "cut cleanly" (the vertex is mapped to exactly 2 locations) + Array SV = Array::Zero(VT.rows(),1); + //std::cout<<"#SV: "< CL = DT.array()==2; + SparseMatrix VTOT; + { + Eigen::MatrixXi I = + igl::LinSpaced(OT.rows(),0,OT.rows()-1).replicate(1,2); + sparse( + OT, + I, + Array::Ones(OT.rows(),OT.cols()), + VT.rows(), + OT.rows(), + VTOT); + Array cuts; + count( (VTOT*OEQ).eval(), 2, cuts); + CL = (CL && (cuts.array() == 2)).eval(); + } + //std::cout<<"#CL: "< earT = Array::Zero(VT.rows(),1); + for(int e = 0;e A; + adjacency_matrix(FT,A); + earT = (earT || (A*earT.matrix()).array()).eval(); + //std::cout<<"#earT: "< V2VTSV,V2VTC; + slice_mask(V2VT,SV,2,V2VTSV); + Array Cb; + any(V2VTSV,2,Cb); + slice_mask(V2VT,Cb,1,V2VTC); + any(V2VTC,1,SV); + } + //std::cout<<"#SV: "< OTVT = VTOT.transpose(); + int nc; + ArrayXi C; + { + // Doesn't Compile on older Eigen: + //SparseMatrix A = OTVT * (!SV).matrix().asDiagonal() * VTOT; + SparseMatrix A = OTVT * (SV!=true).matrix().asDiagonal() * VTOT; + vertex_components(A,C); + nc = C.maxCoeff()+1; + } + //std::cout<<"nc: "< > vUE; + // loop over each component + std::vector done(nc,false); + for(int c = 0;c OEQIc; + slice(OEQ,Ic,1,OEQIc); + Eigen::VectorXi N; + sum(OEQIc,2,N); + const int ncopies = N(0)+1; + assert((N.array() == ncopies-1).all()); + assert((ncopies == 1 || ncopies == 2) && + "Not dealing with non-manifold meshes"); + Eigen::VectorXi vpath,epath,eend; + typedef Eigen::Matrix MatrixX2S; + switch(ncopies) + { + case 1: + { + MatrixX2I OTIc; + slice(OT,Ic,1,OTIc); + edges_to_path(OTIc,vpath,epath,eend); + Array SVvpath; + slice(SV,vpath,1,SVvpath); + assert( + (vpath(0) != vpath(vpath.size()-1) || !SVvpath.any()) && + "Not dealing with 1-loops touching 'sharp' corners"); + // simple open boundary + MatrixX2S PI; + slice(VT,vpath,1,PI); + const Scalar bbd = + (PI.colwise().maxCoeff() - PI.colwise().minCoeff()).norm(); + // Do not collapse boundaries to fewer than 3 vertices + const bool allow_boundary_collapse = false; + assert(PI.size() >= 2); + const bool is_closed = PI(0) == PI(PI.size()-1); + assert(!is_closed || vpath.size() >= 4); + Scalar eff_tol = std::min(tol,2.); + VectorXi UIc; + while(true) + { + MatrixX2S UPI,UTvpath; + ramer_douglas_peucker(PI,eff_tol*bbd,UPI,UIc,UTvpath); + slice_into(UTvpath,vpath,1,UT); + if(!is_closed || allow_boundary_collapse) + { + break; + } + if(UPI.rows()>=4) + { + break; + } + eff_tol = eff_tol*0.5; + } + for(int i = 0;i IV; + SparseMatrix OEQIcT = OEQIc.transpose().eval(); + find(OEQIcT,Icc,II,IV); + assert(II.size() == Ic.size() && + (II.array() == + igl::LinSpaced(Ic.size(),0,Ic.size()-1).array()).all()); + assert(Icc.size() == Ic.size()); + const int cc = C(Icc(0)); + Eigen::VectorXi CIcc; + slice(C,Icc,1,CIcc); + assert((CIcc.array() == cc).all()); + assert(!done[cc]); + done[cc] = true; + } + Array flipped; + { + MatrixX2I OFIc,OFIcc; + slice(OF,Ic,1,OFIc); + slice(OF,Icc,1,OFIcc); + Eigen::VectorXi XOR,IA,IB; + setxor(OFIc,OFIcc,XOR,IA,IB); + assert(XOR.size() == 0); + flipped = OFIc.array().col(0) != OFIcc.array().col(0); + } + if(Ic.size() == 1) + { + // No change to UT + vUE.push_back({OT(Ic(0),0),OT(Ic(0),1)}); + assert(Icc.size() == 1); + vUE.push_back({OT(Icc(0),flipped(0)?1:0),OT(Icc(0),flipped(0)?0:1)}); + }else + { + MatrixX2I OTIc; + slice(OT,Ic,1,OTIc); + edges_to_path(OTIc,vpath,epath,eend); + // Flip endpoints if needed + for(int e = 0;e PI(vpath.size(),VT.cols()*2); + for(int p = 0;p UPI,SI; + VectorXi UIc; + ramer_douglas_peucker(PI,tol*bbd,UPI,UIc,SI); + slice_into(SI.leftCols (VT.cols()), vpath,1,UT); + slice_into(SI.rightCols(VT.cols()),vpathc,1,UT); + for(int i = 0;i, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, double, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, double, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/straighten_seams.h b/src/external/libigl-2.3.0/include/igl/straighten_seams.h new file mode 100644 index 000000000..2eb0e9d46 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/straighten_seams.h @@ -0,0 +1,57 @@ +#ifndef IGL_STRAIGHTEN_SEAMS_H +#define IGL_STRAIGHTEN_SEAMS_H + +#include "igl_inline.h" +#include + +namespace igl +{ + // STRAIGHTEN_SEAMS Given a obj-style mesh with (V,F) defining the geometric + // surface of the mesh and (VT,FT) defining the + // parameterization/texture-mapping of the mesh in the uv-domain, find all + // seams and boundaries in the texture-mapping and "straighten" them, + // remapping vertices along the boundary and in the interior. This will be + // careful to consistently straighten multiple seams in the texture-mesh + // corresponding to the same edge chains in the surface-mesh. + // + // [UT] = straighten_seams(V,F,VT,FT) + // + // Inputs: + // V #V by 3 list of vertices + // F #F by 3 list of triangle indices + // VT #VT by 2 list of texture coordinates + // FT #F by 3 list of triangle texture coordinates + // Optional: + // 'Tol' followed by Ramer-Douglas-Peucker tolerance as a fraction of the + // curves bounding box diagonal (see dpsimplify) + // Outputs: + // UE #UE by 2 list of indices into VT of coarse output polygon edges + // UT #VT by 3 list of new texture coordinates + // OT #OT by 2 list of indices into VT of boundary edges + // + // See also: simplify_curve, dpsimplify + template < + typename DerivedV, + typename DerivedF, + typename DerivedVT, + typename DerivedFT, + typename Scalar, + typename DerivedUE, + typename DerivedUT, + typename DerivedOT> + IGL_INLINE void straighten_seams( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const Eigen::MatrixBase & VT, + const Eigen::MatrixBase & FT, + const Scalar tol, + Eigen::PlainObjectBase & UE, + Eigen::PlainObjectBase & UT, + Eigen::PlainObjectBase & OT); +} + +#ifndef IGL_STATIC_LIBRARY +# include "straighten_seams.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/string_utils.cpp b/src/external/libigl-2.3.0/include/igl/string_utils.cpp new file mode 100644 index 000000000..9d3edb1da --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/string_utils.cpp @@ -0,0 +1,22 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2020 Jérémie Dumas +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "string_utils.h" + +#include + +namespace igl { + +IGL_INLINE bool starts_with(const std::string &str, const std::string &prefix) { + return (str.rfind(prefix, 0) == 0); +} + +IGL_INLINE bool starts_with(const char *str, const char* prefix) { + return strncmp(prefix, str, strlen(prefix)) == 0; +} + +} diff --git a/src/external/libigl-2.3.0/include/igl/string_utils.h b/src/external/libigl-2.3.0/include/igl/string_utils.h new file mode 100644 index 000000000..7f4725082 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/string_utils.h @@ -0,0 +1,27 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2020 Jérémie Dumas +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_STRING_UTILS_H +#define IGL_STRING_UTILS_H + +#include "igl_inline.h" + +#include + +namespace igl { + +IGL_INLINE bool starts_with(const std::string &str, const std::string &prefix); + +IGL_INLINE bool starts_with(const char *str, const char* prefix); + +} + +#ifndef IGL_STATIC_LIBRARY +# include "string_utils.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/sum.cpp b/src/external/libigl-2.3.0/include/igl/sum.cpp new file mode 100644 index 000000000..b994ce405 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/sum.cpp @@ -0,0 +1,64 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "sum.h" +#include "redux.h" + +template +IGL_INLINE void igl::sum( + const Eigen::SparseMatrix& X, + const int dim, + Eigen::SparseVector& S) +{ + assert((dim == 1 || dim == 2) && "dim must be 2 or 1"); + // Get size of input + int m = X.rows(); + int n = X.cols(); + // resize output + if(dim==1) + { + S = Eigen::SparseVector(n); + }else + { + S = Eigen::SparseVector(m); + } + + // Iterate over outside + for(int k=0; k::InnerIterator it (X,k); it; ++it) + { + if(dim == 1) + { + S.coeffRef(it.col()) += it.value(); + }else + { + S.coeffRef(it.row()) += it.value(); + } + } + } +} + +template +IGL_INLINE void igl::sum( + const Eigen::SparseMatrix & A, + const int dim, + Eigen::PlainObjectBase& B) +{ + typedef typename DerivedB::Scalar Scalar; + igl::redux(A,dim,[](Scalar a, Scalar b){ return a+b;},B); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::sum >(Eigen::SparseMatrix const&, int, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::sum >(Eigen::SparseMatrix const&, int, Eigen::PlainObjectBase >&); +template void igl::sum(Eigen::SparseMatrix const&, int, Eigen::SparseVector&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/sum.h b/src/external/libigl-2.3.0/include/igl/sum.h new file mode 100644 index 000000000..6caeac344 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/sum.h @@ -0,0 +1,47 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_SUM_H +#define IGL_SUM_H +#include "igl_inline.h" +#include + +namespace igl +{ + // Note: If your looking for dense matrix matlab like sum for eigen matrics + // just use: + // M.colwise().sum() or M.rowwise().sum() + // + + // Sum the columns or rows of a sparse matrix + // Templates: + // T should be a eigen sparse matrix primitive type like int or double + // Inputs: + // X m by n sparse matrix + // dim dimension along which to sum (1 or 2) + // Output: + // S n-long sparse vector (if dim == 1) + // or + // S m-long sparse vector (if dim == 2) + template + IGL_INLINE void sum( + const Eigen::SparseMatrix& X, + const int dim, + Eigen::SparseVector& S); + // Sum is "conducted" in the type of DerivedB::Scalar + template + IGL_INLINE void sum( + const Eigen::SparseMatrix & A, + const int dim, + Eigen::PlainObjectBase& B); +} + +#ifndef IGL_STATIC_LIBRARY +# include "sum.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/svd3x3.cpp b/src/external/libigl-2.3.0/include/igl/svd3x3.cpp new file mode 100644 index 000000000..dd65e0cf3 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/svd3x3.cpp @@ -0,0 +1,69 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "svd3x3.h" + +#include +#include + +#define USE_SCALAR_IMPLEMENTATION +#undef USE_SSE_IMPLEMENTATION +#undef USE_AVX_IMPLEMENTATION +#define COMPUTE_U_AS_MATRIX +#define COMPUTE_V_AS_MATRIX +#include "Singular_Value_Decomposition_Preamble.hpp" + +#pragma runtime_checks( "u", off ) // disable runtime asserts on xor eax,eax type of stuff (doesn't always work, disable explicitly in compiler settings) +template +IGL_INLINE void igl::svd3x3(const Eigen::Matrix& A, Eigen::Matrix &U, Eigen::Matrix &S, Eigen::Matrix&V) +{ + // this code only supports the scalar version (otherwise we'd need to pass arrays of matrices) + +#include "Singular_Value_Decomposition_Kernel_Declarations.hpp" + + ENABLE_SCALAR_IMPLEMENTATION(Sa11.f=A(0,0);) ENABLE_SSE_IMPLEMENTATION(Va11=_mm_loadu_ps(a11);) ENABLE_AVX_IMPLEMENTATION(Va11=_mm256_loadu_ps(a11);) + ENABLE_SCALAR_IMPLEMENTATION(Sa21.f=A(1,0);) ENABLE_SSE_IMPLEMENTATION(Va21=_mm_loadu_ps(a21);) ENABLE_AVX_IMPLEMENTATION(Va21=_mm256_loadu_ps(a21);) + ENABLE_SCALAR_IMPLEMENTATION(Sa31.f=A(2,0);) ENABLE_SSE_IMPLEMENTATION(Va31=_mm_loadu_ps(a31);) ENABLE_AVX_IMPLEMENTATION(Va31=_mm256_loadu_ps(a31);) + ENABLE_SCALAR_IMPLEMENTATION(Sa12.f=A(0,1);) ENABLE_SSE_IMPLEMENTATION(Va12=_mm_loadu_ps(a12);) ENABLE_AVX_IMPLEMENTATION(Va12=_mm256_loadu_ps(a12);) + ENABLE_SCALAR_IMPLEMENTATION(Sa22.f=A(1,1);) ENABLE_SSE_IMPLEMENTATION(Va22=_mm_loadu_ps(a22);) ENABLE_AVX_IMPLEMENTATION(Va22=_mm256_loadu_ps(a22);) + ENABLE_SCALAR_IMPLEMENTATION(Sa32.f=A(2,1);) ENABLE_SSE_IMPLEMENTATION(Va32=_mm_loadu_ps(a32);) ENABLE_AVX_IMPLEMENTATION(Va32=_mm256_loadu_ps(a32);) + ENABLE_SCALAR_IMPLEMENTATION(Sa13.f=A(0,2);) ENABLE_SSE_IMPLEMENTATION(Va13=_mm_loadu_ps(a13);) ENABLE_AVX_IMPLEMENTATION(Va13=_mm256_loadu_ps(a13);) + ENABLE_SCALAR_IMPLEMENTATION(Sa23.f=A(1,2);) ENABLE_SSE_IMPLEMENTATION(Va23=_mm_loadu_ps(a23);) ENABLE_AVX_IMPLEMENTATION(Va23=_mm256_loadu_ps(a23);) + ENABLE_SCALAR_IMPLEMENTATION(Sa33.f=A(2,2);) ENABLE_SSE_IMPLEMENTATION(Va33=_mm_loadu_ps(a33);) ENABLE_AVX_IMPLEMENTATION(Va33=_mm256_loadu_ps(a33);) + +#include "Singular_Value_Decomposition_Main_Kernel_Body.hpp" + + ENABLE_SCALAR_IMPLEMENTATION(U(0,0)=Su11.f;) ENABLE_SSE_IMPLEMENTATION(_mm_storeu_ps(u11,Vu11);) ENABLE_AVX_IMPLEMENTATION(_mm256_storeu_ps(u11,Vu11);) + ENABLE_SCALAR_IMPLEMENTATION(U(1,0)=Su21.f;) ENABLE_SSE_IMPLEMENTATION(_mm_storeu_ps(u21,Vu21);) ENABLE_AVX_IMPLEMENTATION(_mm256_storeu_ps(u21,Vu21);) + ENABLE_SCALAR_IMPLEMENTATION(U(2,0)=Su31.f;) ENABLE_SSE_IMPLEMENTATION(_mm_storeu_ps(u31,Vu31);) ENABLE_AVX_IMPLEMENTATION(_mm256_storeu_ps(u31,Vu31);) + ENABLE_SCALAR_IMPLEMENTATION(U(0,1)=Su12.f;) ENABLE_SSE_IMPLEMENTATION(_mm_storeu_ps(u12,Vu12);) ENABLE_AVX_IMPLEMENTATION(_mm256_storeu_ps(u12,Vu12);) + ENABLE_SCALAR_IMPLEMENTATION(U(1,1)=Su22.f;) ENABLE_SSE_IMPLEMENTATION(_mm_storeu_ps(u22,Vu22);) ENABLE_AVX_IMPLEMENTATION(_mm256_storeu_ps(u22,Vu22);) + ENABLE_SCALAR_IMPLEMENTATION(U(2,1)=Su32.f;) ENABLE_SSE_IMPLEMENTATION(_mm_storeu_ps(u32,Vu32);) ENABLE_AVX_IMPLEMENTATION(_mm256_storeu_ps(u32,Vu32);) + ENABLE_SCALAR_IMPLEMENTATION(U(0,2)=Su13.f;) ENABLE_SSE_IMPLEMENTATION(_mm_storeu_ps(u13,Vu13);) ENABLE_AVX_IMPLEMENTATION(_mm256_storeu_ps(u13,Vu13);) + ENABLE_SCALAR_IMPLEMENTATION(U(1,2)=Su23.f;) ENABLE_SSE_IMPLEMENTATION(_mm_storeu_ps(u23,Vu23);) ENABLE_AVX_IMPLEMENTATION(_mm256_storeu_ps(u23,Vu23);) + ENABLE_SCALAR_IMPLEMENTATION(U(2,2)=Su33.f;) ENABLE_SSE_IMPLEMENTATION(_mm_storeu_ps(u33,Vu33);) ENABLE_AVX_IMPLEMENTATION(_mm256_storeu_ps(u33,Vu33);) + + ENABLE_SCALAR_IMPLEMENTATION(V(0,0)=Sv11.f;) ENABLE_SSE_IMPLEMENTATION(_mm_storeu_ps(v11,Vv11);) ENABLE_AVX_IMPLEMENTATION(_mm256_storeu_ps(v11,Vv11);) + ENABLE_SCALAR_IMPLEMENTATION(V(1,0)=Sv21.f;) ENABLE_SSE_IMPLEMENTATION(_mm_storeu_ps(v21,Vv21);) ENABLE_AVX_IMPLEMENTATION(_mm256_storeu_ps(v21,Vv21);) + ENABLE_SCALAR_IMPLEMENTATION(V(2,0)=Sv31.f;) ENABLE_SSE_IMPLEMENTATION(_mm_storeu_ps(v31,Vv31);) ENABLE_AVX_IMPLEMENTATION(_mm256_storeu_ps(v31,Vv31);) + ENABLE_SCALAR_IMPLEMENTATION(V(0,1)=Sv12.f;) ENABLE_SSE_IMPLEMENTATION(_mm_storeu_ps(v12,Vv12);) ENABLE_AVX_IMPLEMENTATION(_mm256_storeu_ps(v12,Vv12);) + ENABLE_SCALAR_IMPLEMENTATION(V(1,1)=Sv22.f;) ENABLE_SSE_IMPLEMENTATION(_mm_storeu_ps(v22,Vv22);) ENABLE_AVX_IMPLEMENTATION(_mm256_storeu_ps(v22,Vv22);) + ENABLE_SCALAR_IMPLEMENTATION(V(2,1)=Sv32.f;) ENABLE_SSE_IMPLEMENTATION(_mm_storeu_ps(v32,Vv32);) ENABLE_AVX_IMPLEMENTATION(_mm256_storeu_ps(v32,Vv32);) + ENABLE_SCALAR_IMPLEMENTATION(V(0,2)=Sv13.f;) ENABLE_SSE_IMPLEMENTATION(_mm_storeu_ps(v13,Vv13);) ENABLE_AVX_IMPLEMENTATION(_mm256_storeu_ps(v13,Vv13);) + ENABLE_SCALAR_IMPLEMENTATION(V(1,2)=Sv23.f;) ENABLE_SSE_IMPLEMENTATION(_mm_storeu_ps(v23,Vv23);) ENABLE_AVX_IMPLEMENTATION(_mm256_storeu_ps(v23,Vv23);) + ENABLE_SCALAR_IMPLEMENTATION(V(2,2)=Sv33.f;) ENABLE_SSE_IMPLEMENTATION(_mm_storeu_ps(v33,Vv33);) ENABLE_AVX_IMPLEMENTATION(_mm256_storeu_ps(v33,Vv33);) + + ENABLE_SCALAR_IMPLEMENTATION(S(0,0)=Sa11.f;) ENABLE_SSE_IMPLEMENTATION(_mm_storeu_ps(sigma1,Va11);) ENABLE_AVX_IMPLEMENTATION(_mm256_storeu_ps(sigma1,Va11);) + ENABLE_SCALAR_IMPLEMENTATION(S(1,0)=Sa22.f;) ENABLE_SSE_IMPLEMENTATION(_mm_storeu_ps(sigma2,Va22);) ENABLE_AVX_IMPLEMENTATION(_mm256_storeu_ps(sigma2,Va22);) + ENABLE_SCALAR_IMPLEMENTATION(S(2,0)=Sa33.f;) ENABLE_SSE_IMPLEMENTATION(_mm_storeu_ps(sigma3,Va33);) ENABLE_AVX_IMPLEMENTATION(_mm256_storeu_ps(sigma3,Va33);) +} +#pragma runtime_checks( "u", restore ) + +// forced instantiation +template void igl::svd3x3(const Eigen::Matrix& A, Eigen::Matrix &U, Eigen::Matrix &S, Eigen::Matrix&V); +template void igl::svd3x3(Eigen::Matrix const&, Eigen::Matrix&, Eigen::Matrix&, Eigen::Matrix&); +// doesn't even make sense with double because this SVD code is only single precision anyway... diff --git a/src/external/libigl-2.3.0/include/igl/svd3x3.h b/src/external/libigl-2.3.0/include/igl/svd3x3.h new file mode 100644 index 000000000..9029a0493 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/svd3x3.h @@ -0,0 +1,40 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_SVD3X3_H +#define IGL_SVD3X3_H +#include "igl_inline.h" +#include + +namespace igl +{ + // Super fast 3x3 SVD according to http://pages.cs.wisc.edu/~sifakis/project_pages/svd.html + // The resulting decomposition is A = U * diag(S[0], S[1], S[2]) * V' + // BEWARE: this SVD algorithm guarantees that det(U) = det(V) = 1, but this + // comes at the cost that 'sigma3' can be negative + // for computing polar decomposition it's great because all we need to do is U*V' + // and the result will automatically have positive determinant + // + // Inputs: + // A 3x3 matrix + // Outputs: + // U 3x3 left singular vectors + // S 3x1 singular values + // V 3x3 right singular vectors + // + // Known bugs: this will not work correctly for double precision. + template + IGL_INLINE void svd3x3( + const Eigen::Matrix& A, + Eigen::Matrix &U, + Eigen::Matrix &S, + Eigen::Matrix&V); +} +#ifndef IGL_STATIC_LIBRARY +# include "svd3x3.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/svd3x3_avx.cpp b/src/external/libigl-2.3.0/include/igl/svd3x3_avx.cpp new file mode 100644 index 000000000..db56ee30a --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/svd3x3_avx.cpp @@ -0,0 +1,108 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifdef __AVX__ +#include "svd3x3_avx.h" + +#include +#include + +#undef USE_SCALAR_IMPLEMENTATION +#undef USE_SSE_IMPLEMENTATION +#define USE_AVX_IMPLEMENTATION +#define COMPUTE_U_AS_MATRIX +#define COMPUTE_V_AS_MATRIX +#include "Singular_Value_Decomposition_Preamble.hpp" + +#pragma runtime_checks( "u", off ) // disable runtime asserts on xor eax,eax type of stuff (doesn't always work, disable explicitly in compiler settings) +template +IGL_INLINE void igl::svd3x3_avx( + const Eigen::Matrix& A, + Eigen::Matrix &U, + Eigen::Matrix &S, + Eigen::Matrix&V) +{ + // this code assumes USE_AVX_IMPLEMENTATION is defined + float Ashuffle[9][8], Ushuffle[9][8], Vshuffle[9][8], Sshuffle[3][8]; + for (int i=0; i<3; i++) + { + for (int j=0; j<3; j++) + { + for (int k=0; k<8; k++) + { + Ashuffle[i + j*3][k] = A(i + 3*k, j); + } + } + } + +#include "Singular_Value_Decomposition_Kernel_Declarations.hpp" + + ENABLE_AVX_IMPLEMENTATION(Va11=_mm256_loadu_ps(Ashuffle[0]);) + ENABLE_AVX_IMPLEMENTATION(Va21=_mm256_loadu_ps(Ashuffle[1]);) + ENABLE_AVX_IMPLEMENTATION(Va31=_mm256_loadu_ps(Ashuffle[2]);) + ENABLE_AVX_IMPLEMENTATION(Va12=_mm256_loadu_ps(Ashuffle[3]);) + ENABLE_AVX_IMPLEMENTATION(Va22=_mm256_loadu_ps(Ashuffle[4]);) + ENABLE_AVX_IMPLEMENTATION(Va32=_mm256_loadu_ps(Ashuffle[5]);) + ENABLE_AVX_IMPLEMENTATION(Va13=_mm256_loadu_ps(Ashuffle[6]);) + ENABLE_AVX_IMPLEMENTATION(Va23=_mm256_loadu_ps(Ashuffle[7]);) + ENABLE_AVX_IMPLEMENTATION(Va33=_mm256_loadu_ps(Ashuffle[8]);) + +#include "Singular_Value_Decomposition_Main_Kernel_Body.hpp" + + ENABLE_AVX_IMPLEMENTATION(_mm256_storeu_ps(Ushuffle[0],Vu11);) + ENABLE_AVX_IMPLEMENTATION(_mm256_storeu_ps(Ushuffle[1],Vu21);) + ENABLE_AVX_IMPLEMENTATION(_mm256_storeu_ps(Ushuffle[2],Vu31);) + ENABLE_AVX_IMPLEMENTATION(_mm256_storeu_ps(Ushuffle[3],Vu12);) + ENABLE_AVX_IMPLEMENTATION(_mm256_storeu_ps(Ushuffle[4],Vu22);) + ENABLE_AVX_IMPLEMENTATION(_mm256_storeu_ps(Ushuffle[5],Vu32);) + ENABLE_AVX_IMPLEMENTATION(_mm256_storeu_ps(Ushuffle[6],Vu13);) + ENABLE_AVX_IMPLEMENTATION(_mm256_storeu_ps(Ushuffle[7],Vu23);) + ENABLE_AVX_IMPLEMENTATION(_mm256_storeu_ps(Ushuffle[8],Vu33);) + + ENABLE_AVX_IMPLEMENTATION(_mm256_storeu_ps(Vshuffle[0],Vv11);) + ENABLE_AVX_IMPLEMENTATION(_mm256_storeu_ps(Vshuffle[1],Vv21);) + ENABLE_AVX_IMPLEMENTATION(_mm256_storeu_ps(Vshuffle[2],Vv31);) + ENABLE_AVX_IMPLEMENTATION(_mm256_storeu_ps(Vshuffle[3],Vv12);) + ENABLE_AVX_IMPLEMENTATION(_mm256_storeu_ps(Vshuffle[4],Vv22);) + ENABLE_AVX_IMPLEMENTATION(_mm256_storeu_ps(Vshuffle[5],Vv32);) + ENABLE_AVX_IMPLEMENTATION(_mm256_storeu_ps(Vshuffle[6],Vv13);) + ENABLE_AVX_IMPLEMENTATION(_mm256_storeu_ps(Vshuffle[7],Vv23);) + ENABLE_AVX_IMPLEMENTATION(_mm256_storeu_ps(Vshuffle[8],Vv33);) + + ENABLE_AVX_IMPLEMENTATION(_mm256_storeu_ps(Sshuffle[0],Va11);) + ENABLE_AVX_IMPLEMENTATION(_mm256_storeu_ps(Sshuffle[1],Va22);) + ENABLE_AVX_IMPLEMENTATION(_mm256_storeu_ps(Sshuffle[2],Va33);) + + for (int i=0; i<3; i++) + { + for (int j=0; j<3; j++) + { + for (int k=0; k<8; k++) + { + U(i + 3*k, j) = Ushuffle[i + j*3][k]; + V(i + 3*k, j) = Vshuffle[i + j*3][k]; + } + } + } + + for (int i=0; i<3; i++) + { + for (int k=0; k<8; k++) + { + S(i + 3*k, 0) = Sshuffle[i][k]; + } + } +} +#pragma runtime_checks( "u", restore ) + +#ifdef IGL_STATIC_LIBRARY +// forced instantiation +//template void igl::svd3x3_avx(const Eigen::Matrix& A, Eigen::Matrix &U, Eigen::Matrix &S, Eigen::Matrix&V); +// doesn't even make sense with double because the wunder-SVD code is only single precision anyway... +template void igl::svd3x3_avx(Eigen::Matrix const&, Eigen::Matrix&, Eigen::Matrix&, Eigen::Matrix&); +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/svd3x3_avx.h b/src/external/libigl-2.3.0/include/igl/svd3x3_avx.h new file mode 100644 index 000000000..dbe774a75 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/svd3x3_avx.h @@ -0,0 +1,40 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_SVD3X3_AVX_H +#define IGL_SVD3X3_AVX_H +#include "igl_inline.h" +#include + +namespace igl +{ + // Super fast 3x3 SVD according to + // http://pages.cs.wisc.edu/~sifakis/project_pages/svd.html This is AVX + // version of svd3x3 (see svd3x3.h) which works on 8 matrices at a time These + // eight matrices are simply stacked in columns, the rest is the same as for + // svd3x3 + // + // Inputs: + // A 12 by 3 stack of 3x3 matrices + // Outputs: + // U 12x3 left singular vectors stacked + // S 12x1 singular values stacked + // V 12x3 right singular vectors stacked + // + // Known bugs: this will not work correctly for double precision. + template + IGL_INLINE void svd3x3_avx( + const Eigen::Matrix& A, + Eigen::Matrix &U, + Eigen::Matrix &S, + Eigen::Matrix&V); +} +#ifndef IGL_STATIC_LIBRARY +# include "svd3x3_avx.cpp" +#endif +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/svd3x3_sse.cpp b/src/external/libigl-2.3.0/include/igl/svd3x3_sse.cpp new file mode 100644 index 000000000..2ef4e0fe8 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/svd3x3_sse.cpp @@ -0,0 +1,108 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifdef __SSE__ +#include "svd3x3_sse.h" + +#include +#include + +#undef USE_SCALAR_IMPLEMENTATION +#define USE_SSE_IMPLEMENTATION +#undef USE_AVX_IMPLEMENTATION +#define COMPUTE_U_AS_MATRIX +#define COMPUTE_V_AS_MATRIX +#include "Singular_Value_Decomposition_Preamble.hpp" + +// disable runtime asserts on xor eax,eax type of stuff (doesn't always work, +// disable explicitly in compiler settings) +#pragma runtime_checks( "u", off ) +template +IGL_INLINE void igl::svd3x3_sse( + const Eigen::Matrix& A, + Eigen::Matrix &U, + Eigen::Matrix &S, + Eigen::Matrix&V) +{ + // this code assumes USE_SSE_IMPLEMENTATION is defined + float Ashuffle[9][4], Ushuffle[9][4], Vshuffle[9][4], Sshuffle[3][4]; + for (int i=0; i<3; i++) + { + for (int j=0; j<3; j++) + { + for (int k=0; k<4; k++) + { + Ashuffle[i + j*3][k] = A(i + 3*k, j); + } + } + } + +#include "Singular_Value_Decomposition_Kernel_Declarations.hpp" + + ENABLE_SSE_IMPLEMENTATION(Va11=_mm_loadu_ps(Ashuffle[0]);) + ENABLE_SSE_IMPLEMENTATION(Va21=_mm_loadu_ps(Ashuffle[1]);) + ENABLE_SSE_IMPLEMENTATION(Va31=_mm_loadu_ps(Ashuffle[2]);) + ENABLE_SSE_IMPLEMENTATION(Va12=_mm_loadu_ps(Ashuffle[3]);) + ENABLE_SSE_IMPLEMENTATION(Va22=_mm_loadu_ps(Ashuffle[4]);) + ENABLE_SSE_IMPLEMENTATION(Va32=_mm_loadu_ps(Ashuffle[5]);) + ENABLE_SSE_IMPLEMENTATION(Va13=_mm_loadu_ps(Ashuffle[6]);) + ENABLE_SSE_IMPLEMENTATION(Va23=_mm_loadu_ps(Ashuffle[7]);) + ENABLE_SSE_IMPLEMENTATION(Va33=_mm_loadu_ps(Ashuffle[8]);) + +#include "Singular_Value_Decomposition_Main_Kernel_Body.hpp" + + ENABLE_SSE_IMPLEMENTATION(_mm_storeu_ps(Ushuffle[0],Vu11);) + ENABLE_SSE_IMPLEMENTATION(_mm_storeu_ps(Ushuffle[1],Vu21);) + ENABLE_SSE_IMPLEMENTATION(_mm_storeu_ps(Ushuffle[2],Vu31);) + ENABLE_SSE_IMPLEMENTATION(_mm_storeu_ps(Ushuffle[3],Vu12);) + ENABLE_SSE_IMPLEMENTATION(_mm_storeu_ps(Ushuffle[4],Vu22);) + ENABLE_SSE_IMPLEMENTATION(_mm_storeu_ps(Ushuffle[5],Vu32);) + ENABLE_SSE_IMPLEMENTATION(_mm_storeu_ps(Ushuffle[6],Vu13);) + ENABLE_SSE_IMPLEMENTATION(_mm_storeu_ps(Ushuffle[7],Vu23);) + ENABLE_SSE_IMPLEMENTATION(_mm_storeu_ps(Ushuffle[8],Vu33);) + + ENABLE_SSE_IMPLEMENTATION(_mm_storeu_ps(Vshuffle[0],Vv11);) + ENABLE_SSE_IMPLEMENTATION(_mm_storeu_ps(Vshuffle[1],Vv21);) + ENABLE_SSE_IMPLEMENTATION(_mm_storeu_ps(Vshuffle[2],Vv31);) + ENABLE_SSE_IMPLEMENTATION(_mm_storeu_ps(Vshuffle[3],Vv12);) + ENABLE_SSE_IMPLEMENTATION(_mm_storeu_ps(Vshuffle[4],Vv22);) + ENABLE_SSE_IMPLEMENTATION(_mm_storeu_ps(Vshuffle[5],Vv32);) + ENABLE_SSE_IMPLEMENTATION(_mm_storeu_ps(Vshuffle[6],Vv13);) + ENABLE_SSE_IMPLEMENTATION(_mm_storeu_ps(Vshuffle[7],Vv23);) + ENABLE_SSE_IMPLEMENTATION(_mm_storeu_ps(Vshuffle[8],Vv33);) + + ENABLE_SSE_IMPLEMENTATION(_mm_storeu_ps(Sshuffle[0],Va11);) + ENABLE_SSE_IMPLEMENTATION(_mm_storeu_ps(Sshuffle[1],Va22);) + ENABLE_SSE_IMPLEMENTATION(_mm_storeu_ps(Sshuffle[2],Va33);) + + for (int i=0; i<3; i++) + { + for (int j=0; j<3; j++) + { + for (int k=0; k<4; k++) + { + U(i + 3*k, j) = Ushuffle[i + j*3][k]; + V(i + 3*k, j) = Vshuffle[i + j*3][k]; + } + } + } + + for (int i=0; i<3; i++) + { + for (int k=0; k<4; k++) + { + S(i + 3*k, 0) = Sshuffle[i][k]; + } + } +} +#pragma runtime_checks( "u", restore ) + +// forced instantiation +template void igl::svd3x3_sse(const Eigen::Matrix& A, Eigen::Matrix &U, Eigen::Matrix &S, Eigen::Matrix&V); +//// doesn't even make sense with double because the wunder-SVD code is only single precision anyway... +//template void wunderSVD3x3_SSE(Eigen::Matrix const&, Eigen::Matrix&, Eigen::Matrix&, Eigen::Matrix&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/svd3x3_sse.h b/src/external/libigl-2.3.0/include/igl/svd3x3_sse.h new file mode 100644 index 000000000..5ddb81a66 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/svd3x3_sse.h @@ -0,0 +1,37 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_SVD3X3_SSE_H +#define IGL_SVD3X3_SSE_H +#include "igl_inline.h" +#include + +namespace igl +{ + // Super fast 3x3 SVD according to http://pages.cs.wisc.edu/~sifakis/project_pages/svd.html + // This is SSE version of svd3x3 (see svd3x3.h) which works on 4 matrices at a time + // These four matrices are simply stacked in columns, the rest is the same as for svd3x3 + // + // Inputs: + // A 12 by 3 stack of 3x3 matrices + // Outputs: + // U 12x3 left singular vectors stacked + // S 12x1 singular values stacked + // V 12x3 right singular vectors stacked + // + // Known bugs: this will not work correctly for double precision. + template + IGL_INLINE void svd3x3_sse( + const Eigen::Matrix& A, + Eigen::Matrix &U, + Eigen::Matrix &S, + Eigen::Matrix&V); +} +#ifndef IGL_STATIC_LIBRARY +# include "svd3x3_sse.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/swept_volume.cpp b/src/external/libigl-2.3.0/include/igl/swept_volume.cpp new file mode 100644 index 000000000..3c5ebe73c --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/swept_volume.cpp @@ -0,0 +1,48 @@ +#include "swept_volume.h" +#include "swept_volume_bounding_box.h" +#include "swept_volume_signed_distance.h" +#include "voxel_grid.h" +#include "marching_cubes.h" +#include + +IGL_INLINE void igl::swept_volume( + const Eigen::MatrixXd & V, + const Eigen::MatrixXi & F, + const std::function & transform, + const size_t steps, + const size_t grid_res, + const size_t isolevel_grid, + Eigen::MatrixXd & SV, + Eigen::MatrixXi & SF) +{ + using namespace std; + using namespace Eigen; + using namespace igl; + + const auto & Vtransform = + [&V,&transform](const size_t vi,const double t)->RowVector3d + { + Vector3d Vvi = V.row(vi).transpose(); + return (transform(t)*Vvi).transpose(); + }; + AlignedBox3d Mbox; + swept_volume_bounding_box(V.rows(),Vtransform,steps,Mbox); + + // Amount of padding: pad*h should be >= isolevel + const int pad = isolevel_grid+1; + // number of vertices on the largest side + const int s = grid_res+2*pad; + const double h = Mbox.diagonal().maxCoeff()/(double)(s-2.*pad-1.); + const double isolevel = isolevel_grid*h; + + // create grid + RowVector3i res; + MatrixXd GV; + voxel_grid(Mbox,s,pad,GV,res); + + // compute values + VectorXd S; + swept_volume_signed_distance(V,F,transform,steps,GV,res,h,isolevel,S); + S.array()-=isolevel; + marching_cubes(S,GV,res(0),res(1),res(2),0,SV,SF); +} diff --git a/src/external/libigl-2.3.0/include/igl/swept_volume.h b/src/external/libigl-2.3.0/include/igl/swept_volume.h new file mode 100644 index 000000000..42d9024a5 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/swept_volume.h @@ -0,0 +1,39 @@ +#ifndef IGL_SWEPT_VOLUME_H +#define IGL_SWEPT_VOLUME_H +#include "igl_inline.h" +#include +#include +namespace igl +{ + // Compute the surface of the swept volume of a solid object with surface + // (V,F) mesh under going rigid motion. + // + // Inputs: + // V #V by 3 list of mesh positions in reference pose + // F #F by 3 list of mesh indices into V + // transform function handle so that transform(t) returns the rigid + // transformation at time t∈[0,1] + // steps number of time steps: steps=3 --> t∈{0,0.5,1} + // grid_res number of grid cells on the longest side containing the + // motion (isolevel+1 cells will also be added on each side as padding) + // isolevel distance level to be contoured as swept volume + // Outputs: + // SV #SV by 3 list of mesh positions of the swept surface + // SF #SF by 3 list of mesh faces into SV + IGL_INLINE void swept_volume( + const Eigen::MatrixXd & V, + const Eigen::MatrixXi & F, + const std::function & transform, + const size_t steps, + const size_t grid_res, + const size_t isolevel, + Eigen::MatrixXd & SV, + Eigen::MatrixXi & SF); + +} + +#ifndef IGL_STATIC_LIBRARY +# include "swept_volume.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/swept_volume_bounding_box.cpp b/src/external/libigl-2.3.0/include/igl/swept_volume_bounding_box.cpp new file mode 100644 index 000000000..7fc12e2f1 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/swept_volume_bounding_box.cpp @@ -0,0 +1,28 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "swept_volume_bounding_box.h" +#include "LinSpaced.h" + +IGL_INLINE void igl::swept_volume_bounding_box( + const size_t & n, + const std::function & V, + const size_t & steps, + Eigen::AlignedBox3d & box) +{ + using namespace Eigen; + box.setEmpty(); + const VectorXd t = igl::LinSpaced(steps,0,1); + // Find extent over all time steps + for(int ti = 0;ti +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_SWEPT_VOLUME_BOUNDING_BOX_H +#define IGL_SWEPT_VOLUME_BOUNDING_BOX_H +#include "igl_inline.h" +#include +#include +#include +namespace igl +{ + // Construct an axis-aligned bounding box containing a shape undergoing a + // motion sampled at `steps` discrete momements. + // + // Inputs: + // n number of mesh vertices + // V function handle so that V(i,t) returns the 3d position of vertex + // i at time t, for t∈[0,1] + // steps number of time steps: steps=3 --> t∈{0,0.5,1} + // Outputs: + // box box containing mesh under motion + IGL_INLINE void swept_volume_bounding_box( + const size_t & n, + const std::function< + Eigen::RowVector3d(const size_t vi, const double t)> & V, + const size_t & steps, + Eigen::AlignedBox3d & box); +} + +#ifndef IGL_STATIC_LIBRARY +# include "swept_volume_bounding_box.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/swept_volume_signed_distance.cpp b/src/external/libigl-2.3.0/include/igl/swept_volume_signed_distance.cpp new file mode 100644 index 000000000..2571a7d12 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/swept_volume_signed_distance.cpp @@ -0,0 +1,122 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "swept_volume_signed_distance.h" +#include "LinSpaced.h" +#include "flood_fill.h" +#include "signed_distance.h" +#include "AABB.h" +#include "pseudonormal_test.h" +#include "per_face_normals.h" +#include "per_vertex_normals.h" +#include "per_edge_normals.h" +#include +#include +#include + +IGL_INLINE void igl::swept_volume_signed_distance( + const Eigen::MatrixXd & V, + const Eigen::MatrixXi & F, + const std::function & transform, + const size_t & steps, + const Eigen::MatrixXd & GV, + const Eigen::RowVector3i & res, + const double h, + const double isolevel, + const Eigen::VectorXd & S0, + Eigen::VectorXd & S) +{ + using namespace std; + using namespace igl; + using namespace Eigen; + S = S0; + const VectorXd t = igl::LinSpaced(steps,0,1); + const bool finite_iso = isfinite(isolevel); + const double extension = (finite_iso ? isolevel : 0) + sqrt(3.0)*h; + Eigen::AlignedBox3d box( + V.colwise().minCoeff().array()-extension, + V.colwise().maxCoeff().array()+extension); + // Precomputation + Eigen::MatrixXd FN,VN,EN; + Eigen::MatrixXi E; + Eigen::VectorXi EMAP; + per_face_normals(V,F,FN); + per_vertex_normals(V,F,PER_VERTEX_NORMALS_WEIGHTING_TYPE_ANGLE,FN,VN); + per_edge_normals( + V,F,PER_EDGE_NORMALS_WEIGHTING_TYPE_UNIFORM,FN,EN,E,EMAP); + AABB tree; + tree.init(V,F); + for(int ti = 0;ti::infinity(); + sqrd = tree.squared_distance(V,F,gv,min_sqrd,i,c); + if(sqrd & transform, + const size_t & steps, + const Eigen::MatrixXd & GV, + const Eigen::RowVector3i & res, + const double h, + const double isolevel, + Eigen::VectorXd & S) +{ + using namespace std; + using namespace igl; + using namespace Eigen; + S = VectorXd::Constant(GV.rows(),1,numeric_limits::quiet_NaN()); + return + swept_volume_signed_distance(V,F,transform,steps,GV,res,h,isolevel,S,S); +} diff --git a/src/external/libigl-2.3.0/include/igl/swept_volume_signed_distance.h b/src/external/libigl-2.3.0/include/igl/swept_volume_signed_distance.h new file mode 100644 index 000000000..86074fb67 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/swept_volume_signed_distance.h @@ -0,0 +1,64 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_SWEPT_VOLUME_SIGNED_DISTANCE_H +#define IGL_SWEPT_VOLUME_SIGNED_DISTANCE_H +#include "igl_inline.h" +#include +#include +#include +namespace igl +{ + // Compute the signed distance to a sweep surface of a mesh under-going + // an arbitrary motion V(t) discretely sampled at `steps`-many moments in + // time at a grid. + // + // Inputs: + // V #V by 3 list of mesh positions in reference pose + // F #F by 3 list of triangle indices [0,n) + // transform function handle so that transform(t) returns the rigid + // transformation at time t∈[0,1] + // steps number of time steps: steps=3 --> t∈{0,0.5,1} + // GV #GV by 3 list of evaluation point grid positions + // res 3-long resolution of GV grid + // h edge-length of grid + // isolevel isolevel to "focus" on; grid positions far enough away from + // isolevel (based on h) will get approximate values). Set + // isolevel=infinity to get good values everywhere (slow and + // unnecessary if just trying to extract isolevel-level set). + // S0 #GV initial values (will take minimum with these), can be same + // as S) + // Outputs: + // S #GV list of signed distances + IGL_INLINE void swept_volume_signed_distance( + const Eigen::MatrixXd & V, + const Eigen::MatrixXi & F, + const std::function & transform, + const size_t & steps, + const Eigen::MatrixXd & GV, + const Eigen::RowVector3i & res, + const double h, + const double isolevel, + const Eigen::VectorXd & S0, + Eigen::VectorXd & S); + IGL_INLINE void swept_volume_signed_distance( + const Eigen::MatrixXd & V, + const Eigen::MatrixXi & F, + const std::function & transform, + const size_t & steps, + const Eigen::MatrixXd & GV, + const Eigen::RowVector3i & res, + const double h, + const double isolevel, + Eigen::VectorXd & S); + } + +#ifndef IGL_STATIC_LIBRARY +# include "swept_volume_signed_distance.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/tan_half_angle.cpp b/src/external/libigl-2.3.0/include/igl/tan_half_angle.cpp new file mode 100644 index 000000000..9455241a4 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/tan_half_angle.cpp @@ -0,0 +1,37 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2018 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +#include "tan_half_angle.h" +#include +template < typename Scalar> +IGL_INLINE Scalar igl::tan_half_angle( + const Scalar & a, + const Scalar & b, + const Scalar & c) +{ + // . + // /| + // c/ | + // / | + // / | + // .α | a + // \ | + // \ | + // b\ | + // \| + // + // tan(α/2) + // Fisher 2007 + return sqrt(((a-b+c)*(a+b-c))/((a+b+c)*(-a+b+c))); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template double igl::tan_half_angle(double const&, double const&, double const&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/tan_half_angle.h b/src/external/libigl-2.3.0/include/igl/tan_half_angle.h new file mode 100644 index 000000000..053bd59fd --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/tan_half_angle.h @@ -0,0 +1,35 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2018 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_TAN_HALF_ANGLE_H +#define IGL_TAN_HALF_ANGLE_H +#include "igl_inline.h" +namespace igl +{ + // TAN_HALF_ANGLE Compute the tangent of half of the angle opposite the side + // with length a, in a triangle with side lengths (a,b,c). + // + // Inputs: + // a scalar edge length of first side of triangle + // b scalar edge length of second side of triangle + // c scalar edge length of third side of triangle + // Returns tangent of half of the angle opposite side with length a + // + // See also: is_intrinsic_delaunay + template < typename Scalar> + IGL_INLINE Scalar tan_half_angle( + const Scalar & a, + const Scalar & b, + const Scalar & c); +} + +#ifndef IGL_STATIC_LIBRARY +# include "tan_half_angle.cpp" +#endif + +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/tet_tet_adjacency.cpp b/src/external/libigl-2.3.0/include/igl/tet_tet_adjacency.cpp new file mode 100644 index 000000000..5c8b42d9e --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/tet_tet_adjacency.cpp @@ -0,0 +1,73 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2018 Oded Stein +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + + +#include "tet_tet_adjacency.h" + +#include "parallel_for.h" + +#include +#include + +template +IGL_INLINE void +igl::tet_tet_adjacency( + const Eigen::MatrixBase& T, + Eigen::PlainObjectBase& TT, + Eigen::PlainObjectBase& TTi) +{ + assert(T.cols()==4 && "Tets have four vertices."); + + //Preprocess + using Array = std::array; + std::vector TTT(4*T.rows()); + const auto loop_f = [&](const int t) { + TTT[4*t] = {T(t,0),T(t,1),T(t,2),t,0}; + TTT[4*t+1] = {T(t,0),T(t,1),T(t,3),t,1}; + TTT[4*t+2] = {T(t,1),T(t,2),T(t,3),t,2}; + TTT[4*t+3] = {T(t,2),T(t,0),T(t,3),t,3}; + for(int i=0; i<4; ++i) + std::sort(TTT[4*t+i].begin(), TTT[4*t+i].begin()+3); + }; + + //for(int t=0; t +IGL_INLINE void +igl::tet_tet_adjacency( + const Eigen::MatrixBase& T, + Eigen::PlainObjectBase& TT) +{ + DerivedTT TTi; + tet_tet_adjacency(T, TT, TTi); +} + +#ifdef IGL_STATIC_LIBRARY +template void igl::tet_tet_adjacency, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/tet_tet_adjacency.h b/src/external/libigl-2.3.0/include/igl/tet_tet_adjacency.h new file mode 100644 index 000000000..79b935c75 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/tet_tet_adjacency.h @@ -0,0 +1,51 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2018 Oded Stein +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef IGL_TET_TET_ADJACENCY_H +#define IGL_TET_TET_ADJACENCY_H + +#include + +#include + +namespace igl +{ + + // Constructs the tet_tet adjacency matrix for a given tet mesh with tets T + // + // Inputs: + // T #T by 4 list of tets + // Outputs: + // TT #T by #4 adjacency matrix, the element i,j is the id of the tet + // adjacent to the j face of tet i + // TTi #T by #4 adjacency matrix, the element i,j is the id of face of + // the tet TT(i,j) that is adjacent to tet i + // + // NOTE: the first face of a tet is [0,1,2], the second [0,1,3], the third + // [1,2,3], and the fourth [2,0,3]. + + template + IGL_INLINE void tet_tet_adjacency( + const Eigen::MatrixBase& T, + Eigen::PlainObjectBase& TT, + Eigen::PlainObjectBase& TTi); + + + template + IGL_INLINE void tet_tet_adjacency( + const Eigen::MatrixBase& T, + Eigen::PlainObjectBase& TT); + +} + +#ifndef IGL_STATIC_LIBRARY +# include "tet_tet_adjacency.cpp" +#endif + + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/tetrahedralized_grid.cpp b/src/external/libigl-2.3.0/include/igl/tetrahedralized_grid.cpp new file mode 100644 index 000000000..3bc83bbfc --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/tetrahedralized_grid.cpp @@ -0,0 +1,113 @@ +#include "tetrahedralized_grid.h" +#include "grid.h" + +template < + typename DerivedGV, + typename DerivedGT> +IGL_INLINE void igl::tetrahedralized_grid( + const int nx, + const int ny, + const int nz, + const TetrahedralizedGripType type, + Eigen::PlainObjectBase & GV, + Eigen::PlainObjectBase & GT) +{ + Eigen::RowVector3i res(nx,ny,nz); + igl::grid(res,GV); + return igl::tetrahedralized_grid(GV,res,GT); +} + +template < + typename DerivedGV, + typename Derivedside, + typename DerivedGT> +IGL_INLINE void igl::tetrahedralized_grid( + const Eigen::MatrixBase & GV, + const Eigen::MatrixBase & side, + const TetrahedralizedGripType type, + Eigen::PlainObjectBase & GT) +{ + const int nx = side(0); + const int ny = side(1); + const int nz = side(2); + typedef typename DerivedGT::Scalar Index; + const int m = (nx-1)*(ny-1)*(nz-1); + // Rotationally symmetric + int nt = -1; + switch(type) + { + default: assert(false); break; + case TETRAHEDRALIZED_GRID_TYPE_5: nt = 5; break; + case TETRAHEDRALIZED_GRID_TYPE_6_ROTATIONAL: nt = 6; break; + } + GT.resize(m*nt,4); + { + int u = 0; + for(int i = 0;i, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, igl::TetrahedralizedGripType, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +#endif diff --git a/src/external/libigl-2.3.0/include/igl/tetrahedralized_grid.h b/src/external/libigl-2.3.0/include/igl/tetrahedralized_grid.h new file mode 100644 index 000000000..47cc15f5a --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/tetrahedralized_grid.h @@ -0,0 +1,67 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2020 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_TETRAHEDRALIZED_GRID_H +#define IGL_TETRAHEDRALIZED_GRID_H +#include "igl_inline.h" +#include +namespace igl +{ + enum TetrahedralizedGripType + { + TETRAHEDRALIZED_GRID_TYPE_5 = 0, + TETRAHEDRALIZED_GRID_TYPE_6_ROTATIONAL = 1, + NUM_TETRAHEDRALIZED_GRID_TYPE = 2 + }; + // Construct vertices of a regular grid, suitable for input to + // `igl::marching_tets` + // + // Inputs: + // nx number of grid vertices in x direction + // ny number of grid vertices in y direction + // nz number of grid vertices in z direction + // type type of tetrahedralization of cube to use + // Outputs: + // GV nx*ny*nz by 3 list of grid vertex positions + // GT (nx-1)*(ny-1)*(nz-1)*k by 4 list of tetrahedron indices into rows of + // V, where k is the number of tets per cube (dependent on type) + // + // See also: triangulated_grid, quad_grid + template < + typename DerivedGV, + typename DerivedGT> + IGL_INLINE void tetrahedralized_grid( + const int nx, + const int ny, + const int nz, + const TetrahedralizedGripType type, + Eigen::PlainObjectBase & GV, + Eigen::PlainObjectBase & GT); + // + // Inputs: + // GV nx*ny*nz by 3 list of grid vertex positions + // side 3-long list {nx,ny,nz} see above + // type type of tetrahedralization of cube to use + // Outputs: + // GT (nx-1)*(ny-1)*(nz-1)*k by 4 list of tetrahedron indices into rows of + // V, where k is the number of tets per cube (dependent on type) + // + template < + typename DerivedGV, + typename Derivedside, + typename DerivedGT> + IGL_INLINE void tetrahedralized_grid( + const Eigen::MatrixBase & GV, + const Eigen::MatrixBase & side, + const TetrahedralizedGripType type, + Eigen::PlainObjectBase & GT); +} +#ifndef IGL_STATIC_LIBRARY +# include "tetrahedralized_grid.cpp" +#endif +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/tinyply.cpp b/src/external/libigl-2.3.0/include/igl/tinyply.cpp new file mode 100644 index 000000000..f15e0b18a --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/tinyply.cpp @@ -0,0 +1,794 @@ +#include "tinyply.h" +// Moved from origin tinyply.h +//////////////////////////////// +// tinyply implementation // +//////////////////////////////// + +#include +#include +#include +#include +#include +#include + +namespace tinyply +{ +template T2 endian_swap(const T & v) noexcept {assert(false);} //{ return v; } + +template<> uint16_t IGL_INLINE endian_swap(const uint16_t & v) noexcept { return (v << 8) | (v >> 8); } +template<> uint32_t IGL_INLINE endian_swap(const uint32_t & v) noexcept { return (v << 24) | ((v << 8) & 0x00ff0000) | ((v >> 8) & 0x0000ff00) | (v >> 24); } +template<> uint64_t IGL_INLINE endian_swap(const uint64_t & v) noexcept +{ + return (((v & 0x00000000000000ffLL) << 56) | + ((v & 0x000000000000ff00LL) << 40) | + ((v & 0x0000000000ff0000LL) << 24) | + ((v & 0x00000000ff000000LL) << 8) | + ((v & 0x000000ff00000000LL) >> 8) | + ((v & 0x0000ff0000000000LL) >> 24) | + ((v & 0x00ff000000000000LL) >> 40) | + ((v & 0xff00000000000000LL) >> 56)); +} +template<> int16_t IGL_INLINE endian_swap(const int16_t & v) noexcept { uint16_t r = endian_swap(*(uint16_t*)&v); return *(int16_t*)&r; } +template<> int32_t IGL_INLINE endian_swap(const int32_t & v) noexcept { uint32_t r = endian_swap(*(uint32_t*)&v); return *(int32_t*)&r; } +template<> int64_t IGL_INLINE endian_swap(const int64_t & v) noexcept { uint64_t r = endian_swap(*(uint64_t*)&v); return *(int64_t*)&r; } +template<> float IGL_INLINE endian_swap(const uint32_t & v) noexcept { union { float f; uint32_t i; }; i = endian_swap(v); return f; } +template<> double IGL_INLINE endian_swap(const uint64_t & v) noexcept { union { double d; uint64_t i; }; i = endian_swap(v); return d; } + + +IGL_INLINE uint32_t hash_fnv1a(const std::string & str) noexcept +{ + static const uint32_t fnv1aBase32 = 0x811C9DC5u; + static const uint32_t fnv1aPrime32 = 0x01000193u; + uint32_t result = fnv1aBase32; + for (auto & c : str) { result ^= static_cast(c); result *= fnv1aPrime32; } + return result; +} + +IGL_INLINE Type property_type_from_string(const std::string & t) noexcept +{ + if (t == "int8" || t == "char") return Type::INT8; + else if (t == "uint8" || t == "uchar") return Type::UINT8; + else if (t == "int16" || t == "short") return Type::INT16; + else if (t == "uint16" || t == "ushort") return Type::UINT16; + else if (t == "int32" || t == "int") return Type::INT32; + else if (t == "uint32" || t == "uint") return Type::UINT32; + else if (t == "float32" || t == "float") return Type::FLOAT32; + else if (t == "float64" || t == "double") return Type::FLOAT64; + return Type::INVALID; +} + +struct PlyFile::PlyFileImpl +{ + struct PlyDataCursor + { + size_t byteOffset{ 0 }; + size_t totalSizeBytes{ 0 }; + }; + + struct ParsingHelper + { + std::shared_ptr data; + std::shared_ptr cursor; + uint32_t list_size_hint; + }; + + struct PropertyLookup + { + ParsingHelper * helper{ nullptr }; + bool skip{ false }; + size_t prop_stride{ 0 }; // precomputed + size_t list_stride{ 0 }; // precomputed + }; + + std::unordered_map userData; + + bool isBinary = false; + bool isBigEndian = false; + std::vector elements; + std::vector comments; + std::vector objInfo; + uint8_t scratch[64]; // large enough for max list size + + void read(std::istream & is); + void write(std::ostream & os, bool isBinary); + + std::shared_ptr request_properties_from_element(const std::string & elementKey, + const std::vector propertyKeys, + const uint32_t list_size_hint); + + void add_properties_to_element(const std::string & elementKey, + const std::vector propertyKeys, + const Type type, const size_t count, uint8_t * data, const Type listType, const size_t listCount); + + size_t read_property_binary(const size_t & stride, void * dest, size_t & destOffset, std::istream & is) noexcept; + size_t read_property_ascii(const Type & t, const size_t & stride, void * dest, size_t & destOffset, std::istream & is); + + std::vector> make_property_lookup_table(); + + bool parse_header(std::istream & is); + void parse_data(std::istream & is, bool firstPass); + void read_header_format(std::istream & is); + void read_header_element(std::istream & is); + void read_header_property(std::istream & is); + void read_header_text(std::string line, std::vector & place, int erase = 0); + + void write_header(std::ostream & os) noexcept; + void write_ascii_internal(std::ostream & os) noexcept; + void write_binary_internal(std::ostream & os) noexcept; + void write_property_ascii(Type t, std::ostream & os, uint8_t * src, size_t & srcOffset); + void write_property_binary(std::ostream & os, uint8_t * src, size_t & srcOffset, const size_t & stride) noexcept; +}; + +IGL_INLINE PlyProperty::PlyProperty(std::istream & is) : isList(false) +{ + std::string type; + is >> type; + if (type == "list") + { + std::string countType; + is >> countType >> type; + listType = property_type_from_string(countType); + isList = true; + } + propertyType = property_type_from_string(type); + is >> name; +} + +IGL_INLINE PlyElement::PlyElement(std::istream & is) +{ + is >> name >> size; +} + +template IGL_INLINE T ply_read_ascii(std::istream & is) +{ + T data; + is >> data; + return data; +} + +template +IGL_INLINE void endian_swap_buffer(uint8_t * data_ptr, const size_t num_bytes, const size_t stride) +{ + for (size_t count = 0; count < num_bytes; count += stride) + { + *(reinterpret_cast(data_ptr)) = endian_swap(*(reinterpret_cast(data_ptr))); + data_ptr += stride; + } +} + +template void ply_cast_ascii(void * dest, std::istream & is) +{ + *(static_cast(dest)) = ply_read_ascii(is); +} + +IGL_INLINE int64_t find_element(const std::string & key, const std::vector & list) +{ + for (size_t i = 0; i < list.size(); i++) if (list[i].name == key) return i; + return -1; +} + +IGL_INLINE int64_t find_property(const std::string & key, const std::vector & list) +{ + for (size_t i = 0; i < list.size(); ++i) if (list[i].name == key) return i; + return -1; +} + +// The `userData` table is an easy data structure for capturing what data the +// user would like out of the ply file, but an inner-loop hash lookup is non-ideal. +// The property lookup table flattens the table down into a 2D array optimized +// for parsing. The first index is the element, and the second index is the property. +IGL_INLINE std::vector> PlyFile::PlyFileImpl::make_property_lookup_table() +{ + std::vector> element_property_lookup; + + for (auto & element : elements) + { + std::vector lookups; + + for (auto & property : element.properties) + { + PropertyLookup f; + + auto cursorIt = userData.find(hash_fnv1a(element.name + property.name)); + if (cursorIt != userData.end()) f.helper = &cursorIt->second; + else f.skip = true; + + f.prop_stride = PropertyTable[property.propertyType].stride; + if (property.isList) f.list_stride = PropertyTable[property.listType].stride; + + lookups.push_back(f); + } + + element_property_lookup.push_back(lookups); + } + + return element_property_lookup; +} + +IGL_INLINE bool PlyFile::PlyFileImpl::parse_header(std::istream & is) +{ + std::string line; + bool success = true; + while (std::getline(is, line)) + { + std::istringstream ls(line); + std::string token; + ls >> token; + if (token == "ply" || token == "PLY" || token == "") continue; + else if (token == "comment") read_header_text(line, comments, 8); + else if (token == "format") read_header_format(ls); + else if (token == "element") read_header_element(ls); + else if (token == "property") read_header_property(ls); + else if (token == "obj_info") read_header_text(line, objInfo, 9); + else if (token == "end_header") break; + else success = false; // unexpected header field + } + return success; +} + +IGL_INLINE void PlyFile::PlyFileImpl::read_header_text(std::string line, std::vector& place, int erase) +{ + place.push_back((erase > 0) ? line.erase(0, erase) : line); +} + +IGL_INLINE void PlyFile::PlyFileImpl::read_header_format(std::istream & is) +{ + std::string s; + (is >> s); + if (s == "binary_little_endian") isBinary = true; + else if (s == "binary_big_endian") isBinary = isBigEndian = true; +} + +IGL_INLINE void PlyFile::PlyFileImpl::read_header_element(std::istream & is) +{ + elements.emplace_back(is); +} + +IGL_INLINE void PlyFile::PlyFileImpl::read_header_property(std::istream & is) +{ + if (!elements.size()) throw std::runtime_error("no elements defined; file is malformed"); + elements.back().properties.emplace_back(is); +} + +IGL_INLINE size_t PlyFile::PlyFileImpl::read_property_binary(const size_t & stride, void * dest, size_t & destOffset, std::istream & is) noexcept +{ + destOffset += stride; + is.read((char*)dest, stride); + return stride; +} + +IGL_INLINE size_t PlyFile::PlyFileImpl::read_property_ascii(const Type & t, const size_t & stride, void * dest, size_t & destOffset, std::istream & is) +{ + destOffset += stride; + switch (t) + { + case Type::INT8: *((int8_t *)dest) = static_cast(ply_read_ascii(is)); break; + case Type::UINT8: *((uint8_t *)dest) = static_cast(ply_read_ascii(is)); break; + case Type::INT16: ply_cast_ascii(dest, is); break; + case Type::UINT16: ply_cast_ascii(dest, is); break; + case Type::INT32: ply_cast_ascii(dest, is); break; + case Type::UINT32: ply_cast_ascii(dest, is); break; + case Type::FLOAT32: ply_cast_ascii(dest, is); break; + case Type::FLOAT64: ply_cast_ascii(dest, is); break; + case Type::INVALID: throw std::invalid_argument("invalid ply property"); + } + return stride; +} + +IGL_INLINE void PlyFile::PlyFileImpl::write_property_ascii(Type t, std::ostream & os, uint8_t * src, size_t & srcOffset) +{ + switch (t) + { + case Type::INT8: os << static_cast(*reinterpret_cast(src)); break; + case Type::UINT8: os << static_cast(*reinterpret_cast(src)); break; + case Type::INT16: os << *reinterpret_cast(src); break; + case Type::UINT16: os << *reinterpret_cast(src); break; + case Type::INT32: os << *reinterpret_cast(src); break; + case Type::UINT32: os << *reinterpret_cast(src); break; + case Type::FLOAT32: os << *reinterpret_cast(src); break; + case Type::FLOAT64: os << *reinterpret_cast(src); break; + case Type::INVALID: throw std::invalid_argument("invalid ply property"); + } + os << " "; + srcOffset += PropertyTable[t].stride; +} + +IGL_INLINE void PlyFile::PlyFileImpl::write_property_binary(std::ostream & os, uint8_t * src, size_t & srcOffset, const size_t & stride) noexcept +{ + os.write((char *)src, stride); + srcOffset += stride; +} + +IGL_INLINE void PlyFile::PlyFileImpl::read(std::istream & is) +{ + std::vector> buffers; + for (auto & entry : userData) buffers.push_back(entry.second.data); + + // Discover if we can allocate up front without parsing the file twice + uint32_t list_hints = 0; + for (auto & b : buffers) for (auto & entry : userData) {list_hints += entry.second.list_size_hint;(void)b;} + + // No list hints? Then we need to calculate how much memory to allocate + if (list_hints == 0) + { + parse_data(is, true); + } + + // Count the number of properties (required for allocation) + // e.g. if we have properties x y and z requested, we ensure + // that their buffer points to the same PlyData + std::unordered_map unique_data_count; + for (auto & ptr : buffers) unique_data_count[ptr.get()] += 1; + + // Since group-requested properties share the same cursor, + // we need to find unique cursors so we only allocate once + std::sort(buffers.begin(), buffers.end()); + buffers.erase(std::unique(buffers.begin(), buffers.end()), buffers.end()); + + // We sorted by ptrs on PlyData, need to remap back onto its cursor in the userData table + for (auto & b : buffers) + { + for (auto & entry : userData) + { + if (entry.second.data == b && b->buffer.get() == nullptr) + { + // If we didn't receive any list hints, it means we did two passes over the + // file to compute the total length of all (potentially) variable-length lists + if (list_hints == 0) + { + b->buffer = Buffer(entry.second.cursor->totalSizeBytes); + } + else + { + // otherwise, we can allocate up front, skipping the first pass. + const size_t list_size_multiplier = (entry.second.data->isList ? entry.second.list_size_hint : 1); + auto bytes_per_property = entry.second.data->count * PropertyTable[entry.second.data->t].stride * list_size_multiplier; + bytes_per_property *= unique_data_count[b.get()]; + b->buffer = Buffer(bytes_per_property); + } + + } + } + } + + // Populate the data + parse_data(is, false); + + // In-place big-endian to little-endian swapping if required + if (isBigEndian) + { + for (auto & b : buffers) + { + uint8_t * data_ptr = b->buffer.get(); + const size_t stride = PropertyTable[b->t].stride; + const size_t buffer_size_bytes = b->buffer.size_bytes(); + + switch (b->t) + { + case Type::INT16: endian_swap_buffer(data_ptr, buffer_size_bytes, stride); break; + case Type::UINT16: endian_swap_buffer(data_ptr, buffer_size_bytes, stride); break; + case Type::INT32: endian_swap_buffer(data_ptr, buffer_size_bytes, stride); break; + case Type::UINT32: endian_swap_buffer(data_ptr, buffer_size_bytes, stride); break; + case Type::FLOAT32: endian_swap_buffer(data_ptr, buffer_size_bytes, stride); break; + case Type::FLOAT64: endian_swap_buffer(data_ptr, buffer_size_bytes, stride); break; + default: break; + } + } + } +} + +IGL_INLINE void PlyFile::PlyFileImpl::write(std::ostream & os, bool _isBinary) +{ + for (auto & d : userData) { d.second.cursor->byteOffset = 0; } + if (_isBinary) + { + isBinary = true; + isBigEndian = false; + write_binary_internal(os); + } + else + { + isBinary = false; + isBigEndian = false; + write_ascii_internal(os); + } +} + +IGL_INLINE void PlyFile::PlyFileImpl::write_binary_internal(std::ostream & os) noexcept +{ + isBinary = true; + + write_header(os); + + uint8_t listSize[4] = { 0, 0, 0, 0 }; + size_t dummyCount = 0; + + auto element_property_lookup = make_property_lookup_table(); + + size_t element_idx = 0; + for (auto & e : elements) + { + for (size_t i = 0; i < e.size; ++i) + { + size_t property_index = 0; + for (auto & p : e.properties) + { + auto & f = element_property_lookup[element_idx][property_index]; + auto * helper = f.helper; + if (f.skip || helper == nullptr) continue; + + if (p.isList) + { + std::memcpy(listSize, &p.listCount, sizeof(uint32_t)); + write_property_binary(os, listSize, dummyCount, f.list_stride); + write_property_binary(os, (helper->data->buffer.get() + helper->cursor->byteOffset), helper->cursor->byteOffset, f.prop_stride * p.listCount); + } + else + { + write_property_binary(os, (helper->data->buffer.get() + helper->cursor->byteOffset), helper->cursor->byteOffset, f.prop_stride); + } + property_index++; + } + } + element_idx++; + } +} + +IGL_INLINE void PlyFile::PlyFileImpl::write_ascii_internal(std::ostream & os) noexcept +{ + write_header(os); + + auto element_property_lookup = make_property_lookup_table(); + + size_t element_idx = 0; + for (auto & e : elements) + { + for (size_t i = 0; i < e.size; ++i) + { + size_t property_index = 0; + for (auto & p : e.properties) + { + auto & f = element_property_lookup[element_idx][property_index]; + auto * helper = f.helper; + if (f.skip || helper == nullptr) continue; + + if (p.isList) + { + os << p.listCount << " "; + for (size_t j = 0; j < p.listCount; ++j) + { + write_property_ascii(p.propertyType, os, (helper->data->buffer.get() + helper->cursor->byteOffset), helper->cursor->byteOffset); + } + } + else + { + write_property_ascii(p.propertyType, os, (helper->data->buffer.get() + helper->cursor->byteOffset), helper->cursor->byteOffset); + } + property_index++; + } + os << "\n"; + } + element_idx++; + } +} + +IGL_INLINE void PlyFile::PlyFileImpl::write_header(std::ostream & os) noexcept +{ + const std::locale & fixLoc = std::locale("C"); + os.imbue(fixLoc); + + os << "ply\n"; + if (isBinary) os << ((isBigEndian) ? "format binary_big_endian 1.0" : "format binary_little_endian 1.0") << "\n"; + else os << "format ascii 1.0\n"; + + for (const auto & comment : comments) os << "comment " << comment << "\n"; + + auto property_lookup = make_property_lookup_table(); + + size_t element_idx = 0; + for (auto & e : elements) + { + os << "element " << e.name << " " << e.size << "\n"; + size_t property_idx = 0; + for (const auto & p : e.properties) + { + PropertyLookup & lookup = property_lookup[element_idx][property_idx]; + + if (!lookup.skip) + { + if (p.isList) + { + os << "property list " << PropertyTable[p.listType].str << " " + << PropertyTable[p.propertyType].str << " " << p.name << "\n"; + } + else + { + os << "property " << PropertyTable[p.propertyType].str << " " << p.name << "\n"; + } + } + property_idx++; + } + element_idx++; + } + os << "end_header\n"; +} + +IGL_INLINE std::shared_ptr PlyFile::PlyFileImpl::request_properties_from_element(const std::string & elementKey, + const std::vector propertyKeys, + const uint32_t list_size_hint) +{ + if (elements.empty()) throw std::runtime_error("header had no elements defined. malformed file?"); + if (elementKey.empty()) throw std::invalid_argument("`elementKey` argument is empty"); + if (propertyKeys.empty()) throw std::invalid_argument("`propertyKeys` argument is empty"); + + std::shared_ptr out_data = std::make_shared(); + + const int64_t elementIndex = find_element(elementKey, elements); + + std::vector keys_not_found; + + // Sanity check if the user requested element is in the pre-parsed header + if (elementIndex >= 0) + { + // We found the element + const PlyElement & element = elements[elementIndex]; + + // Each key in `propertyKey` gets an entry into the userData map (keyed by a hash of + // element name and property name), but groups of properties (requested from the + // public api through this function) all share the same `ParsingHelper`. When it comes + // time to .read(), we check the number of unique PlyData shared pointers + // and allocate a single buffer that will be used by each property key group. + // That way, properties like, {"x", "y", "z"} will all be put into the same buffer. + + ParsingHelper helper; + helper.data = out_data; + helper.data->count = element.size; // how many items are in the element? + helper.data->isList = false; + helper.data->t = Type::INVALID; + helper.cursor = std::make_shared(); + helper.list_size_hint = list_size_hint; + + // Find each of the keys + for (const auto & key : propertyKeys) + { + const int64_t propertyIndex = find_property(key, element.properties); + if (propertyIndex < 0) keys_not_found.push_back(key); + } + + if (keys_not_found.size()) + { + std::stringstream ss; + for (auto & str : keys_not_found) ss << str << ", "; + throw std::invalid_argument("the following property keys were not found in the header: " + ss.str()); + } + + for (const auto & key : propertyKeys) + { + const int64_t propertyIndex = find_property(key, element.properties); + const PlyProperty & property = element.properties[propertyIndex]; + helper.data->t = property.propertyType; + helper.data->isList = property.isList; + auto result = userData.insert(std::pair(hash_fnv1a(element.name + property.name), helper)); + if (result.second == false) + { + throw std::invalid_argument("element-property key has already been requested: " + element.name + " " + property.name); + } + } + + // Sanity check that all properties share the same type + std::vector propertyTypes; + for (const auto & key : propertyKeys) + { + const int64_t propertyIndex = find_property(key, element.properties); + const PlyProperty & property = element.properties[propertyIndex]; + propertyTypes.push_back(property.propertyType); + } + + if (std::adjacent_find(propertyTypes.begin(), propertyTypes.end(), std::not_equal_to()) != propertyTypes.end()) + { + throw std::invalid_argument("all requested properties must share the same type."); + } + } + else throw std::invalid_argument("the element key was not found in the header: " + elementKey); + + return out_data; +} + +IGL_INLINE void PlyFile::PlyFileImpl::add_properties_to_element(const std::string & elementKey, + const std::vector propertyKeys, + const Type type, const size_t count, uint8_t * data, const Type listType, const size_t listCount) +{ + ParsingHelper helper; + helper.data = std::make_shared(); + helper.data->count = count; + helper.data->t = type; + helper.data->buffer = Buffer(data); // we should also set size for safety reasons + helper.cursor = std::make_shared(); + + auto create_property_on_element = [&](PlyElement & e) + { + for (auto key : propertyKeys) + { + PlyProperty newProp = (listType == Type::INVALID) ? PlyProperty(type, key) : PlyProperty(listType, type, key, listCount); + userData.insert(std::pair(hash_fnv1a(elementKey + key), helper)); + e.properties.push_back(newProp); + } + }; + + const int64_t idx = find_element(elementKey, elements); + if (idx >= 0) + { + PlyElement & e = elements[idx]; + create_property_on_element(e); + } + else + { + PlyElement newElement = (listType == Type::INVALID) ? PlyElement(elementKey, count) : PlyElement(elementKey, count); + create_property_on_element(newElement); + elements.push_back(newElement); + } +} + +IGL_INLINE void PlyFile::PlyFileImpl::parse_data(std::istream & is, bool firstPass) +{ + std::function read; + std::function skip; + + const auto start = is.tellg(); + + uint32_t listSize = 0; + size_t dummyCount = 0; + std::string skip_ascii_buffer; + + // Special case mirroring read_property_binary but for list types; this + // has an additional big endian check to flip the data in place immediately + // after reading. We do this as a performance optimization; endian flipping is + // done on regular properties as a post-process after reading (also for optimization) + // but we need the correct little-endian list count as we read the file. + auto read_list_binary = [this](const Type & t, void * dst, size_t & destOffset, const size_t & stride, std::istream & _is) noexcept + { + destOffset += stride; + _is.read((char*)dst, stride); + + if (isBigEndian) + { + switch (t) + { + case Type::INT16: *(int16_t*)dst = endian_swap(*(int16_t*)dst); break; + case Type::UINT16: *(uint16_t*)dst = endian_swap(*(uint16_t*)dst); break; + case Type::INT32: *(int32_t*)dst = endian_swap(*(int32_t*)dst); break; + case Type::UINT32: *(uint32_t*)dst = endian_swap(*(uint32_t*)dst); break; + default: break; + } + } + + return stride; + }; + + if (isBinary) + { + read = [this, &listSize, &dummyCount, &read_list_binary](PropertyLookup & f, const PlyProperty & p, uint8_t * dest, size_t & destOffset, std::istream & _is) noexcept + { + if (!p.isList) + { + return read_property_binary(f.prop_stride, dest + destOffset, destOffset, _is); + } + read_list_binary(p.listType, &listSize, dummyCount, f.list_stride, _is); // the list size + return read_property_binary(f.prop_stride * listSize, dest + destOffset, destOffset, _is); // properties in list + }; + skip = [this, &listSize, &dummyCount, &read_list_binary](PropertyLookup & f, const PlyProperty & p, std::istream & _is) noexcept + { + if (!p.isList) + { + _is.read((char*)scratch, f.prop_stride); + return f.prop_stride; + } + read_list_binary(p.listType, &listSize, dummyCount, f.list_stride, _is); // the list size (does not count for memory alloc) + auto bytes_to_skip = f.prop_stride * listSize; + _is.ignore(bytes_to_skip); + return bytes_to_skip; + }; + } + else + { + read = [this, &listSize, &dummyCount](PropertyLookup & f, const PlyProperty & p, uint8_t * dest, size_t & destOffset, std::istream & _is) noexcept + { + if (!p.isList) + { + read_property_ascii(p.propertyType, f.prop_stride, dest + destOffset, destOffset, _is); + } + else + { + read_property_ascii(p.listType, f.list_stride, &listSize, dummyCount, _is); // the list size + for (size_t i = 0; i < listSize; ++i) + { + read_property_ascii(p.propertyType, f.prop_stride, dest + destOffset, destOffset, _is); + } + } + }; + skip = [this, &listSize, &dummyCount, &skip_ascii_buffer](PropertyLookup & f, const PlyProperty & p, std::istream & _is) noexcept + { + skip_ascii_buffer.clear(); + if (p.isList) + { + read_property_ascii(p.listType, f.list_stride, &listSize, dummyCount, _is); // the list size (does not count for memory alloc) + for (size_t i = 0; i < listSize; ++i) _is >> skip_ascii_buffer; // properties in list + return listSize * f.prop_stride; + } + _is >> skip_ascii_buffer; + return f.prop_stride; + }; + } + + std::vector> element_property_lookup = make_property_lookup_table(); + size_t element_idx = 0; + size_t property_idx = 0; + ParsingHelper * helper {nullptr}; + + // This is the inner import loop + for (auto & element : elements) + { + for (size_t count = 0; count < element.size; ++count) + { + property_idx = 0; + for (auto & property : element.properties) + { + PropertyLookup & lookup = element_property_lookup[element_idx][property_idx]; + + if (!lookup.skip) + { + helper = lookup.helper; + if (firstPass) + { + helper->cursor->totalSizeBytes += skip(lookup, property, is); + + // These lines will be changed when tinyply supports + // variable length lists. We add it here so our header data structure + // contains enough info to write it back out again (e.g. transcoding). + if (property.listCount == 0) property.listCount = listSize; + if (property.listCount != listSize) throw std::runtime_error("variable length lists are not supported yet."); + } + else + { + read(lookup, property, helper->data->buffer.get(), helper->cursor->byteOffset, is); + } + } + else + { + skip(lookup, property, is); + } + property_idx++; + } + } + element_idx++; + } + + // Reset istream position to the start of the data + if (firstPass) is.seekg(start, is.beg); +} + +// Wrap the public interface: + +IGL_INLINE PlyFile::PlyFile() { impl.reset(new PlyFileImpl()); } +IGL_INLINE PlyFile::~PlyFile() { } +IGL_INLINE bool PlyFile::parse_header(std::istream & is) { return impl->parse_header(is); } +IGL_INLINE void PlyFile::read(std::istream & is) { return impl->read(is); } +IGL_INLINE void PlyFile::write(std::ostream & os, bool isBinary) { return impl->write(os, isBinary); } +IGL_INLINE std::vector PlyFile::get_elements() const { return impl->elements; } +IGL_INLINE std::vector & PlyFile::get_comments() { return impl->comments; } +IGL_INLINE std::vector PlyFile::get_info() const { return impl->objInfo; } +IGL_INLINE bool PlyFile::is_binary_file() const { return impl->isBinary; } +IGL_INLINE std::shared_ptr PlyFile::request_properties_from_element(const std::string & elementKey, + const std::vector propertyKeys, + const uint32_t list_size_hint) +{ + return impl->request_properties_from_element(elementKey, propertyKeys, list_size_hint); +} +IGL_INLINE void PlyFile::add_properties_to_element(const std::string & elementKey, + const std::vector propertyKeys, + const Type type, const size_t count, uint8_t * data, const Type listType, const size_t listCount) +{ + return impl->add_properties_to_element(elementKey, propertyKeys, type, count, data, listType, listCount); +} + +} // tinyply diff --git a/src/external/libigl-2.3.0/include/igl/tinyply.h b/src/external/libigl-2.3.0/include/igl/tinyply.h new file mode 100644 index 000000000..a5c575321 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/tinyply.h @@ -0,0 +1,184 @@ +/* + * tinyply 2.3.2 (https://github.com/ddiakopoulos/tinyply) + * + * A single-header, zero-dependency (except the C++ STL) public domain implementation + * of the PLY mesh file format. Requires C++11; errors are handled through exceptions. + * + * This software is in the public domain. Where that dedication is not + * recognized, you are granted a perpetual, irrevocable license to copy, + * distribute, and modify this file as you see fit. + * + * Authored by Dimitri Diakopoulos (http://www.dimitridiakopoulos.com) + * + * tinyply.h may be included in many files, however in a single compiled file, + * the implementation must be created with the following defined prior to header inclusion + * #define TINYPLY_IMPLEMENTATION + * + */ + +//////////////////////// +// tinyply header // +//////////////////////// + +#ifndef tinyply_h +#define tinyply_h +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace tinyply +{ + + enum class Type : uint8_t + { + INVALID, + INT8, + UINT8, + INT16, + UINT16, + INT32, + UINT32, + FLOAT32, + FLOAT64 + }; + + struct PropertyInfo + { + PropertyInfo() {}; + PropertyInfo(int stride, std::string str) + : stride(stride), str(str) {} + int stride {0}; + std::string str; + }; + + static std::map PropertyTable + { + { Type::INT8, PropertyInfo(1, std::string("char")) }, + { Type::UINT8, PropertyInfo(1, std::string("uchar")) }, + { Type::INT16, PropertyInfo(2, std::string("short")) }, + { Type::UINT16, PropertyInfo(2, std::string("ushort")) }, + { Type::INT32, PropertyInfo(4, std::string("int")) }, + { Type::UINT32, PropertyInfo(4, std::string("uint")) }, + { Type::FLOAT32, PropertyInfo(4, std::string("float")) }, + { Type::FLOAT64, PropertyInfo(8, std::string("double")) }, + { Type::INVALID, PropertyInfo(0, std::string("INVALID"))} + }; + + class Buffer + { + uint8_t * alias{ nullptr }; + struct delete_array { void operator()(uint8_t * p) { delete[] p; } }; + std::unique_ptr data; + size_t size {0}; + public: + Buffer() {}; + Buffer(const size_t size) : data(new uint8_t[size], delete_array()), size(size) { alias = data.get(); } // allocating + Buffer(uint8_t * ptr): alias(ptr) { } // non-allocating, todo: set size? + uint8_t * get() { return alias; } + size_t size_bytes() const { return size; } + }; + + struct PlyData + { + Type t; + Buffer buffer; + size_t count {0}; + bool isList {false}; + }; + + struct PlyProperty + { + PlyProperty(std::istream & is); + PlyProperty(Type type, std::string & _name) : name(_name), propertyType(type) {} + PlyProperty(Type list_type, Type prop_type, std::string & _name, size_t list_count) + : name(_name), propertyType(prop_type), isList(true), listType(list_type), listCount(list_count) {} + std::string name; + Type propertyType{ Type::INVALID }; + bool isList{ false }; + Type listType{ Type::INVALID }; + size_t listCount {0}; + }; + + struct PlyElement + { + PlyElement(std::istream & istream); + PlyElement(const std::string & _name, size_t count) : name(_name), size(count) {} + std::string name; + size_t size {0}; + std::vector properties; + }; + + struct PlyFile + { + struct PlyFileImpl; + std::unique_ptr impl; + + PlyFile(); + ~PlyFile(); + + /* + * The ply format requires an ascii header. This can be used to determine at + * runtime which properties or elements exist in the file. Limited validation of the + * header is performed; it is assumed the header correctly reflects the contents of the + * payload. This function may throw. Returns true on success, false on failure. + */ + bool parse_header(std::istream & is); + + /* + * Execute a read operation. Data must be requested via `request_properties_from_element(...)` + * prior to calling this function. + */ + void read(std::istream & is); + + /* + * `write` performs no validation and assumes that the data passed into + * `add_properties_to_element` is well-formed. + */ + void write(std::ostream & os, bool isBinary); + + /* + * These functions are valid after a call to `parse_header(...)`. In the case of + * writing, get_comments() reference may also be used to add new comments to the ply header. + */ + std::vector get_elements() const; + std::vector get_info() const; + std::vector & get_comments(); + bool is_binary_file() const; + + /* + * In the general case where |list_size_hint| is zero, `read` performs a two-pass + * parse to support variable length lists. The most general use of the + * ply format is storing triangle meshes. When this fact is known a-priori, we can pass + * an expected list length that will apply to this element. Doing so results in an up-front + * memory allocation and a single-pass import, a 2x performance optimization. + */ + std::shared_ptr request_properties_from_element(const std::string & elementKey, + const std::vector propertyKeys, const uint32_t list_size_hint = 0); + + void add_properties_to_element(const std::string & elementKey, + const std::vector propertyKeys, + const Type type, + const size_t count, + uint8_t * data, + const Type listType, + const size_t listCount); + }; + +} // end namespace tinyply + +#ifndef IGL_STATIC_LIBRARY +// implementation moved to tinyply.cpp +# include "tinyply.cpp" +#endif + + +#endif // end tinyply_h diff --git a/src/external/libigl-2.3.0/include/igl/topological_hole_fill.cpp b/src/external/libigl-2.3.0/include/igl/topological_hole_fill.cpp new file mode 100644 index 000000000..1ecfb536c --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/topological_hole_fill.cpp @@ -0,0 +1,55 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2018 Zhongshi Jiang +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +#include "topological_hole_fill.h" + template < + typename DerivedF, + typename Derivedb, + typename VectorIndex, + typename DerivedF_filled> +IGL_INLINE void igl::topological_hole_fill( + const Eigen::MatrixBase & F, + const Eigen::MatrixBase & b, + const std::vector & holes, + Eigen::PlainObjectBase &F_filled) +{ + int n_filled_faces = 0; + int num_holes = holes.size(); + int real_F_num = F.rows(); + const int V_rows = F.maxCoeff()+1; + + for (int i = 0; i < num_holes; i++) + n_filled_faces += holes[i].size(); + F_filled.resize(n_filled_faces + real_F_num, 3); + F_filled.topRows(real_F_num) = F; + + int new_vert_id = V_rows; + int new_face_id = real_F_num; + + for (int i = 0; i < num_holes; i++, new_vert_id++) + { + int cur_bnd_size = holes[i].size(); + int it = 0; + int back = holes[i].size() - 1; + F_filled.row(new_face_id++) << holes[i][it], holes[i][back], new_vert_id; + while (it != back) + { + F_filled.row(new_face_id++) + << holes[i][(it + 1)], + holes[i][(it)], new_vert_id; + it++; + } + } + assert(new_face_id == F_filled.rows()); + assert(new_vert_id == V_rows + num_holes); + +} + +#ifdef IGL_STATIC_LIBRARY +template void igl::topological_hole_fill, Eigen::Matrix, std::vector > >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, std::vector >, std::allocator > > > const&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/topological_hole_fill.h b/src/external/libigl-2.3.0/include/igl/topological_hole_fill.h new file mode 100644 index 000000000..945e127e8 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/topological_hole_fill.h @@ -0,0 +1,44 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2018 Zhongshi Jiang +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_TOPOLOGICAL_HOLE_FILL_H +#define IGL_TOPOLOGICAL_HOLE_FILL_H +#include "igl_inline.h" +#include +#include +namespace igl +{ + + // Topological fill hole on a mesh, with one additional vertex each hole + // Index of new abstract vertices will be F.maxCoeff() + (index of hole) + // + // Inputs: + // F #F by simplex-size list of element indices + // b #b boundary indices to preserve + // holes vector of hole loops to fill + // Outputs: + // F_filled input F stacked with filled triangles. + // + template < + typename DerivedF, + typename Derivedb, + typename VectorIndex, + typename DerivedF_filled> +IGL_INLINE void topological_hole_fill( + const Eigen::MatrixBase & F, + const Eigen::MatrixBase & b, + const std::vector & holes, + Eigen::PlainObjectBase &F_filled); + +} + + +#ifndef IGL_STATIC_LIBRARY +# include "topological_hole_fill.cpp" +#endif + +#endif \ No newline at end of file diff --git a/src/external/libigl-2.3.0/include/igl/trackball.cpp b/src/external/libigl-2.3.0/include/igl/trackball.cpp new file mode 100644 index 000000000..3a5fa2e9f --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/trackball.cpp @@ -0,0 +1,168 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "trackball.h" + +#include "EPS.h" +#include "dot.h" +#include "cross.h" +#include "axis_angle_to_quat.h" +#include "quat_mult.h" +#include +#include +#include +#include +#include + +// Utility IGL_INLINE functions +template +static IGL_INLINE Q_type _QuatD(double w, double h) +{ + using namespace std; + return (Q_type)(std::abs(w) < std::abs(h) ? std::abs(w) : std::abs(h)) - 4; +} +template +static IGL_INLINE Q_type _QuatIX(double x, double w, double h) +{ + return (2.0f*(Q_type)x - (Q_type)w - 1.0f)/_QuatD(w, h); +} +template +static IGL_INLINE Q_type _QuatIY(double y, double w, double h) +{ + return (-2.0f*(Q_type)y + (Q_type)h - 1.0f)/_QuatD(w, h); +} + +// This is largely the trackball as implemented in AntTweakbar. Much of the +// code is straight from its source in TwMgr.cpp +// http://www.antisphere.com/Wiki/tools:anttweakbar +template +IGL_INLINE void igl::trackball( + const double w, + const double h, + const Q_type speed_factor, + const double down_mouse_x, + const double down_mouse_y, + const double mouse_x, + const double mouse_y, + Q_type * quat) +{ + assert(speed_factor > 0); + + double original_x = + _QuatIX(speed_factor*(down_mouse_x-w/2)+w/2, w, h); + double original_y = + _QuatIY(speed_factor*(down_mouse_y-h/2)+h/2, w, h); + + double x = _QuatIX(speed_factor*(mouse_x-w/2)+w/2, w, h); + double y = _QuatIY(speed_factor*(mouse_y-h/2)+h/2, w, h); + + double z = 1; + double n0 = sqrt(original_x*original_x + original_y*original_y + z*z); + double n1 = sqrt(x*x + y*y + z*z); + if(n0>igl::DOUBLE_EPS && n1>igl::DOUBLE_EPS) + { + double v0[] = { original_x/n0, original_y/n0, z/n0 }; + double v1[] = { x/n1, y/n1, z/n1 }; + double axis[3]; + cross(v0,v1,axis); + double sa = sqrt(dot(axis, axis)); + double ca = dot(v0, v1); + double angle = atan2(sa, ca); + if( x*x+y*y>1.0 ) + { + angle *= 1.0 + 0.2f*(sqrt(x*x+y*y)-1.0); + } + double qrot[4]; + axis_angle_to_quat(axis,angle,qrot); + quat[0] = qrot[0]; + quat[1] = qrot[1]; + quat[2] = qrot[2]; + quat[3] = qrot[3]; + } +} + + +template +IGL_INLINE void igl::trackball( + const double w, + const double h, + const Q_type speed_factor, + const Q_type * down_quat, + const double down_mouse_x, + const double down_mouse_y, + const double mouse_x, + const double mouse_y, + Q_type * quat) +{ + double qrot[4], qres[4], qorig[4]; + igl::trackball( + w,h, + speed_factor, + down_mouse_x,down_mouse_y, + mouse_x,mouse_y, + qrot); + double nqorig = + sqrt(down_quat[0]*down_quat[0]+ + down_quat[1]*down_quat[1]+ + down_quat[2]*down_quat[2]+ + down_quat[3]*down_quat[3]); + + if( fabs(nqorig)>igl::DOUBLE_EPS_SQ ) + { + qorig[0] = down_quat[0]/nqorig; + qorig[1] = down_quat[1]/nqorig; + qorig[2] = down_quat[2]/nqorig; + qorig[3] = down_quat[3]/nqorig; + igl::quat_mult(qrot,qorig,qres); + quat[0] = qres[0]; + quat[1] = qres[1]; + quat[2] = qres[2]; + quat[3] = qres[3]; + } + else + { + quat[0] = qrot[0]; + quat[1] = qrot[1]; + quat[2] = qrot[2]; + quat[3] = qrot[3]; + } +} + +template +IGL_INLINE void igl::trackball( + const double w, + const double h, + const double speed_factor, + const Eigen::Quaternion & down_quat, + const double down_mouse_x, + const double down_mouse_y, + const double mouse_x, + const double mouse_y, + Eigen::Quaternion & quat) +{ + using namespace std; + return trackball( + w, + h, + (Scalarquat)speed_factor, + down_quat.coeffs().data(), + down_mouse_x, + down_mouse_y, + mouse_x, + mouse_y, + quat.coeffs().data()); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::trackball(double, double, double, double const*, double, double, double, double, double*); +// generated by autoexplicit.sh +template void igl::trackball(double, double, float, float const*, double, double, double, double, float*); +template void igl::trackball(double, double, double, Eigen::Quaternion const&, double, double, double, double, Eigen::Quaternion&); +template void igl::trackball(double, double, double, Eigen::Quaternion const&, double, double, double, double, Eigen::Quaternion&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/trackball.h b/src/external/libigl-2.3.0/include/igl/trackball.h new file mode 100644 index 000000000..6bf79e019 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/trackball.h @@ -0,0 +1,80 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_TRACKBALL_H +#define IGL_TRACKBALL_H +#include "igl_inline.h" +#include +#include + +namespace igl +{ + // Applies a trackball drag to identity + // Inputs: + // w width of the trackball context + // h height of the trackball context + // speed_factor controls how fast the trackball feels, 1 is normal + // down_mouse_x x position of mouse down + // down_mouse_y y position of mouse down + // mouse_x current x position of mouse + // mouse_y current y position of mouse + // Outputs: + // quat the resulting rotation (as quaternion) + template + IGL_INLINE void trackball( + const double w, + const double h, + const Q_type speed_factor, + const double down_mouse_x, + const double down_mouse_y, + const double mouse_x, + const double mouse_y, + Q_type * quat); + + // Applies a trackball drag to a given rotation + // Inputs: + // w width of the trackball context + // h height of the trackball context + // speed_factor controls how fast the trackball feels, 1 is normal + // down_quat rotation at mouse down, i.e. the rotation we're applying the + // trackball motion to (as quaternion) + // down_mouse_x x position of mouse down + // down_mouse_y y position of mouse down + // mouse_x current x position of mouse + // mouse_y current y position of mouse + // Outputs: + // quat the resulting rotation (as quaternion) + template + IGL_INLINE void trackball( + const double w, + const double h, + const Q_type speed_factor, + const Q_type * down_quat, + const double down_mouse_x, + const double down_mouse_y, + const double mouse_x, + const double mouse_y, + Q_type * quat); + // Eigen wrapper. + template + IGL_INLINE void trackball( + const double w, + const double h, + const double speed_factor, + const Eigen::Quaternion & down_quat, + const double down_mouse_x, + const double down_mouse_y, + const double mouse_x, + const double mouse_y, + Eigen::Quaternion & quat); +} + +#ifndef IGL_STATIC_LIBRARY +# include "trackball.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/transpose_blocks.cpp b/src/external/libigl-2.3.0/include/igl/transpose_blocks.cpp new file mode 100644 index 000000000..004edd7ac --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/transpose_blocks.cpp @@ -0,0 +1,63 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "transpose_blocks.h" + +#include + +template +IGL_INLINE void igl::transpose_blocks( + const Eigen::Matrix & A, + const size_t k, + const size_t dim, + Eigen::Matrix & B) +{ + // Eigen matrices must be 2d so dim must be only 1 or 2 + assert(dim == 1 || dim == 2); + // Output is not allowed to be input + assert(&A != &B); + + + // block height, width, and number of blocks + int m,n; + if(dim == 1) + { + m = A.rows()/k; + n = A.cols(); + }else// dim == 2 + { + m = A.rows(); + n = A.cols()/k; + } + + // resize output + if(dim == 1) + { + B.resize(n*k,m); + }else//dim ==2 + { + B.resize(n,m*k); + } + + // loop over blocks + for(int b = 0;b<(int)k;b++) + { + if(dim == 1) + { + B.block(b*n,0,n,m) = A.block(b*m,0,m,n).transpose(); + }else//dim ==2 + { + B.block(0,b*m,n,m) = A.block(0,b*n,m,n).transpose(); + } + } +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::transpose_blocks(Eigen::Matrix const&, size_t, size_t, Eigen::Matrix&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/transpose_blocks.h b/src/external/libigl-2.3.0/include/igl/transpose_blocks.h new file mode 100644 index 000000000..65ce89fbd --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/transpose_blocks.h @@ -0,0 +1,61 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_TRANSPOSE_BLOCKS_H +#define IGL_TRANSPOSE_BLOCKS_H +#include "igl_inline.h" + +#include + +namespace igl +{ + // Templates: + // T should be a eigen matrix primitive type like int or double + // Inputs: + // A m*k by n (dim: 1) or m by n*k (dim: 2) eigen Matrix of type T values + // k number of blocks + // dim dimension in which to transpose + // Output + // B n*k by m (dim: 1) or n by m*k (dim: 2) eigen Matrix of type T values, + // NOT allowed to be the same as A + // + // Example: + // A = [ + // 1 2 3 4 + // 5 6 7 8 + // 101 102 103 104 + // 105 106 107 108 + // 201 202 203 204 + // 205 206 207 208]; + // transpose_blocks(A,1,3,B); + // B -> [ + // 1 5 + // 2 6 + // 3 7 + // 4 8 + // 101 105 + // 102 106 + // 103 107 + // 104 108 + // 201 205 + // 202 206 + // 203 207 + // 204 208]; + // + template + IGL_INLINE void transpose_blocks( + const Eigen::Matrix & A, + const size_t k, + const size_t dim, + Eigen::Matrix & B); +} + +#ifndef IGL_STATIC_LIBRARY +# include "transpose_blocks.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/triangle/cdt.cpp b/src/external/libigl-2.3.0/include/igl/triangle/cdt.cpp new file mode 100644 index 000000000..cbe1b3e1a --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/triangle/cdt.cpp @@ -0,0 +1,58 @@ +#include "cdt.h" +#include "../bounding_box.h" +#include "../triangle/triangulate.h" +#include "../remove_duplicate_vertices.h" +#include "../remove_unreferenced.h" +#include "../slice_mask.h" + +template < + typename DerivedV, + typename DerivedE, + typename DerivedWV, + typename DerivedWF, + typename DerivedWE, + typename DerivedJ> +IGL_INLINE void igl::triangle::cdt( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & E, + const std::string & flags, + Eigen::PlainObjectBase & WV, + Eigen::PlainObjectBase & WF, + Eigen::PlainObjectBase & WE, + Eigen::PlainObjectBase & J) +{ + assert(V.cols() == 2); + assert(E.cols() == 2); + typedef typename DerivedV::Scalar Scalar; + typedef Eigen::Matrix MatrixX2S; + //MatrixX2S BV; + //Eigen::MatrixXi BE; + //igl::bounding_box(V,BV,BE); + //WV.resize(V.rows()+BV.rows(),2); + //WV<, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, std::basic_string, std::allocator > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::triangle::cdt, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, std::basic_string, std::allocator > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/triangle/cdt.h b/src/external/libigl-2.3.0/include/igl/triangle/cdt.h new file mode 100644 index 000000000..9f513e853 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/triangle/cdt.h @@ -0,0 +1,54 @@ +#ifndef IGL_TRIANGLE_CDT_H +#define IGL_TRIANGLE_CDT_H + +#include "../igl_inline.h" +#include + +namespace igl +{ + namespace triangle + { + // CDT Construct the constrained delaunay triangulation of the convex hull + // of a given set of points and segments in 2D. This differs from a direct + // call to triangulate because it will preprocess the input to remove + // duplicates and return an adjusted segment list on the output. + // + // + // BACKGROUND_MESH Construct a background mesh for a (messy) texture mesh with + // cosntraint edges that are about to deform. + // + // Inputs: + // V #V by 2 list of texture mesh vertices + // E #E by 2 list of constraint edge indices into V + // flags string of triangle flags should contain "-c" unless the + // some subset of segments are known to enclose all other + // points/segments. + // Outputs: + // WV #WV by 2 list of background mesh vertices + // WF #WF by 2 list of background mesh triangle indices into WV + // WE #WE by 2 list of constraint edge indices into WV (might be smaller + // than E because degenerate constraints have been removed) + // J #V list of indices into WF/WE for each vertex in V + // + template < + typename DerivedV, + typename DerivedE, + typename DerivedWV, + typename DerivedWF, + typename DerivedWE, + typename DerivedJ> + IGL_INLINE void cdt( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & E, + const std::string & flags, + Eigen::PlainObjectBase & WV, + Eigen::PlainObjectBase & WF, + Eigen::PlainObjectBase & WE, + Eigen::PlainObjectBase & J); + } +} + +#ifndef IGL_STATIC_LIBRARY +#include "cdt.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/triangle/scaf.cpp b/src/external/libigl-2.3.0/include/igl/triangle/scaf.cpp new file mode 100644 index 000000000..9db43357b --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/triangle/scaf.cpp @@ -0,0 +1,731 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2018 Zhongshi Jiang +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +#include "scaf.h" +#include "triangulate.h" + +#include +#include +#include +#include +#include +#include "../PI.h" +#include "../Timer.h" +#include "../boundary_loop.h" +#include "../cat.h" +#include "../doublearea.h" +#include "../flip_avoiding_line_search.h" +#include "../flipped_triangles.h" +#include "../grad.h" +#include "../harmonic.h" +#include "../local_basis.h" +#include "../map_vertices_to_circle.h" +#include "../polar_svd.h" +#include "../slice.h" +#include "../slice_into.h" +#include "../slim.h" +#include "../mapping_energy_with_jacobians.h" + +#include +#include +#include +#include +namespace igl +{ +namespace triangle +{ +namespace scaf +{ +IGL_INLINE void update_scaffold(igl::triangle::SCAFData &s) +{ + s.mv_num = s.m_V.rows(); + s.mf_num = s.m_T.rows(); + + s.v_num = s.w_uv.rows(); + s.sf_num = s.s_T.rows(); + + s.sv_num = s.v_num - s.mv_num; + s.f_num = s.sf_num + s.mf_num; + + s.s_M = Eigen::VectorXd::Constant(s.sf_num, s.scaffold_factor); +} + +IGL_INLINE void adjusted_grad(Eigen::MatrixXd &V, + Eigen::MatrixXi &F, + double area_threshold, + Eigen::SparseMatrix &Dx, + Eigen::SparseMatrix &Dy, + Eigen::SparseMatrix &Dz) +{ + Eigen::VectorXd M; + igl::doublearea(V, F, M); + std::vector degen; + for (int i = 0; i < M.size(); i++) + if (M(i) < area_threshold) + degen.push_back(i); + + Eigen::SparseMatrix G; + igl::grad(V, F, G); + + Dx = G.topRows(F.rows()); + Dy = G.block(F.rows(), 0, F.rows(), V.rows()); + Dz = G.bottomRows(F.rows()); + + // handcraft uniform gradient for faces area falling below threshold. + double sin60 = std::sin(igl::PI / 3); + double cos60 = std::cos(igl::PI / 3); + double deno = std::sqrt(sin60 * area_threshold); + Eigen::MatrixXd standard_grad(3, 3); + standard_grad << -sin60 / deno, sin60 / deno, 0, + -cos60 / deno, -cos60 / deno, 1 / deno, + 0, 0, 0; + + for (auto k : degen) + for (int j = 0; j < 3; j++) + { + Dx.coeffRef(k, F(k, j)) = standard_grad(0, j); + Dy.coeffRef(k, F(k, j)) = standard_grad(1, j); + Dz.coeffRef(k, F(k, j)) = standard_grad(2, j); + } +} + +IGL_INLINE void compute_scaffold_gradient_matrix(SCAFData &s, + Eigen::SparseMatrix &D1, + Eigen::SparseMatrix &D2) +{ + using namespace Eigen; + Eigen::SparseMatrix G; + MatrixXi F_s = s.s_T; + int vn = s.v_num; + MatrixXd V = MatrixXd::Zero(vn, 3); + V.leftCols(2) = s.w_uv; + + double min_bnd_edge_len = INFINITY; + int acc_bnd = 0; + for (int i = 0; i < s.bnd_sizes.size(); i++) + { + int current_size = s.bnd_sizes[i]; + + for (int e = acc_bnd; e < acc_bnd + current_size - 1; e++) + { + min_bnd_edge_len = (std::min)(min_bnd_edge_len, + (s.w_uv.row(s.internal_bnd(e)) - + s.w_uv.row(s.internal_bnd(e + 1))) + .squaredNorm()); + } + min_bnd_edge_len = (std::min)(min_bnd_edge_len, + (s.w_uv.row(s.internal_bnd(acc_bnd)) - + s.w_uv.row(s.internal_bnd(acc_bnd + current_size - 1))) + .squaredNorm()); + acc_bnd += current_size; + } + + double area_threshold = min_bnd_edge_len / 4.0; + Eigen::SparseMatrix Dx, Dy, Dz; + adjusted_grad(V, F_s, area_threshold, Dx, Dy, Dz); + + MatrixXd F1, F2, F3; + igl::local_basis(V, F_s, F1, F2, F3); + D1 = F1.col(0).asDiagonal() * Dx + F1.col(1).asDiagonal() * Dy + + F1.col(2).asDiagonal() * Dz; + D2 = F2.col(0).asDiagonal() * Dx + F2.col(1).asDiagonal() * Dy + + F2.col(2).asDiagonal() * Dz; +} + +IGL_INLINE void mesh_improve(igl::triangle::SCAFData &s) +{ + using namespace Eigen; + MatrixXd m_uv = s.w_uv.topRows(s.mv_num); + MatrixXd V_bnd; + V_bnd.resize(s.internal_bnd.size(), 2); + for (int i = 0; i < s.internal_bnd.size(); i++) // redoing step 1. + { + V_bnd.row(i) = m_uv.row(s.internal_bnd(i)); + } + + if (s.rect_frame_V.size() == 0) + { + Matrix2d ob; // = rect_corners; + { + VectorXd uv_max = m_uv.colwise().maxCoeff(); + VectorXd uv_min = m_uv.colwise().minCoeff(); + VectorXd uv_mid = (uv_max + uv_min) / 2.; + + Eigen::Array2d scaf_range(3, 3); + ob.row(0) = uv_mid.array() + scaf_range * ((uv_min - uv_mid).array()); + ob.row(1) = uv_mid.array() + scaf_range * ((uv_max - uv_mid).array()); + } + Vector2d rect_len; + rect_len << ob(1, 0) - ob(0, 0), ob(1, 1) - ob(0, 1); + int frame_points = 5; + + s.rect_frame_V.resize(4 * frame_points, 2); + for (int i = 0; i < frame_points; i++) + { + // 0,0;0,1 + s.rect_frame_V.row(i) << ob(0, 0), ob(0, 1) + i * rect_len(1) / frame_points; + // 0,0;1,1 + s.rect_frame_V.row(i + frame_points) + << ob(0, 0) + i * rect_len(0) / frame_points, + ob(1, 1); + // 1,0;1,1 + s.rect_frame_V.row(i + 2 * frame_points) << ob(1, 0), ob(1, 1) - i * rect_len(1) / frame_points; + // 1,0;0,1 + s.rect_frame_V.row(i + 3 * frame_points) + << ob(1, 0) - i * rect_len(0) / frame_points, + ob(0, 1); + // 0,0;0,1 + } + s.frame_ids = Eigen::VectorXi::LinSpaced(s.rect_frame_V.rows(), s.mv_num, s.mv_num + s.rect_frame_V.rows()); + } + + // Concatenate Vert and Edge + MatrixXd V; + MatrixXi E; + igl::cat(1, V_bnd, s.rect_frame_V, V); + E.resize(V.rows(), 2); + for (int i = 0; i < E.rows(); i++) + E.row(i) << i, i + 1; + int acc_bs = 0; + for (auto bs : s.bnd_sizes) + { + E(acc_bs + bs - 1, 1) = acc_bs; + acc_bs += bs; + } + E(V.rows() - 1, 1) = acc_bs; + assert(acc_bs == s.internal_bnd.size()); + + MatrixXd H = MatrixXd::Zero(s.component_sizes.size(), 2); + { + int hole_f = 0; + int hole_i = 0; + for (auto cs : s.component_sizes) + { + for (int i = 0; i < 3; i++) + H.row(hole_i) += m_uv.row(s.m_T(hole_f, i)); // redoing step 2 + hole_f += cs; + hole_i++; + } + } + H /= 3.; + + MatrixXd uv2; + igl::triangle::triangulate(V, E, H, std::basic_string("qYYQ"), uv2, s.s_T); + auto bnd_n = s.internal_bnd.size(); + + for (auto i = 0; i < s.s_T.rows(); i++) + for (auto j = 0; j < s.s_T.cols(); j++) + { + auto &x = s.s_T(i, j); + if (x < bnd_n) + x = s.internal_bnd(x); + else + x += m_uv.rows() - bnd_n; + } + + igl::cat(1, s.m_T, s.s_T, s.w_T); + s.w_uv.conservativeResize(m_uv.rows() - bnd_n + uv2.rows(), 2); + s.w_uv.bottomRows(uv2.rows() - bnd_n) = uv2.bottomRows(-bnd_n + uv2.rows()); + + update_scaffold(s); + + // after_mesh_improve + compute_scaffold_gradient_matrix(s, s.Dx_s, s.Dy_s); + + s.Dx_s.makeCompressed(); + s.Dy_s.makeCompressed(); + s.Dz_s.makeCompressed(); + s.Ri_s = MatrixXd::Zero(s.Dx_s.rows(), s.dim * s.dim); + s.Ji_s.resize(s.Dx_s.rows(), s.dim * s.dim); + s.W_s.resize(s.Dx_s.rows(), s.dim * s.dim); +} + +IGL_INLINE void add_new_patch(igl::triangle::SCAFData &s, const Eigen::MatrixXd &V_ref, + const Eigen::MatrixXi &F_ref, + const Eigen::RowVectorXd ¢er, + const Eigen::MatrixXd &uv_init) +{ + using namespace std; + using namespace Eigen; + + assert(uv_init.rows() != 0); + Eigen::VectorXd M; + igl::doublearea(V_ref, F_ref, M); + s.mesh_measure += M.sum() / 2; + + Eigen::VectorXi bnd; + Eigen::MatrixXd bnd_uv; + + std::vector> all_bnds; + igl::boundary_loop(F_ref, all_bnds); + int num_holes = all_bnds.size() - 1; + + s.component_sizes.push_back(F_ref.rows()); + + MatrixXd m_uv = s.w_uv.topRows(s.mv_num); + igl::cat(1, m_uv, uv_init, s.w_uv); + + s.m_M.conservativeResize(s.mf_num + M.size()); + s.m_M.bottomRows(M.size()) = M / 2; + + for (auto cur_bnd : all_bnds) + { + s.internal_bnd.conservativeResize(s.internal_bnd.size() + cur_bnd.size()); + s.internal_bnd.bottomRows(cur_bnd.size()) = Map(cur_bnd.data(), cur_bnd.size()) + s.mv_num; + s.bnd_sizes.push_back(cur_bnd.size()); + } + + s.m_T.conservativeResize(s.mf_num + F_ref.rows(), 3); + s.m_T.bottomRows(F_ref.rows()) = F_ref.array() + s.mv_num; + s.mf_num += F_ref.rows(); + + s.m_V.conservativeResize(s.mv_num + V_ref.rows(), 3); + s.m_V.bottomRows(V_ref.rows()) = V_ref; + s.mv_num += V_ref.rows(); + + s.rect_frame_V = MatrixXd(); + + mesh_improve(s); +} + +IGL_INLINE void compute_jacobians(SCAFData &s, const Eigen::MatrixXd &V_new, bool whole) +{ + auto comp_J2 = [](const Eigen::MatrixXd &uv, + const Eigen::SparseMatrix &Dx, + const Eigen::SparseMatrix &Dy, + Eigen::MatrixXd &Ji) { + // Ji=[D1*u,D2*u,D1*v,D2*v]; + Ji.resize(Dx.rows(), 4); + Ji.col(0) = Dx * uv.col(0); + Ji.col(1) = Dy * uv.col(0); + Ji.col(2) = Dx * uv.col(1); + Ji.col(3) = Dy * uv.col(1); + }; + + Eigen::MatrixXd m_V_new = V_new.topRows(s.mv_num); + comp_J2(m_V_new, s.Dx_m, s.Dy_m, s.Ji_m); + if (whole) + comp_J2(V_new, s.Dx_s, s.Dy_s, s.Ji_s); +} + +IGL_INLINE double compute_energy_from_jacobians(const Eigen::MatrixXd &Ji, + const Eigen::VectorXd &areas, + igl::MappingEnergyType energy_type) +{ + double energy = 0; + if (energy_type == igl::MappingEnergyType::SYMMETRIC_DIRICHLET) + energy = -4; // comply with paper description + return energy + igl::mapping_energy_with_jacobians(Ji, areas, energy_type, 0); +} + +IGL_INLINE double compute_soft_constraint_energy(const SCAFData &s) +{ + double e = 0; + for (auto const &x : s.soft_cons) + e += s.soft_const_p * (x.second - s.w_uv.row(x.first)).squaredNorm(); + + return e; +} + +IGL_INLINE double compute_energy(SCAFData &s, const Eigen::MatrixXd &w_uv, bool whole) +{ + if (w_uv.rows() != s.v_num) + assert(!whole); + compute_jacobians(s, w_uv, whole); + double energy = compute_energy_from_jacobians(s.Ji_m, s.m_M, s.slim_energy); + + if (whole) + energy += compute_energy_from_jacobians(s.Ji_s, s.s_M, s.scaf_energy); + energy += compute_soft_constraint_energy(s); + return energy; +} + +IGL_INLINE void buildAm(const Eigen::VectorXd &sqrt_M, + const Eigen::SparseMatrix &Dx, + const Eigen::SparseMatrix &Dy, + const Eigen::MatrixXd &W, + Eigen::SparseMatrix &Am) +{ + std::vector> IJV; + Eigen::SparseMatrix Dz; + + Eigen::SparseMatrix MDx = sqrt_M.asDiagonal() * Dx; + Eigen::SparseMatrix MDy = sqrt_M.asDiagonal() * Dy; + igl::slim_buildA(MDx, MDy, Dz, W, IJV); + + Am.setFromTriplets(IJV.begin(), IJV.end()); + Am.makeCompressed(); +} + +IGL_INLINE void buildRhs(const Eigen::VectorXd &sqrt_M, + const Eigen::MatrixXd &W, + const Eigen::MatrixXd &Ri, + Eigen::VectorXd &f_rhs) +{ + const int dim = (W.cols() == 4) ? 2 : 3; + const int f_n = W.rows(); + f_rhs.resize(dim * dim * f_n); + + for (int i = 0; i < f_n; i++) + { + auto sqrt_area = sqrt_M(i); + f_rhs(i + 0 * f_n) = sqrt_area * (W(i, 0) * Ri(i, 0) + W(i, 1) * Ri(i, 1)); + f_rhs(i + 1 * f_n) = sqrt_area * (W(i, 0) * Ri(i, 2) + W(i, 1) * Ri(i, 3)); + f_rhs(i + 2 * f_n) = sqrt_area * (W(i, 2) * Ri(i, 0) + W(i, 3) * Ri(i, 1)); + f_rhs(i + 3 * f_n) = sqrt_area * (W(i, 2) * Ri(i, 2) + W(i, 3) * Ri(i, 3)); + } +} + +IGL_INLINE void get_complement(const Eigen::VectorXi &bnd_ids, int v_n, Eigen::ArrayXi &unknown_ids) +{ // get the complement of bnd_ids. + int assign = 0, i = 0; + for (int get = 0; i < v_n && get < bnd_ids.size(); i++) + { + if (bnd_ids(get) == i) + get++; + else + unknown_ids(assign++) = i; + } + while (i < v_n) + unknown_ids(assign++) = i++; + assert(assign + bnd_ids.size() == v_n); +} + +IGL_INLINE void build_surface_linear_system(const SCAFData &s, Eigen::SparseMatrix &L, Eigen::VectorXd &rhs) +{ + using namespace Eigen; + using namespace std; + + const int v_n = s.v_num - (s.frame_ids.size()); + const int dim = s.dim; + const int f_n = s.mf_num; + + // to get the complete A + Eigen::VectorXd sqrtM = s.m_M.array().sqrt(); + Eigen::SparseMatrix A(dim * dim * f_n, dim * v_n); + auto decoy_Dx_m = s.Dx_m; + decoy_Dx_m.conservativeResize(s.W_m.rows(), v_n); + auto decoy_Dy_m = s.Dy_m; + decoy_Dy_m.conservativeResize(s.W_m.rows(), v_n); + buildAm(sqrtM, decoy_Dx_m, decoy_Dy_m, s.W_m, A); + + const VectorXi &bnd_ids = s.fixed_ids; + auto bnd_n = bnd_ids.size(); + if (bnd_n == 0) + { + + Eigen::SparseMatrix At = A.transpose(); + At.makeCompressed(); + + Eigen::SparseMatrix id_m(At.rows(), At.rows()); + id_m.setIdentity(); + + L = At * A; + + Eigen::VectorXd frhs; + buildRhs(sqrtM, s.W_m, s.Ri_m, frhs); + rhs = At * frhs; + } + else + { + MatrixXd bnd_pos; + igl::slice(s.w_uv, bnd_ids, 1, bnd_pos); + ArrayXi known_ids(bnd_ids.size() * dim); + ArrayXi unknown_ids((v_n - bnd_ids.rows()) * dim); + get_complement(bnd_ids, v_n, unknown_ids); + VectorXd known_pos(bnd_ids.size() * dim); + for (int d = 0; d < dim; d++) + { + auto n_b = bnd_ids.rows(); + known_ids.segment(d * n_b, n_b) = bnd_ids.array() + d * v_n; + known_pos.segment(d * n_b, n_b) = bnd_pos.col(d); + unknown_ids.block(d * (v_n - n_b), 0, v_n - n_b, unknown_ids.cols()) = + unknown_ids.topRows(v_n - n_b) + d * v_n; + } + + Eigen::SparseMatrix Au, Ae; + igl::slice(A, unknown_ids, 2, Au); + igl::slice(A, known_ids, 2, Ae); + + Eigen::SparseMatrix Aut = Au.transpose(); + Aut.makeCompressed(); + + L = Aut * Au; + + Eigen::VectorXd frhs; + buildRhs(sqrtM, s.W_m, s.Ri_m, frhs); + + rhs = Aut * (frhs - Ae * known_pos); + } + + // add soft constraints. + for (auto const &x : s.soft_cons) + { + int v_idx = x.first; + + for (int d = 0; d < dim; d++) + { + rhs(d * (v_n) + v_idx) += s.soft_const_p * x.second(d); // rhs + L.coeffRef(d * v_n + v_idx, + d * v_n + v_idx) += s.soft_const_p; // diagonal + } + } +} + +IGL_INLINE void build_scaffold_linear_system(const SCAFData &s, Eigen::SparseMatrix &L, Eigen::VectorXd &rhs) +{ + using namespace Eigen; + + const int f_n = s.W_s.rows(); + const int v_n = s.Dx_s.cols(); + const int dim = s.dim; + + Eigen::VectorXd sqrtM = s.s_M.array().sqrt(); + Eigen::SparseMatrix A(dim * dim * f_n, dim * v_n); + buildAm(sqrtM, s.Dx_s, s.Dy_s, s.W_s, A); + + VectorXi bnd_ids; + igl::cat(1, s.fixed_ids, s.frame_ids, bnd_ids); + + auto bnd_n = bnd_ids.size(); + assert(bnd_n > 0); + MatrixXd bnd_pos; + igl::slice(s.w_uv, bnd_ids, 1, bnd_pos); + + ArrayXi known_ids(bnd_ids.size() * dim); + ArrayXi unknown_ids((v_n - bnd_ids.rows()) * dim); + + get_complement(bnd_ids, v_n, unknown_ids); + + VectorXd known_pos(bnd_ids.size() * dim); + for (int d = 0; d < dim; d++) + { + auto n_b = bnd_ids.rows(); + known_ids.segment(d * n_b, n_b) = bnd_ids.array() + d * v_n; + known_pos.segment(d * n_b, n_b) = bnd_pos.col(d); + unknown_ids.block(d * (v_n - n_b), 0, v_n - n_b, unknown_ids.cols()) = + unknown_ids.topRows(v_n - n_b) + d * v_n; + } + Eigen::VectorXd sqrt_M = s.s_M.array().sqrt(); + + // manual slicing for A(:, unknown/known)' + Eigen::SparseMatrix Au, Ae; + igl::slice(A, unknown_ids, 2, Au); + igl::slice(A, known_ids, 2, Ae); + + Eigen::SparseMatrix Aut = Au.transpose(); + Aut.makeCompressed(); + + L = Aut * Au; + + Eigen::VectorXd frhs; + buildRhs(sqrtM, s.W_s, s.Ri_s, frhs); + + rhs = Aut * (frhs - Ae * known_pos); +} + +IGL_INLINE void build_weighted_arap_system(SCAFData &s, Eigen::SparseMatrix &L, Eigen::VectorXd &rhs) +{ + // fixed frame solving: + // x_e as the fixed frame, x_u for unknowns (mesh + unknown scaffold) + // min ||(A_u*x_u + A_e*x_e) - b||^2 + // => A_u'*A_u*x_u = Au'* (b - A_e*x_e) := Au'* b_u + // + // separate matrix build: + // min ||A_m x_m - b_m||^2 + ||A_s x_all - b_s||^2 + soft + proximal + // First change dimension of A_m to fit for x_all + // (Not just at the end, since x_all is flattened along dimensions) + // L = A_m'*A_m + A_s'*A_s + soft + proximal + // rhs = A_m'* b_m + A_s' * b_s + soft + proximal + // + Eigen::SparseMatrix L_m, L_s; + Eigen::VectorXd rhs_m, rhs_s; + build_surface_linear_system(s, L_m, rhs_m); // complete Am, with soft + build_scaffold_linear_system(s, L_s, rhs_s); // complete As, without proximal + + L = L_m + L_s; + rhs = rhs_m + rhs_s; + L.makeCompressed(); +} + +IGL_INLINE void solve_weighted_arap(SCAFData &s, Eigen::MatrixXd &uv) +{ + using namespace Eigen; + using namespace std; + int dim = s.dim; + igl::Timer timer; + timer.start(); + + VectorXi bnd_ids; + igl::cat(1, s.fixed_ids, s.frame_ids, bnd_ids); + const auto v_n = s.v_num; + const auto bnd_n = bnd_ids.size(); + assert(bnd_n > 0); + MatrixXd bnd_pos; + igl::slice(s.w_uv, bnd_ids, 1, bnd_pos); + + ArrayXi known_ids(bnd_n * dim); + ArrayXi unknown_ids((v_n - bnd_n) * dim); + + get_complement(bnd_ids, v_n, unknown_ids); + + VectorXd known_pos(bnd_ids.size() * dim); + for (int d = 0; d < dim; d++) + { + auto n_b = bnd_ids.rows(); + known_ids.segment(d * n_b, n_b) = bnd_ids.array() + d * v_n; + known_pos.segment(d * n_b, n_b) = bnd_pos.col(d); + unknown_ids.block(d * (v_n - n_b), 0, v_n - n_b, unknown_ids.cols()) = + unknown_ids.topRows(v_n - n_b) + d * v_n; + } + + Eigen::SparseMatrix L; + Eigen::VectorXd rhs; + build_weighted_arap_system(s, L, rhs); + + Eigen::VectorXd unknown_Uc((v_n - s.frame_ids.size() - s.fixed_ids.size()) * dim), Uc(dim * v_n); + + SimplicialLDLT> solver; + unknown_Uc = solver.compute(L).solve(rhs); + igl::slice_into(unknown_Uc, unknown_ids.matrix(), 1, Uc); + igl::slice_into(known_pos, known_ids.matrix(), 1, Uc); + + uv = Map>(Uc.data(), v_n, dim); +} + +IGL_INLINE double perform_iteration(SCAFData &s) +{ + Eigen::MatrixXd V_out = s.w_uv; + compute_jacobians(s, V_out, true); + igl::slim_update_weights_and_closest_rotations_with_jacobians(s.Ji_m, s.slim_energy, 0, s.W_m, s.Ri_m); + igl::slim_update_weights_and_closest_rotations_with_jacobians(s.Ji_s, s.scaf_energy, 0, s.W_s, s.Ri_s); + solve_weighted_arap(s, V_out); + auto whole_E = [&s](Eigen::MatrixXd &uv) { return compute_energy(s, uv, true); }; + + Eigen::MatrixXi w_T; + if (s.m_T.cols() == s.s_T.cols()) + igl::cat(1, s.m_T, s.s_T, w_T); + else + w_T = s.s_T; + return igl::flip_avoiding_line_search(w_T, s.w_uv, V_out, + whole_E, -1) / + s.mesh_measure; +} + +} +} +} + +IGL_INLINE void igl::triangle::scaf_precompute( + const Eigen::MatrixXd &V, + const Eigen::MatrixXi &F, + const Eigen::MatrixXd &V_init, + igl::triangle::SCAFData &data, + igl::MappingEnergyType slim_energy, + Eigen::VectorXi &b, + Eigen::MatrixXd &bc, + double soft_p) +{ + Eigen::MatrixXd CN; + Eigen::MatrixXi FN; + igl::triangle::scaf::add_new_patch(data, V, F, Eigen::RowVector2d(0, 0), V_init); + data.soft_const_p = soft_p; + for (int i = 0; i < b.rows(); i++) + data.soft_cons[b(i)] = bc.row(i); + data.slim_energy = slim_energy; + + auto &s = data; + + if (!data.has_pre_calc) + { + int v_n = s.mv_num + s.sv_num; + int f_n = s.mf_num + s.sf_num; + int dim = s.dim; + Eigen::MatrixXd F1, F2, F3; + igl::local_basis(s.m_V, s.m_T, F1, F2, F3); + auto face_proj = [](Eigen::MatrixXd& F){ + std::vector >IJV; + int f_num = F.rows(); + for(int i=0; i(i, i, F(i,0))); + IJV.push_back(Eigen::Triplet(i, i+f_num, F(i,1))); + IJV.push_back(Eigen::Triplet(i, i+2*f_num, F(i,2))); + } + Eigen::SparseMatrix P(f_num, 3*f_num); + P.setFromTriplets(IJV.begin(), IJV.end()); + return P; + }; + Eigen::SparseMatrix G; + igl::grad(s.m_V, s.m_T, G); + s.Dx_m = face_proj(F1) * G; + s.Dy_m = face_proj(F2) * G; + + igl::triangle::scaf::compute_scaffold_gradient_matrix(s, s.Dx_s, s.Dy_s); + + s.Dx_m.makeCompressed(); + s.Dy_m.makeCompressed(); + s.Ri_m = Eigen::MatrixXd::Zero(s.Dx_m.rows(), dim * dim); + s.Ji_m.resize(s.Dx_m.rows(), dim * dim); + s.W_m.resize(s.Dx_m.rows(), dim * dim); + + s.Dx_s.makeCompressed(); + s.Dy_s.makeCompressed(); + s.Ri_s = Eigen::MatrixXd::Zero(s.Dx_s.rows(), dim * dim); + s.Ji_s.resize(s.Dx_s.rows(), dim * dim); + s.W_s.resize(s.Dx_s.rows(), dim * dim); + + data.has_pre_calc = true; + } +} + +IGL_INLINE Eigen::MatrixXd igl::triangle::scaf_solve(igl::triangle::SCAFData &s, int iter_num) +{ + using namespace std; + using namespace Eigen; + s.energy = igl::triangle::scaf::compute_energy(s, s.w_uv, false) / s.mesh_measure; + + for (int it = 0; it < iter_num; it++) + { + s.total_energy = igl::triangle::scaf::compute_energy(s, s.w_uv, true) / s.mesh_measure; + s.rect_frame_V = Eigen::MatrixXd(); + igl::triangle::scaf::mesh_improve(s); + + double new_weight = s.mesh_measure * s.energy / (s.sf_num * 100); + s.scaffold_factor = new_weight; + igl::triangle::scaf::update_scaffold(s); + + s.total_energy = igl::triangle::scaf::perform_iteration(s); + + s.energy = + igl::triangle::scaf::compute_energy(s, s.w_uv, false) / s.mesh_measure; + } + + return s.w_uv.topRows(s.mv_num); +} + +IGL_INLINE void igl::triangle::scaf_system(igl::triangle::SCAFData &s, Eigen::SparseMatrix &L, Eigen::VectorXd &rhs) +{ + s.energy = igl::triangle::scaf::compute_energy(s, s.w_uv, false) / s.mesh_measure; + + s.total_energy = igl::triangle::scaf::compute_energy(s, s.w_uv, true) / s.mesh_measure; + s.rect_frame_V = Eigen::MatrixXd(); + igl::triangle::scaf::mesh_improve(s); + + double new_weight = s.mesh_measure * s.energy / (s.sf_num * 100); + s.scaffold_factor = new_weight; + igl::triangle::scaf::update_scaffold(s); + + igl::triangle::scaf::compute_jacobians(s, s.w_uv, true); + igl::slim_update_weights_and_closest_rotations_with_jacobians(s.Ji_m, s.slim_energy, 0, s.W_m, s.Ri_m); + igl::slim_update_weights_and_closest_rotations_with_jacobians(s.Ji_s, s.scaf_energy, 0, s.W_s, s.Ri_s); + + igl::triangle::scaf::build_weighted_arap_system(s, L, rhs); +} + +#ifdef IGL_STATIC_LIBRARY +#endif diff --git a/src/external/libigl-2.3.0/include/igl/triangle/scaf.h b/src/external/libigl-2.3.0/include/igl/triangle/scaf.h new file mode 100644 index 000000000..101e06b77 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/triangle/scaf.h @@ -0,0 +1,122 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2018 Zhongshi Jiang +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_SCAF_H +#define IGL_SCAF_H + +#include "../slim.h" +#include "../igl_inline.h" +#include "../MappingEnergyType.h" + +namespace igl +{ + namespace triangle + { + // Use a similar interface to igl::slim + // Implement ready-to-use 2D version of the algorithm described in + // SCAF: Simplicial Complex Augmentation Framework for Bijective Maps + // Zhongshi Jiang, Scott Schaefer, Daniele Panozzo, ACM Trancaction on Graphics (Proc. SIGGRAPH Asia 2017) + // For a complete implementation and customized UI, please refer to https://github.com/jiangzhongshi/scaffold-map + + struct SCAFData + { + double scaffold_factor = 10; + igl::MappingEnergyType scaf_energy = igl::MappingEnergyType::SYMMETRIC_DIRICHLET; + igl::MappingEnergyType slim_energy = igl::MappingEnergyType::SYMMETRIC_DIRICHLET; + + // Output + int dim = 2; + double total_energy; // scaffold + isometric + double energy; // objective value + + long mv_num = 0, mf_num = 0; + long sv_num = 0, sf_num = 0; + long v_num{}, f_num = 0; + Eigen::MatrixXd m_V; // input initial mesh V + Eigen::MatrixXi m_T; // input initial mesh F/T + // INTERNAL + Eigen::MatrixXd w_uv; // whole domain uv: mesh + free vertices + Eigen::MatrixXi s_T; // scaffold domain tets: scaffold tets + Eigen::MatrixXi w_T; + + Eigen::VectorXd m_M; // mesh area or volume + Eigen::VectorXd s_M; // scaffold area or volume + Eigen::VectorXd w_M; // area/volume weights for whole + double mesh_measure; // area or volume + double proximal_p = 0; + + Eigen::VectorXi frame_ids; + Eigen::VectorXi fixed_ids; + + std::map soft_cons; + double soft_const_p = 1e4; + + Eigen::VectorXi internal_bnd; + Eigen::MatrixXd rect_frame_V; + // multi-chart support + std::vector component_sizes; + std::vector bnd_sizes; + + // reweightedARAP interior variables. + bool has_pre_calc = false; + Eigen::SparseMatrix Dx_s, Dy_s, Dz_s; + Eigen::SparseMatrix Dx_m, Dy_m, Dz_m; + Eigen::MatrixXd Ri_m, Ji_m, Ri_s, Ji_s; + Eigen::MatrixXd W_m, W_s; + }; + + + // Compute necessary information to start using SCAF + // Inputs: + // V #V by 3 list of mesh vertex positions + // F #F by 3/3 list of mesh faces (triangles/tets) + // data igl::SCAFData + // slim_energy Energy type to minimize + // b list of boundary indices into V (soft constraint) + // bc #b by dim list of boundary conditions (soft constraint) + // soft_p Soft penalty factor (can be zero) + IGL_INLINE void scaf_precompute( + const Eigen::MatrixXd &V, + const Eigen::MatrixXi &F, + const Eigen::MatrixXd &V_init, + triangle::SCAFData &data, + MappingEnergyType slim_energy, + Eigen::VectorXi& b, + Eigen::MatrixXd& bc, + double soft_p); + + // Run iter_num iterations of SCAF, with precomputed data + // Outputs: + // V_o (in SLIMData): #V by dim list of mesh vertex positions + IGL_INLINE Eigen::MatrixXd scaf_solve(triangle::SCAFData &data, int iter_num); + + // Set up the SCAF system L * uv = rhs, without solving it. + // Inputs: + // s: igl::SCAFData. Will be modified by energy and Jacobian computation. + // Outputs: + // L: m by m matrix + // rhs: m by 1 vector + // with m = dim * (#V_mesh + #V_scaf - #V_frame) + IGL_INLINE void scaf_system(triangle::SCAFData &s, Eigen::SparseMatrix &L, Eigen::VectorXd &rhs); + + namespace scaf + { + // Compute SCAF energy + // Inputs: + // s: igl::SCAFData + // w_uv: (#V_mesh + #V_scaf) by dim matrix + // whole: Include scaffold if true + IGL_INLINE double compute_energy(SCAFData &s, const Eigen::MatrixXd &w_uv, bool whole); + } + } +} + +#ifndef IGL_STATIC_LIBRARY +# include "scaf.cpp" +#endif + +#endif //IGL_SCAF_H diff --git a/src/external/libigl-2.3.0/include/igl/triangle/triangulate.cpp b/src/external/libigl-2.3.0/include/igl/triangle/triangulate.cpp new file mode 100644 index 000000000..1169c3b76 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/triangle/triangulate.cpp @@ -0,0 +1,179 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Daniele Panozzo +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "triangulate.h" +#ifdef ANSI_DECLARATORS +# define IGL_PREVIOUSLY_DEFINED_ANSI_DECLARATORS ANSI_DECLARATORS +# undef ANSI_DECLARATORS +#endif +#ifdef REAL +# define IGL_PREVIOUSLY_DEFINED_REAL REAL +# undef REAL +#endif +#ifdef VOID +# define IGL_PREVIOUSLY_DEFINED_VOID VOID +# undef VOID +#endif +#define ANSI_DECLARATORS +#define REAL double +#define VOID int + +extern "C" +{ +#include +} + +#undef ANSI_DECLARATORS +#ifdef IGL_PREVIOUSLY_DEFINED_ANSI_DECLARATORS +# define ANSI_DECLARATORS IGL_PREVIOUSLY_DEFINED_ANSI_DECLARATORS +#endif + +#undef REAL +#ifdef IGL_PREVIOUSLY_DEFINED_REAL +# define REAL IGL_PREVIOUSLY_DEFINED_REAL +#endif + +#undef VOID +#ifdef IGL_PREVIOUSLY_DEFINED_VOID +# define VOID IGL_PREVIOUSLY_DEFINED_VOID +#endif + +template < + typename DerivedV, + typename DerivedE, + typename DerivedH, + typename DerivedV2, + typename DerivedF2> +IGL_INLINE void igl::triangle::triangulate( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & E, + const Eigen::MatrixBase & H, + const std::string flags, + Eigen::PlainObjectBase & V2, + Eigen::PlainObjectBase & F2) +{ + Eigen::VectorXi VM,EM,VM2,EM2; + return triangulate(V,E,H,VM,EM,flags,V2,F2,VM2,EM2); +} + +template < + typename DerivedV, + typename DerivedE, + typename DerivedH, + typename DerivedVM, + typename DerivedEM, + typename DerivedV2, + typename DerivedF2, + typename DerivedVM2, + typename DerivedEM2> +IGL_INLINE void igl::triangle::triangulate( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & E, + const Eigen::MatrixBase & H, + const Eigen::MatrixBase & VM, + const Eigen::MatrixBase & EM, + const std::string flags, + Eigen::PlainObjectBase & V2, + Eigen::PlainObjectBase & F2, + Eigen::PlainObjectBase & VM2, + Eigen::PlainObjectBase & EM2) +{ + using namespace std; + using namespace Eigen; + + assert( (VM.size() == 0 || V.rows() == VM.size()) && + "Vertex markers must be empty or same size as V"); + assert( (EM.size() == 0 || E.rows() == EM.size()) && + "Segment markers must be empty or same size as E"); + assert(V.cols() == 2); + assert(E.size() == 0 || E.cols() == 2); + assert(H.size() == 0 || H.cols() == 2); + + // Prepare the flags + string full_flags = flags + "pz" + (EM.size() || VM.size() ? "" : "B"); + + typedef Map< Matrix > MapXdr; + typedef Map< Matrix > MapXir; + + // Prepare the input struct + triangulateio in; + in.numberofpoints = V.rows(); + in.pointlist = (double*)calloc(V.size(),sizeof(double)); + { + MapXdr inpl(in.pointlist,V.rows(),V.cols()); + inpl = V.template cast(); + } + + in.numberofpointattributes = 0; + in.pointmarkerlist = (int*)calloc(V.size(),sizeof(int)) ; + for(unsigned i=0;i(); + } + in.segmentmarkerlist = (int*)calloc(E.rows(),sizeof(int)); + for (unsigned i=0;i(); + } + in.numberofregions = 0; + + // Prepare the output struct + triangulateio out; + out.pointlist = NULL; + out.trianglelist = NULL; + out.segmentlist = NULL; + out.segmentmarkerlist = NULL; + out.pointmarkerlist = NULL; + + // Call triangle + ::triangulate(const_cast(full_flags.c_str()), &in, &out, 0); + + // Return the mesh + V2 = MapXdr(out.pointlist,out.numberofpoints,2).cast(); + F2 = MapXir(out.trianglelist,out.numberoftriangles,3).cast(); + if(VM.size()) + { + VM2 = MapXir(out.pointmarkerlist,out.numberofpoints,1).cast(); + } + if(EM.size()) + { + EM2 = MapXir(out.segmentmarkerlist,out.numberofsegments,1).cast(); + } + + // Cleanup in + free(in.pointlist); + free(in.pointmarkerlist); + free(in.segmentlist); + free(in.segmentmarkerlist); + free(in.holelist); + // Cleanup out + free(out.pointlist); + free(out.trianglelist); + free(out.segmentlist); + free(out.segmentmarkerlist); + free(out.pointmarkerlist); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +template void igl::triangle::triangulate, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, std::basic_string, std::allocator >, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::triangle::triangulate, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, std::basic_string, std::allocator >, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/triangle/triangulate.h b/src/external/libigl-2.3.0/include/igl/triangle/triangulate.h new file mode 100644 index 000000000..90abdac9d --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/triangle/triangulate.h @@ -0,0 +1,87 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Daniele Panozzo +// Copyright (C) 2017 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_TRIANGLE_TRIANGULATE_H +#define IGL_TRIANGLE_TRIANGULATE_H +#include "../igl_inline.h" +#include +#include + +namespace igl +{ + namespace triangle + { + // Triangulate the interior of a polygon using the triangle library. + // + // Inputs: + // V #V by 2 list of 2D vertex positions + // E #E by 2 list of vertex ids forming unoriented edges of the boundary of the polygon + // H #H by 2 coordinates of points contained inside holes of the polygon + // flags string of options pass to triangle (see triangle documentation) + // Outputs: + // V2 #V2 by 2 coordinates of the vertives of the generated triangulation + // F2 #F2 by 3 list of indices forming the faces of the generated triangulation + // + template < + typename DerivedV, + typename DerivedE, + typename DerivedH, + typename DerivedV2, + typename DerivedF2> + IGL_INLINE void triangulate( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & E, + const Eigen::MatrixBase & H, + const std::string flags, + Eigen::PlainObjectBase & V2, + Eigen::PlainObjectBase & F2); + + // Triangulate the interior of a polygon using the triangle library. + // + // Inputs: + // V #V by 2 list of 2D vertex positions + // E #E by 2 list of vertex ids forming unoriented edges of the boundary of the polygon + // H #H by 2 coordinates of points contained inside holes of the polygon + // M #V list of markers for input vertices + // flags string of options pass to triangle (see triangle documentation) + // Outputs: + // V2 #V2 by 2 coordinates of the vertives of the generated triangulation + // F2 #F2 by 3 list of indices forming the faces of the generated triangulation + // M2 #V2 list of markers for output vertices + // + // TODO: expose the option to prevent Steiner points on the boundary + // + template < + typename DerivedV, + typename DerivedE, + typename DerivedH, + typename DerivedVM, + typename DerivedEM, + typename DerivedV2, + typename DerivedF2, + typename DerivedVM2, + typename DerivedEM2> + IGL_INLINE void triangulate( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & E, + const Eigen::MatrixBase & H, + const Eigen::MatrixBase & VM, + const Eigen::MatrixBase & EM, + const std::string flags, + Eigen::PlainObjectBase & V2, + Eigen::PlainObjectBase & F2, + Eigen::PlainObjectBase & VM2, + Eigen::PlainObjectBase & EM2); + } +} + +#ifndef IGL_STATIC_LIBRARY +# include "triangulate.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/triangle_fan.cpp b/src/external/libigl-2.3.0/include/igl/triangle_fan.cpp new file mode 100644 index 000000000..97f2887ec --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/triangle_fan.cpp @@ -0,0 +1,58 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "triangle_fan.h" +#include "exterior_edges.h" +#include "list_to_matrix.h" + +template +IGL_INLINE void igl::triangle_fan( + const Eigen::MatrixBase & E, + Eigen::PlainObjectBase & cap) +{ + using namespace std; + using namespace Eigen; + + // Handle lame base case + if(E.size() == 0) + { + cap.resize(0,E.cols()+1); + return; + } + // "Triangulate" aka "close" the E trivially with facets + // Note: in 2D we need to know if E endpoints are incoming or + // outgoing (left or right). Thus this will not work. + assert(E.cols() == 2); + // Arbitrary starting vertex + //int s = E(int(((double)rand() / RAND_MAX)*E.rows()),0); + int s = E(rand()%E.rows(),0); + vector > lcap; + for(int i = 0;i e(3); + e[0] = s; + e[1] = E(i,0); + e[2] = E(i,1); + lcap.push_back(e); + } + list_to_matrix(lcap,cap); +} + +IGL_INLINE Eigen::MatrixXi igl::triangle_fan( const Eigen::MatrixXi & E) +{ + Eigen::MatrixXi cap; + triangle_fan(E,cap); + return cap; +} + +#if IGL_STATIC_LIBRARY +#endif diff --git a/src/external/libigl-2.3.0/include/igl/triangle_fan.h b/src/external/libigl-2.3.0/include/igl/triangle_fan.h new file mode 100644 index 000000000..bd9dca73b --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/triangle_fan.h @@ -0,0 +1,31 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_TRIANGLE_FAN_H +#define IGL_TRIANGLE_FAN_H +#include "igl_inline.h" +#include +namespace igl +{ + // Given a list of faces tessellate all of the "exterior" edges forming another + // list of + // + // Inputs: + // E #E by simplex_size-1 list of exterior edges (see exterior_edges.h) + // Outputs: + // cap #cap by simplex_size list of "faces" tessellating the boundary edges + template + IGL_INLINE void triangle_fan( + const Eigen::MatrixBase & E, + Eigen::PlainObjectBase & cap); + // In-line version + IGL_INLINE Eigen::MatrixXi triangle_fan( const Eigen::MatrixXi & E); +} +#ifndef IGL_STATIC_LIBRARY +# include "triangle_fan.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/triangle_triangle_adjacency.cpp b/src/external/libigl-2.3.0/include/igl/triangle_triangle_adjacency.cpp new file mode 100644 index 000000000..901d2e12f --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/triangle_triangle_adjacency.cpp @@ -0,0 +1,275 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2018 Alec Jacobson, Marc Alexa +// Copyright (C) 2014 Daniele Panozzo +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "triangle_triangle_adjacency.h" +#include "vertex_triangle_adjacency.h" +#include "parallel_for.h" +#include "unique_edge_map.h" +#include +#include + +// Extract the face adjacencies +template +IGL_INLINE void igl::triangle_triangle_adjacency_extractTT( + const Eigen::MatrixBase& F, + std::vector >& TTT, + Eigen::PlainObjectBase& TT) +{ + TT.setConstant((int)(F.rows()),F.cols(),-1); + + for(int i=1;i<(int)TTT.size();++i) + { + std::vector& r1 = TTT[i-1]; + std::vector& r2 = TTT[i]; + if ((r1[0] == r2[0]) && (r1[1] == r2[1])) + { + TT(r1[2],r1[3]) = r2[2]; + TT(r2[2],r2[3]) = r1[2]; + } + } +} + +template +IGL_INLINE void igl::triangle_triangle_adjacency( + const Eigen::MatrixBase& F, + Eigen::PlainObjectBase& TT) +{ + const int n = F.maxCoeff()+1; + typedef Eigen::Matrix VectorXI; + VectorXI VF,NI; + vertex_triangle_adjacency(F,n,VF,NI); + TT = DerivedTT::Constant(F.rows(),3,-1); + // Loop over faces + igl::parallel_for(F.rows(),[&](int f) + { + // Loop over corners + for (int k = 0; k < 3; k++) + { + int vi = F(f,k), vin = F(f,(k+1)%3); + // Loop over face neighbors incident on this corner + for (int j = NI[vi]; j < NI[vi+1]; j++) + { + int fn = VF[j]; + // Not this face + if (fn != f) + { + // Face neighbor also has [vi,vin] edge + if (F(fn,0) == vin || F(fn,1) == vin || F(fn,2) == vin) + { + TT(f,k) = fn; + break; + } + } + } + } + }); +} + +template +IGL_INLINE void igl::triangle_triangle_adjacency_preprocess( + const Eigen::MatrixBase& F, + std::vector >& TTT) +{ + for(int f=0;f v2) std::swap(v1,v2); + std::vector r(4); + r[0] = v1; r[1] = v2; + r[2] = f; r[3] = i; + TTT.push_back(r); + } + std::sort(TTT.begin(),TTT.end()); +} + +// Extract the face adjacencies indices (needed for fast traversal) +template +IGL_INLINE void igl::triangle_triangle_adjacency_extractTTi( + const Eigen::MatrixBase& F, + std::vector >& TTT, + Eigen::PlainObjectBase& TTi) +{ + TTi.setConstant((int)(F.rows()),F.cols(),-1); + + for(int i=1;i<(int)TTT.size();++i) + { + std::vector& r1 = TTT[i-1]; + std::vector& r2 = TTT[i]; + if ((r1[0] == r2[0]) && (r1[1] == r2[1])) + { + TTi(r1[2],r1[3]) = r2[3]; + TTi(r2[2],r2[3]) = r1[3]; + } + } +} + +// Compute triangle-triangle adjacency with indices +template +IGL_INLINE void igl::triangle_triangle_adjacency( + const Eigen::MatrixBase& F, + Eigen::PlainObjectBase& TT, + Eigen::PlainObjectBase& TTi) +{ + triangle_triangle_adjacency(F,TT); + TTi = DerivedTTi::Constant(TT.rows(),TT.cols(),-1); + //for(int f = 0; f= 0) + { + for(int kn = 0;kn<3;kn++) + { + int vin = F(fn,kn), vjn = F(fn,(kn+1)%3); + if(vi == vjn && vin == vj) + { + TTi(f,k) = kn; + break; + } + } + } + } + }); +} + +template < + typename DerivedF, + typename TTIndex, + typename TTiIndex> + IGL_INLINE void igl::triangle_triangle_adjacency( + const Eigen::MatrixBase & F, + std::vector > > & TT, + std::vector > > & TTi) +{ + return triangle_triangle_adjacency(F,true,TT,TTi); +} + +template < + typename DerivedF, + typename TTIndex> + IGL_INLINE void igl::triangle_triangle_adjacency( + const Eigen::MatrixBase & F, + std::vector > > & TT) +{ + std::vector > > not_used; + return triangle_triangle_adjacency(F,false,TT,not_used); +} + +template < + typename DerivedF, + typename TTIndex, + typename TTiIndex> + IGL_INLINE void igl::triangle_triangle_adjacency( + const Eigen::MatrixBase & F, + const bool construct_TTi, + std::vector > > & TT, + std::vector > > & TTi) +{ + using namespace Eigen; + using namespace std; + assert(F.cols() == 3 && "Faces must be triangles"); + // number of faces + typedef typename DerivedF::Index Index; + typedef Matrix MatrixX2I; + typedef Matrix VectorXI; + MatrixX2I E,uE; + VectorXI EMAP; + vector > uE2E; + unique_edge_map(F,E,uE,EMAP,uE2E); + return triangle_triangle_adjacency(E,EMAP,uE2E,construct_TTi,TT,TTi); +} + +template < + typename DerivedE, + typename DerivedEMAP, + typename uE2EType, + typename TTIndex, + typename TTiIndex> + IGL_INLINE void igl::triangle_triangle_adjacency( + const Eigen::MatrixBase & E, + const Eigen::MatrixBase & EMAP, + const std::vector > & uE2E, + const bool construct_TTi, + std::vector > > & TT, + std::vector > > & TTi) +{ + using namespace std; + using namespace Eigen; + typedef typename DerivedE::Index Index; + const size_t m = E.rows()/3; + assert((size_t)E.rows() == m*3 && "E should come from list of triangles."); + // E2E[i] --> {j,k,...} means face edge i corresponds to other faces edges j + // and k + TT.resize (m,vector >(3)); + if(construct_TTi) + { + TTi.resize(m,vector >(3)); + } + + // No race conditions because TT*[f][c]'s are in bijection with e's + // Minimum number of items per thread + //const size_t num_e = E.rows(); + // Slightly better memory access than loop over E + igl::parallel_for( + m, + [&](const Index & f) + { + for(Index c = 0;c<3;c++) + { + const Index e = f + m*c; + //const Index c = e/m; + const vector & N = uE2E[EMAP(e)]; + for(const auto & ne : N) + { + const Index nf = ne%m; + // don't add self + if(nf != f) + { + TT[f][c].push_back(nf); + if(construct_TTi) + { + const Index nc = ne/m; + TTi[f][c].push_back(nc); + } + } + } + } + }, + 1000ul); + + +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::triangle_triangle_adjacency, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::triangle_triangle_adjacency, int>(Eigen::MatrixBase > const&, std::vector >, std::allocator > > >, std::allocator >, std::allocator > > > > >&); +// generated by autoexplicit.sh +template void igl::triangle_triangle_adjacency, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::triangle_triangle_adjacency, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::triangle_triangle_adjacency, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::triangle_triangle_adjacency, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::triangle_triangle_adjacency, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::triangle_triangle_adjacency, long, long>(Eigen::MatrixBase > const&, std::vector >, std::allocator > > >, std::allocator >, std::allocator > > > > >&, std::vector >, std::allocator > > >, std::allocator >, std::allocator > > > > >&); +template void igl::triangle_triangle_adjacency, int>(Eigen::MatrixBase > const&, std::vector >, std::allocator > > >, std::allocator >, std::allocator > > > > >&); +#ifdef WIN32 +template void igl::triangle_triangle_adjacency, __int64, __int64>(class Eigen::MatrixBase> const &, class std::vector>, class std::allocator>>>, class std::allocator>, class std::allocator>>>>> &, class std::vector>, class std::allocator>>>, class std::allocator>, class std::allocator>>>>> &); +template void igl::triangle_triangle_adjacency, class Eigen::Matrix, unsigned __int64, int, int>(class Eigen::MatrixBase> const &, class Eigen::MatrixBase> const &, class std::vector>, class std::allocator>>> const &, bool, class std::vector>, class std::allocator>>>, class std::allocator>, class std::allocator>>>>> &, class std::vector>, class std::allocator>>>, class std::allocator>, class std::allocator>>>>> &); +#endif +template void igl::triangle_triangle_adjacency, Eigen::Matrix, long, long, long>(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, std::vector >, std::allocator > > > const&, bool, std::vector >, std::allocator > > >, std::allocator >, std::allocator > > > > >&, std::vector >, std::allocator > > >, std::allocator >, std::allocator > > > > >&); +template void igl::triangle_triangle_adjacency, Eigen::Matrix, unsigned long, int, int>(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, std::vector >, std::allocator > > > const&, bool, std::vector >, std::allocator > > >, std::allocator >, std::allocator > > > > >&, std::vector >, std::allocator > > >, std::allocator >, std::allocator > > > > >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/triangle_triangle_adjacency.h b/src/external/libigl-2.3.0/include/igl/triangle_triangle_adjacency.h new file mode 100644 index 000000000..7a3148f05 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/triangle_triangle_adjacency.h @@ -0,0 +1,126 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Daniele Panozzo +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_TRIANGLE_TRIANGLE_ADJACENCY_H +#define IGL_TRIANGLE_TRIANGLE_ADJACENCY_H +#include "igl_inline.h" +#include +#include + +namespace igl +{ + // Constructs the triangle-triangle adjacency matrix for a given + // mesh (V,F). + // + // Inputs: + // F #F by simplex_size list of mesh faces (must be triangles) + // Outputs: + // TT #F by #3 adjacent matrix, the element i,j is the id of the triangle + // adjacent to the j edge of triangle i + // TTi #F by #3 adjacent matrix, the element i,j is the id of edge of the + // triangle TT(i,j) that is adjacent with triangle i + // + // NOTE: the first edge of a triangle is [0,1] the second [1,2] and the third + // [2,3]. this convention is DIFFERENT from + // cotmatrix_entries.h/edge_lengths.h/etc. To fix this you could use: + // // Fix mis-match convention + // { + // Eigen::PermutationMatrix<3,3> perm(3); + // perm.indices() = Eigen::Vector3i(1,2,0); + // TT = (TT*perm).eval(); + // TTi = (TTi*perm).eval(); + // for(int i=0;i + IGL_INLINE void triangle_triangle_adjacency( + const Eigen::MatrixBase& F, + Eigen::PlainObjectBase& TT, + Eigen::PlainObjectBase& TTi); + template + IGL_INLINE void triangle_triangle_adjacency( + const Eigen::MatrixBase& F, + Eigen::PlainObjectBase& TT); + // Preprocessing + template + IGL_INLINE void triangle_triangle_adjacency_preprocess( + const Eigen::MatrixBase& F, + std::vector >& TTT); + // Extract the face adjacencies + template + IGL_INLINE void triangle_triangle_adjacency_extractTT( + const Eigen::MatrixBase& F, + std::vector >& TTT, + Eigen::PlainObjectBase& TT); + // Extract the face adjacencies indices (needed for fast traversal) + template + IGL_INLINE void triangle_triangle_adjacency_extractTTi( + const Eigen::MatrixBase& F, + std::vector >& TTT, + Eigen::PlainObjectBase& TTi); + // Adjacency list version, which works with non-manifold meshes + // + // Inputs: + // F #F by 3 list of triangle indices + // Outputs: + // TT #F by 3 list of lists so that TT[i][c] --> {j,k,...} means that + // faces j and k etc. are edge-neighbors of face i on face i's edge + // opposite corner c + // TTj #F list of lists so that TTj[i][c] --> {j,k,...} means that face + // TT[i][c][0] is an edge-neighbor of face i incident on the edge of face + // TT[i][c][0] opposite corner j, and TT[i][c][1] " corner k, etc. + template < + typename DerivedF, + typename TTIndex, + typename TTiIndex> + IGL_INLINE void triangle_triangle_adjacency( + const Eigen::MatrixBase & F, + std::vector > > & TT, + std::vector > > & TTi); + template < typename DerivedF, typename TTIndex> + IGL_INLINE void triangle_triangle_adjacency( + const Eigen::MatrixBase & F, + std::vector > > & TT); + // Wrapper with bool to choose whether to compute TTi (this prototype should + // be "hidden"). + template < + typename DerivedF, + typename TTIndex, + typename TTiIndex> + IGL_INLINE void triangle_triangle_adjacency( + const Eigen::MatrixBase & F, + const bool construct_TTi, + std::vector > > & TT, + std::vector > > & TTi); + // Inputs: + // E #F*3 by 2 list of all of directed edges in order (see + // `oriented_facets`) + // EMAP #F*3 list of indices into uE, mapping each directed edge to unique + // undirected edge + // uE2E #uE list of lists of indices into E of coexisting edges + // See also: unique_edge_map, oriented_facets + template < + typename DerivedE, + typename DerivedEMAP, + typename uE2EType, + typename TTIndex, + typename TTiIndex> + IGL_INLINE void triangle_triangle_adjacency( + const Eigen::MatrixBase & E, + const Eigen::MatrixBase & EMAP, + const std::vector > & uE2E, + const bool construct_TTi, + std::vector > > & TT, + std::vector > > & TTi); +} + +#ifndef IGL_STATIC_LIBRARY +# include "triangle_triangle_adjacency.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/triangles_from_strip.cpp b/src/external/libigl-2.3.0/include/igl/triangles_from_strip.cpp new file mode 100644 index 000000000..1db854834 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/triangles_from_strip.cpp @@ -0,0 +1,36 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "triangles_from_strip.h" +#include + +template +IGL_INLINE void igl::triangles_from_strip( + const Eigen::MatrixBase& S, + Eigen::PlainObjectBase& F) +{ + using namespace std; + F.resize(S.size()-2,3); + for(int s = 0;s < S.size()-2;s++) + { + if(s%2 == 0) + { + F(s,0) = S(s+2); + F(s,1) = S(s+1); + F(s,2) = S(s+0); + }else + { + F(s,0) = S(s+0); + F(s,1) = S(s+1); + F(s,2) = S(s+2); + } + } +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +#endif diff --git a/src/external/libigl-2.3.0/include/igl/triangles_from_strip.h b/src/external/libigl-2.3.0/include/igl/triangles_from_strip.h new file mode 100644 index 000000000..01ffd6402 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/triangles_from_strip.h @@ -0,0 +1,33 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_TRIANGLES_FROM_STRIP_H +#define IGL_TRIANGLES_FROM_STRIP_H +#include "igl_inline.h" +#include +namespace igl +{ + // TRIANGLES_FROM_STRIP Create a list of triangles from a stream of indices + // along a strip. + // + // Inputs: + // S #S list of indices + // Outputs: + // F #S-2 by 3 list of triangle indices + // + template + IGL_INLINE void triangles_from_strip( + const Eigen::MatrixBase& S, + Eigen::PlainObjectBase& F); +} + +#ifndef IGL_STATIC_LIBRARY +# include "triangles_from_strip.cpp" +#endif + +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/triangulated_grid.cpp b/src/external/libigl-2.3.0/include/igl/triangulated_grid.cpp new file mode 100644 index 000000000..8c84f9e37 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/triangulated_grid.cpp @@ -0,0 +1,65 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "triangulated_grid.h" +#include "grid.h" +#include + +template < + typename XType, + typename YType, + typename DerivedGV, + typename DerivedGF> +IGL_INLINE void igl::triangulated_grid( + const XType & nx, + const YType & ny, + Eigen::PlainObjectBase & GV, + Eigen::PlainObjectBase & GF) +{ + using namespace Eigen; + Eigen::Matrix res(nx,ny); + igl::grid(res,GV); + return igl::triangulated_grid(nx,ny,GF); +}; + +template < + typename XType, + typename YType, + typename DerivedGF> +IGL_INLINE void igl::triangulated_grid( + const XType & nx, + const YType & ny, + Eigen::PlainObjectBase & GF) +{ + GF.resize((nx-1)*(ny-1)*2,3); + for(int y = 0;y, Eigen::Matrix >(int const&, int const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/triangulated_grid.h b/src/external/libigl-2.3.0/include/igl/triangulated_grid.h new file mode 100644 index 000000000..3e75db130 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/triangulated_grid.h @@ -0,0 +1,48 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2018 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_TRIANGULATEGRID_H +#define IGL_TRIANGULATEGRID_H +#include "igl_inline.h" +#include +namespace igl +{ + // Create a regular grid of elements (only 2D supported, currently) + // Vertex position order is compatible with `igl::grid` + // + // Inputs: + // nx number of vertices in the x direction + // ny number of vertices in the y direction + // Outputs: + // GV nx*ny by 2 list of mesh vertex positions. + // GF 2*(nx-1)*(ny-1) by 3 list of triangle indices + // + // See also: grid, quad_grid + template < + typename XType, + typename YType, + typename DerivedGV, + typename DerivedGF> + IGL_INLINE void triangulated_grid( + const XType & nx, + const YType & ny, + Eigen::PlainObjectBase & GV, + Eigen::PlainObjectBase & GF); + template < + typename XType, + typename YType, + typename DerivedGF> + IGL_INLINE void triangulated_grid( + const XType & nx, + const YType & ny, + Eigen::PlainObjectBase & GF); +} +#ifndef IGL_STATIC_LIBRARY +# include "triangulated_grid.cpp" +#endif +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/two_axis_valuator_fixed_up.cpp b/src/external/libigl-2.3.0/include/igl/two_axis_valuator_fixed_up.cpp new file mode 100644 index 000000000..4ffb607f4 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/two_axis_valuator_fixed_up.cpp @@ -0,0 +1,49 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "two_axis_valuator_fixed_up.h" +#include "PI.h" + +template +IGL_INLINE void igl::two_axis_valuator_fixed_up( + const int w, + const int h, + const double speed, + const Eigen::Quaternion & down_quat, + const int down_x, + const int down_y, + const int mouse_x, + const int mouse_y, + Eigen::Quaternion & quat) +{ + using namespace Eigen; + Matrix axis(0,1,0); + quat = down_quat * + Quaternion( + AngleAxis( + PI*((Scalarquat)(mouse_x-down_x))/(Scalarquat)w*speed/2.0, + axis.normalized())); + quat.normalize(); + { + Matrix axis(1,0,0); + if(axis.norm() != 0) + { + quat = + Quaternion( + AngleAxis( + PI*(mouse_y-down_y)/(Scalarquat)h*speed/2.0, + axis.normalized())) * quat; + quat.normalize(); + } + } +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +template void igl::two_axis_valuator_fixed_up(int, int, double, Eigen::Quaternion const&, int, int, int, int, Eigen::Quaternion&); +template void igl::two_axis_valuator_fixed_up(int, int, double, Eigen::Quaternion const&, int, int, int, int, Eigen::Quaternion&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/two_axis_valuator_fixed_up.h b/src/external/libigl-2.3.0/include/igl/two_axis_valuator_fixed_up.h new file mode 100644 index 000000000..7b2e9aabf --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/two_axis_valuator_fixed_up.h @@ -0,0 +1,51 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_TWO_AXIS_VALUATOR_FIXED_AXIS_UP_H +#define IGL_TWO_AXIS_VALUATOR_FIXED_AXIS_UP_H + +#include "igl_inline.h" +#include +#include + +namespace igl +{ + // Applies a two-axis valuator drag rotation (as seen in Maya/Studio max) to a given rotation. + // Inputs: + // w width of the trackball context + // h height of the trackball context + // speed controls how fast the trackball feels, 1 is normal + // down_quat rotation at mouse down, i.e. the rotation we're applying the + // trackball motion to (as quaternion). **Note:** Up-vector that is fixed + // is with respect to this rotation. + // down_x position of mouse down + // down_y position of mouse down + // mouse_x current x position of mouse + // mouse_y current y position of mouse + // Outputs: + // quat the resulting rotation (as quaternion) + // + // See also: snap_to_fixed_up + template + IGL_INLINE void two_axis_valuator_fixed_up( + const int w, + const int h, + const double speed, + const Eigen::Quaternion & down_quat, + const int down_x, + const int down_y, + const int mouse_x, + const int mouse_y, + Eigen::Quaternion & quat); +} + +#ifndef IGL_STATIC_LIBRARY +# include "two_axis_valuator_fixed_up.cpp" +#endif + +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/uniformly_sample_two_manifold.cpp b/src/external/libigl-2.3.0/include/igl/uniformly_sample_two_manifold.cpp new file mode 100644 index 000000000..d35f74113 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/uniformly_sample_two_manifold.cpp @@ -0,0 +1,427 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "uniformly_sample_two_manifold.h" +#include "verbose.h" +#include "slice.h" +#include "colon.h" +#include "all_pairs_distances.h" +#include "mat_max.h" +#include "vertex_triangle_adjacency.h" +#include "get_seconds.h" +#include "cat.h" +//#include "MT19937.h" +#include "partition.h" + +////////////////////////////////////////////////////////////////////////////// +// Helper functions +////////////////////////////////////////////////////////////////////////////// + +IGL_INLINE void igl::uniformly_sample_two_manifold( + const Eigen::MatrixXd & W, + const Eigen::MatrixXi & F, + const int k, + const double push, + Eigen::MatrixXd & WS) +{ + using namespace Eigen; + using namespace std; + + // Euclidean distance between two points on a mesh given as barycentric + // coordinates + // Inputs: + // W #W by dim positions of mesh in weight space + // F #F by 3 indices of triangles + // face_A face index where 1st point lives + // bary_A barycentric coordinates of 1st point on face_A + // face_B face index where 2nd point lives + // bary_B barycentric coordinates of 2nd point on face_B + // Returns distance in euclidean space + const auto & bary_dist = [] ( + const Eigen::MatrixXd & W, + const Eigen::MatrixXi & F, + const int face_A, + const Eigen::Vector3d & bary_A, + const int face_B, + const Eigen::Vector3d & bary_B) -> double + { + return + ((bary_A(0)*W.row(F(face_A,0)) + + bary_A(1)*W.row(F(face_A,1)) + + bary_A(2)*W.row(F(face_A,2))) + - + (bary_B(0)*W.row(F(face_B,0)) + + bary_B(1)*W.row(F(face_B,1)) + + bary_B(2)*W.row(F(face_B,2)))).norm(); + }; + + // Base case if F is a tet list, find all faces and pass as non-manifold + // triangle mesh + if(F.cols() == 4) + { + verbose("uniform_sample.h: sampling tet mesh\n"); + MatrixXi T0 = F.col(0); + MatrixXi T1 = F.col(1); + MatrixXi T2 = F.col(2); + MatrixXi T3 = F.col(3); + // Faces from tets + MatrixXi TF = + cat(1, + cat(1, + cat(2,T0, cat(2,T1,T2)), + cat(2,T0, cat(2,T2,T3))), + cat(1, + cat(2,T0, cat(2,T3,T1)), + cat(2,T1, cat(2,T3,T2))) + ); + assert(TF.rows() == 4*F.rows()); + assert(TF.cols() == 3); + uniformly_sample_two_manifold(W,TF,k,push,WS); + return; + } + + double start = get_seconds(); + + VectorXi S; + // First get sampling as best as possible on mesh + uniformly_sample_two_manifold_at_vertices(W,k,push,S); + verbose("Lap: %g\n",get_seconds()-start); + slice(W,S,colon(0,W.cols()-1),WS); + //cout<<"WSmesh=["< > VF,VFi; + vertex_triangle_adjacency(W,F,VF,VFi); + + // List of list of face indices, for each sample gives index to face it is on + vector > sample_faces; sample_faces.resize(k); + // List of list of barycentric coordinates, for each sample gives b-coords in + // face its on + vector > sample_barys; sample_barys.resize(k); + // List of current maxmins amongst samples + vector cur_maxmin; cur_maxmin.resize(k); + // List of distance matrices, D(i)(s,j) reveals distance from i's sth sample + // to jth seed if j D; D.resize(k); + + // Precompute an W.cols() by W.cols() identity matrix + MatrixXd I(MatrixXd::Identity(W.cols(),W.cols())); + + // Describe each seed as a face index and barycentric coordinates + for(int i = 0;i < k;i++) + { + // Unreferenced vertex? + assert(VF[S(i)].size() > 0); + sample_faces[i].push_back(VF[S(i)][0]); + // We're right on a face vertex so barycentric coordinates are 0, but 1 at + // that vertex + Eigen::Vector3d bary(0,0,0); + bary( VFi[S(i)][0] ) = 1; + sample_barys[i].push_back(bary); + // initialize this to current maxmin + cur_maxmin[i] = 0; + } + + // initialize radius + double radius = 1.0; + // minimum radius (bound on precision) + //double min_radius = 1e-5; + double min_radius = 1e-5; + int max_num_rand_samples_per_triangle = 100; + int max_sample_attempts_per_triangle = 1000; + // Max number of outer iterations for a given radius + int max_iters = 1000; + + // continue iterating until radius is smaller than some threshold + while(radius > min_radius) + { + // initialize each seed + for(int i = 0;i < k;i++) + { + // Keep track of cur_maxmin data + int face_i = sample_faces[i][cur_maxmin[i]]; + Eigen::Vector3d bary(sample_barys[i][cur_maxmin[i]]); + // Find index in face of closest mesh vertex (on this face) + int index_in_face = + (bary(0) > bary(1) ? (bary(0) > bary(2) ? 0 : 2) + : (bary(1) > bary(2) ? 1 : 2)); + // find closest mesh vertex + int vertex_i = F(face_i,index_in_face); + // incident triangles + vector incident_F = VF[vertex_i]; + // We're going to try to place num_rand_samples_per_triangle samples on + // each sample *after* this location + sample_barys[i].clear(); + sample_faces[i].clear(); + cur_maxmin[i] = 0; + sample_barys[i].push_back(bary); + sample_faces[i].push_back(face_i); + // Current seed location in weight space + VectorXd seed = + bary(0)*W.row(F(face_i,0)) + + bary(1)*W.row(F(face_i,1)) + + bary(2)*W.row(F(face_i,2)); +#ifdef EXTREME_VERBOSE + verbose("i: %d\n",i); + verbose("face_i: %d\n",face_i); + //cout<<"bary: "<1) + { + u = 1-rv; + v = 1-ru; + }else + { + u = ru; + v = rv; + } + Eigen::Vector3d sample_bary(u,v,1-u-v); + double d = bary_dist(W,F,face_i,bary,face_f,sample_bary); + // check that sample is close enough + if(d= max_num_rand_samples_per_triangle) + { +#ifdef EXTREME_VERBOSE + verbose("Reached maximum number of samples per face\n"); +#endif + break; + } + if(s==(max_sample_attempts_per_triangle-1)) + { +#ifdef EXTREME_VERBOSE + verbose("Reached maximum sample attempts per triangle\n"); +#endif + } + } +#ifdef EXTREME_VERBOSE + verbose("sample_faces[%d].size(): %d\n",i,sample_faces[i].size()); + verbose("sample_barys[%d].size(): %d\n",i,sample_barys[i].size()); +#endif + } + } + + // Precompute distances from each seed's random samples to each "pushed" + // corner + // Put -1 in entries corresponding distance of a seed's random samples to + // self + // Loop over seeds + for(int i = 0;i < k;i++) + { + // resize distance matrix for new samples + D[i].resize(sample_faces[i].size(),k+W.cols()); + // Loop over i's samples + for(int s = 0;s<(int)sample_faces[i].size();s++) + { + int sample_face = sample_faces[i][s]; + Eigen::Vector3d sample_bary = sample_barys[i][s]; + // Loop over other seeds + for(int j = 0;j < k;j++) + { + // distance from sample(i,s) to seed j + double d; + if(i==j) + { + // phony self distance: Ilya's idea of infinite + d = 10; + }else + { + int seed_j_face = sample_faces[j][cur_maxmin[j]]; + Eigen::Vector3d seed_j_bary(sample_barys[j][cur_maxmin[j]]); + d = bary_dist(W,F,sample_face,sample_bary,seed_j_face,seed_j_bary); + } + D[i](s,j) = d; + } + // Loop over corners + for(int j = 0;j < W.cols();j++) + { + // distance from sample(i,s) to corner j + double d = + ((sample_bary(0)*W.row(F(sample_face,0)) + + sample_bary(1)*W.row(F(sample_face,1)) + + sample_bary(2)*W.row(F(sample_face,2))) + - I.row(j)).norm()/push; + // append after distances to seeds + D[i](s,k+j) = d; + } + } + } + + int iters = 0; + while(true) + { + bool has_changed = false; + // try to move each seed + for(int i = 0;i < k;i++) + { + // for each sample look at distance to closest seed/corner + VectorXd minD = D[i].rowwise().minCoeff(); + assert(minD.size() == (int)sample_faces[i].size()); + // find random sample with maximum minimum distance to other seeds + int old_cur_maxmin = cur_maxmin[i]; + double max_min = -2; + for(int s = 0;s<(int)sample_faces[i].size();s++) + { + if(max_min < minD(s)) + { + max_min = minD(s); + // Set this as the new seed location + cur_maxmin[i] = s; + } + } +#ifdef EXTREME_VERBOSE + verbose("max_min: %g\n",max_min); + verbose("cur_maxmin[%d]: %d->%d\n",i,old_cur_maxmin,cur_maxmin[i]); +#endif + // did location change? + has_changed |= (old_cur_maxmin!=cur_maxmin[i]); + // update distances of random samples of other seeds + } + // if no seed moved, exit + if(!has_changed) + { + break; + } + iters++; + if(iters>=max_iters) + { + verbose("Hit max iters (%d) before converging\n",iters); + } + } + // shrink radius + //radius *= 0.9; + //radius *= 0.99; + radius *= 0.9; + } + // Collect weight space locations + WS.resize(k,W.cols()); + for(int i = 0;i ignore; + partition(W,k+W.cols(),G,S,ignore); + // Remove corners, which better be at top + S = S.segment(W.cols(),k).eval(); + + MatrixXd WS; + slice(W,S,colon(0,W.cols()-1),WS); + //cout<<"WSpartition=["< +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_UNIFORMLY_SAMPLE_TWO_MANIFOLD_H +#define IGL_UNIFORMLY_SAMPLE_TWO_MANIFOLD_H +#include "igl_inline.h" +#include +namespace igl +{ + // UNIFORMLY_SAMPLE_TWO_MANIFOLD Attempt to sample a mesh uniformly with + // k-points by furthest point relaxation as described in "Fast Automatic + // Skinning Transformations" [Jacobson et al. 12] Section 3.3. The input is + // not expected to be a typical 3D triangle mesh (e.g., [V,F]), instead each + // vertex is embedded in a high dimensional unit-hypercude ("weight space") + // defined by W, with triangles given by F. This algorithm will first conduct + // furthest point sampling from the set of vertices and then attempt to relax + // the sampled points along the surface of the high-dimensional triangle mesh + // (i.e., the output points may be in the middle of triangles, not just at + // vertices). An additional "push" factor will repel samples away from the + // corners of the hypercube. + // + // Inputs: + // W #W by dim positions of mesh in weight space + // F #F by 3 indices of triangles + // k number of samples + // push factor by which corners should be pushed away + // Outputs + // WS k by dim locations in weight space + // + // See also: + // random_points_on_mesh + // + IGL_INLINE void uniformly_sample_two_manifold( + const Eigen::MatrixXd & W, + const Eigen::MatrixXi & F, + const int k, + const double push, + Eigen::MatrixXd & WS); + // Find uniform sampling up to placing samples on mesh vertices + IGL_INLINE void uniformly_sample_two_manifold_at_vertices( + const Eigen::MatrixXd & OW, + const int k, + const double push, + Eigen::VectorXi & S); +} +#ifndef IGL_STATIC_LIBRARY +# include "uniformly_sample_two_manifold.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/unique.cpp b/src/external/libigl-2.3.0/include/igl/unique.cpp new file mode 100644 index 000000000..5420e44aa --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/unique.cpp @@ -0,0 +1,223 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "unique.h" +#include "sort.h" +#include "IndexComparison.h" +#include "SortableRow.h" +#include "sortrows.h" +#include "list_to_matrix.h" +#include "matrix_to_list.h" + +#include +#include +#include + +template +IGL_INLINE void igl::unique( + const std::vector & A, + std::vector & C, + std::vector & IA, + std::vector & IC) +{ + using namespace std; + std::vector IM; + std::vector sortA; + igl::sort(A,true,sortA,IM); + // Original unsorted index map + IA.resize(sortA.size()); + for(int i=0;i<(int)sortA.size();i++) + { + IA[i] = i; + } + IA.erase( + std::unique( + IA.begin(), + IA.end(), + igl::IndexEquals& >(sortA)),IA.end()); + + IC.resize(A.size()); + { + int j = 0; + for(int i = 0;i<(int)sortA.size();i++) + { + if(sortA[IA[j]] != sortA[i]) + { + j++; + } + IC[IM[i]] = j; + } + } + C.resize(IA.size()); + // Reindex IA according to IM + for(int i = 0;i<(int)IA.size();i++) + { + IA[i] = IM[IA[i]]; + C[i] = A[IA[i]]; + } + +} + +template +IGL_INLINE void igl::unique( + const std::vector & A, + std::vector & C) +{ + std::vector IA,IC; + return igl::unique(A,C,IA,IC); +} + +template < + typename DerivedA, + typename DerivedC, + typename DerivedIA, + typename DerivedIC> +IGL_INLINE void igl::unique( + const Eigen::MatrixBase & A, + Eigen::PlainObjectBase & C, + Eigen::PlainObjectBase & IA, + Eigen::PlainObjectBase & IC) +{ + using namespace std; + using namespace Eigen; + vector vA; + vector vC; + vector vIA,vIC; + matrix_to_list(A,vA); + unique(vA,vC,vIA,vIC); + list_to_matrix(vC,C); + list_to_matrix(vIA,IA); + list_to_matrix(vIC,IC); +} + +template < + typename DerivedA, + typename DerivedC + > +IGL_INLINE void igl::unique( + const Eigen::MatrixBase & A, + Eigen::PlainObjectBase & C) +{ + using namespace std; + using namespace Eigen; + vector vA; + vector vC; + vector vIA,vIC; + matrix_to_list(A,vA); + unique(vA,vC,vIA,vIC); + list_to_matrix(vC,C); +} + +// Obsolete slow version converting to vectors +// template +// IGL_INLINE void igl::unique_rows( +// const Eigen::PlainObjectBase& A, +// Eigen::PlainObjectBase& C, +// Eigen::PlainObjectBase& IA, +// Eigen::PlainObjectBase& IC) +// { +// using namespace std; +// +// typedef Eigen::Matrix RowVector; +// vector > rows; +// rows.resize(A.rows()); +// // Loop over rows +// for(int i = 0;i(ri); +// } +// vector > vC; +// +// // unique on rows +// vector vIA; +// vector vIC; +// unique(rows,vC,vIA,vIC); +// +// // Convert to eigen +// C.resize(vC.size(),A.cols()); +// IA.resize(vIA.size(),1); +// IC.resize(vIC.size(),1); +// for(int i = 0;i +// IGL_INLINE void igl::unique_rows_many( +// const Eigen::PlainObjectBase& A, +// Eigen::PlainObjectBase& C, +// Eigen::PlainObjectBase& IA, +// Eigen::PlainObjectBase& IC) +// { +// using namespace std; +// // frequency map +// typedef Eigen::Matrix RowVector; +// IC.resize(A.rows(),1); +// map, int> fm; +// const int m = A.rows(); +// for(int i = 0;i(ri)) == 0) +// { +// fm[SortableRow(ri)] = i; +// } +// IC(i) = fm[SortableRow(ri)]; +// } +// IA.resize(fm.size(),1); +// Eigen::VectorXi RIA(m); +// C.resize(fm.size(),A.cols()); +// { +// int i = 0; +// for(typename map , int >::const_iterator fit = fm.begin(); +// fit != fm.end(); +// fit++) +// { +// IA(i) = fit->second; +// RIA(fit->second) = i; +// C.row(i) = fit->first.data; +// i++; +// } +// } +// // IC should index C +// for(int i = 0;i, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::unique, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::unique, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::unique, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::unique, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::unique, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::unique, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::unique, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::unique, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::unique, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::unique, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::unique(std::vector > const&, std::vector >&); +template void igl::unique(std::vector > const&, std::vector >&); +template void igl::unique(std::vector > const&, std::vector >&, std::vector >&, std::vector >&); +template void igl::unique(std::vector > const&, std::vector >&, std::vector >&, std::vector >&); +#ifdef WIN32 +template void igl::unique,class Eigen::Matrix,class Eigen::Matrix<__int64,-1,1,0,-1,1>,class Eigen::Matrix<__int64,-1,1,0,-1,1> >(class Eigen::MatrixBase > const &,class Eigen::PlainObjectBase > &,class Eigen::PlainObjectBase > &,class Eigen::PlainObjectBase > &); +template void igl::unique<__int64>(class std::vector<__int64,class std::allocator<__int64> > const &,class std::vector<__int64,class std::allocator<__int64> > &,class std::vector > &,class std::vector > &); +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/unique.h b/src/external/libigl-2.3.0/include/igl/unique.h new file mode 100644 index 000000000..0e5061d46 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/unique.h @@ -0,0 +1,58 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_UNIQUE_H +#define IGL_UNIQUE_H +#include "igl_inline.h" + +#include +#include +namespace igl +{ + // Act like matlab's [C,IA,IC] = unique(X) + // + // Templates: + // T comparable type T + // Inputs: + // A #A vector of type T + // Outputs: + // C #C vector of unique entries in A + // IA #C index vector so that C = A(IA); + // IC #A index vector so that A = C(IC); + template + IGL_INLINE void unique( + const std::vector & A, + std::vector & C, + std::vector & IA, + std::vector & IC); + template + IGL_INLINE void unique( + const std::vector & A, + std::vector & C); + template < + typename DerivedA, + typename DerivedC, + typename DerivedIA, + typename DerivedIC> + IGL_INLINE void unique( + const Eigen::MatrixBase & A, + Eigen::PlainObjectBase & C, + Eigen::PlainObjectBase & IA, + Eigen::PlainObjectBase & IC); + template < + typename DerivedA, + typename DerivedC> + IGL_INLINE void unique( + const Eigen::MatrixBase & A, + Eigen::PlainObjectBase & C); +} + +#ifndef IGL_STATIC_LIBRARY +# include "unique.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/unique_edge_map.cpp b/src/external/libigl-2.3.0/include/igl/unique_edge_map.cpp new file mode 100644 index 000000000..6058fa5b8 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/unique_edge_map.cpp @@ -0,0 +1,140 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "unique_edge_map.h" +#include "oriented_facets.h" +#include "unique_simplices.h" +#include "cumsum.h" +#include "accumarray.h" +#include +#include + +template < + typename DerivedF, + typename DerivedE, + typename DeriveduE, + typename DerivedEMAP, + typename uE2EType> +IGL_INLINE void igl::unique_edge_map( + const Eigen::MatrixBase & F, + Eigen::PlainObjectBase & E, + Eigen::PlainObjectBase & uE, + Eigen::PlainObjectBase & EMAP, + std::vector > & uE2E) +{ + using namespace Eigen; + using namespace std; + unique_edge_map(F,E,uE,EMAP); + uE2E.resize(uE.rows()); + // This does help a little + for_each(uE2E.begin(),uE2E.end(),[](vector & v){v.reserve(2);}); + const size_t ne = E.rows(); + assert((size_t)EMAP.size() == ne); + for(uE2EType e = 0;e<(uE2EType)ne;e++) + { + uE2E[EMAP(e)].push_back(e); + } +} + +template < + typename DerivedF, + typename DerivedE, + typename DeriveduE, + typename DerivedEMAP> +IGL_INLINE void igl::unique_edge_map( + const Eigen::MatrixBase & F, + Eigen::PlainObjectBase & E, + Eigen::PlainObjectBase & uE, + Eigen::PlainObjectBase & EMAP) +{ + using namespace Eigen; + using namespace std; + // All occurrences of directed edges + oriented_facets(F,E); + const size_t ne = E.rows(); + // This is 2x faster to create than a map from pairs to lists of edges and 5x + // faster to access (actually access is probably assympotically faster O(1) + // vs. O(log m) + Matrix IA; + unique_simplices(E,uE,IA,EMAP); + assert((size_t)EMAP.size() == ne); +} + +template < + typename DerivedF, + typename DerivedE, + typename DeriveduE, + typename DerivedEMAP, + typename DeriveduEC, + typename DeriveduEE> +IGL_INLINE void igl::unique_edge_map( + const Eigen::MatrixBase & F, + Eigen::PlainObjectBase & E, + Eigen::PlainObjectBase & uE, + Eigen::PlainObjectBase & EMAP, + Eigen::PlainObjectBase & uEC, + Eigen::PlainObjectBase & uEE) +{ + // Avoid using uE2E + igl::unique_edge_map(F,E,uE,EMAP); + assert(EMAP.maxCoeff() < uE.rows()); + // counts of each unique edge + typedef Eigen::Matrix VectorXI; + VectorXI uEK; + igl::accumarray(EMAP,1,uEK); + assert(uEK.rows() == uE.rows()); + // base offset in uEE + igl::cumsum(uEK,1,true,uEC); + assert(uEK.rows()+1 == uEC.rows()); + // running inner offset in uEE + VectorXI uEO = VectorXI::Zero(uE.rows(),1); + // flat array of faces incide on each uE + uEE.resize(EMAP.rows(),1); + for(Eigen::Index e = 0;e, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::unique_edge_map, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::unique_edge_map, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::unique_edge_map, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::unique_edge_map, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::unique_edge_map, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::unique_edge_map, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, unsigned long>(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, std::vector >, std::allocator > > >&); +template void igl::unique_edge_map, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, int>(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, std::vector >, std::allocator > > >&); +template void igl::unique_edge_map, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, unsigned long>(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, std::vector >, std::allocator > > >&); +template void igl::unique_edge_map, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, long>(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, std::vector >, std::allocator > > >&); +template void igl::unique_edge_map, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, long>(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, std::vector >, std::allocator > > >&); +template void igl::unique_edge_map, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, int>(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, std::vector >, std::allocator > > >&); +template void igl::unique_edge_map, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, int>(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, std::vector >, std::allocator > > >&); +template void igl::unique_edge_map, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, long>(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, std::vector >, std::allocator > > >&); +template void igl::unique_edge_map, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, int>(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, std::vector >, std::allocator > > >&); +template void igl::unique_edge_map, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, unsigned long>(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, std::vector >, std::allocator > > >&); +template void igl::unique_edge_map, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, int>(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, std::vector >, std::allocator > > >&); + +#ifdef WIN32 +template void igl::unique_edge_map, class Eigen::Matrix, class Eigen::Matrix, class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>, __int64>(class Eigen::MatrixBase > const &, class Eigen::PlainObjectBase > &, class Eigen::PlainObjectBase > &, class Eigen::PlainObjectBase > &, class std::vector >, class std::allocator > > > &); +template void igl::unique_edge_map,class Eigen::Matrix,class Eigen::Matrix,class Eigen::Matrix<__int64,-1,1,0,-1,1>,__int64>(class Eigen::MatrixBase > const &,class Eigen::PlainObjectBase > &,class Eigen::PlainObjectBase > &,class Eigen::PlainObjectBase > &,class std::vector >,class std::allocator > > > &); +template void igl::unique_edge_map, class Eigen::Matrix, class Eigen::Matrix, class Eigen::Matrix, unsigned __int64>(class Eigen::MatrixBase> const &, class Eigen::PlainObjectBase> &, class Eigen::PlainObjectBase> &, class Eigen::PlainObjectBase> &, class std::vector>, class std::allocator>>> &); +template void igl::unique_edge_map, class Eigen::Matrix, class Eigen::Matrix, class Eigen::Matrix, unsigned __int64>(class Eigen::MatrixBase> const &, class Eigen::PlainObjectBase> &, class Eigen::PlainObjectBase> &, class Eigen::PlainObjectBase> &, class std::vector>, class std::allocator>>> &); +template void igl::unique_edge_map,class Eigen::Matrix,class Eigen::Matrix,class Eigen::Matrix,unsigned __int64>(class Eigen::MatrixBase > const &,class Eigen::PlainObjectBase > &,class Eigen::PlainObjectBase > &,class Eigen::PlainObjectBase > &,class std::vector >,class std::allocator > > > &); +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/unique_edge_map.h b/src/external/libigl-2.3.0/include/igl/unique_edge_map.h new file mode 100644 index 000000000..348bccfda --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/unique_edge_map.h @@ -0,0 +1,79 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_UNIQUE_EDGE_MAP_H +#define IGL_UNIQUE_EDGE_MAP_H +#include "igl_inline.h" +#include +#include +namespace igl +{ + // Construct relationships between facet "half"-(or rather "viewed")-edges E + // to unique edges of the mesh seen as a graph. + // + // Inputs: + // F #F by 3 list of simplices + // Outputs: + // E #F*3 by 2 list of all directed edges, such that E.row(f+#F*c) is the + // edge opposite F(f,c) + // uE #uE by 2 list of unique undirected edges + // EMAP #F*3 list of indices into uE, mapping each directed edge to unique + // undirected edge so that uE(EMAP(f+#F*c)) is the unique edge + // corresponding to E.row(f+#F*c) + // uE2E #uE list of lists of indices into E of coexisting edges, so that + // E.row(uE2E[i][j]) corresponds to uE.row(i) for all j in + // 0..uE2E[i].size()-1. + template < + typename DerivedF, + typename DerivedE, + typename DeriveduE, + typename DerivedEMAP, + typename uE2EType> + IGL_INLINE void unique_edge_map( + const Eigen::MatrixBase & F, + Eigen::PlainObjectBase & E, + Eigen::PlainObjectBase & uE, + Eigen::PlainObjectBase & EMAP, + std::vector > & uE2E); + template < + typename DerivedF, + typename DerivedE, + typename DeriveduE, + typename DerivedEMAP> + IGL_INLINE void unique_edge_map( + const Eigen::MatrixBase & F, + Eigen::PlainObjectBase & E, + Eigen::PlainObjectBase & uE, + Eigen::PlainObjectBase & EMAP); + // Outputs: + // uEC #uEC+1 list of cumulative counts of directed edges sharing each + // unique edge so the uEC(i+1)-uEC(i) is the number of directed edges + // sharing the ith unique edge. + // uEE #E list of indices into E, so that the consecutive segment of + // indices uEE.segment(uEC(i),uEC(i+1)-uEC(i)) lists all directed edges + // sharing the ith unique edge. + template < + typename DerivedF, + typename DerivedE, + typename DeriveduE, + typename DerivedEMAP, + typename DeriveduEC, + typename DeriveduEE> + IGL_INLINE void unique_edge_map( + const Eigen::MatrixBase & F, + Eigen::PlainObjectBase & E, + Eigen::PlainObjectBase & uE, + Eigen::PlainObjectBase & EMAP, + Eigen::PlainObjectBase & uEC, + Eigen::PlainObjectBase & uEE); + +} +#ifndef IGL_STATIC_LIBRARY +# include "unique_edge_map.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/unique_rows.cpp b/src/external/libigl-2.3.0/include/igl/unique_rows.cpp new file mode 100644 index 000000000..5289bbca6 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/unique_rows.cpp @@ -0,0 +1,126 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2017 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "unique_rows.h" +#include "sortrows.h" + +#include +#include +#include + + +template +IGL_INLINE void igl::unique_rows( + const Eigen::DenseBase& A, + Eigen::PlainObjectBase& C, + Eigen::PlainObjectBase& IA, + Eigen::PlainObjectBase& IC) +{ + using namespace std; + using namespace Eigen; + VectorXi IM; + DerivedA sortA; + sortrows(A,true,sortA,IM); + + + const int num_rows = sortA.rows(); + const int num_cols = sortA.cols(); + vector vIA(num_rows); + for(int i=0;i, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::DenseBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::unique_rows, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::DenseBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::unique_rows, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::DenseBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::unique_rows, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::DenseBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::unique_rows, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::DenseBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::unique_rows, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::DenseBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::unique_rows, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::DenseBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::unique_rows, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::DenseBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::unique_rows, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::DenseBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::unique_rows, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::DenseBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::unique_rows, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::DenseBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::unique_rows, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::DenseBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::unique_rows, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::DenseBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::unique_rows, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::DenseBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::unique_rows, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::DenseBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::unique_rows, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::DenseBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::unique_rows,Eigen::Matrix,Eigen::Matrix,Eigen::Matrix >(Eigen::DenseBase > const&,Eigen::PlainObjectBase >&,Eigen::PlainObjectBase >&,Eigen::PlainObjectBase >&); +template void igl::unique_rows,Eigen::Matrix,Eigen::Matrix,Eigen::Matrix >(Eigen::DenseBase > const&,Eigen::PlainObjectBase >&,Eigen::PlainObjectBase >&,Eigen::PlainObjectBase >&); +template void igl::unique_rows,Eigen::Matrix,Eigen::Matrix,Eigen::Matrix >(Eigen::DenseBase > const&,Eigen::PlainObjectBase >&,Eigen::PlainObjectBase >&,Eigen::PlainObjectBase >&); +template void igl::unique_rows,Eigen::Matrix,Eigen::Matrix,Eigen::Matrix >(Eigen::DenseBase > const&,Eigen::PlainObjectBase >&,Eigen::PlainObjectBase >&,Eigen::PlainObjectBase >&); +template void igl::unique_rows,Eigen::Matrix,Eigen::Matrix,Eigen::Matrix >(Eigen::DenseBase > const&,Eigen::PlainObjectBase >&,Eigen::PlainObjectBase >&,Eigen::PlainObjectBase >&); +template void igl::unique_rows,Eigen::Matrix,Eigen::Matrix,Eigen::Matrix >(Eigen::DenseBase > const&,Eigen::PlainObjectBase >&,Eigen::PlainObjectBase >&,Eigen::PlainObjectBase >&); +template void igl::unique_rows,Eigen::Matrix,Eigen::Matrix,Eigen::Matrix >(Eigen::DenseBase > const&,Eigen::PlainObjectBase >&,Eigen::PlainObjectBase >&,Eigen::PlainObjectBase >&); +template void igl::unique_rows,Eigen::Matrix,Eigen::Matrix,Eigen::Matrix >(Eigen::DenseBase > const&,Eigen::PlainObjectBase >&,Eigen::PlainObjectBase >&,Eigen::PlainObjectBase >&); +template void igl::unique_rows,Eigen::Matrix,Eigen::Matrix,Eigen::Matrix >(Eigen::DenseBase > const&,Eigen::PlainObjectBase >&,Eigen::PlainObjectBase >&,Eigen::PlainObjectBase >&); +template void igl::unique_rows,Eigen::Matrix,Eigen::Matrix,Eigen::Matrix >(Eigen::DenseBase > const&,Eigen::PlainObjectBase >&,Eigen::PlainObjectBase >&,Eigen::PlainObjectBase >&); +template void igl::unique_rows,Eigen::Matrix,Eigen::Matrix,Eigen::Matrix >(Eigen::DenseBase > const&,Eigen::PlainObjectBase >&,Eigen::PlainObjectBase >&,Eigen::PlainObjectBase >&); +template void igl::unique_rows,Eigen::Matrix,Eigen::Matrix,Eigen::Matrix >(Eigen::DenseBase > const&,Eigen::PlainObjectBase >&,Eigen::PlainObjectBase >&,Eigen::PlainObjectBase >&); +template void igl::unique_rows,Eigen::Matrix,Eigen::Matrix,Eigen::Matrix >(Eigen::DenseBase > const&,Eigen::PlainObjectBase >&,Eigen::PlainObjectBase >&,Eigen::PlainObjectBase >&); +template void igl::unique_rows,Eigen::Matrix,Eigen::Matrix,Eigen::Matrix >(Eigen::DenseBase > const&,Eigen::PlainObjectBase >&,Eigen::PlainObjectBase >&,Eigen::PlainObjectBase >&); +template void igl::unique_rows,Eigen::Matrix,Eigen::Matrix,Eigen::Matrix >(Eigen::DenseBase > const&,Eigen::PlainObjectBase >&,Eigen::PlainObjectBase >&,Eigen::PlainObjectBase >&); +template void igl::unique_rows,Eigen::Matrix,Eigen::Matrix,Eigen::Matrix >(Eigen::DenseBase > const&,Eigen::PlainObjectBase >&,Eigen::PlainObjectBase >&,Eigen::PlainObjectBase >&); +template void igl::unique_rows, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::DenseBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#ifdef WIN32 +template void igl::unique_rows, class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>, class Eigen::Matrix<__int64, -1, 1, 0, -1, 1> >(class Eigen::DenseBase > const &, class Eigen::PlainObjectBase > &, class Eigen::PlainObjectBase > &, class Eigen::PlainObjectBase > &); +template void igl::unique_rows,class Eigen::Matrix,class Eigen::Matrix<__int64,-1,1,0,-1,1>,class Eigen::Matrix<__int64,-1,1,0,-1,1> >(class Eigen::DenseBase > const &,class Eigen::PlainObjectBase > &,class Eigen::PlainObjectBase > &,class Eigen::PlainObjectBase > &); +template void igl::unique_rows,class Eigen::Matrix,class Eigen::Matrix<__int64,-1,1,0,-1,1>,class Eigen::Matrix<__int64,-1,1,0,-1,1> >(class Eigen::DenseBase > const &,class Eigen::PlainObjectBase > &,class Eigen::PlainObjectBase > &,class Eigen::PlainObjectBase > &); +template void igl::unique_rows,class Eigen::Matrix,class Eigen::Matrix<__int64,-1,1,0,-1,1>,class Eigen::Matrix<__int64,-1,1,0,-1,1> >(class Eigen::DenseBase > const &,class Eigen::PlainObjectBase > &,class Eigen::PlainObjectBase > &,class Eigen::PlainObjectBase > &); +template void igl::unique_rows,class Eigen::Matrix,class Eigen::Matrix<__int64,-1,1,0,-1,1>,class Eigen::Matrix<__int64,-1,1,0,-1,1> >(class Eigen::DenseBase > const &,class Eigen::PlainObjectBase > &,class Eigen::PlainObjectBase > &,class Eigen::PlainObjectBase > &); +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/unique_rows.h b/src/external/libigl-2.3.0/include/igl/unique_rows.h new file mode 100644 index 000000000..c612c8b1d --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/unique_rows.h @@ -0,0 +1,41 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2017 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_UNIQUE_ROWS_H +#define IGL_UNIQUE_ROWS_H +#include "igl_inline.h" + +#include +#include +namespace igl +{ + // Act like matlab's [C,IA,IC] = unique(X,'rows') + // + // Templates: + // DerivedA derived scalar type, e.g. MatrixXi or MatrixXd + // DerivedIA derived integer type, e.g. MatrixXi + // DerivedIC derived integer type, e.g. MatrixXi + // Inputs: + // A m by n matrix whose entries are to unique'd according to rows + // Outputs: + // C #C vector of unique rows in A + // IA #C index vector so that C = A(IA,:); + // IC #A index vector so that A = C(IC,:); + template + IGL_INLINE void unique_rows( + const Eigen::DenseBase& A, + Eigen::PlainObjectBase& C, + Eigen::PlainObjectBase& IA, + Eigen::PlainObjectBase& IC); + +} + +#ifndef IGL_STATIC_LIBRARY +# include "unique_rows.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/unique_simplices.cpp b/src/external/libigl-2.3.0/include/igl/unique_simplices.cpp new file mode 100644 index 000000000..6f20ff227 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/unique_simplices.cpp @@ -0,0 +1,76 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "unique_simplices.h" +#include "sort.h" +#include "unique_rows.h" +#include "parallel_for.h" + +template < + typename DerivedF, + typename DerivedFF, + typename DerivedIA, + typename DerivedIC> +IGL_INLINE void igl::unique_simplices( + const Eigen::MatrixBase& F, + Eigen::PlainObjectBase& FF, + Eigen::PlainObjectBase& IA, + Eigen::PlainObjectBase& IC) +{ + using namespace Eigen; + using namespace std; + typedef Eigen::Matrix + MatrixXI; + // Sort each face + MatrixXI sortF, unusedI; + igl::sort(F,2,true,sortF,unusedI); + // Find unique faces + MatrixXI C; + igl::unique_rows(sortF,C,IA,IC); + FF.resize(IA.size(),F.cols()); + const size_t mff = FF.rows(); + parallel_for(mff,[&F,&IA,&FF](size_t & i) + { + FF.row(i) = F.row(IA(i)).template cast(); + },1000ul); +} + +template < + typename DerivedF, + typename DerivedFF> +IGL_INLINE void igl::unique_simplices( + const Eigen::MatrixBase& F, + Eigen::PlainObjectBase& FF) +{ + Eigen::VectorXi IA,IC; + return unique_simplices(F,FF,IA,IC); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::unique_simplices, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::unique_simplices, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::unique_simplices, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::unique_simplices, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::unique_simplices, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::unique_simplices, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::unique_simplices, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::unique_simplices, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::unique_simplices, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::unique_simplices, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::unique_simplices, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::unique_simplices, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::unique_simplices, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::unique_simplices, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#ifdef WIN32 +template void igl::unique_simplices, class Eigen::Matrix, class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>, class Eigen::Matrix<__int64, -1, 1, 0, -1, 1> >(class Eigen::MatrixBase > const &, class Eigen::PlainObjectBase > &, class Eigen::PlainObjectBase > &, class Eigen::PlainObjectBase > &); +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/unique_simplices.h b/src/external/libigl-2.3.0/include/igl/unique_simplices.h new file mode 100644 index 000000000..a7c13849e --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/unique_simplices.h @@ -0,0 +1,44 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_UNIQUE_SIMPLICES_H +#define IGL_UNIQUE_SIMPLICES_H +#include "igl_inline.h" +#include +namespace igl +{ + // Find *combinatorially* unique simplices in F. **Order independent** + // + // Inputs: + // F #F by simplex-size list of simplices + // Outputs: + // FF #FF by simplex-size list of unique simplices in F + // IA #FF index vector so that FF == sort(F(IA,:),2); + // IC #F index vector so that sort(F,2) == FF(IC,:); + template < + typename DerivedF, + typename DerivedFF, + typename DerivedIA, + typename DerivedIC> + IGL_INLINE void unique_simplices( + const Eigen::MatrixBase& F, + Eigen::PlainObjectBase& FF, + Eigen::PlainObjectBase& IA, + Eigen::PlainObjectBase& IC); + template < + typename DerivedF, + typename DerivedFF> + IGL_INLINE void unique_simplices( + const Eigen::MatrixBase& F, + Eigen::PlainObjectBase& FF); +} + +#ifndef IGL_STATIC_LIBRARY +# include "unique_simplices.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/unproject.cpp b/src/external/libigl-2.3.0/include/igl/unproject.cpp new file mode 100644 index 000000000..3487cb697 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/unproject.cpp @@ -0,0 +1,76 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "unproject.h" + +#include +#include + +template < + typename Derivedwin, + typename Derivedmodel, + typename Derivedproj, + typename Derivedviewport, + typename Derivedscene> +IGL_INLINE void igl::unproject( + const Eigen::MatrixBase& win, + const Eigen::MatrixBase& model, + const Eigen::MatrixBase& proj, + const Eigen::MatrixBase& viewport, + Eigen::PlainObjectBase & scene) +{ + if(win.cols() != 3) + { + assert(win.rows() == 3); + // needless transposes + Eigen::Matrix sceneT; + unproject(win.transpose().eval(),model,proj,viewport,sceneT); + scene = sceneT.head(3); + return; + } + assert(win.cols() == 3); + const int n = win.rows(); + scene.resize(n,3); + for(int i = 0;i Inverse = + (proj.template cast() * model.template cast()).inverse(); + + Eigen::Matrix tmp; + tmp << win.row(i).head(3).transpose(), 1; + tmp(0) = (tmp(0) - viewport(0, 0)) / viewport(2, 0); + tmp(1) = (tmp(1) - viewport(1, 0)) / viewport(3, 0); + tmp = tmp.array() * 2.0f - 1.0f; + + Eigen::Matrix obj = Inverse * tmp; + obj /= obj(3); + + scene.row(i).head(3) = obj.head(3); + } +} + +template +IGL_INLINE Eigen::Matrix igl::unproject( + const Eigen::Matrix& win, + const Eigen::Matrix& model, + const Eigen::Matrix& proj, + const Eigen::Matrix& viewport) +{ + Eigen::Matrix scene; + unproject(win,model,proj,viewport,scene); + return scene; +} + +#ifdef IGL_STATIC_LIBRARY +template Eigen::Matrix igl::unproject(Eigen::Matrix const&, Eigen::Matrix const&, Eigen::Matrix const&, Eigen::Matrix const&); +template Eigen::Matrix igl::unproject(Eigen::Matrix const&, Eigen::Matrix const&, Eigen::Matrix const&, Eigen::Matrix const&); +template void igl::unproject, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::unproject, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::unproject, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::unproject, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/unproject.h b/src/external/libigl-2.3.0/include/igl/unproject.h new file mode 100644 index 000000000..72b4808cf --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/unproject.h @@ -0,0 +1,51 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_UNPROJECT_H +#define IGL_UNPROJECT_H +#include "igl_inline.h" +#include +namespace igl +{ + // Eigen reimplementation of gluUnproject + // + // Inputs: + // win #P by 3 or 3-vector (#P=1) of screen space x, y, and z coordinates + // model 4x4 model-view matrix + // proj 4x4 projection matrix + // viewport 4-long viewport vector + // Outputs: + // scene #P by 3 or 3-vector (#P=1) the unprojected x, y, and z coordinates + // + // Known issue: + // The compiler will not complain if V and P are Vector3d, but the result + // will be incorrect. + template < + typename Derivedwin, + typename Derivedmodel, + typename Derivedproj, + typename Derivedviewport, + typename Derivedscene> + IGL_INLINE void unproject( + const Eigen::MatrixBase& win, + const Eigen::MatrixBase& model, + const Eigen::MatrixBase& proj, + const Eigen::MatrixBase& viewport, + Eigen::PlainObjectBase & scene); + template + IGL_INLINE Eigen::Matrix unproject( + const Eigen::Matrix& win, + const Eigen::Matrix& model, + const Eigen::Matrix& proj, + const Eigen::Matrix& viewport); +} + +#ifndef IGL_STATIC_LIBRARY +# include "unproject.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/unproject_in_mesh.cpp b/src/external/libigl-2.3.0/include/igl/unproject_in_mesh.cpp new file mode 100644 index 000000000..a16e0b6a1 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/unproject_in_mesh.cpp @@ -0,0 +1,100 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "unproject_in_mesh.h" +#include "unproject_ray.h" +#include "ray_mesh_intersect.h" + +template < typename Derivedobj> + IGL_INLINE int igl::unproject_in_mesh( + const Eigen::Vector2f& pos, + const Eigen::Matrix4f& model, + const Eigen::Matrix4f& proj, + const Eigen::Vector4f& viewport, + const std::function< + void( + const Eigen::Vector3f&, + const Eigen::Vector3f&, + std::vector &) + > & shoot_ray, + Eigen::PlainObjectBase & obj, + std::vector & hits) +{ + using namespace std; + using namespace Eigen; + Vector3f s,dir; + unproject_ray(pos,model,proj,viewport,s,dir); + shoot_ray(s,dir,hits); + switch(hits.size()) + { + case 0: + break; + case 1: + { + obj = (s + dir*hits[0].t).cast(); + break; + } + case 2: + default: + { + obj = 0.5*((s + dir*hits[0].t) + (s + dir*hits[1].t)).cast(); + break; + } + } + return hits.size(); +} + +extern "C" +{ +#include "raytri.c" +} + +template < typename DerivedV, typename DerivedF, typename Derivedobj> + IGL_INLINE int igl::unproject_in_mesh( + const Eigen::Vector2f& pos, + const Eigen::Matrix4f& model, + const Eigen::Matrix4f& proj, + const Eigen::Vector4f& viewport, + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + Eigen::PlainObjectBase & obj, + std::vector & hits) +{ + using namespace std; + using namespace Eigen; + const auto & shoot_ray = [&V,&F]( + const Eigen::Vector3f& s, + const Eigen::Vector3f& dir, + std::vector & hits) + { + ray_mesh_intersect(s,dir,V,F,hits); + }; + return unproject_in_mesh(pos,model,proj,viewport,shoot_ray,obj,hits); +} + +template < typename DerivedV, typename DerivedF, typename Derivedobj> + IGL_INLINE int igl::unproject_in_mesh( + const Eigen::Vector2f& pos, + const Eigen::Matrix4f& model, + const Eigen::Matrix4f& proj, + const Eigen::Vector4f& viewport, + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + Eigen::PlainObjectBase & obj) +{ + std::vector hits; + return unproject_in_mesh(pos,model,proj,viewport,V,F,obj,hits); +} +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template int igl::unproject_in_mesh, Eigen::Matrix, Eigen::Matrix >(Eigen::Matrix const&, Eigen::Matrix const&, Eigen::Matrix const&, Eigen::Matrix const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, std::vector >&); +template int igl::unproject_in_mesh >(Eigen::Matrix const&, Eigen::Matrix const&, Eigen::Matrix const&, Eigen::Matrix const&, std::function const&, Eigen::Matrix const&, std::vector >&)> const&, Eigen::PlainObjectBase >&, std::vector >&); +template int igl::unproject_in_mesh >(Eigen::Matrix const&, Eigen::Matrix const&, Eigen::Matrix const&, Eigen::Matrix const&, std::function const&, Eigen::Matrix const&, std::vector >&)> const&, Eigen::PlainObjectBase >&, std::vector >&); +template int igl::unproject_in_mesh >(Eigen::Matrix const&, Eigen::Matrix const&, Eigen::Matrix const&, Eigen::Matrix const&, std::function const&, Eigen::Matrix const&, std::vector >&)> const&, Eigen::PlainObjectBase >&, std::vector >&); +template int igl::unproject_in_mesh, Eigen::Matrix, Eigen::Matrix >(Eigen::Matrix const&, Eigen::Matrix const&, Eigen::Matrix const&, Eigen::Matrix const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/unproject_in_mesh.h b/src/external/libigl-2.3.0/include/igl/unproject_in_mesh.h new file mode 100644 index 000000000..02c392004 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/unproject_in_mesh.h @@ -0,0 +1,88 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_UNPROJECT_IN_MESH +#define IGL_UNPROJECT_IN_MESH +#include "igl_inline.h" +#include + +#include +#include "Hit.h" + +namespace igl +{ + // Unproject a screen location (using current opengl viewport, projection, and + // model view) to a 3D position _inside_ a given mesh. If the ray through the + // given screen location (x,y) _hits_ the mesh more than twice then the 3D + // midpoint between the first two hits is return. If it hits once, then that + // point is return. If it does not hit the mesh then obj is not set. + // + // Inputs: + // pos screen space coordinates + // model model matrix + // proj projection matrix + // viewport vieweport vector + // V #V by 3 list of mesh vertex positions + // F #F by 3 list of mesh triangle indices into V + // Outputs: + // obj 3d unprojected mouse point in mesh + // hits vector of hits + // Returns number of hits + // + template < typename DerivedV, typename DerivedF, typename Derivedobj> + IGL_INLINE int unproject_in_mesh( + const Eigen::Vector2f& pos, + const Eigen::Matrix4f& model, + const Eigen::Matrix4f& proj, + const Eigen::Vector4f& viewport, + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + Eigen::PlainObjectBase & obj, + std::vector & hits); + // + // Inputs: + // pos screen space coordinates + // model model matrix + // proj projection matrix + // viewport vieweport vector + // shoot_ray function handle that outputs first hit of a given ray + // against a mesh (embedded in function handles as captured + // variable/data) + // Outputs: + // obj 3d unprojected mouse point in mesh + // hits vector of hits + // Returns number of hits + // + template < typename Derivedobj> + IGL_INLINE int unproject_in_mesh( + const Eigen::Vector2f& pos, + const Eigen::Matrix4f& model, + const Eigen::Matrix4f& proj, + const Eigen::Vector4f& viewport, + const std::function< + void( + const Eigen::Vector3f&, + const Eigen::Vector3f&, + std::vector &) + > & shoot_ray, + Eigen::PlainObjectBase & obj, + std::vector & hits); + template < typename DerivedV, typename DerivedF, typename Derivedobj> + IGL_INLINE int unproject_in_mesh( + const Eigen::Vector2f& pos, + const Eigen::Matrix4f& model, + const Eigen::Matrix4f& proj, + const Eigen::Vector4f& viewport, + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + Eigen::PlainObjectBase & obj); +} +#ifndef IGL_STATIC_LIBRARY +# include "unproject_in_mesh.cpp" +#endif +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/unproject_on_line.cpp b/src/external/libigl-2.3.0/include/igl/unproject_on_line.cpp new file mode 100644 index 000000000..37a952c8b --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/unproject_on_line.cpp @@ -0,0 +1,63 @@ +#include "unproject_on_line.h" +#include "projection_constraint.h" + +template < + typename DerivedUV, + typename DerivedM, + typename DerivedVP, + typename Derivedorigin, + typename Deriveddir> +void igl::unproject_on_line( + const Eigen::MatrixBase & UV, + const Eigen::MatrixBase & M, + const Eigen::MatrixBase & VP, + const Eigen::MatrixBase & origin, + const Eigen::MatrixBase & dir, + typename DerivedUV::Scalar & t) +{ + using namespace Eigen; + typedef typename DerivedUV::Scalar Scalar; + Matrix A; + Matrix B; + projection_constraint(UV,M,VP,A,B); + // min_z,t ‖Az - B‖² subject to z = origin + t*dir + // min_t ‖A(origin + t*dir) - B‖² + // min_t ‖A*t*dir + A*origin - B‖² + // min_t ‖D*t + C‖² + // t = -(D'D)\(D'*C) + Matrix C = A*origin.template cast() - B; + Matrix D = A*dir.template cast(); + // Solve least squares system directly + const Matrix t_mat = D.jacobiSvd(ComputeFullU | ComputeFullV).solve(-C); + t = t_mat(0,0); +} + +template < + typename DerivedUV, + typename DerivedM, + typename DerivedVP, + typename Derivedorigin, + typename Deriveddir, + typename DerivedZ> +void igl::unproject_on_line( + const Eigen::MatrixBase & UV, + const Eigen::MatrixBase & M, + const Eigen::MatrixBase & VP, + const Eigen::MatrixBase & origin, + const Eigen::MatrixBase & dir, + Eigen::PlainObjectBase & Z) +{ + typedef typename DerivedZ::Scalar Scalar; + typename DerivedUV::Scalar t; + unproject_on_line(UV,M,VP,origin,dir,t); + Z = origin + dir*Scalar(t); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::unproject_on_line, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::unproject_on_line, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::unproject_on_line, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::Matrix::Scalar&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/unproject_on_line.h b/src/external/libigl-2.3.0/include/igl/unproject_on_line.h new file mode 100644 index 000000000..9dbb39eb0 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/unproject_on_line.h @@ -0,0 +1,56 @@ +#ifndef IGL_UNPROJECT_ON_LINE_H +#define IGL_UNPROJECT_ON_LINE_H + +#include + +namespace igl +{ + // Given a screen space point (u,v) and the current projection matrix (e.g. + // gl_proj * gl_modelview) and viewport, _unproject_ the point into the scene + // so that it lies on given line (origin and dir) and projects as closely as + // possible to the given screen space point. + // + // Inputs: + // UV 2-long uv-coordinates of screen space point + // M 4 by 4 projection matrix + // VP 4-long viewport: (corner_u, corner_v, width, height) + // origin point on line + // dir vector parallel to line + // Output: + // t line parameter so that closest poin on line to viewer ray through UV + // lies at origin+t*dir + template < + typename DerivedUV, + typename DerivedM, + typename DerivedVP, + typename Derivedorigin, + typename Deriveddir> + void unproject_on_line( + const Eigen::MatrixBase & UV, + const Eigen::MatrixBase & M, + const Eigen::MatrixBase & VP, + const Eigen::MatrixBase & origin, + const Eigen::MatrixBase & dir, + typename DerivedUV::Scalar & t); + // Z 3d position of closest point on line to viewing ray through UV + template < + typename DerivedUV, + typename DerivedM, + typename DerivedVP, + typename Derivedorigin, + typename Deriveddir, + typename DerivedZ> + void unproject_on_line( + const Eigen::MatrixBase & UV, + const Eigen::MatrixBase & M, + const Eigen::MatrixBase & VP, + const Eigen::MatrixBase & origin, + const Eigen::MatrixBase & dir, + Eigen::PlainObjectBase & Z); +} + +#ifndef IGL_STATIC_LIBRARY +# include "unproject_on_line.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/unproject_on_plane.cpp b/src/external/libigl-2.3.0/include/igl/unproject_on_plane.cpp new file mode 100644 index 000000000..a5b935404 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/unproject_on_plane.cpp @@ -0,0 +1,36 @@ +#include "unproject_on_plane.h" +#include "projection_constraint.h" +#include + +template < + typename DerivedUV, + typename DerivedM, + typename DerivedVP, + typename DerivedP, + typename DerivedZ> +void igl::unproject_on_plane( + const Eigen::MatrixBase & UV, + const Eigen::MatrixBase & M, + const Eigen::MatrixBase & VP, + const Eigen::MatrixBase & P, + Eigen::PlainObjectBase & Z) +{ + using namespace Eigen; + typedef typename DerivedZ::Scalar Scalar; + Matrix A; + Matrix B; + projection_constraint(UV,M,VP,A,B); + Matrix AA; + AA.topRows(2) = A.template cast(); + AA.row(2) = P.head(3).template cast(); + Matrix BB; + BB.head(2) = B.template cast(); + BB(2) = -P(3); + Z = AA.fullPivHouseholderQr().solve(BB); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::unproject_on_plane, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/unproject_on_plane.h b/src/external/libigl-2.3.0/include/igl/unproject_on_plane.h new file mode 100644 index 000000000..edc8ba4c5 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/unproject_on_plane.h @@ -0,0 +1,37 @@ +#ifndef IGL_UNPROJECT_ON_PLANE_H +#define IGL_UNPROJECT_ON_PLANE_H + +#include + +namespace igl +{ + // Given a screen space point (u,v) and the current projection matrix (e.g. + // gl_proj * gl_modelview) and viewport, _unproject_ the point into the scene + // so that it lies on given plane. + // + // Inputs: + // UV 2-long uv-coordinates of screen space point + // M 4 by 4 projection matrix + // VP 4-long viewport: (corner_u, corner_v, width, height) + // P 4-long plane equation coefficients: P*(X 1) = 0 + // Outputs: + // Z 3-long world coordinate + template < + typename DerivedUV, + typename DerivedM, + typename DerivedVP, + typename DerivedP, + typename DerivedZ> + void unproject_on_plane( + const Eigen::MatrixBase & UV, + const Eigen::MatrixBase & M, + const Eigen::MatrixBase & VP, + const Eigen::MatrixBase & P, + Eigen::PlainObjectBase & Z); +} + +#ifndef IGL_STATIC_LIBRARY +# include "unproject_on_plane.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/unproject_onto_mesh.cpp b/src/external/libigl-2.3.0/include/igl/unproject_onto_mesh.cpp new file mode 100644 index 000000000..49e816674 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/unproject_onto_mesh.cpp @@ -0,0 +1,81 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "unproject_onto_mesh.h" +#include "unproject.h" +#include "unproject_ray.h" +#include "ray_mesh_intersect.h" +#include + +template < typename DerivedV, typename DerivedF, typename Derivedbc> +IGL_INLINE bool igl::unproject_onto_mesh( + const Eigen::Vector2f& pos, + const Eigen::Matrix4f& model, + const Eigen::Matrix4f& proj, + const Eigen::Vector4f& viewport, + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + int & fid, + Eigen::PlainObjectBase & bc) +{ + using namespace std; + using namespace Eigen; + const auto & shoot_ray = [&V,&F]( + const Eigen::Vector3f& s, + const Eigen::Vector3f& dir, + igl::Hit & hit)->bool + { + std::vector hits; + if(!ray_mesh_intersect(s,dir,V,F,hits)) + { + return false; + } + hit = hits[0]; + return true; + }; + return unproject_onto_mesh(pos,model,proj,viewport,shoot_ray,fid,bc); +} + +template +IGL_INLINE bool igl::unproject_onto_mesh( + const Eigen::Vector2f& pos, + const Eigen::Matrix4f& model, + const Eigen::Matrix4f& proj, + const Eigen::Vector4f& viewport, + const std::function< + bool( + const Eigen::Vector3f&, + const Eigen::Vector3f&, + igl::Hit &) + > & shoot_ray, + int & fid, + Eigen::PlainObjectBase & bc) +{ + using namespace std; + using namespace Eigen; + Vector3f s,dir; + unproject_ray(pos,model,proj,viewport,s,dir); + Hit hit; + if(!shoot_ray(s,dir,hit)) + { + return false; + } + bc.resize(3, 1); + bc << 1.0-hit.u-hit.v, hit.u, hit.v; + fid = hit.id; + return true; +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template bool igl::unproject_onto_mesh, Eigen::Matrix, Eigen::Matrix >(Eigen::Matrix const&, Eigen::Matrix const&, Eigen::Matrix const&, Eigen::Matrix const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, int&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template bool igl::unproject_onto_mesh, Eigen::Matrix, Eigen::Matrix >(Eigen::Matrix const&, Eigen::Matrix const&, Eigen::Matrix const&, Eigen::Matrix const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, int&, Eigen::PlainObjectBase >&); +template bool igl::unproject_onto_mesh, Eigen::Matrix, Eigen::Matrix >(Eigen::Matrix const&, Eigen::Matrix const&, Eigen::Matrix const&, Eigen::Matrix const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, int&, Eigen::PlainObjectBase >&); +template bool igl::unproject_onto_mesh, Eigen::Matrix, Eigen::Matrix >(Eigen::Matrix const&, Eigen::Matrix const&, Eigen::Matrix const&, Eigen::Matrix const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, int&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/unproject_onto_mesh.h b/src/external/libigl-2.3.0/include/igl/unproject_onto_mesh.h new file mode 100644 index 000000000..1912c2c63 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/unproject_onto_mesh.h @@ -0,0 +1,80 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_UNPROJECT_ONTO_MESH +#define IGL_UNPROJECT_ONTO_MESH +#include "igl_inline.h" +#include "Hit.h" +#include +#include + +namespace igl +{ + // Unproject a screen location (using current opengl viewport, projection, and + // model view) to a 3D position _onto_ a given mesh, if the ray through the + // given screen location (x,y) _hits_ the mesh. + // + // Inputs: + // pos screen space coordinates + // model model matrix + // proj projection matrix + // viewport vieweport vector + // V #V by 3 list of mesh vertex positions + // F #F by 3 list of mesh triangle indices into V + // Outputs: + // fid id of the first face hit + // bc barycentric coordinates of hit + // Returns true if there's a hit + // + // Example: + // igl::opengl::glfw::Viewer vr; + // ... + // igl::unproject_onto_mesh( + // pos,vr.core().view,vr.core().proj,vr.core().viewport,V,F,fid,bc); + template < typename DerivedV, typename DerivedF, typename Derivedbc> + IGL_INLINE bool unproject_onto_mesh( + const Eigen::Vector2f& pos, + const Eigen::Matrix4f& model, + const Eigen::Matrix4f& proj, + const Eigen::Vector4f& viewport, + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + int & fid, + Eigen::PlainObjectBase & bc); + // + // Inputs: + // pos screen space coordinates + // model model matrix + // proj projection matrix + // viewport viewport vector + // shoot_ray function handle that outputs hits of a given ray against a + // mesh (embedded in function handles as captured variable/data) + // Outputs: + // fid id of the first face hit + // bc barycentric coordinates of hit + // Returns true if there's a hit + template + IGL_INLINE bool unproject_onto_mesh( + const Eigen::Vector2f& pos, + const Eigen::Matrix4f& model, + const Eigen::Matrix4f& proj, + const Eigen::Vector4f& viewport, + const std::function< + bool( + const Eigen::Vector3f&, + const Eigen::Vector3f&, + igl::Hit &) + > & shoot_ray, + int & fid, + Eigen::PlainObjectBase & bc); +} +#ifndef IGL_STATIC_LIBRARY +# include "unproject_onto_mesh.cpp" +#endif +#endif + + diff --git a/src/external/libigl-2.3.0/include/igl/unproject_ray.cpp b/src/external/libigl-2.3.0/include/igl/unproject_ray.cpp new file mode 100644 index 000000000..07bc84f6e --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/unproject_ray.cpp @@ -0,0 +1,41 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "unproject_ray.h" +#include "unproject.h" + +template < + typename Derivedpos, + typename Derivedmodel, + typename Derivedproj, + typename Derivedviewport, + typename Deriveds, + typename Deriveddir> +IGL_INLINE void igl::unproject_ray( + const Eigen::MatrixBase & pos, + const Eigen::MatrixBase & model, + const Eigen::MatrixBase & proj, + const Eigen::MatrixBase & viewport, + Eigen::PlainObjectBase & s, + Eigen::PlainObjectBase & dir) +{ + using namespace std; + using namespace Eigen; + // Source and direction on screen + typedef Eigen::Matrix Vec3; + Vec3 win_s(pos(0, 0),pos(1, 0),0); + Vec3 win_d(pos(0, 0),pos(1, 0),1); + // Source, destination and direction in world + Vec3 d; + igl::unproject(win_s,model,proj,viewport,s); + igl::unproject(win_d,model,proj,viewport,d); + dir = d-s; +} + +#ifdef IGL_STATIC_LIBRARY +template void igl::unproject_ray, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/unproject_ray.h b/src/external/libigl-2.3.0/include/igl/unproject_ray.h new file mode 100644 index 000000000..2bca6151c --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/unproject_ray.h @@ -0,0 +1,44 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_UNPROJECT_RAY_H +#define IGL_UNPROJECT_RAY_H +#include "igl_inline.h" +#include +namespace igl +{ + // Construct a ray (source point + direction vector) given a screen space + // positions (e.g. mouse) and a model-view projection constellation. + // + // Inputs: + // pos 2d screen-space position (x,y) + // model 4x4 model-view matrix + // proj 4x4 projection matrix + // viewport 4-long viewport vector + // Outputs: + // s source of ray (pos unprojected with z=0) + /// dir direction of ray (d - s) where d is pos unprojected with z=1 + // + template < + typename Derivedpos, + typename Derivedmodel, + typename Derivedproj, + typename Derivedviewport, + typename Deriveds, + typename Deriveddir> + IGL_INLINE void unproject_ray( + const Eigen::MatrixBase & pos, + const Eigen::MatrixBase & model, + const Eigen::MatrixBase & proj, + const Eigen::MatrixBase & viewport, + Eigen::PlainObjectBase & s, + Eigen::PlainObjectBase & dir); +} +#ifndef IGL_STATIC_LIBRARY +# include "unproject_ray.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/unzip_corners.cpp b/src/external/libigl-2.3.0/include/igl/unzip_corners.cpp new file mode 100644 index 000000000..0a2ed004c --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/unzip_corners.cpp @@ -0,0 +1,48 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "unzip_corners.h" + +#include "unique_rows.h" +#include "slice.h" + +template < typename DerivedA, typename DerivedU, typename DerivedG, typename DerivedJ > +IGL_INLINE void igl::unzip_corners( + const std::vector > & A, + Eigen::PlainObjectBase & U, + Eigen::PlainObjectBase & G, + Eigen::PlainObjectBase & J) +{ + if(A.size() == 0) + { + U.resize(0,0); + G.resize(0,3); + J.resize(0,0); + return; + } + const size_t num_a = A.size(); + const typename DerivedA::Index m = A[0].get().rows(); + DerivedU C(m*3,num_a); + for(int a = 0;a +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_UNZIP_CORNERS_H +#define IGL_UNZIP_CORNERS_H +#include "igl_inline.h" +#include +#include +#include + +namespace igl +{ + // UNZIP_CORNERS Given a triangle mesh where corners of each triangle index + // different matrices of attributes (e.g. read from an OBJ file), unzip the + // corners into unique efficiently: attributes become properly vertex valued + // (usually creating greater than #V but less than #F*3 vertices). + // + // To pass a list of attributes this function takes an std::vector of + // std::reference_wrapper of an Eigen::... type. This allows you to use list + // initializers **without** incurring a copy, but means you'll need to + // provide the derived type of A as an explicit template parameter: + // + // unzip_corners({F,FTC,FN},U,G,J); + // + // Inputs: + // A #A list of #F by 3 attribute indices, typically {F,FTC,FN} + // Outputs: + // U #U by #A list of indices into each attribute for each unique mesh + // vertex: U(v,a) is the attribute index of vertex v in attribute a. + // G #F by 3 list of triangle indices into U + // Example: + // [V,F,TC,FTC] = readOBJ('~/Downloads/kiwis/kiwi.obj'); + // [U,G] = unzip_corners(cat(3,F,FTC)); + // % display mesh + // tsurf(G,V(U(:,1),:)); + // % display texture coordinates + // tsurf(G,TC(U(:,2),:)); + // + template < typename DerivedA, typename DerivedU, typename DerivedG, typename DerivedJ> + IGL_INLINE void unzip_corners( + const std::vector > & A, + Eigen::PlainObjectBase & U, + Eigen::PlainObjectBase & G, + Eigen::PlainObjectBase & J); +} + +#ifndef IGL_STATIC_LIBRARY +# include "unzip_corners.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/upsample.cpp b/src/external/libigl-2.3.0/include/igl/upsample.cpp new file mode 100644 index 000000000..483b814f7 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/upsample.cpp @@ -0,0 +1,145 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "upsample.h" + +#include "triangle_triangle_adjacency.h" + + +template < + typename DerivedF, + typename SType, + typename DerivedNF> +IGL_INLINE void igl::upsample( + const int n_verts, + const Eigen::MatrixBase& F, + Eigen::SparseMatrix& S, + Eigen::PlainObjectBase& NF) +{ + using namespace std; + using namespace Eigen; + + typedef Eigen::Triplet Triplet_t; + + Eigen::Matrix< typename DerivedF::Scalar,Eigen::Dynamic,Eigen::Dynamic> + FF,FFi; + triangle_triangle_adjacency(F,FF,FFi); + + // TODO: Cache optimization missing from here, it is a mess + + // Compute the number and positions of the vertices to insert (on edges) + Eigen::MatrixXi NI = Eigen::MatrixXi::Constant(FF.rows(),FF.cols(),-1); + Eigen::MatrixXi NIdoubles = Eigen::MatrixXi::Zero(FF.rows(), FF.cols()); + int counter = 0; + + for(int i=0;i tripletList; + + // Fill the odd vertices position + for (int i=0; i VI(6); + VI << F(i,0), F(i,1), F(i,2), NI(i,0) + n_odd, NI(i,1) + n_odd, NI(i,2) + n_odd; + + Eigen::Matrix f0(3), f1(3), f2(3), f3(3); + f0 << VI(0), VI(3), VI(5); + f1 << VI(1), VI(4), VI(3); + f2 << VI(3), VI(4), VI(5); + f3 << VI(4), VI(2), VI(5); + + NF.row((i*4)+0) = f0; + NF.row((i*4)+1) = f1; + NF.row((i*4)+2) = f2; + NF.row((i*4)+3) = f3; + } +} + +template < + typename DerivedV, + typename DerivedF, + typename DerivedNV, + typename DerivedNF> +IGL_INLINE void igl::upsample( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + Eigen::PlainObjectBase& NV, + Eigen::PlainObjectBase& NF, + const int number_of_subdivs) +{ + NV = V; + NF = F; + for(int i=0; iS; + upsample(NV.rows(), tempF, S, NF); + // This .eval is super important + NV = (S*NV).eval(); + } +} + +template < + typename MatV, + typename MatF> +IGL_INLINE void igl::upsample( + MatV& V, + MatF& F, + const int number_of_subdivs) +{ + const MatV V_copy = V; + const MatF F_copy = F; + return upsample(V_copy,F_copy,V,F,number_of_subdivs); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +template void igl::upsample, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, int); +template void igl::upsample, double, Eigen::Matrix >(int, Eigen::MatrixBase > const&, Eigen::SparseMatrix&, Eigen::PlainObjectBase >&); +template void igl::upsample, Eigen::Matrix >(Eigen::Matrix&, Eigen::Matrix&, int); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/upsample.h b/src/external/libigl-2.3.0/include/igl/upsample.h new file mode 100644 index 000000000..588f3c5ba --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/upsample.h @@ -0,0 +1,82 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_UPSAMPLE_H +#define IGL_UPSAMPLE_H +#include "igl_inline.h" + +#include +#include + +// History: +// changed templates from generic matrices to PlainObjectBase Alec May 7, 2011 +namespace igl +{ + // Subdivide without moving vertices: Given the triangle mesh [V, F], + // where n_verts = V.rows(), computes newV and a sparse matrix S s.t. + // [newV, newF] is the subdivided mesh where newV = S*V. + // + // Inputs: + // n_verts an integer (number of mesh vertices) + // F an m by 3 matrix of integers of triangle faces + // Outputs: + // S a sparse matrix (will become the subdivision matrix) + // newF a matrix containing the new faces + template < + typename DerivedF, + typename SType, + typename DerivedNF> + IGL_INLINE void upsample( + const int n_verts, + const Eigen::MatrixBase& F, + Eigen::SparseMatrix& S, + Eigen::PlainObjectBase& NF); + // Subdivide a mesh without moving vertices: loop subdivision but odd + // vertices stay put and even vertices are just edge midpoints + // + // Templates: + // MatV matrix for vertex positions, e.g. MatrixXd + // MatF matrix for vertex positions, e.g. MatrixXi + // Inputs: + // V #V by dim mesh vertices + // F #F by 3 mesh triangles + // Outputs: + // NV new vertex positions, V is guaranteed to be at top + // NF new list of face indices + // + // NOTE: V should not be the same as NV, + // NOTE: F should not be the same as NF, use other proto + // + // Known issues: + // - assumes (V,F) is edge-manifold. + template < + typename DerivedV, + typename DerivedF, + typename DerivedNV, + typename DerivedNF> + IGL_INLINE void upsample( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + Eigen::PlainObjectBase& NV, + Eigen::PlainObjectBase& NF, + const int number_of_subdivs = 1); + + // Virtually in place wrapper + template < + typename MatV, + typename MatF> + IGL_INLINE void upsample( + MatV& V, + MatF& F, + const int number_of_subdivs = 1); +} + +#ifndef IGL_STATIC_LIBRARY +# include "upsample.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/vector_area_matrix.cpp b/src/external/libigl-2.3.0/include/igl/vector_area_matrix.cpp new file mode 100644 index 000000000..6bafb8871 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/vector_area_matrix.cpp @@ -0,0 +1,52 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Daniele Panozzo +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "vector_area_matrix.h" +#include "boundary_facets.h" +#include + +// Bug in unsupported/Eigen/SparseExtra needs iostream first +#include +#include + +template +IGL_INLINE void igl::vector_area_matrix( + const Eigen::MatrixBase & F, + Eigen::SparseMatrix& A) +{ + using namespace Eigen; + using namespace std; + + // number of vertices + const int n = F.maxCoeff()+1; + + MatrixXi E; + boundary_facets(F,E); + + //Prepare a vector of triplets to set the matrix + vector > tripletList; + tripletList.reserve(4*E.rows()); + + for(int k = 0; k < E.rows(); k++) + { + int i = E(k,0); + int j = E(k,1); + tripletList.push_back(Triplet(i+n, j, -0.25)); + tripletList.push_back(Triplet(j, i+n, -0.25)); + tripletList.push_back(Triplet(i, j+n, 0.25)); + tripletList.push_back(Triplet(j+n, i, 0.25)); + } + + //Set A from triplets (Eigen will sum triplets with same coordinates) + A.resize(n * 2, n * 2); + A.setFromTriplets(tripletList.begin(), tripletList.end()); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +template void igl::vector_area_matrix, double>(Eigen::MatrixBase > const&, Eigen::SparseMatrix&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/vector_area_matrix.h b/src/external/libigl-2.3.0/include/igl/vector_area_matrix.h new file mode 100644 index 000000000..4a42ea5af --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/vector_area_matrix.h @@ -0,0 +1,41 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Daniele Panozzo +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_VECTOR_AREA_MATRIX_H +#define IGL_VECTOR_AREA_MATRIX_H +#include "igl_inline.h" + +#include +#include + +namespace igl +{ + // Constructs the symmetric area matrix A, s.t. [V.col(0)' V.col(1)'] * A * + // [V.col(0); V.col(1)] is the **vector area** of the mesh (V,F). + // + // Templates: + // DerivedV derived type of eigen matrix for V (e.g. derived from + // MatrixXd) + // DerivedF derived type of eigen matrix for F (e.g. derived from + // MatrixXi) + // Scalar scalar type for eigen sparse matrix (e.g. double) + // Inputs: + // F #F by 3 list of mesh faces (must be triangles) + // Outputs: + // A #Vx2 by #Vx2 area matrix + // + template + IGL_INLINE void vector_area_matrix( + const Eigen::MatrixBase & F, + Eigen::SparseMatrix& A); +} + +#ifndef IGL_STATIC_LIBRARY +# include "vector_area_matrix.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/verbose.h b/src/external/libigl-2.3.0/include/igl/verbose.h new file mode 100644 index 000000000..e4aa86958 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/verbose.h @@ -0,0 +1,46 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_VERBOSE_H +#define IGL_VERBOSE_H + +// This function is only useful as a header-only inlined function + +namespace igl +{ + // Provide a wrapper for printf, called verbose that functions exactly like + // printf if VERBOSE is defined and does exactly nothing if VERBOSE is + // undefined + inline int verbose(const char * msg,...); +} + + + +#include +#ifdef VERBOSE +# include +#endif + +#include +// http://channel9.msdn.com/forums/techoff/254707-wrapping-printf-in-c/ +#ifdef VERBOSE +inline int igl::verbose(const char * msg,...) +{ + va_list argList; + va_start(argList, msg); + int count = vprintf(msg, argList); + va_end(argList); + return count; +} +#else +inline int igl::verbose(const char * /*msg*/,...) +{ + return 0; +} +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/vertex_components.cpp b/src/external/libigl-2.3.0/include/igl/vertex_components.cpp new file mode 100644 index 000000000..44d41cf17 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/vertex_components.cpp @@ -0,0 +1,98 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "vertex_components.h" +#include "adjacency_matrix.h" +#include +#include + +template +IGL_INLINE void igl::vertex_components( + const Eigen::SparseCompressedBase & A, + Eigen::PlainObjectBase & C, + Eigen::PlainObjectBase & counts) +{ + using namespace Eigen; + using namespace std; + assert(A.rows() == A.cols() && "A should be square."); + const size_t n = A.rows(); + Array seen = Array::Zero(n,1); + C.resize(n,1); + typename DerivedC::Scalar id = 0; + vector vcounts; + // breadth first search + for(int k=0; k Q; + Q.push(k); + vcounts.push_back(0); + while(!Q.empty()) + { + const int f = Q.front(); + Q.pop(); + if(seen(f)) + { + continue; + } + seen(f) = true; + C(f,0) = id; + vcounts[id]++; + // Iterate over inside + for(typename DerivedA::InnerIterator it (A,f); it; ++it) + { + const int g = it.index(); + if(!seen(g) && it.value()) + { + Q.push(g); + } + } + } + id++; + } + assert((size_t) id == vcounts.size()); + const size_t ncc = vcounts.size(); + assert((size_t)C.maxCoeff()+1 == ncc); + counts.resize(ncc,1); + for(size_t i = 0;i +IGL_INLINE void igl::vertex_components( + const Eigen::SparseCompressedBase & A, + Eigen::PlainObjectBase & C) +{ + Eigen::VectorXi counts; + return vertex_components(A,C,counts); +} + +template +IGL_INLINE void igl::vertex_components( + const Eigen::MatrixBase & F, + Eigen::PlainObjectBase & C) +{ + Eigen::SparseMatrix A; + adjacency_matrix(F,A); + return vertex_components(A,C); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::vertex_components, Eigen::Array >(Eigen::SparseCompressedBase> const&, Eigen::PlainObjectBase >&); +template void igl::vertex_components, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template void igl::vertex_components, Eigen::Matrix >(Eigen::SparseCompressedBase> const&, Eigen::PlainObjectBase >&); +template void igl::vertex_components, Eigen::Matrix >(Eigen::SparseCompressedBase> const&, Eigen::PlainObjectBase >&); +template void igl::vertex_components, Eigen::Matrix, Eigen::Matrix >(Eigen::SparseCompressedBase> const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::vertex_components, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/vertex_components.h b/src/external/libigl-2.3.0/include/igl/vertex_components.h new file mode 100644 index 000000000..f744fa8b4 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/vertex_components.h @@ -0,0 +1,59 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_COMPONENTS_H +#define IGL_COMPONENTS_H +#include "igl_inline.h" +#include +#include +namespace igl +{ + // Compute connected components of a graph represented by an adjacency + // matrix. + // + // Returns a component ID per vertex of the graph where connectivity is established by edges. + // + // Inputs: + // A n by n adjacency matrix + // Outputs: + // C n list of component ids (starting with 0) + // counts #components list of counts for each component + // + template + IGL_INLINE void vertex_components( + const Eigen::SparseCompressedBase & A, + Eigen::PlainObjectBase & C, + Eigen::PlainObjectBase & counts); + + template + IGL_INLINE void vertex_components( + const Eigen::SparseCompressedBase & A, + Eigen::PlainObjectBase & C); + + // Compute the connected components for a mesh given its faces. + // Returns a component ID per vertex of the mesh where connectivity is established by edges. + // + // For computing connected components per face see igl::facet_components + // + // + // Inputs: + // F n by 3 list of triangle indices + // Outputs: + // C max(F) list of component ids + template + IGL_INLINE void vertex_components( + const Eigen::MatrixBase & F, + Eigen::PlainObjectBase & C); + +} + +#ifndef IGL_STATIC_LIBRARY +# include "vertex_components.cpp" +#endif + +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/vertex_triangle_adjacency.cpp b/src/external/libigl-2.3.0/include/igl/vertex_triangle_adjacency.cpp new file mode 100644 index 000000000..1c3208982 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/vertex_triangle_adjacency.cpp @@ -0,0 +1,104 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Daniele Panozzo +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "vertex_triangle_adjacency.h" +#include "cumsum.h" + +template +IGL_INLINE void igl::vertex_triangle_adjacency( + const typename DerivedF::Scalar n, + const Eigen::MatrixBase& F, + std::vector >& VF, + std::vector >& VFi) +{ + VF.clear(); + VFi.clear(); + + VF.resize(n); + VFi.resize(n); + + typedef typename DerivedF::Index Index; + for(Index fi=0; fi +IGL_INLINE void igl::vertex_triangle_adjacency( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + std::vector >& VF, + std::vector >& VFi) +{ + return vertex_triangle_adjacency(V.rows(),F,VF,VFi); +} + +template < + typename DerivedF, + typename DerivedVF, + typename DerivedNI> +IGL_INLINE void igl::vertex_triangle_adjacency( + const Eigen::MatrixBase & F, + const int n, + Eigen::PlainObjectBase & VF, + Eigen::PlainObjectBase & NI) +{ + typedef Eigen::Matrix VectorXI; + // vfd #V list so that vfd(i) contains the vertex-face degree (number of + // faces incident on vertex i) + VectorXI vfd = VectorXI::Zero(n); + for (int i = 0; i < F.rows(); i++) + { + for (int j = 0; j < 3; j++) + { + vfd[F(i,j)]++; + } + } + igl::cumsum(vfd,1,NI); + // Prepend a zero + NI = (DerivedNI(n+1)<<0,NI).finished(); + // vfd now acts as a counter + vfd = NI; + + VF.derived()= Eigen::Matrix(3*F.rows(), 1); + for (int i = 0; i < F.rows(); i++) + { + for (int j = 0; j < 3; j++) + { + VF[vfd[F(i,j)]] = i; + vfd[F(i,j)]++; + } + } +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::vertex_triangle_adjacency, unsigned long, unsigned long>(Eigen::Matrix::Scalar, Eigen::MatrixBase > const&, std::vector >, std::allocator > > >&, std::vector >, std::allocator > > >&); +// generated by autoexplicit.sh +template void igl::vertex_triangle_adjacency, Eigen::Matrix, int>(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, std::vector >, std::allocator > > >&, std::vector >, std::allocator > > >&); +template void igl::vertex_triangle_adjacency, Eigen::Matrix, unsigned int>(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, std::vector >, std::allocator > > >&, std::vector >, std::allocator > > >&); +template void igl::vertex_triangle_adjacency, Eigen::Matrix, int>(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, std::vector >, std::allocator > > >&, std::vector >, std::allocator > > >&); +template void igl::vertex_triangle_adjacency, long, long>(Eigen::Matrix::Scalar, Eigen::MatrixBase > const&, std::vector >, std::allocator > > >&, std::vector >, std::allocator > > >&); +template void igl::vertex_triangle_adjacency, long, long>(Eigen::Matrix::Scalar, Eigen::MatrixBase > const&, std::vector >, std::allocator > > >&, std::vector >, std::allocator > > >&); +template void igl::vertex_triangle_adjacency, unsigned long, unsigned long>(Eigen::Matrix::Scalar, Eigen::MatrixBase > const&, std::vector >, std::allocator > > >&, std::vector >, std::allocator > > >&); +template void igl::vertex_triangle_adjacency, Eigen::Matrix, int>(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, std::vector >, std::allocator > > >&, std::vector >, std::allocator > > >&); +template void igl::vertex_triangle_adjacency, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, int, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::vertex_triangle_adjacency, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, int, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::vertex_triangle_adjacency, int, int>(Eigen::Matrix::Scalar, Eigen::MatrixBase > const&, std::vector >, std::allocator > > >&, std::vector >, std::allocator > > >&); +#ifdef WIN32 +template void igl::vertex_triangle_adjacency, unsigned __int64, unsigned __int64>(int, class Eigen::MatrixBase> const &, class std::vector>, class std::allocator>>> &, class std::vector>, class std::allocator>>> &); +template void igl::vertex_triangle_adjacency, unsigned __int64, unsigned __int64>(int, class Eigen::MatrixBase> const &, class std::vector>, class std::allocator>>> &, class std::vector>, class std::allocator>>> &); +template void igl::vertex_triangle_adjacency,__int64,__int64>(int,class Eigen::MatrixBase > const &,class std::vector >,class std::allocator > > > &,class std::vector >,class std::allocator > > > &); +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/vertex_triangle_adjacency.h b/src/external/libigl-2.3.0/include/igl/vertex_triangle_adjacency.h new file mode 100644 index 000000000..ce67b1f3d --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/vertex_triangle_adjacency.h @@ -0,0 +1,71 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Daniele Panozzo +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_VERTEX_TRIANGLE_ADJACENCY_H +#define IGL_VERTEX_TRIANGLE_ADJACENCY_H +#include "igl_inline.h" + +#include +#include + +namespace igl +{ + // vertex_face_adjacency constructs the vertex-face topology of a given mesh (V,F) + // + // Inputs: + // //V #V by 3 list of vertex coordinates + // n number of vertices #V (e.g. `F.maxCoeff()+1` or `V.rows()`) + // F #F by dim list of mesh faces (must be triangles) + // Outputs: + // VF #V list of lists of incident faces (adjacency list) + // VI #V list of lists of index of incidence within incident faces listed + // in VF + // + // See also: edges, cotmatrix, diag, vv + // + // Known bugs: this should not take V as an input parameter. + // Known bugs/features: if a facet is combinatorially degenerate then faces + // will appear multiple times in VF and correspondingly in VFI (j appears + // twice in F.row(i) then i will appear twice in VF[j]) + template + IGL_INLINE void vertex_triangle_adjacency( + const typename DerivedF::Scalar n, + const Eigen::MatrixBase& F, + std::vector >& VF, + std::vector >& VFi); + template + IGL_INLINE void vertex_triangle_adjacency( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + std::vector >& VF, + std::vector >& VFi); + // Inputs: + // F #F by 3 list of triangle indices into some vertex list V + // n number of vertices, #V (e.g., F.maxCoeff()+1) + // Outputs: + // VF 3*#F list List of faces indice on each vertex, so that VF(NI(i)+j) = + // f, means that face f is the jth face (in no particular order) incident + // on vertex i. + // NI #V+1 list cumulative sum of vertex-triangle degrees with a + // preceeding zero. "How many faces" have been seen before visiting this + // vertex and its incident faces. + template < + typename DerivedF, + typename DerivedVF, + typename DerivedNI> + IGL_INLINE void vertex_triangle_adjacency( + const Eigen::MatrixBase & F, + const int n, + Eigen::PlainObjectBase & VF, + Eigen::PlainObjectBase & NI); +} + +#ifndef IGL_STATIC_LIBRARY +# include "vertex_triangle_adjacency.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/volume.cpp b/src/external/libigl-2.3.0/include/igl/volume.cpp new file mode 100644 index 000000000..d44f25fc2 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/volume.cpp @@ -0,0 +1,126 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "volume.h" +#include "cross.h" +#include +template < + typename DerivedV, + typename DerivedT, + typename Derivedvol> +IGL_INLINE void igl::volume( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& T, + Eigen::PlainObjectBase& vol) +{ + using namespace Eigen; + const int m = T.rows(); + vol.resize(m,1); + for(int t = 0;t RowVector3S; + const RowVector3S & a = V.row(T(t,0)); + const RowVector3S & b = V.row(T(t,1)); + const RowVector3S & c = V.row(T(t,2)); + const RowVector3S & d = V.row(T(t,3)); + vol(t) = -(a-d).dot((b-d).cross(c-d))/6.; + } +} + +template < + typename DerivedA, + typename DerivedB, + typename DerivedC, + typename DerivedD, + typename Derivedvol> +IGL_INLINE void igl::volume( + const Eigen::MatrixBase & A, + const Eigen::MatrixBase & B, + const Eigen::MatrixBase & C, + const Eigen::MatrixBase & D, + Eigen::PlainObjectBase & vol) +{ + const auto & AmD = A-D; + const auto & BmD = B-D; + const auto & CmD = C-D; + Eigen::Matrix BmDxCmD; + cross(BmD.eval(),CmD.eval(),BmDxCmD); + const auto & AmDdx = (AmD.array() * BmDxCmD.array()).rowwise().sum(); + vol = -AmDdx/6.; +} + +template < + typename VecA, + typename VecB, + typename VecC, + typename VecD> +IGL_INLINE typename VecA::Scalar igl::volume_single( + const VecA & a, + const VecB & b, + const VecC & c, + const VecD & d) +{ + return -(a-d).dot((b-d).cross(c-d))/6.; +} + + +template < + typename DerivedL, + typename Derivedvol> +IGL_INLINE void igl::volume( + const Eigen::MatrixBase& L, + Eigen::PlainObjectBase& vol) +{ + using namespace Eigen; + const int m = L.rows(); + typedef typename Derivedvol::Scalar ScalarS; + vol.resize(m,1); + for(int t = 0;t, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +// Nonsense template +namespace igl{ template<> void volume, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&){} } +// generated by autoexplicit.sh +template void igl::volume, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::volume, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::volume, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::volume, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +template Eigen::Matrix::Scalar igl::volume_single, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::Matrix const&, Eigen::Matrix const&, Eigen::Matrix const&, Eigen::Matrix const&); +template void igl::volume,Eigen::Matrix,Eigen::Matrix >(Eigen::MatrixBase > const &,Eigen::MatrixBase > const &,Eigen::PlainObjectBase > &); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/volume.h b/src/external/libigl-2.3.0/include/igl/volume.h new file mode 100644 index 000000000..960d95f41 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/volume.h @@ -0,0 +1,74 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_VOLUME_H +#define IGL_VOLUME_H +#include "igl_inline.h" +#include +namespace igl +{ + // VOLUME Compute volume for all tets of a given tet mesh + // (V,T) + // + // vol = volume(V,T) + // + // Inputs: + // V #V by dim list of vertex positions + // T #V by 4 list of tet indices + // Outputs: + // vol #T list of tetrahedron volumes + // + template < + typename DerivedV, + typename DerivedT, + typename Derivedvol> + IGL_INLINE void volume( + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& T, + Eigen::PlainObjectBase& vol); + template < + typename DerivedA, + typename DerivedB, + typename DerivedC, + typename DerivedD, + typename Derivedvol> + IGL_INLINE void volume( + const Eigen::MatrixBase & A, + const Eigen::MatrixBase & B, + const Eigen::MatrixBase & C, + const Eigen::MatrixBase & D, + Eigen::PlainObjectBase & vol); + // Single tet + template < + typename VecA, + typename VecB, + typename VecC, + typename VecD> + IGL_INLINE typename VecA::Scalar volume_single( + const VecA & a, + const VecB & b, + const VecC & c, + const VecD & d); + // Intrinsic version: + // + // Inputs: + // L #V by 6 list of edge lengths (see edge_lengths) + template < + typename DerivedL, + typename Derivedvol> + IGL_INLINE void volume( + const Eigen::MatrixBase& L, + Eigen::PlainObjectBase& vol); +} + +#ifndef IGL_STATIC_LIBRARY +# include "volume.cpp" +#endif + +#endif + + diff --git a/src/external/libigl-2.3.0/include/igl/voxel_grid.cpp b/src/external/libigl-2.3.0/include/igl/voxel_grid.cpp new file mode 100644 index 000000000..9e337a844 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/voxel_grid.cpp @@ -0,0 +1,107 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "voxel_grid.h" +#include "grid.h" + +template < + typename Scalar, + typename DerivedGV, + typename Derivedside> +IGL_INLINE void igl::voxel_grid( + const Eigen::AlignedBox & box, + const int in_s, + const int pad_count, + Eigen::PlainObjectBase & GV, + Eigen::PlainObjectBase & side) +{ + using namespace Eigen; + using namespace std; + typename DerivedGV::Index si = -1; + side.resize(1, 3); + box.diagonal().maxCoeff(&si); + //DerivedGV::Index si = 0; + //assert(si>=0); + const Scalar s_len = box.diagonal()(si); + assert(in_s>(pad_count*2+1) && "s should be > 2*pad_count+1"); + const Scalar s = in_s - 2*pad_count; + side(si) = s; + for(int i = 0;i<3;i++) + { + if(i!=si) + { + side(i) = std::ceil(s * (box.max()(i)-box.min()(i))/s_len); + } + } + side.array() += 2*pad_count; + grid(side,GV); + // A * p/s + B = min + // A * (1-p/s) + B = max + // B = min - A * p/s + // A * (1-p/s) + min - A * p/s = max + // A * (1-p/s) - A * p/s = max-min + // A * (1-2p/s) = max-min + // A = (max-min)/(1-2p/s) + const Array ps= + (Scalar)(pad_count)/(side.transpose().template cast().array()-1.); + const Array A = box.diagonal().array()/(1.0-2.*ps); + //// This would result in an "anamorphic", but perfectly fit grid: + //const Array B = box.min().array() - A.array()*ps; + //GV.array().rowwise() *= A.transpose(); + //GV.array().rowwise() += B.transpose(); + // Instead scale by largest factor and move to match center + typename Array::Index ai = -1; + Scalar a = A.maxCoeff(&ai); + const Array ratio = + a*(side.template cast().array()-1.0)/(Scalar)(side(ai)-1.0); + GV.array().rowwise() *= ratio; + const Eigen::Matrix offset = (box.center().transpose()-GV.colwise().mean()).eval(); + GV.rowwise() += offset; +} + +template < + typename DerivedV, + typename DerivedGV, + typename Derivedside> +IGL_INLINE void igl::voxel_grid( + const Eigen::MatrixBase & V, + const typename DerivedV::Scalar offset, + const int s, + const int pad_count, + Eigen::PlainObjectBase & GV, + Eigen::PlainObjectBase & side) +{ + typedef typename DerivedV::Scalar Scalar; + Eigen::AlignedBox box; + typedef Eigen::Matrix RowVector3S; + assert(V.cols() == 3 && "V must contain positions in 3D"); + RowVector3S min_ext = V.colwise().minCoeff().array() - offset; + RowVector3S max_ext = V.colwise().maxCoeff().array() + offset; + box.extend(min_ext.transpose()); + box.extend(max_ext.transpose()); + return igl::voxel_grid(box,s,1,GV,side); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template void igl::voxel_grid, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::Matrix::Scalar, int, int, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::voxel_grid, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::Matrix::Scalar, int, int, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::voxel_grid, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::Matrix::Scalar, int, int, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::voxel_grid, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::Matrix::Scalar, int, int, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::voxel_grid, Eigen::Matrix >(Eigen::AlignedBox const&, int, int, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template void igl::voxel_grid, Eigen::Matrix >(Eigen::AlignedBox const&, int, int, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::voxel_grid, Eigen::Matrix >(Eigen::AlignedBox const&, int, int, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::voxel_grid, Eigen::Matrix >(Eigen::AlignedBox const&, int, int, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::voxel_grid, Eigen::Matrix >(Eigen::AlignedBox const&, int, int, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::voxel_grid, Eigen::Matrix >(Eigen::AlignedBox const&, int, int, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/voxel_grid.h b/src/external/libigl-2.3.0/include/igl/voxel_grid.h new file mode 100644 index 000000000..8dc9ae859 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/voxel_grid.h @@ -0,0 +1,50 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_VOXEL_GRID_H +#define IGL_VOXEL_GRID_H +#include "igl_inline.h" +#include +#include +namespace igl +{ + // Construct the cell center positions of a regular voxel grid (lattice) made + // of perfectly square voxels. + // + // Inputs: + // box bounding box to enclose by grid + // s number of cell centers on largest side (including 2*pad_count) + // pad_count number of cells beyond box + // Outputs: + // GV side(0)*side(1)*side(2) by 3 list of cell center positions + // side 1 by 3 list of dimension of voxel grid + template < + typename Scalar, + typename DerivedGV, + typename Derivedside> + IGL_INLINE void voxel_grid( + const Eigen::AlignedBox & box, + const int s, + const int pad_count, + Eigen::PlainObjectBase & GV, + Eigen::PlainObjectBase & side); + template < + typename DerivedV, + typename DerivedGV, + typename Derivedside> + IGL_INLINE void voxel_grid( + const Eigen::MatrixBase & V, + const typename DerivedV::Scalar offset, + const int s, + const int pad_count, + Eigen::PlainObjectBase & GV, + Eigen::PlainObjectBase & side); +} +#ifndef IGL_STATIC_LIBRARY +# include "voxel_grid.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/winding_number.cpp b/src/external/libigl-2.3.0/include/igl/winding_number.cpp new file mode 100644 index 000000000..6ce082361 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/winding_number.cpp @@ -0,0 +1,119 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "winding_number.h" +#include "WindingNumberAABB.h" +#include "signed_angle.h" +#include "parallel_for.h" +#include "solid_angle.h" +#include "PI.h" + +#include + +template < + typename DerivedV, + typename DerivedF, + typename DerivedO, + typename DerivedW> +IGL_INLINE void igl::winding_number( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const Eigen::MatrixBase & O, + Eigen::PlainObjectBase & W) +{ + using namespace Eigen; + // make room for output + W.resize(O.rows(),1); + switch(F.cols()) + { + case 2: + { + igl::parallel_for(O.rows(),[&](const int o) + { + W(o) = winding_number(V,F,O.row(o)); + },10000); + return; + } + case 3: + { + WindingNumberAABB< + Eigen::Matrix, + DerivedV, + DerivedF> + hier(V,F); + hier.grow(); + // loop over origins + igl::parallel_for(O.rows(),[&](const int o) + { + W(o) = hier.winding_number(O.row(o)); + },10000); + break; + } + default: assert(false && "Bad simplex size"); break; + } +} + +template < + typename DerivedV, + typename DerivedF, + typename Derivedp> +IGL_INLINE typename DerivedV::Scalar igl::winding_number( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const Eigen::MatrixBase & p) +{ + typedef typename DerivedV::Scalar wType; + const int ss = F.cols(); + const int m = F.rows(); + wType w = 0; + for(int f = 0;f, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template Eigen::Matrix::Scalar igl::winding_number, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&); +// generated by autoexplicit.sh +template Eigen::Matrix::Scalar igl::winding_number, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&); +// generated by autoexplicit.sh +template void igl::winding_number, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); +// generated by autoexplicit.sh +template Eigen::Matrix::Scalar igl::winding_number, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&); +// generated by autoexplicit.sh +template Eigen::Matrix::Scalar igl::winding_number, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&); +// generated by autoexplicit.sh +template Eigen::Matrix::Scalar igl::winding_number, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&); +// generated by autoexplicit.sh +template Eigen::Matrix::Scalar igl::winding_number, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&); +// generated by autoexplicit.sh +template Eigen::Matrix::Scalar igl::winding_number, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&); +// generated by autoexplicit.sh +template Eigen::Matrix::Scalar igl::winding_number, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&); +// generated by autoexplicit.sh +template Eigen::Matrix::Scalar igl::winding_number, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&); +// generated by autoexplicit.sh +template Eigen::Matrix::Scalar igl::winding_number, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/winding_number.h b/src/external/libigl-2.3.0/include/igl/winding_number.h new file mode 100644 index 000000000..4a1c51d81 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/winding_number.h @@ -0,0 +1,64 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_WINDING_NUMBER_H +#define IGL_WINDING_NUMBER_H +#include "igl_inline.h" +#include + +// Minimum number of iterms per openmp thread +#ifndef IGL_WINDING_NUMBER_OMP_MIN_VALUE +# define IGL_WINDING_NUMBER_OMP_MIN_VALUE 1000 +#endif +namespace igl +{ + // WINDING_NUMBER Compute the sum of solid angles of a triangle/tetrahedron + // described by points (vectors) V + // + // Templates: + // dim dimension of input + // Inputs: + // V n by 3 list of vertex positions + // F #F by 3 list of triangle indices, minimum index is 0 + // O no by 3 list of origin positions + // Outputs: + // S no by 1 list of winding numbers + // + template < + typename DerivedV, + typename DerivedF, + typename DerivedO, + typename DerivedW> + IGL_INLINE void winding_number( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const Eigen::MatrixBase & O, + Eigen::PlainObjectBase & W); + // Compute winding number of a single point + // + // Inputs: + // V n by dim list of vertex positions + // F #F by dim list of triangle indices, minimum index is 0 + // p single origin position + // Outputs: + // w winding number of this point + // + template < + typename DerivedV, + typename DerivedF, + typename Derivedp> + IGL_INLINE typename DerivedV::Scalar winding_number( + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const Eigen::MatrixBase & p); +} + +#ifndef IGL_STATIC_LIBRARY +# include "winding_number.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/writeBF.cpp b/src/external/libigl-2.3.0/include/igl/writeBF.cpp new file mode 100644 index 000000000..18dc6a934 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/writeBF.cpp @@ -0,0 +1,49 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "writeBF.h" +#include +#include +template < + typename DerivedWI, + typename DerivedP, + typename DerivedO> +IGL_INLINE bool igl::writeBF( + const std::string & filename, + const Eigen::PlainObjectBase & WI, + const Eigen::PlainObjectBase & P, + const Eigen::PlainObjectBase & O) +{ + using namespace Eigen; + using namespace std; + const int n = WI.rows(); + assert(n == WI.rows() && "WI must have n rows"); + assert(n == P.rows() && "P must have n rows"); + assert(n == O.rows() && "O must have n rows"); + MatrixXd WIPO(n,1+1+3); + for(int i = 0;i, Eigen::Matrix, Eigen::Matrix >(std::basic_string, std::allocator > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/writeBF.h b/src/external/libigl-2.3.0/include/igl/writeBF.h new file mode 100644 index 000000000..5ea51f1bc --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/writeBF.h @@ -0,0 +1,37 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_WRITEBF_H +#define IGL_WRITEBF_H +#include "igl_inline.h" +#include +#include +namespace igl +{ + // Write a bones forest to a file + // + // Input: + // file_name path to .bf bones tree file + // WI #B list of unique weight indices + // P #B list of parent indices into B, -1 for roots + // O #B list of tip offsets + // Returns true on success, false on errors + template < + typename DerivedWI, + typename DerivedP, + typename DerivedO> + IGL_INLINE bool writeBF( + const std::string & filename, + const Eigen::PlainObjectBase & WI, + const Eigen::PlainObjectBase & P, + const Eigen::PlainObjectBase & O); +} + +#ifndef IGL_STATIC_LIBRARY +# include "writeBF.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/writeDMAT.cpp b/src/external/libigl-2.3.0/include/igl/writeDMAT.cpp new file mode 100644 index 000000000..fa39855f9 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/writeDMAT.cpp @@ -0,0 +1,99 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "writeDMAT.h" +#include "list_to_matrix.h" +#include + +#include + +template +IGL_INLINE bool igl::writeDMAT( + const std::string file_name, + const Eigen::MatrixBase & W, + const bool ascii) +{ + FILE * fp = fopen(file_name.c_str(),"wb"); + if(fp == NULL) + { + fprintf(stderr,"IOError: writeDMAT() could not open %s...",file_name.c_str()); + return false; + } + if(ascii) + { + // first line contains number of rows and number of columns + fprintf(fp,"%d %d\n",(int)W.cols(),(int)W.rows()); + // Loop over columns slowly + for(int j = 0;j < W.cols();j++) + { + // loop over rows (down columns) quickly + for(int i = 0;i < W.rows();i++) + { + fprintf(fp,"%0.17lg\n",(double)W(i,j)); + } + } + }else + { + // write header for ascii + fprintf(fp,"0 0\n"); + // first line contains number of rows and number of columns + fprintf(fp,"%d %d\n",(int)W.cols(),(int)W.rows()); + // reader assumes the binary part is double precision + Eigen::MatrixXd Wd = W.template cast(); + fwrite(Wd.data(),sizeof(double),Wd.size(),fp); + //// Loop over columns slowly + //for(int j = 0;j < W.cols();j++) + //{ + // // loop over rows (down columns) quickly + // for(int i = 0;i < W.rows();i++) + // { + // double d = (double)W(i,j); + // fwrite(&d,sizeof(double),1,fp); + // } + //} + } + fclose(fp); + return true; +} + +template +IGL_INLINE bool igl::writeDMAT( + const std::string file_name, + const std::vector > & W, + const bool ascii) +{ + Eigen::Matrix mW; + list_to_matrix(W,mW); + return igl::writeDMAT(file_name,mW,ascii); +} + +template +IGL_INLINE bool igl::writeDMAT( + const std::string file_name, + const std::vector & W, + const bool ascii) +{ + Eigen::Matrix mW; + list_to_matrix(W,mW); + return igl::writeDMAT(file_name,mW,ascii); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +template bool igl::writeDMAT >(std::basic_string, std::allocator >, Eigen::MatrixBase > const&, bool); +template bool igl::writeDMAT >(std::basic_string, std::allocator >, Eigen::MatrixBase > const&, bool); +template bool igl::writeDMAT >(std::string, Eigen::MatrixBase > const&, bool); +template bool igl::writeDMAT >(std::basic_string, std::allocator >, Eigen::MatrixBase > const&, bool); +template bool igl::writeDMAT >(std::basic_string, std::allocator >, Eigen::MatrixBase > const&, bool); +template bool igl::writeDMAT >(std::basic_string, std::allocator >, Eigen::MatrixBase > const&, bool); +template bool igl::writeDMAT >(std::string, Eigen::MatrixBase > const&, bool); +template bool igl::writeDMAT >(std::basic_string, std::allocator >, Eigen::MatrixBase > const&, bool); +template bool igl::writeDMAT >(std::basic_string, std::allocator >, Eigen::MatrixBase > const&, bool); +template bool igl::writeDMAT >(std::basic_string, std::allocator >, Eigen::MatrixBase > const&, bool); +template bool igl::writeDMAT >(std::basic_string, std::allocator >, Eigen::MatrixBase > const&, bool); +template bool igl::writeDMAT >(std::basic_string, std::allocator >, Eigen::MatrixBase > const&, bool); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/writeDMAT.h b/src/external/libigl-2.3.0/include/igl/writeDMAT.h new file mode 100644 index 000000000..08409ef67 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/writeDMAT.h @@ -0,0 +1,48 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_WRITEDMAT_H +#define IGL_WRITEDMAT_H +#include "igl_inline.h" +// See writeDMAT.h for a description of the .dmat file type +#include +#include +#include +namespace igl +{ + // Write a matrix using ascii dmat file type + // + // Template: + // Mat matrix type that supports .rows(), .cols(), operator(i,j) + // Inputs: + // file_name path to .dmat file + // W eigen matrix containing to-be-written coefficients + // ascii write ascii file {true} + // Returns true on success, false on error + // + template + IGL_INLINE bool writeDMAT( + const std::string file_name, + const Eigen::MatrixBase & W, + const bool ascii=true); + template + IGL_INLINE bool writeDMAT( + const std::string file_name, + const std::vector > & W, + const bool ascii=true); + template + IGL_INLINE bool writeDMAT( + const std::string file_name, + const std::vector &W, + const bool ascii=true); +} + +#ifndef IGL_STATIC_LIBRARY +# include "writeDMAT.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/writeMESH.cpp b/src/external/libigl-2.3.0/include/igl/writeMESH.cpp new file mode 100644 index 000000000..6b2e929ef --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/writeMESH.cpp @@ -0,0 +1,152 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "writeMESH.h" + +#include "verbose.h" +#include "list_to_matrix.h" +#include + +#include +#include +#include + +template +IGL_INLINE bool igl::writeMESH( + const std::string mesh_file_name, + const std::vector > & V, + const std::vector > & T, + const std::vector > & F) +{ + Eigen::MatrixXd mV; + Eigen::MatrixXi mT,mF; + bool is_rect; + is_rect = list_to_matrix(V,mV); + if(!is_rect) + { + return false; + } + is_rect = list_to_matrix(T,mT); + if(!is_rect) + { + return false; + } + is_rect = list_to_matrix(F,mF); + if(!is_rect) + { + return false; + } + return igl::writeMESH(mesh_file_name,mV,mT,mF); +} + + +template +IGL_INLINE bool igl::writeMESH( + const std::string str, + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & T, + const Eigen::MatrixBase & F) +{ + using namespace std; + using namespace Eigen; + + //// This is (surprisingly) slower than the C-ish code below + //ofstream mesh_file; + //mesh_file.open(str.c_str()); + //if(!mesh_file.is_open()) + //{ + // cerr<<"IOError: "<, Eigen::Matrix, Eigen::Matrix >(std::basic_string, std::allocator >, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&); +// generated by autoexplicit.sh +template bool igl::writeMESH, Eigen::Matrix, Eigen::Matrix >(std::basic_string, std::allocator >, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&); +// generated by autoexplicit.sh +template bool igl::writeMESH, Eigen::Matrix, Eigen::Matrix >(std::basic_string, std::allocator >, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&); +// generated by autoexplicit.sh +template bool igl::writeMESH, Eigen::Matrix, Eigen::Matrix >(std::basic_string, std::allocator >, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&); +//template bool igl::writeMESH, Eigen::Matrix, Eigen::Matrix >(std::basic_string, std::allocator >, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&); +template bool igl::writeMESH, Eigen::Matrix, Eigen::Matrix >(std::basic_string, std::allocator >, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&); + +template bool igl::writeMESH, Eigen::Matrix, Eigen::Matrix >(std::basic_string, std::allocator >, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&); +template bool igl::writeMESH(std::basic_string, std::allocator >, std::vector >, std::allocator > > > const&, std::vector >, std::allocator > > > const&, std::vector >, std::allocator > > > const&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/writeMESH.h b/src/external/libigl-2.3.0/include/igl/writeMESH.h new file mode 100644 index 000000000..feae1f0ff --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/writeMESH.h @@ -0,0 +1,58 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_WRITEMESH_H +#define IGL_WRITEMESH_H +#include "igl_inline.h" + +#include +#include +#include + +namespace igl +{ + // save a tetrahedral volume mesh to a .mesh file + // + // Templates: + // Scalar type for positions and vectors (will be cast as double) + // Index type for indices (will be cast to int) + // Input: + // mesh_file_name path of .mesh file + // V double matrix of vertex positions #V by 3 + // T #T list of tet indices into vertex positions + // F #F list of face indices into vertex positions + // + // Known bugs: Holes and regions are not supported + template + IGL_INLINE bool writeMESH( + const std::string mesh_file_name, + const std::vector > & V, + const std::vector > & T, + const std::vector > & F); + + // Templates: + // DerivedV real-value: i.e. from MatrixXd + // DerivedT integer-value: i.e. from MatrixXi + // DerivedF integer-value: i.e. from MatrixXi + // Input: + // mesh_file_name path of .mesh file + // V eigen double matrix #V by 3 + // T eigen int matrix #T by 4 + // F eigen int matrix #F by 3 + template + IGL_INLINE bool writeMESH( + const std::string str, + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & T, + const Eigen::MatrixBase & F); +} + +#ifndef IGL_STATIC_LIBRARY +# include "writeMESH.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/writeMSH.cpp b/src/external/libigl-2.3.0/include/igl/writeMSH.cpp new file mode 100644 index 000000000..b0decc4bd --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/writeMSH.cpp @@ -0,0 +1,149 @@ +/* high level interface for MshSaver*/ + +/* Copyright (C) 2020 Vladimir Fonov */ +/* +/* This Source Code Form is subject to the terms of the Mozilla */ +/* Public License v. 2.0. If a copy of the MPL was not distributed */ +/* with this file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "writeMSH.h" +#include "MshSaver.h" +#include "MshLoader.h" +#include + + +namespace igl { +namespace internal { + + // helper function, appends contents of Eigen matrix to an std::vector, in RowMajor fashion + template + void append_mat_to_vec(std::vector &vec, const Eigen::PlainObjectBase & mat) + { + size_t st = vec.size(); + vec.resize(st + mat.size()); + + Eigen::Map< Eigen::Matrix > + _map_vec( reinterpret_cast( vec.data() + st ), mat.rows(), mat.cols() ); + _map_vec = mat; + } + +} +} + +IGL_INLINE bool igl::writeMSH( + const std::string &msh, + const Eigen::MatrixXd &X, + const Eigen::MatrixXi &Tri, + const Eigen::MatrixXi &Tet, + const Eigen::MatrixXi &TriTag, + const Eigen::MatrixXi &TetTag, + const std::vector &XFields, + const std::vector &XF, + const std::vector &EFields, + const std::vector &TriF, + const std::vector &TetF + ) +{ + using namespace internal; + + try + { + // error checks + if(!XFields.empty()) + { + if(XFields.size()!=XF.size()) + throw std::invalid_argument("Vertex field count mismatch"); + for(int i=0;i _X; + append_mat_to_vec(_X, X); + + std::vector _Tri_Tet; + append_mat_to_vec( _Tri_Tet, Tri); + append_mat_to_vec( _Tri_Tet, Tet); + + std::vector _Tri_Tet_len(Tri.rows(), 3); //each is 3 elements long + _Tri_Tet_len.insert(_Tri_Tet_len.end(), Tet.rows(), 4); + + std::vector _Tri_Tet_type(Tri.rows(), MshLoader::ELEMENT_TRI); + _Tri_Tet_type.insert(_Tri_Tet_type.end(), Tet.rows(), MshLoader::ELEMENT_TET); + + std::vector _Tri_Tet_tag; + append_mat_to_vec(_Tri_Tet_tag, TriTag); + append_mat_to_vec(_Tri_Tet_tag, TetTag); + + + igl::MshSaver msh_saver(msh, true); + msh_saver.save_mesh( _X, + _Tri_Tet, + _Tri_Tet_len, + _Tri_Tet_type, + _Tri_Tet_tag); + + // append vertex data + for(size_t i=0;i _XF; + append_mat_to_vec(_XF, XF[i]); + + if(XF[i].cols() == 1) + msh_saver.save_scalar_field(XFields[i], _XF ); + else if(XF[i].cols() == 3) + msh_saver.save_vector_field(XFields[i], _XF ); + else + { + throw std::invalid_argument("unsupported vertex field dimensionality"); + } + } + + // append node data + for(size_t i=0; i _EF; + append_mat_to_vec(_EF, TriF[i]); + append_mat_to_vec(_EF, TetF[i]); + + assert(_EF.size() == (TriF[i].size()+TetF[i].size())); + + if( TriF[i].cols() == 1 ) + msh_saver.save_elem_scalar_field(EFields[i], _EF ); + else if( TriF[i].cols() == 3 ) + msh_saver.save_elem_vector_field(EFields[i], _EF ); + else + { + throw std::invalid_argument("unsupported node field dimensionality"); + } + } + } catch(const std::exception& e) { + std::cerr << e.what() << std::endl; + return false; + } + return true; +} + diff --git a/src/external/libigl-2.3.0/include/igl/writeMSH.h b/src/external/libigl-2.3.0/include/igl/writeMSH.h new file mode 100644 index 000000000..6e4e05772 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/writeMSH.h @@ -0,0 +1,57 @@ +/* high level interface for MshSaver */ + +/* Copyright (C) 2020 Vladimir Fonov */ +/* +/* This Source Code Form is subject to the terms of the Mozilla */ +/* Public License v. 2.0. If a copy of the MPL was not distributed */ +/* with this file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef IGL_WRITE_MSH_H +#define IGL_WRITE_MSH_H +#include "igl_inline.h" + +#include +#include +#include + +namespace igl +{ + // write triangle surface mesh and tetrahedral volume mesh to .msh file + // Inputs: + // msh - file name + // X eigen double matrix of vertex positions #X by 3 + // Tri #Tri eigen integer matrix of triangular faces indices into vertex positions + // Tet #Tet eigen integer matrix of tetrahedral indices into vertex positions + // TriTag #Tri eigen integer vector of tags associated with surface faces + // TetTag #Tet eigen integer vector of tags associated with volume elements + // XFields #XFields list of strings with field names associated with nodes + // XF #XFields list of eigen double matrices, fields associated with nodes + // EFields #EFields list of strings with field names associated with elements + // TriF #EFields list of eigen double matrices, fields associated with surface elements + // TetF #EFields list of eigen double matrices, fields associated with volume elements + // Known bugs: + // files are always stored in binary format + // file format is 2.2 + // only triangle surface elements and tetrahedral volumetric elements are supported + // only 3D information is supported + // the tag id is duplicated for physical (0) and elementary (1) + // same element fields are expected to be associated with surface elements and volumetric elements + IGL_INLINE bool writeMSH(const std::string &msh, + const Eigen::MatrixXd &X, + const Eigen::MatrixXi &Tri, + const Eigen::MatrixXi &Tet, + const Eigen::MatrixXi &TriTag, + const Eigen::MatrixXi &TetTag, + const std::vector &XFields, + const std::vector &XF, + const std::vector &EFields, + const std::vector &TriF, + const std::vector &TetF + ); + +} + +#ifndef IGL_STATIC_LIBRARY +# include "writeMSH.cpp" +#endif + +#endif //IGL_WRITE_MSH_H \ No newline at end of file diff --git a/src/external/libigl-2.3.0/include/igl/writeOBJ.cpp b/src/external/libigl-2.3.0/include/igl/writeOBJ.cpp new file mode 100644 index 000000000..0848dbd4a --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/writeOBJ.cpp @@ -0,0 +1,169 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "writeOBJ.h" + +#include +#include +#include +#include +#include +#include + +template < + typename DerivedV, + typename DerivedF, + typename DerivedCN, + typename DerivedFN, + typename DerivedTC, + typename DerivedFTC> +IGL_INLINE bool igl::writeOBJ( + const std::string str, + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + const Eigen::MatrixBase& CN, + const Eigen::MatrixBase& FN, + const Eigen::MatrixBase& TC, + const Eigen::MatrixBase& FTC) +{ + FILE * obj_file = fopen(str.c_str(),"w"); + if(NULL==obj_file) + { + printf("IOError: %s could not be opened for writing...",str.c_str()); + return false; + } + // Loop over V + for(int i = 0;i<(int)V.rows();i++) + { + fprintf(obj_file,"v"); + for(int j = 0;j<(int)V.cols();++j) + { + fprintf(obj_file," %0.17g", V(i,j)); + } + fprintf(obj_file,"\n"); + } + bool write_N = CN.rows() >0; + + if(write_N) + { + for(int i = 0;i<(int)CN.rows();i++) + { + fprintf(obj_file,"vn %0.17g %0.17g %0.17g\n", + CN(i,0), + CN(i,1), + CN(i,2) + ); + } + fprintf(obj_file,"\n"); + } + + bool write_texture_coords = TC.rows() >0; + + if(write_texture_coords) + { + for(int i = 0;i<(int)TC.rows();i++) + { + fprintf(obj_file, "vt %0.17g %0.17g\n",TC(i,0),TC(i,1)); + } + fprintf(obj_file,"\n"); + } + + // loop over F + for(int i = 0;i<(int)F.rows();++i) + { + fprintf(obj_file,"f"); + for(int j = 0; j<(int)F.cols();++j) + { + // OBJ is 1-indexed + fprintf(obj_file," %u",F(i,j)+1); + + if(write_texture_coords) + fprintf(obj_file,"/%u",FTC(i,j)+1); + if(write_N) + { + if (write_texture_coords) + fprintf(obj_file,"/%u",FN(i,j)+1); + else + fprintf(obj_file,"//%u",FN(i,j)+1); + } + } + fprintf(obj_file,"\n"); + } + fclose(obj_file); + return true; +} + +template +IGL_INLINE bool igl::writeOBJ( + const std::string str, + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F) +{ + using namespace std; + using namespace Eigen; + assert(V.cols() == 3 && "V should have 3 columns"); + ofstream s(str); + if(!s.is_open()) + { + fprintf(stderr,"IOError: writeOBJ() could not open %s\n",str.c_str()); + return false; + } + s<< + V.format(IOFormat(FullPrecision,DontAlignCols," ","\n","v ","","","\n"))<< + (F.array()+1).format(IOFormat(FullPrecision,DontAlignCols," ","\n","f ","","","\n")); + return true; +} + +template +IGL_INLINE bool igl::writeOBJ( + const std::string &str, + const Eigen::MatrixBase& V, + const std::vector >& F) +{ + using namespace std; + using namespace Eigen; + assert(V.cols() == 3 && "V should have 3 columns"); + ofstream s(str); + if(!s.is_open()) + { + fprintf(stderr,"IOError: writeOBJ() could not open %s\n",str.c_str()); + return false; + } + s<, Eigen::Matrix >(std::basic_string, std::allocator >, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&); +// generated by autoexplicit.sh +template bool igl::writeOBJ, Eigen::Matrix >(std::basic_string, std::allocator >, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&); +// generated by autoexplicit.sh +template bool igl::writeOBJ, Eigen::Matrix >(std::basic_string, std::allocator >, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&); +// generated by autoexplicit.sh +template bool igl::writeOBJ, Eigen::Matrix >(std::basic_string, std::allocator >, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&); +template bool igl::writeOBJ, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(std::basic_string, std::allocator >, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&); +template bool igl::writeOBJ, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(std::basic_string, std::allocator >, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&); +template bool igl::writeOBJ, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(std::basic_string, std::allocator >, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&); +template bool igl::writeOBJ, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(std::basic_string, std::allocator >, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&); +template bool igl::writeOBJ, Eigen::Matrix >(std::basic_string, std::allocator >, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/writeOBJ.h b/src/external/libigl-2.3.0/include/igl/writeOBJ.h new file mode 100644 index 000000000..218661570 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/writeOBJ.h @@ -0,0 +1,72 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_WRITEOBJ_H +#define IGL_WRITEOBJ_H +#include "igl_inline.h" +// History: +// return type changed from void to bool Alec 20 Sept 2011 + +#include +#include +#include + +namespace igl +{ + // Write a mesh in an ascii obj file + // Inputs: + // str path to outputfile + // V #V by 3 mesh vertex positions + // F #F by 3|4 mesh indices into V + // CN #CN by 3 normal vectors + // FN #F by 3|4 corner normal indices into CN + // TC #TC by 2|3 texture coordinates + // FTC #F by 3|4 corner texture coord indices into TC + // Returns true on success, false on error + // + // Known issues: Horrifyingly, this does not have the same order of + // parameters as readOBJ. + template < + typename DerivedV, + typename DerivedF, + typename DerivedCN, + typename DerivedFN, + typename DerivedTC, + typename DerivedFTC> + IGL_INLINE bool writeOBJ( + const std::string str, + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + const Eigen::MatrixBase& CN, + const Eigen::MatrixBase& FN, + const Eigen::MatrixBase& TC, + const Eigen::MatrixBase& FTC); + template + IGL_INLINE bool writeOBJ( + const std::string str, + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F); + + // Write a mesh of mixed tris and quads to an ascii obj file + // Inputs: + // str path to outputfile + // V #V by 3 mesh vertex positions + // F #F std::vector of std::vector of size 3 or 4 mesh indices into V + // Returns true on success, false on error + template + IGL_INLINE bool writeOBJ( + const std::string &str, + const Eigen::MatrixBase& V, + const std::vector >& F); + +} + +#ifndef IGL_STATIC_LIBRARY +# include "writeOBJ.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/writeOFF.cpp b/src/external/libigl-2.3.0/include/igl/writeOFF.cpp new file mode 100644 index 000000000..c86508624 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/writeOFF.cpp @@ -0,0 +1,94 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "writeOFF.h" +#include +#include + +// write mesh to an ascii off file +template +IGL_INLINE bool igl::writeOFF( + const std::string fname, + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F) +{ + using namespace std; + using namespace Eigen; + assert(V.cols() == 3 && "V should have 3 columns"); + ofstream s(fname); + if(!s.is_open()) + { + fprintf(stderr,"IOError: writeOFF() could not open %s\n",fname.c_str()); + return false; + } + + s<< + "OFF\n"< +IGL_INLINE bool igl::writeOFF( + const std::string fname, + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + const Eigen::MatrixBase& C) +{ + using namespace std; + using namespace Eigen; + assert(V.cols() == 3 && "V should have 3 columns"); + assert(C.cols() == 3 && "C should have 3 columns"); + + if(V.rows() != C.rows()) + { + fprintf(stderr,"IOError: writeOFF() Only color per vertex supported. V and C should have same size.\n"); + return false; + } + + ofstream s(fname); + if(!s.is_open()) + { + fprintf(stderr,"IOError: writeOFF() could not open %s\n",fname.c_str()); + return false; + } + + //Check if RGB values are in the range [0..1] or [0..255] + int rgbScale = (C.maxCoeff() <= 1.0)?255:1; + // Use RGB_Array instead of RGB because of clash with mingw macro + // (https://github.com/libigl/libigl/pull/679) + Eigen::Matrix RGB_Array = rgbScale * C; + + s<< "COFF\n"<, Eigen::Matrix >(std::basic_string, std::allocator >, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&); +// generated by autoexplicit.sh +template bool igl::writeOFF, Eigen::Matrix >(std::basic_string, std::allocator >, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&); +// generated by autoexplicit.sh +template bool igl::writeOFF, Eigen::Matrix >(std::basic_string, std::allocator >, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&); +template bool igl::writeOFF, Eigen::Matrix >(std::basic_string, std::allocator >, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&); +template bool igl::writeOFF, Eigen::Matrix >(std::basic_string, std::allocator >, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&); +template bool igl::writeOFF, Eigen::Matrix >(std::basic_string, std::allocator >, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&); +template bool igl::writeOFF, Eigen::Matrix >(std::basic_string, std::allocator >, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&); +template bool igl::writeOFF, Eigen::Matrix >(std::basic_string, std::allocator >, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&); +template bool igl::writeOFF, Eigen::Matrix, Eigen::Matrix >(std::basic_string, std::allocator >, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&); +template bool igl::writeOFF, Eigen::Matrix, Eigen::Matrix >(std::basic_string, std::allocator >, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/writeOFF.h b/src/external/libigl-2.3.0/include/igl/writeOFF.h new file mode 100644 index 000000000..a7312373d --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/writeOFF.h @@ -0,0 +1,50 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_WRITEOFF_H +#define IGL_WRITEOFF_H +#include "igl_inline.h" + +#include +#include + +namespace igl +{ + //Export geometry and colors-by-vertex + // Export a mesh from an ascii OFF file, filling in vertex positions. + // Only triangle meshes are supported + // + // Templates: + // Scalar type for positions and vectors (will be read as double and cast + // to Scalar) + // Index type for indices (will be read as int and cast to Index) + // Inputs: + // str path to .off output file + // V #V by 3 mesh vertex positions + // F #F by 3 mesh indices into V + // C double matrix of rgb values per vertex #V by 3 + // Outputs: + // Returns true on success, false on errors + template + IGL_INLINE bool writeOFF( + const std::string str, + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + const Eigen::MatrixBase& C); + + template + IGL_INLINE bool writeOFF( + const std::string str, + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F); +} + +#ifndef IGL_STATIC_LIBRARY +# include "writeOFF.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/writePLY.cpp b/src/external/libigl-2.3.0/include/igl/writePLY.cpp new file mode 100644 index 000000000..fa08d65cf --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/writePLY.cpp @@ -0,0 +1,420 @@ +#include "writePLY.h" +#include + +#include "tinyply.h" + + +namespace igl +{ + template tinyply::Type tynyply_type(); + template <> tinyply::Type IGL_INLINE tynyply_type(){ return tinyply::Type::INT8; } + template <> tinyply::Type IGL_INLINE tynyply_type(){ return tinyply::Type::INT16; } + template <> tinyply::Type IGL_INLINE tynyply_type(){ return tinyply::Type::INT32; } + template <> tinyply::Type IGL_INLINE tynyply_type(){ return tinyply::Type::UINT8; } + template <> tinyply::Type IGL_INLINE tynyply_type(){ return tinyply::Type::UINT16; } + template <> tinyply::Type IGL_INLINE tynyply_type(){ return tinyply::Type::UINT32; } + template <> tinyply::Type IGL_INLINE tynyply_type(){ return tinyply::Type::FLOAT32; } + template <> tinyply::Type IGL_INLINE tynyply_type(){ return tinyply::Type::FLOAT64; } + + +template < + typename DerivedV, + typename DerivedF, + typename DerivedE, + typename DerivedN, + typename DerivedUV, + typename DerivedVD, + typename DerivedFD, + typename DerivedED +> +bool writePLY( + std::ostream & ply_stream, + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const Eigen::MatrixBase & E, + const Eigen::MatrixBase & N, + const Eigen::MatrixBase & UV, + + const Eigen::MatrixBase & VD, + const std::vector & VDheader, + + const Eigen::MatrixBase & FD, + const std::vector & FDheader, + + const Eigen::MatrixBase & ED, + const std::vector & EDheader, + + const std::vector & comments, + FileEncoding encoding + ) +{ + typedef typename DerivedV::Scalar VScalar; + typedef typename DerivedN::Scalar NScalar; + typedef typename DerivedUV::Scalar UVScalar; + typedef typename DerivedF::Scalar FScalar; + typedef typename DerivedE::Scalar EScalar; + + typedef typename DerivedVD::Scalar VDScalar; + typedef typename DerivedFD::Scalar FDScalar; + typedef typename DerivedED::Scalar EDScalar; + + // temporary storage for data to be passed to tinyply internals + std::vector _v; + std::vector _n; + std::vector _uv; + std::vector _vd; + std::vector _fd; + std::vector _ev; + std::vector _ed; + + // check dimensions + if( V.cols()!=3) + { + std::cerr << "writePLY: unexpected dimensions " << std::endl; + return false; + } + tinyply::PlyFile file; + + _v.resize(V.size()); + Eigen::Map< Eigen::Matrix >( &_v[0], V.rows(), V.cols() ) = V; + + file.add_properties_to_element("vertex", { "x", "y", "z" }, + tynyply_type(), V.rows(), reinterpret_cast( &_v[0] ), tinyply::Type::INVALID, 0); + + if(N.rows()>0) + { + _n.resize(N.size()); + Eigen::Map >( &_n[0], N.rows(), N.cols() ) = N; + file.add_properties_to_element("vertex", { "nx", "ny", "nz" }, + tynyply_type(), N.rows(), reinterpret_cast( &_n[0] ),tinyply::Type::INVALID, 0); + } + + if(UV.rows()>0) + { + _uv.resize(UV.size()); + Eigen::Map >( &_uv[0], UV.rows(), UV.cols() ) = UV; + + file.add_properties_to_element("vertex", { "u", "v" }, + tynyply_type(), UV.rows() , reinterpret_cast( &_uv[0] ), tinyply::Type::INVALID, 0); + } + + if(VD.cols()>0) + { + assert(VD.cols() == VDheader.size()); + assert(VD.rows() == V.rows()); + + _vd.resize(VD.size()); + Eigen::Map< Eigen::Matrix >( &_vd[0], VD.rows(), VD.cols() ) = VD; + + file.add_properties_to_element("vertex", VDheader, + tynyply_type(), VD.rows(), reinterpret_cast( &_vd[0] ), tinyply::Type::INVALID, 0); + } + + + + std::vector _f(F.size()); + Eigen::Map >( &_f[0], F.rows(), F.cols() ) = F; + file.add_properties_to_element("face", { "vertex_indices" }, + tynyply_type(), F.rows(), reinterpret_cast(&_f[0]), tinyply::Type::UINT8, F.cols() ); + + if(FD.cols()>0) + { + assert(FD.rows()==F.rows()); + assert(FD.cols() == FDheader.size()); + + _fd.resize(FD.size()); + Eigen::Map >( &_fd[0], FD.rows(), FD.cols() ) = FD; + + file.add_properties_to_element("face", FDheader, + tynyply_type(), FD.rows(), reinterpret_cast( &_fd[0] ), tinyply::Type::INVALID, 0); + } + + if(E.rows()>0) + { + assert(E.cols()==2); + _ev.resize(E.size()); + Eigen::Map >( &_ev[0], E.rows(), E.cols() ) = E; + + file.add_properties_to_element("edge", { "vertex1", "vertex2" }, + tynyply_type(), E.rows() , reinterpret_cast( &_ev[0] ), tinyply::Type::INVALID, 0); + } + + if(ED.cols()>0) + { + assert(ED.rows()==F.rows()); + assert(ED.cols() == EDheader.size()); + + _ed.resize(ED.size()); + Eigen::Map >( &_ed[0], ED.rows(), ED.cols() ) = ED; + + file.add_properties_to_element("edge", EDheader, + tynyply_type(), ED.rows(), reinterpret_cast( &_ed[0] ), tinyply::Type::INVALID, 0); + } + + for(auto a:comments) + file.get_comments().push_back(a); + + // Write a binary file + file.write(ply_stream, (encoding == FileEncoding::Binary)); + + return true; +} + +template < + typename DerivedV, + typename DerivedF, + typename DerivedE, + typename DerivedN, + typename DerivedUV, + typename DerivedVD, + typename DerivedFD, + typename DerivedED +> +bool writePLY( + const std::string & filename, + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const Eigen::MatrixBase & E, + const Eigen::MatrixBase & N, + const Eigen::MatrixBase & UV, + + const Eigen::MatrixBase & VD, + const std::vector & VDheader, + + const Eigen::MatrixBase & FD, + const std::vector & FDheader, + + const Eigen::MatrixBase & ED, + const std::vector & EDheader, + + const std::vector & comments, + FileEncoding encoding + ) +{ + try + { + if(encoding == FileEncoding::Binary) + { + std::filebuf fb_binary; + fb_binary.open(filename , std::ios::out | std::ios::binary); + std::ostream outstream_binary(&fb_binary); + if (outstream_binary.fail()) { + std::cerr << "writePLY: Error opening file " << filename << std::endl; + return false; //throw std::runtime_error("failed to open " + filename); + } + return writePLY(outstream_binary,V,F,E,N,UV,VD,VDheader,FD,FDheader,ED,EDheader,comments,encoding); + } else { + std::filebuf fb_ascii; + fb_ascii.open(filename, std::ios::out); + std::ostream outstream_ascii(&fb_ascii); + if (outstream_ascii.fail()) { + std::cerr << "writePLY: Error opening file " << filename << std::endl; + return false; //throw std::runtime_error("failed to open " + filename); + } + return writePLY(outstream_ascii,V,F,E,N,UV,VD,VDheader,FD,FDheader,ED,EDheader,comments,encoding); + } + } + catch(const std::exception& e) + { + std::cerr << "writePLY error: " << filename << e.what() << std::endl; + } + return false; +} + +template < + typename DerivedV, + typename DerivedF +> +bool writePLY( + const std::string & filename, + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F + ) +{ + Eigen::MatrixXd _dummy; + std::vector _dummy_header; + + return writePLY(filename,V,F,_dummy, _dummy, _dummy, _dummy, _dummy_header, _dummy, _dummy_header, _dummy, _dummy_header, _dummy_header, FileEncoding::Binary); +} + +template < + typename DerivedV, + typename DerivedF, + typename DerivedE +> +bool writePLY( + const std::string & filename, + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const Eigen::MatrixBase & E + ) +{ + Eigen::MatrixXd _dummy; + std::vector _dummy_header; + + return writePLY(filename,V,F,E, _dummy, _dummy, _dummy, _dummy_header, _dummy, _dummy_header, _dummy, _dummy_header, _dummy_header, FileEncoding::Binary); +} + + +template < + typename DerivedV, + typename DerivedF, + typename DerivedN, + typename DerivedUV +> +bool writePLY( + const std::string & filename, + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const Eigen::MatrixBase & N, + const Eigen::MatrixBase & UV + ) +{ + Eigen::MatrixXd _dummy; + std::vector _dummy_header; + + return writePLY(filename,V,F,_dummy, N,UV, _dummy, _dummy_header, _dummy, _dummy_header, _dummy, _dummy_header, _dummy_header, FileEncoding::Binary); +} + +template < + typename DerivedV, + typename DerivedF, + typename DerivedE, + typename DerivedN, + typename DerivedUV +> +bool writePLY( + const std::string & filename, + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const Eigen::MatrixBase & E, + const Eigen::MatrixBase & N, + const Eigen::MatrixBase & UV + ) +{ + Eigen::MatrixXd _dummy; + std::vector _dummy_header; + + return writePLY(filename,V,F,E, N,UV, _dummy, _dummy_header, _dummy, _dummy_header, _dummy, _dummy_header, _dummy_header, FileEncoding::Binary); +} + +template < + typename DerivedV, + typename DerivedF +> +bool writePLY( + const std::string & filename, + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + FileEncoding encoding + ) +{ + Eigen::MatrixXd _dummy(0,0); + std::vector _dummy_header; + + return writePLY(filename,V,F,_dummy, _dummy,_dummy, _dummy, _dummy_header, + _dummy, _dummy_header, _dummy, _dummy_header, _dummy_header, encoding); +} + +template < + typename DerivedV, + typename DerivedF, + typename DerivedE +> +bool writePLY( + const std::string & filename, + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const Eigen::MatrixBase & E, + FileEncoding encoding + ) +{ + Eigen::MatrixXd _dummy(0,0); + std::vector _dummy_header; + + return writePLY(filename,V,F,E, _dummy,_dummy, _dummy, _dummy_header, + _dummy, _dummy_header, _dummy, _dummy_header, _dummy_header, encoding); +} + + + + +template < + typename DerivedV, + typename DerivedF, + typename DerivedN, + typename DerivedUV, + typename DerivedVD +> +bool writePLY( + const std::string & filename, + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const Eigen::MatrixBase & N, + const Eigen::MatrixBase & UV, + const Eigen::MatrixBase & VD, + const std::vector & VDheader, + const std::vector & comments + ) +{ + Eigen::MatrixXd _dummy(0,0); + std::vector _dummy_header; + + return writePLY(filename,V,F,_dummy, N, UV, VD, VDheader, + _dummy, _dummy_header, _dummy, _dummy_header, comments, FileEncoding::Binary); +} + + + + +template < + typename DerivedV, + typename DerivedF, + typename DerivedE, + typename DerivedN, + typename DerivedUV, + typename DerivedVD +> +bool writePLY( + const std::string & filename, + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const Eigen::MatrixBase & E, + const Eigen::MatrixBase & N, + const Eigen::MatrixBase & UV, + const Eigen::MatrixBase & VD, + const std::vector & VDheader, + const std::vector & comments + ) +{ + Eigen::MatrixXd _dummy(0,0); + std::vector _dummy_header; + + return writePLY(filename,V,F,E, N, UV, VD, VDheader, + _dummy, _dummy_header, _dummy, _dummy_header, comments, FileEncoding::Binary); + +} + + + +} + + + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template bool igl::writePLY, Eigen::Matrix >(std::basic_string, std::allocator > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, igl::FileEncoding); +// generated by autoexplicit.sh +template bool igl::writePLY, Eigen::Matrix >(std::basic_string, std::allocator > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, igl::FileEncoding); +// generated by autoexplicit.sh +template bool igl::writePLY, Eigen::Matrix >(std::basic_string, std::allocator > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, igl::FileEncoding); +// generated by autoexplicit.sh +template bool igl::writePLY, Eigen::Matrix >(std::basic_string, std::allocator > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, igl::FileEncoding); +// generated by autoexplicit.sh +template bool igl::writePLY, Eigen::Matrix >(std::basic_string, std::allocator > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, igl::FileEncoding); +template bool igl::writePLY, Eigen::Matrix >(std::basic_string, std::allocator > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&); +template bool igl::writePLY, Eigen::Matrix >(std::basic_string, std::allocator > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&); +template bool igl::writePLY, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(std::basic_string, std::allocator > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, std::vector, std::allocator >, std::allocator, std::allocator > > > const&, Eigen::MatrixBase > const&, std::vector, std::allocator >, std::allocator, std::allocator > > > const&, Eigen::MatrixBase > const&, std::vector, std::allocator >, std::allocator, std::allocator > > > const&, std::vector, std::allocator >, std::allocator, std::allocator > > > const&, igl::FileEncoding); +template bool igl::writePLY, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(std::basic_string, std::allocator > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, std::vector, std::allocator >, std::allocator, std::allocator > > > const&, Eigen::MatrixBase > const&, std::vector, std::allocator >, std::allocator, std::allocator > > > const&, Eigen::MatrixBase > const&, std::vector, std::allocator >, std::allocator, std::allocator > > > const&, std::vector, std::allocator >, std::allocator, std::allocator > > > const&, igl::FileEncoding); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/writePLY.h b/src/external/libigl-2.3.0/include/igl/writePLY.h new file mode 100644 index 000000000..52a78fb4d --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/writePLY.h @@ -0,0 +1,240 @@ +#ifndef IGL_WRITEPLY_H +#define IGL_WRITEPLY_H +#include +#include + +#include +#include +#include +#include + + +namespace igl +{ + // write triangular mesh to ply file + // + // Templates: + // Derived from Eigen matrix parameters + // Inputs: + // ply_stream ply file output stream + // V (#V,3) matrix of vertex positions + // F (#F,3) list of face indices into vertex positions + // E (#E,2) list of edge indices into vertex positions + // N (#V,3) list of normals + // UV (#V,2) list of texture coordinates + // VD (#V,*) additional vertex data + // Vheader (#V) list of vertex data headers + // FD (#F,*) additional face data + // Fheader (#F) list of face data headers + // ED (#E,*) additional edge data + // Eheader (#E) list of edge data headers + // comments (*) file comments + // encoding - enum, to set binary or ascii file format + // Returns true on success, false on errors + template < + typename DerivedV, + typename DerivedF, + typename DerivedE, + typename DerivedN, + typename DerivedUV, + typename DerivedVD, + typename DerivedFD, + typename DerivedED +> +bool writePLY( + std::ostream & ply_stream, + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const Eigen::MatrixBase & E, + const Eigen::MatrixBase & N, + const Eigen::MatrixBase & UV, + + const Eigen::MatrixBase & VD, + const std::vector & VDheader, + + const Eigen::MatrixBase & FD, + const std::vector & FDheader, + + const Eigen::MatrixBase & ED, + const std::vector & EDheader, + + const std::vector & comments, + FileEncoding encoding + ); + + // write triangular mesh to ply file + // + // Templates: + // Derived from Eigen matrix parameters + // Inputs: + // filename ply file name + // V (#V,3) matrix of vertex positions + // F (#F,3) list of face indices into vertex positions + // E (#E,2) list of edge indices into vertex positions + // N (#V,3) list of normals + // UV (#V,2) list of texture coordinates + // VD (#V,*) additional vertex data + // Vheader (#V) list of vertex data headers + // FD (#F,*) additional face data + // Fheader (#F) list of face data headers + // ED (#E,*) additional edge data + // Eheader (#E) list of edge data headers + // comments (*) file comments + // encoding - enum, to set binary or ascii file format + // Returns true on success, false on errors +template < + typename DerivedV, + typename DerivedF, + typename DerivedE, + typename DerivedN, + typename DerivedUV, + typename DerivedVD, + typename DerivedFD, + typename DerivedED +> +bool writePLY( + const std::string & filename, + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const Eigen::MatrixBase & E, + const Eigen::MatrixBase & N, + const Eigen::MatrixBase & UV, + + const Eigen::MatrixBase & VD, + const std::vector & VDheader, + + const Eigen::MatrixBase & FD, + const std::vector & FDheader, + + const Eigen::MatrixBase & ED, + const std::vector & EDheader, + + const std::vector & comments, + FileEncoding encoding + ); + +template < + typename DerivedV, + typename DerivedF +> +bool writePLY( + const std::string & filename, + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F + ); + +template < + typename DerivedV, + typename DerivedF, + typename DerivedE +> +bool writePLY( + const std::string & filename, + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const Eigen::MatrixBase & E + ); + + +template < + typename DerivedV, + typename DerivedF, + typename DerivedN, + typename DerivedUV +> +bool writePLY( + const std::string & filename, + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const Eigen::MatrixBase & N, + const Eigen::MatrixBase & UV + ); + + +template < + typename DerivedV, + typename DerivedF, + typename DerivedE, + typename DerivedN, + typename DerivedUV +> +bool writePLY( + const std::string & filename, + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const Eigen::MatrixBase & E, + const Eigen::MatrixBase & N, + const Eigen::MatrixBase & UV + ); + + +template < + typename DerivedV, + typename DerivedF +> +bool writePLY( + const std::string & filename, + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + FileEncoding encoding + ); + +template < + typename DerivedV, + typename DerivedF, + typename DerivedE +> +bool writePLY( + const std::string & filename, + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const Eigen::MatrixBase & E, + FileEncoding encoding + ); + +template < + typename DerivedV, + typename DerivedF, + typename DerivedN, + typename DerivedUV, + typename DerivedVD +> +bool writePLY( + const std::string & filename, + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const Eigen::MatrixBase & N, + const Eigen::MatrixBase & UV, + const Eigen::MatrixBase & VD=Eigen::MatrixXd(0,0), + const std::vector & VDheader={}, + const std::vector & comments={} + ); + +template < + typename DerivedV, + typename DerivedF, + typename DerivedE, + typename DerivedN, + typename DerivedUV, + typename DerivedVD +> +bool writePLY( + const std::string & filename, + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const Eigen::MatrixBase & E, + const Eigen::MatrixBase & N, + const Eigen::MatrixBase & UV, + const Eigen::MatrixBase & VD=Eigen::MatrixXd(0,0), + const std::vector & VDheader={}, + const std::vector & comments={} + ); + +} + + + +#ifndef IGL_STATIC_LIBRARY +# include "writePLY.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/writeSTL.cpp b/src/external/libigl-2.3.0/include/igl/writeSTL.cpp new file mode 100644 index 000000000..720c92df8 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/writeSTL.cpp @@ -0,0 +1,123 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "writeSTL.h" +#include + +template +IGL_INLINE bool igl::writeSTL( + const std::string & filename, + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const Eigen::MatrixBase & N, + FileEncoding encoding) +{ + using namespace std; + assert(N.rows() == 0 || F.rows() == N.rows()); + if(encoding == FileEncoding::Ascii) + { + FILE * stl_file = fopen(filename.c_str(),"w"); + if(stl_file == NULL) + { + cerr<<"IOError: "<0) + { + fprintf(stl_file,"%e %e %e\n", + (float)N(f,0), + (float)N(f,1), + (float)N(f,2)); + }else + { + fprintf(stl_file,"0 0 0\n"); + } + fprintf(stl_file,"outer loop\n"); + for(int c = 0;c n(3,0); + if(N.rows() > 0) + { + n[0] = N(f,0); + n[1] = N(f,1); + n[2] = N(f,2); + } + fwrite(&n[0],sizeof(float),3,stl_file); + for(int c = 0;c<3;c++) + { + vector v(3); + v[0] = V(F(f,c),0); + v[1] = V(F(f,c),1); + v[2] = V(F(f,c),2); + fwrite(&v[0],sizeof(float),3,stl_file); + } + unsigned short att_count = 0; + fwrite(&att_count,sizeof(unsigned short),1,stl_file); + } + fclose(stl_file); + return true; + } +} + +template +IGL_INLINE bool igl::writeSTL( + const std::string & filename, + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + FileEncoding encoding) +{ + return writeSTL(filename,V,F, Eigen::Matrix(), encoding); +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template bool igl::writeSTL, Eigen::Matrix >(std::basic_string, std::allocator > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, igl::FileEncoding); +// generated by autoexplicit.sh +template bool igl::writeSTL, Eigen::Matrix >(std::basic_string, std::allocator > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, igl::FileEncoding); +// generated by autoexplicit.sh +template bool igl::writeSTL, Eigen::Matrix >(std::basic_string, std::allocator > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, igl::FileEncoding); +// generated by autoexplicit.sh +template bool igl::writeSTL, Eigen::Matrix >(std::basic_string, std::allocator > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, igl::FileEncoding); +template bool igl::writeSTL, Eigen::Matrix >(std::basic_string, std::allocator > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, igl::FileEncoding); +template bool igl::writeSTL, Eigen::Matrix >(std::basic_string, std::allocator > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, igl::FileEncoding); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/writeSTL.h b/src/external/libigl-2.3.0/include/igl/writeSTL.h new file mode 100644 index 000000000..6cf9896d2 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/writeSTL.h @@ -0,0 +1,53 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_WRITESTL_H +#define IGL_WRITESTL_H +#include "igl_inline.h" +#include + +#ifndef IGL_NO_EIGEN +# include +#endif +#include +#include + +namespace igl +{ + // Write a mesh to an stl file. + // + // Templates: + // Scalar type for positions and vectors (will be read as double and cast + // to Scalar) + // Inputs: + // filename path to .obj file + // V double matrix of vertex positions #F*3 by 3 + // F index matrix of triangle indices #F by 3 + // N double matrix of vertex positions #F by 3 + // encoding enum to set file encoding (ascii by default) + // Returns true on success, false on errors + // + template + IGL_INLINE bool writeSTL( + const std::string & filename, + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const Eigen::MatrixBase & N, + FileEncoding encoding=FileEncoding::Ascii); + template + IGL_INLINE bool writeSTL( + const std::string & filename, + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + FileEncoding encoding=FileEncoding::Ascii); +} + +#ifndef IGL_STATIC_LIBRARY +# include "writeSTL.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/writeTGF.cpp b/src/external/libigl-2.3.0/include/igl/writeTGF.cpp new file mode 100644 index 000000000..65c8fc6a4 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/writeTGF.cpp @@ -0,0 +1,73 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "writeTGF.h" +#include + +IGL_INLINE bool igl::writeTGF( + const std::string tgf_filename, + const std::vector > & C, + const std::vector > & E) +{ + FILE * tgf_file = fopen(tgf_filename.c_str(),"w"); + if(NULL==tgf_file) + { + printf("IOError: %s could not be opened\n",tgf_filename.c_str()); + return false; + } + // Loop over vertices + for(int i = 0; i<(int)C.size();i++) + { + assert(C[i].size() == 3); + // print a line with vertex number then "description" + // Where "description" in our case is the 3d position in space + // + fprintf(tgf_file, + "%4d " + "%10.17g %10.17g %10.17g " // current location + // All others are not needed for this legacy support + "\n", + i+1, + C[i][0], C[i][1], C[i][2]); + } + + // print a comment to separate vertices and edges + fprintf(tgf_file,"#\n"); + + // loop over edges + for(int i = 0;i<(int)E.size();i++) + { + assert(E[i].size()==2); + fprintf(tgf_file,"%4d %4d\n", + E[i][0]+1, + E[i][1]+1); + } + + // print a comment to separate edges and faces + fprintf(tgf_file,"#\n"); + + fclose(tgf_file); + + return true; +} + +#ifndef IGL_NO_EIGEN +#include "matrix_to_list.h" + +IGL_INLINE bool igl::writeTGF( + const std::string tgf_filename, + const Eigen::MatrixXd & C, + const Eigen::MatrixXi & E) +{ + using namespace std; + vector > vC; + vector > vE; + matrix_to_list(C,vC); + matrix_to_list(E,vE); + return writeTGF(tgf_filename,vC,vE); +} +#endif diff --git a/src/external/libigl-2.3.0/include/igl/writeTGF.h b/src/external/libigl-2.3.0/include/igl/writeTGF.h new file mode 100644 index 000000000..999584463 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/writeTGF.h @@ -0,0 +1,48 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_WRITETGF_H +#define IGL_WRITETGF_H +#include "igl_inline.h" + +#include +#include +#ifndef IGL_NO_EIGEN +#include +#endif + +namespace igl +{ + // WRITETGF + // + // Write a graph to a .tgf file + // + // Input: + // filename .tgf file name + // V # vertices by 3 list of vertex positions + // E # edges by 2 list of edge indices + // + // Assumes that graph vertices are 3 dimensional + IGL_INLINE bool writeTGF( + const std::string tgf_filename, + const std::vector > & C, + const std::vector > & E); + + #ifndef IGL_NO_EIGEN + IGL_INLINE bool writeTGF( + const std::string tgf_filename, + const Eigen::MatrixXd & C, + const Eigen::MatrixXi & E); + #endif +} + +#ifndef IGL_STATIC_LIBRARY +# include "writeTGF.cpp" +#endif + +#endif + diff --git a/src/external/libigl-2.3.0/include/igl/writeWRL.cpp b/src/external/libigl-2.3.0/include/igl/writeWRL.cpp new file mode 100644 index 000000000..76dfb9088 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/writeWRL.cpp @@ -0,0 +1,126 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "writeWRL.h" +#include +#include +template +IGL_INLINE bool igl::writeWRL( + const std::string & str, + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F) +{ + using namespace std; + using namespace Eigen; + assert(V.cols() == 3 && "V should have 3 columns"); + assert(F.cols() == 3 && "F should have 3 columns"); + ofstream s(str); + if(!s.is_open()) + { + cerr<<"IOError: writeWRL() could not open "< FF(F.rows(),4); + FF.leftCols(3) = F; + FF.col(3).setConstant(-1); + + s< +IGL_INLINE bool igl::writeWRL( + const std::string & str, + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const Eigen::MatrixBase & C) +{ + using namespace std; + using namespace Eigen; + assert(V.cols() == 3 && "V should have 3 columns"); + assert(F.cols() == 3 && "F should have 3 columns"); + ofstream s(str); + if(!s.is_open()) + { + cerr<<"IOError: writeWRL() could not open "< FF(F.rows(),4); + FF.leftCols(3) = F; + FF.col(3).setConstant(-1); + + + //Check if RGB values are in the range [0..1] or [0..255] + double rgbScale = (C.maxCoeff() <= 1.0)?1.0:1.0/255.0; + Eigen::MatrixXd RGB = rgbScale * C; + + s<, Eigen::Matrix >(std::basic_string, std::allocator > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&); +// generated by autoexplicit.sh +template bool igl::writeWRL, Eigen::Matrix >(std::basic_string, std::allocator > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&); +// generated by autoexplicit.sh +template bool igl::writeWRL, Eigen::Matrix >(std::basic_string, std::allocator > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&); +// generated by autoexplicit.sh +template bool igl::writeWRL, Eigen::Matrix >(std::basic_string, std::allocator > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&); +template bool igl::writeWRL, Eigen::Matrix >(std::basic_string, std::allocator > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&); +template bool igl::writeWRL, Eigen::Matrix, Eigen::Matrix >(std::basic_string, std::allocator > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/writeWRL.h b/src/external/libigl-2.3.0/include/igl/writeWRL.h new file mode 100644 index 000000000..3b01c277f --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/writeWRL.h @@ -0,0 +1,46 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2015 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_WRITE_WRL_H +#define IGL_WRITE_WRL_H +#include "igl_inline.h" +#include +#include +namespace igl +{ + // Write mesh to a .wrl file + // + // Inputs: + // str path to .wrl file + // V #V by 3 list of vertex positions + // F #F by 3 list of triangle indices + // Returns true iff succes + template + IGL_INLINE bool writeWRL( + const std::string & str, + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F); + + // Write mesh to a .wrl file + // + // Inputs: + // str path to .wrl file + // V #V by 3 list of vertex positions + // F #F by 3 list of triangle indices + // C double matrix of rgb values per vertex #V by 3 + // Returns true iff succes + template + IGL_INLINE bool writeWRL( + const std::string & str, + const Eigen::MatrixBase & V, + const Eigen::MatrixBase & F, + const Eigen::MatrixBase & C); +} +#ifndef IGL_STATIC_LIBRARY +#include "writeWRL.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/write_triangle_mesh.cpp b/src/external/libigl-2.3.0/include/igl/write_triangle_mesh.cpp new file mode 100644 index 000000000..d10a7dc13 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/write_triangle_mesh.cpp @@ -0,0 +1,70 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "write_triangle_mesh.h" +#include "pathinfo.h" +#include "writeMESH.h" +#include "writeOBJ.h" +#include "writeOFF.h" +#include "writePLY.h" +#include "writeSTL.h" +#include "writeWRL.h" + +#include + +template +IGL_INLINE bool igl::write_triangle_mesh( + const std::string str, + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + FileEncoding encoding) +{ + using namespace std; + // dirname, basename, extension and filename + string d,b,e,f; + pathinfo(str,d,b,e,f); + // Convert extension to lower case + std::transform(e.begin(), e.end(), e.begin(), ::tolower); + if(e == "mesh") + { + Eigen::MatrixXi _1; + return writeMESH(str,V,_1,F); + }else if(e == "obj") + { + return writeOBJ(str,V,F); + }else if(e == "off") + { + return writeOFF(str,V,F); + }else if(e == "ply") + { + return writePLY(str,V,F,encoding); + }else if(e == "stl") + { + return writeSTL(str,V,F,encoding); + }else if(e == "wrl") + { + return writeWRL(str,V,F); + }else + { + assert("Unsupported file format"); + cerr<<"Unsupported file format: ."<, Eigen::Matrix >(std::basic_string, std::allocator >, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, igl::FileEncoding); +// generated by autoexplicit.sh +template bool igl::write_triangle_mesh, Eigen::Matrix >(std::basic_string, std::allocator >, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, igl::FileEncoding); +// generated by autoexplicit.sh +template bool igl::write_triangle_mesh, Eigen::Matrix >(std::basic_string, std::allocator >, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, igl::FileEncoding); +// generated by autoexplicit.sh +template bool igl::write_triangle_mesh, Eigen::Matrix >(std::basic_string, std::allocator >, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, igl::FileEncoding); +template bool igl::write_triangle_mesh, Eigen::Matrix >(std::basic_string, std::allocator >, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, igl::FileEncoding); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/write_triangle_mesh.h b/src/external/libigl-2.3.0/include/igl/write_triangle_mesh.h new file mode 100644 index 000000000..e3ec6ee7a --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/write_triangle_mesh.h @@ -0,0 +1,43 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_WRITE_TRIANGLE_MESH_H +#define IGL_WRITE_TRIANGLE_MESH_H +#include "igl_inline.h" +#include + +#include +#include + +namespace igl +{ + // write mesh to a file with automatic detection of file format. supported: + // obj, off, stl, wrl, ply, mesh). + // + // Templates: + // Scalar type for positions and vectors (will be read as double and cast + // to Scalar) + // Index type for indices (will be read as int and cast to Index) + // Inputs: + // str path to file + // V eigen double matrix #V by 3 + // F eigen int matrix #F by 3 + // encoding set file encoding (ascii or binary) when both are available + // Returns true iff success + template + IGL_INLINE bool write_triangle_mesh( + const std::string str, + const Eigen::MatrixBase& V, + const Eigen::MatrixBase& F, + FileEncoding encoding = FileEncoding::Ascii); +} + +#ifndef IGL_STATIC_LIBRARY +# include "write_triangle_mesh.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/xml/ReAntTweakBarXMLSerialization.h b/src/external/libigl-2.3.0/include/igl/xml/ReAntTweakBarXMLSerialization.h new file mode 100644 index 000000000..c43af0c80 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/xml/ReAntTweakBarXMLSerialization.h @@ -0,0 +1,269 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2013 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_XML_REANTTWEAKBAR_XML_SERIALIZATION_H +#define IGL_XML_REANTTWEAKBAR_XML_SERIALIZATION_H +#include "../igl_inline.h" +#include "serialize_xml.h" + +#undef IGL_HEADER_ONLY +#include "../anttweakbar/ReAntTweakBar.h" + +// Forward declarations +namespace igl +{ + namespace anttweakbar + { + class ReTwBar; + } +}; +namespace tinyxml2 +{ + class XMLDocument; +}; + +namespace igl +{ + namespace xml + { + +// namespace +// { + +// IGL_INLINE bool save_ReAntTweakBar(::igl::anttweakbar::ReTwBar* bar, const char* file_name); +// IGL_INLINE bool save_ReAntTweakBar(::igl::anttweakbar::ReTwBar* bar, tinyxml2::XMLDocument* doc); +// IGL_INLINE bool load_ReAntTweakBar(::igl::anttweakbar::ReTwBar* bar, const char *file_name); +// IGL_INLINE bool load_ReAntTweakBar(::igl::anttweakbar::ReTwBar* bar, tinyxml2::XMLDocument* doc); + + + IGL_INLINE bool save_ReAntTweakBar(::igl::anttweakbar::ReTwBar* bar, const char* file_name) + { + const char * name_chars = TwGetBarName(bar->bar); + std::string name = std::string(name_chars) + "_AntTweakBar"; + + const std::vector< ::igl::anttweakbar::ReTwRWItem>& rw_items = bar->get_rw_items(); + for(std::vector< ::igl::anttweakbar::ReTwRWItem>::const_iterator it = rw_items.begin(); it != rw_items.end(); it++) + { + std::string val = bar->get_value_as_string(it->var,it->type); + //::igl::XMLSerializer::SaveObject(val,it->name,name,file_name,false); + ::igl::serialize_xml(val,it->name,file_name,false,false); + } + + char var[REANTTWEAKBAR_MAX_CB_VAR_SIZE]; + // Print all CB variables + const std::vector< ::igl::anttweakbar::ReTwCBItem>& cb_items = bar->get_cb_items(); + for(std::vector< ::igl::anttweakbar::ReTwCBItem>::const_iterator it = cb_items.begin(); it != cb_items.end(); it++) + { + TwType type = it->type; + //TwSetVarCallback setCallback = it->setCallback; + TwGetVarCallback getCallback = it->getCallback; + void * clientData = it->clientData; + // I'm not sure how to do what I want to do. getCallback needs to be sure + // that it can write to var. So var needs to point to a valid and big + // enough chunk of memory + getCallback(var,clientData); + + std::string val = bar->get_value_as_string(var,type); + //::igl::XMLSerializer::SaveObject(val,it->name,name,file_name,false); + ::igl::serialize_xml(val,it->name,file_name,false,false); + } + + return true; + } + + /*IGL_INLINE bool save_ReAntTweakBar(::igl::anttweakbar::ReTwBar* bar, tinyxml2::XMLDocument* doc) + { + std::vector buffer; + + const char * name_chars = TwGetBarName(bar->bar); + std::string name = std::string(name_chars) + "_AntTweakBar"; + ::igl::XMLSerializer* s = new ::igl::XMLSerializer(name); + + const std::vector< ::igl::anttweakbar::ReTwRWItem>& rw_items = bar->get_rw_items(); + for(std::vector< ::igl::anttweakbar::ReTwRWItem>::const_iterator it = rw_items.begin(); it != rw_items.end(); it++) + { + std::string val = bar->get_value_as_string(it->var,it->type); + char** cval = new char*; // create char* on heap + *cval = new char[val.size()+1]; + buffer.push_back(cval); + strcpy(*cval,val.c_str()); + s->Add(*cval,it->name); + } + + char var[REANTTWEAKBAR_MAX_CB_VAR_SIZE]; + // Print all CB variables + const std::vector< ::igl::anttweakbar::ReTwCBItem>& cb_items = bar->get_cb_items(); + for(std::vector< ::igl::anttweakbar::ReTwCBItem>::const_iterator it = cb_items.begin(); it != cb_items.end(); it++) + { + TwType type = it->type; + //TwSetVarCallback setCallback = it->setCallback; + TwGetVarCallback getCallback = it->getCallback; + void * clientData = it->clientData; + // I'm not sure how to do what I want to do. getCallback needs to be sure + // that it can write to var. So var needs to point to a valid and big + // enough chunk of memory + getCallback(var,clientData); + + std::string val = bar->get_value_as_string(var,type); + char** cval = new char*; // create char* on heap + *cval = new char[val.size()+1]; + buffer.push_back(cval); + strcpy(*cval,val.c_str()); + s->Add(*cval,it->name); + } + + s->SaveToXMLDoc(name,doc); + + // delete pointer buffers + for(unsigned int i=0;ibar); + std::string name = std::string(name_chars) + "_AntTweakBar"; + + const std::vector< ::igl::anttweakbar::ReTwRWItem>& rw_items = bar->get_rw_items(); + for(std::vector< ::igl::anttweakbar::ReTwRWItem>::const_iterator it = rw_items.begin(); it != rw_items.end(); it++) + { + char* val; + //::igl::XMLSerializer::LoadObject(val,it->name,name,file_name); + ::igl::deserialize_xml(val,it->name,file_name); + sscanf(val,"%s %[^\n]",type_str,value_str); + + if(!bar->type_from_string(type_str,type)) + { + printf("ERROR: %s type not found... Skipping...\n",type_str); + continue; + } + + bar->set_value_from_string(it->name.c_str(),type,value_str); + delete[] val; + } + + const std::vector< ::igl::anttweakbar::ReTwCBItem>& cb_items = bar->get_cb_items(); + for(std::vector< ::igl::anttweakbar::ReTwCBItem>::const_iterator it = cb_items.begin(); it != cb_items.end(); it++) + { + char* val; + //::igl::XMLSerializer::LoadObject(val,it->name,name,file_name); + ::igl::deserialize_xml(val,it->name,file_name); + sscanf(val,"%s %[^\n]",type_str,value_str); + + if(!bar->type_from_string(type_str,type)) + { + printf("ERROR: %s type not found... Skipping...\n",type_str); + continue; + } + + bar->set_value_from_string(it->name.c_str(),type,value_str); + delete[] val; + } + + return true; + } + + /*IGL_INLINE bool load_ReAntTweakBar(::igl::anttweakbar::ReTwBar* bar, tinyxml2::XMLDocument* doc) + { + std::map variables; + std::map cbVariables; + + const char * name_chars = TwGetBarName(bar->bar); + std::string name = std::string(name_chars) + "_AntTweakBar"; + ::igl::XMLSerializer* s = new ::igl::XMLSerializer(name); + + std::map::iterator iter; + const std::vector< ::igl::anttweakbar::ReTwRWItem>& rw_items = bar->get_rw_items(); + for(std::vector< ::igl::anttweakbar::ReTwRWItem>::const_iterator it = rw_items.begin(); it != rw_items.end(); it++) + { + variables[it->name] = NULL; + iter = variables.find(it->name); + s->Add(iter->second,iter->first); + } + + // Add all CB variables + const std::vector< ::igl::anttweakbar::ReTwCBItem>& cb_items = bar->get_cb_items(); + for(std::vector< ::igl::anttweakbar::ReTwCBItem>::const_iterator it = cb_items.begin(); it != cb_items.end(); it++) + { + cbVariables[it->name] = NULL; + iter = cbVariables.find(it->name); + s->Add(iter->second,iter->first); + } + + s->LoadFromXMLDoc(doc); + + // Set loaded values + char type_str[REANTTWEAKBAR_MAX_WORD]; + char value_str[REANTTWEAKBAR_MAX_WORD]; + TwType type; + + for(iter = variables.begin(); iter != variables.end(); iter++) + { + if(iter->second == NULL) + { + printf("ERROR: '%s' entry not found... Skipping...\n",iter->first.c_str()); + continue; + } + + sscanf(iter->second,"%s %[^\n]",type_str,value_str); + + if(!bar->type_from_string(type_str,type)) + { + printf("ERROR: Type '%s' of '%s' not found... Skipping...\n",type_str,iter->first.c_str()); + continue; + } + + bar->set_value_from_string(iter->first.c_str(),type,value_str); + } + + for(iter = cbVariables.begin(); iter != cbVariables.end(); iter++) + { + if(iter->second == NULL) + { + printf("ERROR: '%s' entry not found... Skipping...\n",iter->first.c_str()); + continue; + } + + sscanf(iter->second,"%s %[^\n]",type_str,value_str); + + if(!bar->type_from_string(type_str,type)) + { + printf("ERROR: Type '%s' of '%s' not found... Skipping...\n",type_str,iter->first.c_str()); + continue; + } + + bar->set_value_from_string(iter->first.c_str(),type,value_str); + } + + // delete buffers + for(iter = variables.begin(); iter != variables.end(); iter++) + delete[] iter->second; + + for(iter = cbVariables.begin(); iter != cbVariables.end(); iter++) + delete[] iter->second; + + delete s; + + return true; + }*/ + +// } + } +} + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/xml/XMLSerializable.h b/src/external/libigl-2.3.0/include/igl/xml/XMLSerializable.h new file mode 100644 index 000000000..610559643 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/xml/XMLSerializable.h @@ -0,0 +1,225 @@ +#ifndef IGL_XML_XMLSERIALIZABLE_H +#define IGL_XML_XMLSERIALIZABLE_H + +#include "serialize_xml.h" +#include "../igl_inline.h" +#include "../serialize.h" + +#include + + +// Interface for xml-serializable class see serialize_xml.h + +// Pretty sure all of these IGL_INLINE should be inline + +namespace igl +{ + namespace xml + { + // interface for user defined types + struct XMLSerializableBase : public SerializableBase + { + virtual void Serialize(std::vector& buffer) const = 0; + virtual void Deserialize(const std::vector& buffer) = 0; + virtual void Serialize(tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element) const = 0; + virtual void Deserialize(const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element) = 0; + }; + + // Convenient interface for user defined types + class XMLSerializable: public XMLSerializableBase + { + private: + + template + struct XMLSerializationObject: public XMLSerializableBase + { + bool Binary; + std::string Name; + T* Object; + + void Serialize(std::vector& buffer) const { + serialize(*Object,Name,buffer); + } + + void Deserialize(const std::vector& buffer) { + deserialize(*Object,Name,buffer); + } + + void Serialize(tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element) const { + serialize_xml(*Object,Name,doc,element,Binary); + } + + void Deserialize(const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element) { + deserialize_xml(*Object,Name,doc,element); + } + }; + + mutable bool initialized; + mutable std::vector objects; + + public: + + // Override this function to add your member variables which should be serialized + IGL_INLINE virtual void InitSerialization() = 0; + + // Following functions can be overridden to handle the specific events. + // Return false to prevent the de-/serialization of an object. + IGL_INLINE virtual bool PreSerialization() const; + IGL_INLINE virtual void PostSerialization() const; + IGL_INLINE virtual bool PreDeserialization(); + IGL_INLINE virtual void PostDeserialization(); + + // Default implementation of XMLSerializableBase interface + IGL_INLINE void Serialize(std::vector& buffer) const; + IGL_INLINE void Deserialize(const std::vector& buffer); + IGL_INLINE void Serialize(tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element) const; + IGL_INLINE void Deserialize(const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element); + + // Default constructor, destructor, assignment and copy constructor + IGL_INLINE XMLSerializable(); + IGL_INLINE XMLSerializable(const XMLSerializable& obj); + IGL_INLINE ~XMLSerializable(); + IGL_INLINE XMLSerializable& operator=(const XMLSerializable& obj); + + // Use this function to add your variables which should be serialized + template + IGL_INLINE void Add(T& obj,std::string name,bool binary = false); + }; + + // IMPLEMENTATION + + IGL_INLINE bool XMLSerializable::PreSerialization() const + { + return true; + } + + IGL_INLINE void XMLSerializable::PostSerialization() const + { + } + + IGL_INLINE bool XMLSerializable::PreDeserialization() + { + return true; + } + + IGL_INLINE void XMLSerializable::PostDeserialization() + { + } + + IGL_INLINE void XMLSerializable::Serialize(std::vector& buffer) const + { + if(this->PreSerialization()) + { + if(initialized == false) + { + objects.clear(); + (const_cast(this))->InitSerialization(); + initialized = true; + } + + for(unsigned int i=0;iSerialize(buffer); + + this->PostSerialization(); + } + } + + IGL_INLINE void XMLSerializable::Deserialize(const std::vector& buffer) + { + if(this->PreDeserialization()) + { + if(initialized == false) + { + objects.clear(); + (const_cast(this))->InitSerialization(); + initialized = true; + } + + for(unsigned int i=0;iDeserialize(buffer); + + this->PostDeserialization(); + } + } + + IGL_INLINE void XMLSerializable::Serialize(tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element) const + { + if(this->PreSerialization()) + { + if(initialized == false) + { + objects.clear(); + (const_cast(this))->InitSerialization(); + initialized = true; + } + + for(unsigned int i=0;iSerialize(doc,element); + + this->PostSerialization(); + } + } + + IGL_INLINE void XMLSerializable::Deserialize(const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element) + { + if(this->PreDeserialization()) + { + if(initialized == false) + { + objects.clear(); + (const_cast(this))->InitSerialization(); + initialized = true; + } + + for(unsigned int i=0;iDeserialize(doc,element); + + this->PostDeserialization(); + } + } + + IGL_INLINE XMLSerializable::XMLSerializable() + { + initialized = false; + } + + IGL_INLINE XMLSerializable::XMLSerializable(const XMLSerializable& obj) + { + initialized = false; + objects.clear(); + } + + IGL_INLINE XMLSerializable::~XMLSerializable() + { + initialized = false; + objects.clear(); + } + + + IGL_INLINE XMLSerializable& XMLSerializable::operator=(const XMLSerializable& obj) + { + if(this != &obj) + { + if(initialized) + { + initialized = false; + objects.clear(); + } + } + return *this; + } + + template + IGL_INLINE void XMLSerializable::Add(T& obj,std::string name,bool binary) + { + XMLSerializationObject* object = new XMLSerializationObject(); + object->Binary = binary; + object->Name = name; + object->Object = &obj; + + objects.push_back(object); + } + + } +} +#endif diff --git a/src/external/libigl-2.3.0/include/igl/xml/serialization_test.skip b/src/external/libigl-2.3.0/include/igl/xml/serialization_test.skip new file mode 100644 index 000000000..5888075c4 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/xml/serialization_test.skip @@ -0,0 +1,489 @@ +// +// Copyright (C) 2014 Christian Schüller +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +//#ifndef IGL_SERIALIZATION_TEST_H +//#define IGL_SERIALIZATION_TEST_H + +//#include +#include "serialize_xml.h" +#include "XMLSerializable.h" + +namespace igl +{ + namespace xml + { + + struct Test1111 + { + }; + + struct Test1 : public XMLSerializable + { + std::string ts; + std::vector tvt; + Test1* tt; + + Test1() + { + tt = NULL; + } + + void InitSerialization() + { + Add(ts,"ts",false); + Add(tvt,"tvt"); + Add(tt,"tt"); + } + }; + + struct Test2: public XMLSerializableBase + { + char tc; + int* ti; + std::vector tvb; + float tf; + + Test2() + { + tc = '1'; + ti = NULL; + tf = 1.0004; + tvb.push_back(2); + tvb.push_back(3); + } + + void Serialize(tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element) const + { + serialize_xml(tc,"tc",doc,element); + serialize_xml(ti,"ti",doc,element); + serialize_xml(tvb,"tvb",doc,element); + } + void Deserialize(const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element) + { + deserialize_xml(tc,"tc",doc,element); + deserialize_xml(ti,"ti",doc,element); + deserialize_xml(tvb,"tvb",doc,element); + } + void Serialize(std::vector& buffer) const + { + serialize(tc,"tc",buffer); + serialize(ti,"ti",buffer); + serialize(tvb,"tvb",buffer); + serialize(tf,"tf",buffer); + } + void Deserialize(const std::vector& buffer) + { + deserialize(tc,"tc",buffer); + deserialize(ti,"ti",buffer); + deserialize(tvb,"tvb",buffer); + deserialize(tf,"tf",buffer); + } + }; + + void serialization_test() + { + std::string file("test"); + + bool tbIn = true,tbOut; + char tcIn = 't',tcOut; + unsigned char tucIn = 'u',tucOut; + short tsIn = 6,tsOut; + int tiIn = -10,tiOut; + unsigned int tuiIn = 10,tuiOut; + float tfIn = 1.0005,tfOut; + double tdIn = 1.000000005,tdOut; + + int* tinpIn = NULL,*tinpOut = NULL; + float* tfpIn = new float,*tfpOut = NULL; + *tfpIn = 1.11101; + + std::string tstrIn("test12345"),tstrOut; + + Test2 tObjIn,tObjOut; + int ti = 2; + tObjIn.ti = &ti; + + + Test1 test1,test2,test3; + test1.ts = "100"; + test2.ts = "200"; + test3.ts = "300"; + + Test1 testA, testC; + testA.tt = &test1; + testA.ts = "test123"; + testA.tvt.push_back(&test2); + testA.tvt.push_back(&test3); + + Test1 testB = testA; + testB.ts = "400"; + testB.tvt.pop_back(); + + std::pair tPairIn(10,true); + std::pair tPairOut; + + std::vector tVector1In ={1,2,3,4,5}; + std::vector tVector1Out; + + std::pair p1(10,1); + std::pair p2(1,0); + std::pair p3(10000,1); + std::vector > tVector2In ={p1,p2,p3}; + std::vector > tVector2Out; + + std::set > tSetIn ={p1,p2,p3}; + std::set > tSetOut; + + std::map tMapIn ={p1,p2,p3}; + std::map tMapOut; + + Eigen::Matrix tDenseMatrixIn; + tDenseMatrixIn << Eigen::Matrix::Random(); + tDenseMatrixIn.coeffRef(0,0) = 1.00001; + Eigen::Matrix tDenseMatrixOut; + + Eigen::Matrix tDenseRowMatrixIn; + tDenseRowMatrixIn << Eigen::Matrix::Random(); + Eigen::Matrix tDenseRowMatrixOut; + + Eigen::SparseMatrix tSparseMatrixIn; + tSparseMatrixIn.resize(3,3); + tSparseMatrixIn.insert(0,0) = 1.3; + tSparseMatrixIn.insert(1,1) = 10.2; + tSparseMatrixIn.insert(2,2) = 100.1; + tSparseMatrixIn.finalize(); + Eigen::SparseMatrix tSparseMatrixOut; + + // binary serialization + + serialize(tbIn,file); + deserialize(tbOut,file); + assert(tbIn == tbOut); + + serialize(tcIn,file); + deserialize(tcOut,file); + assert(tcIn == tcOut); + + serialize(tucIn,file); + deserialize(tucOut,file); + assert(tucIn == tucOut); + + serialize(tsIn,file); + deserialize(tsOut,file); + assert(tsIn == tsOut); + + serialize(tiIn,file); + deserialize(tiOut,file); + assert(tiIn == tiOut); + + serialize(tuiIn,file); + deserialize(tuiOut,file); + assert(tuiIn == tuiOut); + + serialize(tfIn,file); + deserialize(tfOut,file); + assert(tfIn == tfOut); + + serialize(tdIn,file); + deserialize(tdOut,file); + assert(tdIn == tdOut); + + serialize(tinpIn,file); + deserialize(tinpOut,file); + assert(tinpIn == tinpOut); + + serialize(tfpIn,file); + deserialize(tfpOut,file); + assert(*tfpIn == *tfpOut); + tfpOut = NULL; + + serialize(tstrIn,file); + deserialize(tstrOut,file); + assert(tstrIn == tstrOut); + + // updating + serialize(tbIn,"tb",file,true); + serialize(tcIn,"tc",file); + serialize(tiIn,"ti",file); + tiIn++; + serialize(tiIn,"ti",file); + tiIn++; + serialize(tiIn,"ti",file); + deserialize(tbOut,"tb",file); + deserialize(tcOut,"tc",file); + deserialize(tiOut,"ti",file); + assert(tbIn == tbOut); + assert(tcIn == tcOut); + assert(tiIn == tiOut); + + serialize(tsIn,"tsIn",file,true); + serialize(tVector1In,"tVector1In",file); + serialize(tVector2In,"tsIn",file); + deserialize(tVector2Out,"tsIn",file); + for(unsigned int i=0;its == testC.tvt[i]->ts); + assert(testB.tvt[i]->tvt.size() == testC.tvt[i]->tvt.size()); + assert(testB.tvt[i]->tt == testC.tvt[i]->tt); + } + assert(testB.tt->ts == testC.tt->ts); + assert(testB.tt->tvt.size() == testC.tt->tvt.size()); + assert(testB.tt->tt == testC.tt->tt); + testC = Test1(); + + // big data test + /*std::vector > bigDataIn,bigDataOut; + for(unsigned int i=0;i<10000;i++) + { + std::vector v; + for(unsigned int j=0;j<10000;j++) + { + v.push_back(j); + } + bigDataIn.push_back(v); + } + + Timer timer; + timer.start(); + serialize(bigDataIn,file); + timer.stop(); + std::cout << "ser: " << timer.getElapsedTimeInMilliSec() << std::endl; + + timer.start(); + deserialize(bigDataOut,file); + timer.stop(); + std::cout << "des: " << timer.getElapsedTimeInMilliSec() << std::endl; + char c; + std::cin >> c; */ + + // xml serialization + + serialize_xml(tbIn,file); + deserialize_xml(tbOut,file); + assert(tbIn == tbOut); + + serialize_xml(tcIn,file); + deserialize_xml(tcOut,file); + assert(tcIn == tcOut); + + serialize_xml(tucIn,file); + deserialize_xml(tucOut,file); + assert(tucIn == tucOut); + + serialize_xml(tsIn,file); + deserialize_xml(tsOut,file); + assert(tsIn == tsOut); + + serialize_xml(tiIn,file); + deserialize_xml(tiOut,file); + assert(tiIn == tiOut); + + serialize_xml(tuiIn,file); + deserialize_xml(tuiOut,file); + assert(tuiIn == tuiOut); + + serialize_xml(tfIn,file); + deserialize_xml(tfOut,file); + assert(tfIn == tfOut); + + serialize_xml(tdIn,file); + deserialize_xml(tdOut,file); + assert(tdIn == tdOut); + + serialize_xml(tinpIn,file); + deserialize_xml(tinpOut,file); + assert(tinpIn == tinpOut); + + serialize_xml(tfpIn,file); + deserialize_xml(tfpOut,file); + assert(*tfpIn == *tfpOut); + + serialize_xml(tstrIn,file); + deserialize_xml(tstrOut,file); + assert(tstrIn == tstrOut); + + // updating + serialize_xml(tbIn,"tb",file,false,true); + serialize_xml(tcIn,"tc",file); + serialize_xml(tiIn,"ti",file); + tiIn++; + serialize_xml(tiIn,"ti",file); + tiIn++; + serialize_xml(tiIn,"ti",file); + deserialize_xml(tbOut,"tb",file); + deserialize_xml(tcOut,"tc",file); + deserialize_xml(tiOut,"ti",file); + assert(tbIn == tbOut); + assert(tcIn == tcOut); + assert(tiIn == tiOut); + + serialize_xml(tsIn,"tsIn",file,false,true); + serialize_xml(tVector1In,"tVector1In",file); + serialize_xml(tVector2In,"tsIn",file); + deserialize_xml(tVector2Out,"tsIn",file); + for(unsigned int i=0;its == testC.tvt[i]->ts); + assert(testB.tvt[i]->tvt.size() == testC.tvt[i]->tvt.size()); + assert(testB.tvt[i]->tt == testC.tvt[i]->tt); + } + assert(testB.tt->ts == testC.tt->ts); + assert(testB.tt->tvt.size() == testC.tt->tvt.size()); + assert(testB.tt->tt == testC.tt->tt); + + // big data test + /*std::vector > bigDataIn,bigDataOut; + for(unsigned int i=0;i<10000;i++) + { + std::vector v; + for(unsigned int j=0;j<10000;j++) + { + v.push_back(j); + } + bigDataIn.push_back(v); + } + + Timer timer; + timer.start(); + serialize_xml(bigDataIn,"bigDataIn",file,seRIALIZE_BINARY); + timer.stop(); + std::cout << "ser: " << timer.getElapsedTimeInMilliSec() << std::endl; + + timer.start(); + deserialize_xml(bigDataOut,"bigDataIn",file); + timer.stop(); + std::cout << "des: " << timer.getElapsedTimeInMilliSec() << std::endl; + char c; + std::cin >> c;*/ + + std::cout << "All tests run successfully!\n"; + } + } +} + +//#endif diff --git a/src/external/libigl-2.3.0/include/igl/xml/serialize_xml.cpp b/src/external/libigl-2.3.0/include/igl/xml/serialize_xml.cpp new file mode 100644 index 000000000..b68b2f732 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/xml/serialize_xml.cpp @@ -0,0 +1,912 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Christian Schüller +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. + +#include "serialize_xml.h" +#include "../STR.h" +#include "../serialize.h" +#include "XMLSerializable.h" + +#include +#include +#include + +namespace igl +{ + namespace xml + { + template + IGL_INLINE void serialize_xml( + const T& obj, + const std::string& filename) + { + serialize_xml(obj,"object",filename,false,true); + } + + template + IGL_INLINE void serialize_xml( + const T& obj, + const std::string& objectName, + const std::string& filename, + bool binary, + bool overwrite) + { + tinyxml2::XMLDocument* doc = new tinyxml2::XMLDocument(); + + if(overwrite == false) + { + // Check if file exists + tinyxml2::XMLError error = doc->LoadFile(filename.c_str()); + if(error != tinyxml2::XML_SUCCESS) + { + doc->Clear(); + } + } + + tinyxml2::XMLElement* element = doc->FirstChildElement("serialization"); + if(element == NULL) + { + element = doc->NewElement("serialization"); + doc->InsertEndChild(element); + } + + serialize_xml(obj,objectName,doc,element,binary); + + // Save + tinyxml2::XMLError error = doc->SaveFile(filename.c_str()); + if(error != tinyxml2::XML_SUCCESS) + { + doc->PrintError(); + } + + delete doc; + } + + template + IGL_INLINE void serialize_xml( + const T& obj, + const std::string& objectName, + tinyxml2::XMLDocument* doc, + tinyxml2::XMLElement* element, + bool binary) + { + static_assert( + serialization_xml::is_serializable::value, + "'igl::xml::serialize_xml': type is not serializable"); + + std::string name(objectName); + serialization_xml::encodeXMLElementName(name); + + tinyxml2::XMLElement* child = element->FirstChildElement(name.c_str()); + + if(child != NULL) + element->DeleteChild(child); + + child = doc->NewElement(name.c_str()); + element->InsertEndChild(child); + + if(binary) + { + std::vector buffer; + serialize(obj,name,buffer); + std::string data = + serialization_xml::base64_encode( + reinterpret_cast( + buffer.data()),buffer.size()); + + child->SetAttribute("binary",true); + + serialization_xml::serialize(data,doc,element,name); + } + else + { + serialization_xml::serialize(obj,doc,element,name); + } + } + + template + IGL_INLINE void deserialize_xml(T& obj,const std::string& filename) + { + deserialize_xml(obj,"object",filename); + } + + template + IGL_INLINE void deserialize_xml(T& obj,const std::string& objectName,const std::string& filename) + { + tinyxml2::XMLDocument* doc = new tinyxml2::XMLDocument(); + + tinyxml2::XMLError error = doc->LoadFile(filename.c_str()); + if(error != tinyxml2::XML_SUCCESS) + { + std::cerr << "File not found!" << std::endl; + doc->PrintError(); + delete doc; + } + else + { + tinyxml2::XMLElement* element = doc->FirstChildElement("serialization"); + if(element == NULL) + { + std::cerr << "Name of object not found! Initialized with default value." << std::endl; + obj = T(); + } + else + { + deserialize_xml(obj,objectName,doc,element); + } + + delete doc; + } + } + + template + IGL_INLINE void deserialize_xml(T& obj,const std::string& objectName,const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element) + { + static_assert(serialization::is_serializable::value,"'igl::xml::deserialize_xml': type is not deserializable"); + + std::string name(objectName); + serialization_xml::encodeXMLElementName(name); + + const tinyxml2::XMLElement* child = element->FirstChildElement(name.c_str()); + if(child != NULL) + { + bool isBinary = false; + const tinyxml2::XMLAttribute* attr = child->FindAttribute("binary"); + if(attr != NULL) + { + std::string code; + serialization_xml::deserialize(code,doc,element,name); + std::string decoded = serialization_xml::base64_decode(code); + + std::vector buffer; + std::copy(decoded.c_str(),decoded.c_str()+decoded.length(),std::back_inserter(buffer)); + + deserialize(obj,name,buffer); + } + else + { + serialization_xml::deserialize(obj,doc,element,name); + } + } + } + + namespace serialization_xml + { + // fundamental types + + template + IGL_INLINE typename std::enable_if::value>::type serialize(const T& obj,tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element,const std::string& name) + { + tinyxml2::XMLElement* child = getElement(doc,element,name.c_str()); + child->SetAttribute("val",obj); + } + + template + IGL_INLINE typename std::enable_if::value>::type deserialize(T& obj,const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element,const std::string& name) + { + const tinyxml2::XMLElement* child = element->FirstChildElement(name.c_str()); + if(child != NULL) + { + getAttribute(child->Attribute("val"),obj); + } + else + { + obj = T(); + } + } + + // std::string + + IGL_INLINE void serialize(const std::string& obj,tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element,const std::string& name) + { + tinyxml2::XMLElement* child = getElement(doc,element,name.c_str()); + child->SetAttribute("val",obj.c_str()); + } + + IGL_INLINE void deserialize(std::string& obj,const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element,const std::string& name) + { + const tinyxml2::XMLElement* child = element->FirstChildElement(name.c_str()); + if(child != NULL) + { + getAttribute(child->Attribute("val"),obj); + } + else + { + obj = std::string(""); + } + } + + // Serializable + + template + IGL_INLINE typename std::enable_if::value>::type serialize(const T& obj,tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element,const std::string& name) + { + // Serialize object implementing Serializable interface + const XMLSerializableBase& object = dynamic_cast(obj); + + tinyxml2::XMLElement* child = getElement(doc,element,name.c_str()); + object.Serialize(doc,child); + } + + template + IGL_INLINE typename std::enable_if::value>::type deserialize(T& obj,const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element,const std::string& name) + { + const tinyxml2::XMLElement* child = element->FirstChildElement(name.c_str()); + + if(child != NULL) + { + obj.Deserialize(doc,child); + } + else + { + obj = T(); + } + } + + // STL containers + + template + IGL_INLINE void serialize(const std::pair& obj,tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element,const std::string& name) + { + tinyxml2::XMLElement* pair = getElement(doc,element,name.c_str()); + serialize(obj.first,doc,pair,"first"); + serialize(obj.second,doc,pair,"second"); + } + + template + IGL_INLINE void deserialize(std::pair& obj,const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element,const std::string& name) + { + const tinyxml2::XMLElement* child = element->FirstChildElement(name.c_str()); + if(child != NULL) + { + deserialize(obj.first,doc,child,"first"); + deserialize(obj.second,doc,child,"second"); + } + else + { + obj.first = T1(); + obj.second = T2(); + } + } + + template + IGL_INLINE void serialize(const std::vector& obj,tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element,const std::string& name) + { + tinyxml2::XMLElement* vector = getElement(doc,element,name.c_str()); + vector->SetAttribute("size",(unsigned int)obj.size()); + + std::stringstream num; + for(unsigned int i=0;i + IGL_INLINE void deserialize(std::vector& obj,const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element,const std::string& name) + { + obj.clear(); + + const tinyxml2::XMLElement* child = element->FirstChildElement(name.c_str()); + if(child != NULL) + { + unsigned int size = child->UnsignedAttribute("size"); + obj.resize(size); + + std::stringstream num; + for(unsigned int i=0;i + IGL_INLINE void serialize(const std::set& obj,tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element,const std::string& name) + { + tinyxml2::XMLElement* set = getElement(doc,element,name.c_str()); + set->SetAttribute("size",(unsigned int)obj.size()); + + std::stringstream num; + typename std::set::iterator iter = obj.begin(); + for(int i=0;iter!=obj.end();iter++,i++) + { + num.str(""); + num << "value" << i; + serialize((T)*iter,doc,set,num.str()); + } + } + + template + IGL_INLINE void deserialize(std::set& obj,const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element,const std::string& name) + { + obj.clear(); + + const tinyxml2::XMLElement* child = element->FirstChildElement(name.c_str()); + if(child != NULL) + { + unsigned int size = child->UnsignedAttribute("size"); + + std::stringstream num; + typename std::set::iterator iter = obj.begin(); + for(int i=0;i + IGL_INLINE void serialize(const std::map& obj,tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element,const std::string& name) + { + tinyxml2::XMLElement* map = getElement(doc,element,name.c_str()); + map->SetAttribute("size",(unsigned int)obj.size()); + + std::stringstream num; + typename std::map::const_iterator iter = obj.cbegin(); + for(int i=0;iter!=obj.end();iter++,i++) + { + num.str(""); + num << "value" << i; + serialize((std::pair)*iter,doc,map,num.str()); + } + } + + template + IGL_INLINE void deserialize(std::map& obj,const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element,const std::string& name) + { + obj.clear(); + + const tinyxml2::XMLElement* child = element->FirstChildElement(name.c_str()); + if(child != NULL) + { + unsigned int size = child->UnsignedAttribute("size"); + + std::stringstream num; + typename std::map::iterator iter = obj.begin(); + for(int i=0;i pair; + deserialize(pair,doc,child,num.str()); + obj.insert(pair); + } + } + else + { + obj.clear(); + } + } + + template + IGL_INLINE void serialize( + const Eigen::Matrix& obj, + const std::string& name, + const std::function& to_string, + tinyxml2::XMLDocument* doc, + tinyxml2::XMLElement* element) + { + tinyxml2::XMLElement* matrix = getElement(doc,element,name.c_str()); + + const unsigned int rows = obj.rows(); + const unsigned int cols = obj.cols(); + + matrix->SetAttribute("rows",rows); + matrix->SetAttribute("cols",cols); + + std::stringstream ms; + ms << "\n"; + for(unsigned int r=0;r 1) + mString[mString.size()-2] = '\0'; + + matrix->SetAttribute("matrix",mString.c_str()); + } + + // Eigen types + template + IGL_INLINE void serialize( + const Eigen::Matrix& obj, + tinyxml2::XMLDocument* doc, + tinyxml2::XMLElement* element, + const std::string& name) + { + const std::function to_string = + [](const T & v)->std::string + { + return + STR(std::setprecision(std::numeric_limits::digits10+2)< + IGL_INLINE void deserialize( + const tinyxml2::XMLDocument* doc, + const tinyxml2::XMLElement* element, + const std::string& name, + const std::function & from_string, + Eigen::Matrix& obj) + { + const tinyxml2::XMLElement* child = element->FirstChildElement(name.c_str()); + bool initialized = false; + if(child != NULL) + { + const unsigned int rows = child->UnsignedAttribute("rows"); + const unsigned int cols = child->UnsignedAttribute("cols"); + + if(rows > 0 && cols > 0) + { + obj.resize(rows,cols); + + const tinyxml2::XMLAttribute* attribute = child->FindAttribute("matrix"); + if(attribute != NULL) + { + std::string matTemp; + getAttribute(attribute->Value(),matTemp); + + std::string line,srows,scols; + std::stringstream mats; + mats << matTemp; + + int r=0; + std::string val; + // for each line + getline(mats,line); + while(getline(mats,line)) + { + // get current line + std::stringstream liness(line); + + for(unsigned int c=0;c(); + } + } + + template + IGL_INLINE void deserialize( + Eigen::Matrix& obj, + const tinyxml2::XMLDocument* doc, + const tinyxml2::XMLElement* element, + const std::string& name) + { + const std::function & from_string = + [](const std::string & s,T & v) + { + getAttribute(s.c_str(),v); + }; + deserialize(doc,element,name,from_string,obj); + } + + template + IGL_INLINE void serialize(const Eigen::SparseMatrix& obj,tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element,const std::string& name) + { + tinyxml2::XMLElement* matrix = getElement(doc,element,name.c_str()); + + const unsigned int rows = obj.rows(); + const unsigned int cols = obj.cols(); + + matrix->SetAttribute("rows",rows); + matrix->SetAttribute("cols",cols); + + char buffer[200]; + std::stringstream ms; + ms << "\n"; + for(int k=0;k::InnerIterator it(obj,k);it;++it) + { + tinyxml2::XMLUtil::ToStr(it.value(),buffer,200); + ms << it.row() << "," << it.col() << "," << buffer << "\n"; + } + } + + std::string mString = ms.str(); + if(mString.size() > 0) + mString[mString.size()-1] = '\0'; + + matrix->SetAttribute("matrix",mString.c_str()); + } + + template + IGL_INLINE void deserialize(Eigen::SparseMatrix& obj,const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element,const std::string& name) + { + const tinyxml2::XMLElement* child = element->FirstChildElement(name.c_str()); + bool initialized = false; + if(child != NULL) + { + const unsigned int rows = child->UnsignedAttribute("rows"); + const unsigned int cols = child->UnsignedAttribute("cols"); + + if(rows > 0 && cols > 0) + { + obj.resize(rows,cols); + obj.setZero(); + + const tinyxml2::XMLAttribute* attribute = child->FindAttribute("matrix"); + if(attribute != NULL) + { + std::string matTemp; + getAttribute(attribute->Value(),matTemp); + + std::string line,srows,scols; + std::stringstream mats; + mats << matTemp; + + std::vector > triplets; + int r=0; + std::string val; + + // for each line + getline(mats,line); + while(getline(mats,line)) + { + // get current line + std::stringstream liness(line); + + // row + getline(liness,val,','); + int row = atoi(val.c_str()); + // col + getline(liness,val,','); + int col = atoi(val.c_str()); + // val + getline(liness,val); + T value; + getAttribute(val.c_str(),value); + + triplets.push_back(Eigen::Triplet(row,col,value)); + + r++; + } + + obj.setFromTriplets(triplets.begin(),triplets.end()); + initialized = true; + } + } + } + + if(!initialized) + { + obj = Eigen::SparseMatrix(); + } + } + + // pointers + + template + IGL_INLINE typename std::enable_if::value>::type serialize(const T& obj,tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element,const std::string& name) + { + tinyxml2::XMLElement* pointer = getElement(doc,element,name.c_str()); + + bool isNullPtr = (obj == NULL); + + pointer->SetAttribute("isNullPtr",isNullPtr); + + if(isNullPtr == false) + serialization_xml::serialize(*obj,doc,element,name); + } + + template + IGL_INLINE typename std::enable_if::value>::type deserialize(T& obj,const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element,const std::string& name) + { + const tinyxml2::XMLElement* child = element->FirstChildElement(name.c_str()); + if(child != NULL) + { + bool isNullPtr = child->BoolAttribute("isNullPtr"); + + if(isNullPtr) + { + if(obj != NULL) + { + std::cout << "deserialization: possible memory leak for '" << typeid(obj).name() << "'" << std::endl; + obj = NULL; + } + } + else + { + if(obj != NULL) + std::cout << "deserialization: possible memory leak for '" << typeid(obj).name() << "'" << std::endl; + + obj = new typename std::remove_pointer::type(); + + serialization_xml::deserialize(*obj,doc,element,name); + } + } + } + + // helper functions + + IGL_INLINE tinyxml2::XMLElement* getElement(tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element,const std::string& name) + { + tinyxml2::XMLElement* child = element->FirstChildElement(name.c_str()); + if(child == NULL) + { + child = doc->NewElement(name.c_str()); + element->InsertEndChild(child); + } + return child; + } + + IGL_INLINE void getAttribute(const char* src,bool& dest) + { + tinyxml2::XMLUtil::ToBool(src,&dest); + } + + IGL_INLINE void getAttribute(const char* src,char& dest) + { + dest = (char)atoi(src); + } + + IGL_INLINE void getAttribute(const char* src,std::string& dest) + { + dest = src; + } + + IGL_INLINE void getAttribute(const char* src,float& dest) + { + tinyxml2::XMLUtil::ToFloat(src,&dest); + } + + IGL_INLINE void getAttribute(const char* src,double& dest) + { + tinyxml2::XMLUtil::ToDouble(src,&dest); + } + + template + IGL_INLINE typename std::enable_if::value && std::is_unsigned::value>::type getAttribute(const char* src,T& dest) + { + unsigned int val; + tinyxml2::XMLUtil::ToUnsigned(src,&val); + dest = (T)val; + } + + template + IGL_INLINE typename std::enable_if::value && !std::is_unsigned::value>::type getAttribute(const char* src,T& dest) + { + int val; + tinyxml2::XMLUtil::ToInt(src,&val); + dest = (T)val; + } + + // tinyXML2 related stuff + static const int numForbiddenChars = 8; + static const char forbiddenChars[] ={' ','/','~','#','&','>','<','='}; + + IGL_INLINE void replaceSubString(std::string& str,const std::string& search,const std::string& replace) + { + size_t pos = 0; + while((pos = str.find(search,pos)) != std::string::npos) + { + str.replace(pos,search.length(),replace); + pos += replace.length(); + } + } + + IGL_INLINE void encodeXMLElementName(std::string& name) + { + // must not start with a digit + if(isdigit(*name.begin())) + { + name = ":::" + name; + } + + std::stringstream stream; + for(int i=0;i> 2; + char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); + char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); + char_array_4[3] = char_array_3[2] & 0x3f; + + for(i = 0; (i <4) ; i++) + ret += base64_chars[char_array_4[i]]; + + i = 0; + } + } + + if(i) + { + for(j = i; j < 3; j++) + char_array_3[j] = '\0'; + + char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; + char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); + char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); + char_array_4[3] = char_array_3[2] & 0x3f; + + for(j = 0; (j < i + 1); j++) + ret += base64_chars[char_array_4[j]]; + + while((i++ < 3)) + ret += '='; + } + + return ret; + } + + std::string base64_decode(std::string const& encoded_string) + { + int in_len = encoded_string.size(); + int i = 0; + int j = 0; + int in_ = 0; + unsigned char char_array_4[4],char_array_3[3]; + std::string ret; + + // construct fast lookup table + // added by Christian Sch�ller (schuellc@inf.ethz.ch) + int charLookup[200]; + for(int i=0;i<(int)(base64_chars.length());i++) + charLookup[(int)base64_chars[i]] = i; + + while(in_len-- && (encoded_string[in_] != '=') && is_base64(encoded_string[in_])) { + char_array_4[i++] = encoded_string[in_]; in_++; + if(i ==4) { + for(i = 0; i <4; i++) + char_array_4[i] = charLookup[char_array_4[i]]; // new fast lookup + //char_array_4[i] = base64_chars.find(char_array_4[i]); // original version + + char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); + char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); + char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; + + for(i = 0; (i < 3); i++) + ret += char_array_3[i]; + + i = 0; + } + } + + if(i) { + for(j = i; j <4; j++) + char_array_4[j] = 0; + + for(j = 0; j <4; j++) + char_array_4[j] = base64_chars.find(char_array_4[j]); + + char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); + char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); + char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; + + for(j = 0; (j < i - 1); + j++) ret += char_array_3[j]; + } + + return ret; + } + } + } +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +template void igl::xml::serialize_xml > >(std::vector > const&, std::basic_string, std::allocator > const&, std::basic_string, std::allocator > const&, bool, bool); +template void igl::xml::deserialize_xml > >(std::vector >&, std::basic_string, std::allocator > const&, std::basic_string, std::allocator > const&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/xml/serialize_xml.h b/src/external/libigl-2.3.0/include/igl/xml/serialize_xml.h new file mode 100644 index 000000000..2190f676a --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/xml/serialize_xml.h @@ -0,0 +1,247 @@ +// +// Copyright (C) 2014 Christian Sch�ller +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_XML_SERIALIZABLE_XML_H +#define IGL_XML_SERIALIZABLE_XML_H +// ----------------------------------------------------------------------------- +// Functions to save and load a serialization of fundamental c++ data types to +// and from a xml file. STL containers, Eigen matrix types and nested data +// structures are also supported. To serialize a user defined class implement +// the interface XMLSerializable or XMLSerializableBase. +// +// See also: serialize.h +// ----------------------------------------------------------------------------- + +#include "../igl_inline.h" + + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +//#define SERIALIZE_XML(x) igl::xml::serialize_xml(x,#x,doc,element); +//#define DESERIALIZE_XML(x) igl::xml::deserialize_xml(x,#x,,doc,element); + +namespace igl +{ + namespace xml + { + struct XMLSerializableBase; + // serializes the given object either to a xml file or to the provided doc data + // + // Templates: + // T type of the object to serialize + // Inputs: + // obj object to serialize + // objectName unique object name,used for the identification + // filename name of the file containing the serialization + // binary set to true to serialize the object in binary format (faster for big data) + // overwrite set to true to overwrite an existing xml file + // element tinyxml2 virtual representation of the current xml node + // Outputs: + // doc contains current tinyxml2 virtual representation of the xml data + // + template + IGL_INLINE void serialize_xml(const T& obj,const std::string& filename); + template + IGL_INLINE void serialize_xml( + const T& obj, + const std::string& objectName, + const std::string& filename, + bool binary = false, + bool overwrite = false); + template + IGL_INLINE void serialize_xml( + const T& obj, + const std::string& objectName, + tinyxml2::XMLDocument* doc, + tinyxml2::XMLElement* element, + bool binary = false); + + // deserializes the given data from a xml file or doc data back to the provided object + // + // Templates: + // T type of the object to serialize + // Inputs: + // + // objectName unique object name,used for the identification + // filename name of the file containing the serialization + // binary set to true to serialize the object in binary format (faster for big data) + // overwrite set to true to overwrite an existing xml file + // doc contains current tinyxml2 virtual representation of the xml data + // element tinyxml2 virtual representation of the current xml node + // Outputs: + // obj object to load back serialization to + // + template + IGL_INLINE void deserialize_xml(T& obj,const std::string& filename); + template + IGL_INLINE void deserialize_xml(T& obj,const std::string& objectName,const std::string& filename); + template + IGL_INLINE void deserialize_xml(T& obj,const std::string& objectName,const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element); + + // internal functions + namespace serialization_xml + { + // fundamental types + template + IGL_INLINE typename std::enable_if::value>::type serialize(const T& obj,tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element,const std::string& name); + template + IGL_INLINE typename std::enable_if::value>::type deserialize(T& obj,const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element,const std::string& name); + + // std::string + IGL_INLINE void serialize(const std::string& obj,tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element,const std::string& name); + IGL_INLINE void deserialize(std::string& obj,const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element,const std::string& name); + + // XMLSerializableBase + template + IGL_INLINE typename std::enable_if::value>::type serialize(const T& obj,tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element,const std::string& name); + template + IGL_INLINE typename std::enable_if::value>::type deserialize(T& obj,const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element,const std::string& name); + + // STL containers + template + IGL_INLINE void serialize(const std::pair& obj,tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element,const std::string& name); + template + IGL_INLINE void deserialize(std::pair& obj,const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element,const std::string& name); + + template + IGL_INLINE void serialize(const std::vector& obj,tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element,const std::string& name); + template + IGL_INLINE void deserialize(std::vector& obj,const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element,const std::string& name); + + template + IGL_INLINE void serialize(const std::set& obj,tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element,const std::string& name); + template + IGL_INLINE void deserialize(std::set& obj,const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element,const std::string& name); + + template + IGL_INLINE void serialize(const std::map& obj,tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element,const std::string& name); + template + IGL_INLINE void deserialize(std::map& obj,const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element,const std::string& name); + + // Eigen types + + // Serialize a Dense Eigen Matrix to xml (in the matrix= attribute, + // awkward...) + // + // Inputs: + // obj MR by MC matrix of T types + // name name of matrix + // to_string function converting T to string + // Outputs: + // doc pointer to xml document + // element pointer to xml element + // + template + IGL_INLINE void serialize( + const Eigen::Matrix& obj, + const std::string& name, + const std::function& to_string, + tinyxml2::XMLDocument* doc, + tinyxml2::XMLElement* element); + // De-Serialize a Dense Eigen Matrix from xml (in the matrix= attribute, + // awkward...) + // + // Inputs: + // doc pointer to xml document + // element pointer to xml element + // name name of matrix + // from_string function string to T + // Outputs: + // obj MR by MC matrix of T types + template + IGL_INLINE void deserialize( + const tinyxml2::XMLDocument* doc, + const tinyxml2::XMLElement* element, + const std::string& name, + const std::function & from_string, + Eigen::Matrix& obj); + + // Legacy APIs + template + IGL_INLINE void serialize( + const Eigen::Matrix& obj, + tinyxml2::XMLDocument* doc, + tinyxml2::XMLElement* element, + const std::string& name); + template + IGL_INLINE void deserialize( + Eigen::Matrix& obj, + const tinyxml2::XMLDocument* doc, + const tinyxml2::XMLElement* element, + const std::string& name); + + template + IGL_INLINE void serialize(const Eigen::SparseMatrix& obj,tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element,const std::string& name); + template + IGL_INLINE void deserialize(Eigen::SparseMatrix& obj,const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element,const std::string& name); + + // raw pointers + template + IGL_INLINE typename std::enable_if::value>::type serialize(const T& obj,tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element,const std::string& name); + template + IGL_INLINE typename std::enable_if::value>::type deserialize(T& obj,const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element,const std::string& name); + + // helper functions + tinyxml2::XMLElement* getElement(tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element,const std::string& name); + IGL_INLINE void getAttribute(const char* src,bool& dest); + IGL_INLINE void getAttribute(const char* scr,char& dest); + IGL_INLINE void getAttribute(const char* src,std::string& dest); + IGL_INLINE void getAttribute(const char* src,float& dest); + IGL_INLINE void getAttribute(const char* src,double& dest); + template + IGL_INLINE typename std::enable_if::value && std::is_unsigned::value>::type getAttribute(const char* src,T& dest); + template + IGL_INLINE typename std::enable_if::value && !std::is_unsigned::value>::type getAttribute(const char* src,T& dest); + IGL_INLINE void replaceSubString(std::string& str,const std::string& search,const std::string& replace); + IGL_INLINE void encodeXMLElementName(std::string& name); + IGL_INLINE void decodeXMLElementName(std::string& name); + IGL_INLINE std::string base64_encode(unsigned char const* bytes_to_encode,unsigned int in_len); + IGL_INLINE std::string base64_decode(std::string const& encoded_string); + + // compile time type serializable check + template + struct is_stl_container { static const bool value = false; }; + template + struct is_stl_container > { static const bool value = true; }; + template + struct is_stl_container > { static const bool value = true; }; + template + struct is_stl_container > { static const bool value = true; }; + template + struct is_stl_container > { static const bool value = true; }; + + template + struct is_eigen_type { static const bool value = false; }; + template + struct is_eigen_type > { static const bool value = true; }; + template + struct is_eigen_type > { static const bool value = true; }; + + template + struct is_serializable { + using T0 = typename std::remove_pointer::type; + static const bool value = std::is_fundamental::value || std::is_same::value || std::is_base_of::value + || is_stl_container::value || is_eigen_type::value; + }; + } + } +} + +#ifndef IGL_STATIC_LIBRARY + #include "serialize_xml.cpp" +#endif + +#endif diff --git a/src/external/libigl-2.3.0/include/igl/xml/writeDAE.cpp b/src/external/libigl-2.3.0/include/igl/xml/writeDAE.cpp new file mode 100644 index 000000000..44bcd0cee --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/xml/writeDAE.cpp @@ -0,0 +1,143 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "writeDAE.h" +#include "../STR.h" +#include +#include +#include + +template +IGL_INLINE bool igl::xml::writeDAE( + const std::string & filename, + const Eigen::PlainObjectBase & V, + const Eigen::PlainObjectBase & F) +{ + using namespace std; + using namespace Eigen; + + tinyxml2::XMLDocument* doc = new tinyxml2::XMLDocument(); + + const auto & ele = [&doc]( + const std::string tag, + // Can't just use `{}` as the default argument because of a clang-bug + // http://stackoverflow.com/questions/17264067/ + const std::map attribs = + std::map(), + const std::string text="", + const std::list children = + std::list() + )->tinyxml2::XMLElement * + { + tinyxml2::XMLElement * element = doc->NewElement(tag.c_str()); + for(const auto & key_value : attribs) + { + element->SetAttribute(key_value.first.c_str(),key_value.second.c_str()); + } + if(!text.empty()) + { + element->InsertEndChild(doc->NewText(text.c_str())); + } + for(auto & child : children) + { + element->InsertEndChild(child); + } + return element; + }; + + Eigen::IOFormat row_format(Eigen::FullPrecision,0," "," ","","",""); + doc->InsertEndChild( + ele("COLLADA", + { + {"xmlns","http://www.collada.org/2005/11/COLLADASchema"}, + {"version","1.4.1"} + }, + "", + { + ele("asset",{},"", + { + ele("unit",{{"meter","0.0254000"},{"name","inch"}}), + ele("up_axis",{},"Y_UP") + }), + ele("library_visual_scenes",{},"", + { + ele("visual_scene",{{"id","ID2"}},"", + { + ele("node",{{"name","SketchUp"}},"", + { + ele("node",{{"id","ID3"},{"name","group_0"}},"", + { + ele("matrix",{},"1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1"), + ele("instance_geometry",{{"url","#ID4"}},"", + { + ele("bind_material",{},"",{ele("technique_common")}), + }), + }), + }), + }), + }), + ele("library_geometries",{},"", + { + ele("geometry",{{"id","ID4"}},"", + { + ele("mesh",{},"", + { + ele("source",{{"id","ID7"}},"", + { + ele( + "float_array", + {{"count",STR(V.size())},{"id","ID10"}}, + STR(V.format(row_format))), + ele("technique_common",{},"", + { + ele( + "accessor", + {{"count",STR(V.rows())},{"source","#ID8"},{"stride","3"}}, + "", + { + ele("param",{{"name","X"},{"type","float"}}), + ele("param",{{"name","Y"},{"type","float"}}), + ele("param",{{"name","Z"},{"type","float"}}), + }) + }) + }), + ele( + "vertices", + {{"id","ID9"}}, + "", + {ele("input",{{"semantic","POSITION"},{"source","#ID7"}})}), + ele( + "triangles", + {{"count",STR(F.rows())}}, + "", + { + ele("input",{{"semantic","VERTEX"},{"source","#ID9"}}), + ele("p",{},STR(F.format(row_format))), + }) + }) + }) + }), + ele("scene",{},"",{ele("instance_visual_scene",{{"url","#ID2"}})}), + })); + // tinyxml2 seems **not** to print the header by default, but it + // also seems that that's OK + tinyxml2::XMLError error = doc->SaveFile(filename.c_str()); + bool ret = true; + if(error != tinyxml2::XML_SUCCESS) + { + doc->PrintError(); + ret = false; + } + delete doc; + return ret; +} + +#ifdef IGL_STATIC_LIBRARY +// Explicit template instantiation +// generated by autoexplicit.sh +template bool igl::xml::writeDAE, Eigen::Matrix >(std::basic_string, std::allocator > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&); +#endif diff --git a/src/external/libigl-2.3.0/include/igl/xml/writeDAE.h b/src/external/libigl-2.3.0/include/igl/xml/writeDAE.h new file mode 100644 index 000000000..731fe7255 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/xml/writeDAE.h @@ -0,0 +1,38 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_XML_WRITEDAE_H +#define IGL_XML_WRITEDAE_H +#include "../igl_inline.h" +#include +#include +namespace igl +{ + namespace xml + { + // Write a mesh to a Collada .dae scene file. The resulting scene contains + // a single "geometry" suitable for solid operaions (boolean union, + // intersection, etc.) in SketchUp. + // + // Inputs: + // filename path to .dae file + // V #V by 3 list of vertex positions + // F #F by 3 list of face indices + // Returns true iff success + // + template + IGL_INLINE bool writeDAE( + const std::string & filename, + const Eigen::PlainObjectBase & V, + const Eigen::PlainObjectBase & F); + } +} + +#ifndef IGL_STATIC_LIBRARY +#include "writeDAE.cpp" +#endif +#endif diff --git a/src/external/libigl-2.3.0/include/igl/xml/write_triangle_mesh.cpp b/src/external/libigl-2.3.0/include/igl/xml/write_triangle_mesh.cpp new file mode 100644 index 000000000..830cb5275 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/xml/write_triangle_mesh.cpp @@ -0,0 +1,33 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#include "write_triangle_mesh.h" +#include "../write_triangle_mesh.h" +#include "../pathinfo.h" +#include "writeDAE.h" + +template +IGL_INLINE bool igl::xml::write_triangle_mesh( + const std::string str, + const Eigen::PlainObjectBase& V, + const Eigen::PlainObjectBase& F, + const FileEncoding fe) +{ + using namespace std; + // dirname, basename, extension and filename + string d,b,e,f; + pathinfo(str,d,b,e,f); + // Convert extension to lower case + std::transform(e.begin(), e.end(), e.begin(), ::tolower); + if(e == "dae") + { + return writeDAE(str,V,F); + }else + { + return igl::write_triangle_mesh(str,V,F,fe); + } +} diff --git a/src/external/libigl-2.3.0/include/igl/xml/write_triangle_mesh.h b/src/external/libigl-2.3.0/include/igl/xml/write_triangle_mesh.h new file mode 100644 index 000000000..ca968eb97 --- /dev/null +++ b/src/external/libigl-2.3.0/include/igl/xml/write_triangle_mesh.h @@ -0,0 +1,46 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2016 Alec Jacobson +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// obtain one at http://mozilla.org/MPL/2.0/. +#ifndef IGL_XML_WRITE_TRIANGLE_MESH_H +#define IGL_XML_WRITE_TRIANGLE_MESH_H +#include "../igl_inline.h" +#include "../FileEncoding.h" + +#include +#include + +namespace igl +{ + namespace xml + { + // write mesh to a file with automatic detection of file format. supported: + // dae, or any of the formats supported by igl::write_triangle_mesh + // + // Templates: + // Scalar type for positions and vectors (will be read as double and cast + // to Scalar) + // Index type for indices (will be read as int and cast to Index) + // Inputs: + // str path to file + // V eigen double matrix #V by 3 + // F eigen int matrix #F by 3 + // Returns true iff success + template + IGL_INLINE bool write_triangle_mesh( + const std::string str, + const Eigen::PlainObjectBase& V, + const Eigen::PlainObjectBase& F, + const FileEncoding fe = FileEncoding::Ascii); + } +} + +#ifndef IGL_STATIC_LIBRARY +# include "write_triangle_mesh.cpp" +#endif + +#endif + diff --git a/src/external/libigl.cmake b/src/external/libigl.cmake new file mode 100644 index 000000000..bf79528f0 --- /dev/null +++ b/src/external/libigl.cmake @@ -0,0 +1,13 @@ +# Copyright 2019, 2021, Collabora, Ltd. +# Copyright 2019, 2021, Visual Computing Lab, ISTI - Italian National Research Council +# SPDX-License-Identifier: BSL-1.0 + +option(ALLOW_BUNDLED_LIBIGL "Allow use of bundled LIBIGL source" ON) + +set(LIBIGL_DIR ${CMAKE_CURRENT_LIST_DIR}/libigl-2.3.0) + +if(ALLOW_BUNDLED_LIBIGL AND EXISTS "${LIBIGL_DIR}/include/igl/igl_inline.h") + message(STATUS "- libigl - using bundled source") + add_library(external-libigl INTERFACE) + target_include_directories(external-libigl INTERFACE "${LIBIGL_DIR}/include/") +endif() diff --git a/src/external/mpir/CMakeLists.txt b/src/external/mpir/CMakeLists.txt deleted file mode 100644 index e8b090caa..000000000 --- a/src/external/mpir/CMakeLists.txt +++ /dev/null @@ -1,29 +0,0 @@ -if(GMP_FOUND) - message(STATUS "- GMP/MPIR - using system-provided GMP library") - add_library(external-gmp INTERFACE) - target_include_directories(external-gmp SYSTEM INTERFACE ${GMP_INCLUDE_DIRS}) - target_link_libraries(external-gmp INTERFACE ${GMP_LIBRARIES}) -else() - if (APPLE OR (WIN32 AND MSVC)) - message(STATUS "- GMP/MPIR - using already built MPIR library") - add_library(external-mpir SHARED IMPORTED GLOBAL) - add_library(external-mpirxx SHARED IMPORTED GLOBAL) - if (WIN32 AND MSVC) - file( - COPY ${MPIR_DIR}/win32-msvc/mpir.lib ${MPIR_DIR}/win32-msvc/mpirxx.lib - DESTINATION ${MESHLAB_LIB_OUTPUT_DIR}) - set_property(TARGET external-mpir PROPERTY IMPORTED_IMPLIB "${MESHLAB_LIB_OUTPUT_DIR}/mpir.lib") - set_property(TARGET external-mpir PROPERTY IMPORTED_LOCATION "${MESHLAB_LIB_OUTPUT_DIR}/mpir.lib") - set_property(TARGET external-mpirxx PROPERTY IMPORTED_IMPLIB "${MESHLAB_LIB_OUTPUT_DIR}/mpirxx.lib") - set_property(TARGET external-mpirxx PROPERTY IMPORTED_LOCATION "${MESHLAB_LIB_OUTPUT_DIR}/mpirxx.lib") - target_include_directories(external-mpir INTERFACE ${EXTERNAL_DIR}/inc/win32-msvc/mpir-2.2.1_x64) - elseif(APPLE) - file( - COPY ${MPIR_DIR}/macx64/libmpir.a ${MPIR_DIR}/macx64/libmpirxx.a - DESTINATION ${MESHLAB_LIB_OUTPUT_DIR}) - set_property(TARGET external-mpir PROPERTY IMPORTED_LOCATION "${MESHLAB_LIB_OUTPUT_DIR}/libmpir.a") - set_property(TARGET external-mpirxx PROPERTY IMPORTED_LOCATION "${MESHLAB_LIB_OUTPUT_DIR}/libmpirxx.a") - target_include_directories(external-mpir INTERFACE ${EXTERNAL_DIR}/inc/macx64/mpir-2.4.0) - endif() - endif() -endif() diff --git a/src/external/mpir/macx64/libmpir.a b/src/external/mpir/macx64/libmpir.a deleted file mode 100644 index 0730e78a1..000000000 Binary files a/src/external/mpir/macx64/libmpir.a and /dev/null differ diff --git a/src/external/mpir/macx64/libmpirxx.a b/src/external/mpir/macx64/libmpirxx.a deleted file mode 100644 index 22a58c054..000000000 Binary files a/src/external/mpir/macx64/libmpirxx.a and /dev/null differ diff --git a/src/external/mpir/macx64/mpir.txt b/src/external/mpir/macx64/mpir.txt deleted file mode 100644 index 5e33f2e74..000000000 --- a/src/external/mpir/macx64/mpir.txt +++ /dev/null @@ -1,3 +0,0 @@ -This version of mpir (2.4.0) for mac64 has been compiled with the following configure command line: - - ./configure CFLAGS="-mmacosx-version-min=10.5" LDFLAGS="-mmacosx-version-min=10.5" --enable-cxx --enable-static --with-pic diff --git a/src/external/mpir/readme.txt b/src/external/mpir/readme.txt deleted file mode 100644 index be7c8915f..000000000 --- a/src/external/mpir/readme.txt +++ /dev/null @@ -1,22 +0,0 @@ -Some compilation notes ------- libgmp ------ - -For mac osx 10.6 with meshlab 32 bit -After extracting the archive - -./configure CFLAGS="-mmacosx-version-min=10.5 -arch i386" LDFLAGS="-mmacosx-version-min=10.5 -arch i386" ABI=32 --enable-cxx --enable-static --with-pic - -make - -cp .libs/*.a ../../external/lib/macx/ - ---- using mpir instead GMP --- -Exactly the same steps as above� -For mac osx 10.6 with meshlab 32 bit� -After extracting the archive - -./configure CFLAGS="-mmacosx-version-min=10.5 -arch i386" LDFLAGS="-mmacosx-version-min=10.5 -arch i386" ABI=32 --enable-cxx --enable-static --with-pic - -make - -cp .libs/*.a ../../external/lib/macx/ diff --git a/src/external/mpir/win32-msvc/mpir.lib b/src/external/mpir/win32-msvc/mpir.lib deleted file mode 100644 index cd191c7ac..000000000 Binary files a/src/external/mpir/win32-msvc/mpir.lib and /dev/null differ diff --git a/src/external/mpir/win32-msvc/mpirxx.lib b/src/external/mpir/win32-msvc/mpirxx.lib deleted file mode 100644 index 17f6d049a..000000000 Binary files a/src/external/mpir/win32-msvc/mpirxx.lib and /dev/null differ diff --git a/src/external/muparser.cmake b/src/external/muparser.cmake index 8ef243638..6334c84fd 100644 --- a/src/external/muparser.cmake +++ b/src/external/muparser.cmake @@ -6,7 +6,7 @@ option(ALLOW_BUNDLED_MUPARSER "Allow use of bundled muparser source" ON) option(ALLOW_SYSTEM_MUPARSER "Allow use of system-provided muparser" ON) find_package(muparser) -set(MUPARSER_DIR ${EXTERNAL_DIR}/muparser_v225) +set(MUPARSER_DIR ${CMAKE_CURRENT_LIST_DIR}/muparser_v225) if(ALLOW_SYSTEM_MUPARSER AND TARGET muparser::muparser) message(STATUS "- muparser - using system-provided library") diff --git a/src/external/newuoa.cmake b/src/external/newuoa.cmake index 4945df40d..73821e8fe 100644 --- a/src/external/newuoa.cmake +++ b/src/external/newuoa.cmake @@ -7,7 +7,7 @@ option(ALLOW_BUNDLED_NEWUOA "Allow use of bundled newuoa source" ON) set(NEWUOA_DIR ${VCGDIR}/wrap/newuoa) if(ALLOW_BUNDLED_NEWUOA AND EXISTS "${NEWUOA_DIR}/include/newuoa.h") - message(STATUS "- newuoa - using bundled source") - add_library(external-newuoa INTERFACE) - target_include_directories(external-newuoa INTERFACE ${NEWUOA_DIR}/include) + message(STATUS "- newuoa - using bundled source") + add_library(external-newuoa INTERFACE) + target_include_directories(external-newuoa INTERFACE ${NEWUOA_DIR}/include) endif() diff --git a/src/external/openctm.cmake b/src/external/openctm.cmake index c00c90f3d..bb3c880ca 100644 --- a/src/external/openctm.cmake +++ b/src/external/openctm.cmake @@ -6,7 +6,7 @@ option(ALLOW_BUNDLED_OPENCTM "Allow use of bundled OpenCTM source" ON) option(ALLOW_SYSTEM_OPENCTM "Allow use of system-provided OpenCTM" ON) find_package(OpenCTM) -set(OPENCTM_DIR ${EXTERNAL_DIR}/OpenCTM-1.0.3) +set(OPENCTM_DIR ${CMAKE_CURRENT_LIST_DIR}/OpenCTM-1.0.3) if(ALLOW_SYSTEM_OPENCTM AND TARGET OpenCTM::OpenCTM) message(STATUS "- OpenCTM - using system-provided library") diff --git a/src/external/qhull.cmake b/src/external/qhull.cmake index a185e426f..e27f7c9c4 100644 --- a/src/external/qhull.cmake +++ b/src/external/qhull.cmake @@ -6,7 +6,7 @@ option(ALLOW_BUNDLED_QHULL "Allow use of bundled Qhull source" ON) option(ALLOW_SYSTEM_QHULL "Allow use of system-provided QHull" ON) find_package(Qhull COMPONENTS libqhull) -set(QHULL_DIR ${EXTERNAL_DIR}/qhull-2003.1) +set(QHULL_DIR ${CMAKE_CURRENT_LIST_DIR}/qhull-2003.1) if(ALLOW_SYSTEM_QHULL AND TARGET Qhull::libqhull) message(STATUS "- qhull - using system-provided library") diff --git a/src/external/readme.txt b/src/external/readme.txt deleted file mode 100644 index aaf5559a5..000000000 --- a/src/external/readme.txt +++ /dev/null @@ -1,34 +0,0 @@ -This folder contains other not so common GPL libraries that we need link into meshlab. The compiled libraries for the various systems should go in the 'lib' folder in a subdir named according to the QT system configuration files (win32-g++, macx, etc). - -Currently: - ----- ann-1.1.1 - ----- bzip2-1.0.5 - ----- glew-1.7.0 - ------lib3ds-1.3.0 -Direct expansion of lib3ds-1.3.0.zip -The latest stable version of lib3ds -Downloaded from lib3ds.sourceforge.net -Modifications: -* added qmake project files in folder lib3ds - ----- muparser_v225 - ----- qhull-2003.1 -Direct expansion of qhull-2003.1.tar.gz. -Downloaded from www.qhull.org. -Modifications: -* added qmake project files - ----- tsai-30b3 -direct expansion of tsai30b3.zip -The latest stable version of routines for calibrating Roger Tsai's perspective projection camera model. (October 28, 95) -Downloaded from http://www.cs.cmu.edu/~rgw/TsaiCode.html -Modifications: -* added qmake project files -* converted from uppercase to lowercase filenames (internally the files refers to themselves using lowercase names) - - diff --git a/src/external/ssynth.cmake b/src/external/ssynth.cmake index 0d54b9b93..22baf6c6c 100644 --- a/src/external/ssynth.cmake +++ b/src/external/ssynth.cmake @@ -3,7 +3,7 @@ # SPDX-License-Identifier: BSL-1.0 option(ALLOW_BUNDLED_SSYNTH "Allow use of bundled structure-synth source" ON) -set(SSYNTH_DIR ${EXTERNAL_DIR}/structuresynth-1.5) +set(SSYNTH_DIR ${CMAKE_CURRENT_LIST_DIR}/structuresynth-1.5) if(ALLOW_BUNDLED_SSYNTH AND EXISTS "${SSYNTH_DIR}/ssynth/StructureSynth/Model/Action.h") message(STATUS "- structure-synth - using bundled source") diff --git a/src/external/u3d.cmake b/src/external/u3d.cmake index d216cd2d8..60d0d2c58 100644 --- a/src/external/u3d.cmake +++ b/src/external/u3d.cmake @@ -4,10 +4,10 @@ option(ALLOW_BUNDLED_U3D "Allow use of bundled u3d source" ON) -if(ALLOW_BUNDLED_U3D AND EXISTS "${EXTERNAL_DIR}/u3d/CMakeLists.txt") +if(ALLOW_BUNDLED_U3D AND EXISTS "${CMAKE_CURRENT_LIST_DIR}/u3d/CMakeLists.txt") message(STATUS "- u3d - using bundled source") set(MESSAGE_QUIET ON) - add_subdirectory(${EXTERNAL_DIR}/u3d) + add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/u3d) unset(MESSAGE_QUIET) endif() diff --git a/src/external/u3d/CMakeLists.txt b/src/external/u3d/CMakeLists.txt index 189b2be5d..84c6e51e7 100644 --- a/src/external/u3d/CMakeLists.txt +++ b/src/external/u3d/CMakeLists.txt @@ -1459,6 +1459,7 @@ ENDIF(APPLE) IF(UNIX AND NOT APPLE) ADD_LIBRARY( external-IDTFConverter STATIC ${IDTFConverter_SRCS} ${IDTFConverter_HDRS} ) ENDIF(UNIX AND NOT APPLE) +target_include_directories(external-IDTFConverter PUBLIC ${U3D_DIR}/src/IDTF) IF(UNIX AND NOT APPLE) set(U3D_LIB_RELATIVE_PATH "../external/u3d/") diff --git a/src/meshlab.pro b/src/meshlab.pro index 6d446386c..7d59105dc 100644 --- a/src/meshlab.pro +++ b/src/meshlab.pro @@ -25,7 +25,6 @@ SUBDIRS = \ #sub projects names external \ common \ meshlab \ - #meshlabserver \ io_base \ # a few basic file formats (ply, obj, off), without this you cannot open anything decorate_base \ filter_measure \ @@ -103,10 +102,7 @@ SUBDIRS += \ #sub projects names edit_pickpoints } -linux{ - SUBDIRS += \ - filter_csg #filter_csg is supported only on linux with qmake -} + meshlab_mini { message(Compiling only MeshLab Mini!) } @@ -121,7 +117,6 @@ win32 { external.subdir = external common.subdir = common meshlab.subdir = meshlab -meshlabserver.subdir = meshlabserver io_base.subdir = meshlabplugins/io_base decorate_base.subdir = meshlabplugins/decorate_base filter_measure.subdir = meshlabplugins/filter_measure @@ -198,7 +193,6 @@ edit_pickpoints.subdir = meshlabplugins/edit_pickpoints # meshlab_mini subdirs #common.depends = external meshlab.depends = common -meshlabserver.depends = common io_base.depends = common decorate_base.depends = common filter_measure.depends = common diff --git a/src/meshlab/CMakeLists.txt b/src/meshlab/CMakeLists.txt index 87b0f7eae..41ce36b24 100644 --- a/src/meshlab/CMakeLists.txt +++ b/src/meshlab/CMakeLists.txt @@ -1,10 +1,8 @@ # Copyright 2019-2020, Collabora, Ltd. # SPDX-License-Identifier: BSL-1.0 - set(SOURCES additionalgui.cpp - changetexturename.cpp glarea.cpp glarea_setting.cpp layerDialog.cpp @@ -16,12 +14,12 @@ set(SOURCES ml_rendering_actions.cpp ml_std_par_dialog.cpp multiViewer_Container.cpp - savemaskexporter.cpp dialogs/about_dialog.cpp dialogs/congrats_dialog.cpp dialogs/filter_script_dialog.cpp dialogs/options_dialog.cpp dialogs/plugin_info_dialog.cpp + dialogs/save_mesh_attributes_dialog.cpp dialogs/save_snapshot_dialog.cpp dialogs/setting_dialog.cpp rich_parameter_gui/richparameterlistdialog.cpp @@ -29,12 +27,10 @@ set(SOURCES rich_parameter_gui/richparameterwidgets.cpp ${VCGDIR}/wrap/gui/trackball.cpp ${VCGDIR}/wrap/gui/trackmode.cpp - ${VCGDIR}/wrap/gui/coordinateframe.cpp - ${EXTERNAL_DIR}/easyexif/exif.cpp) + ${VCGDIR}/wrap/gui/coordinateframe.cpp) set(HEADERS additionalgui.h - changetexturename.h glarea.h glarea_setting.h layerDialog.h @@ -44,13 +40,13 @@ set(HEADERS ml_rendering_actions.h ml_std_par_dialog.h multiViewer_Container.h - savemaskexporter.h snapshotsetting.h dialogs/about_dialog.h dialogs/congrats_dialog.h dialogs/filter_script_dialog.h dialogs/options_dialog.h dialogs/plugin_info_dialog.h + dialogs/save_mesh_attributes_dialog.h dialogs/save_snapshot_dialog.h dialogs/setting_dialog.h rich_parameter_gui/richparameterlistdialog.h @@ -67,10 +63,9 @@ set(UI dialogs/congrats_dialog.ui dialogs/filter_script_dialog.ui dialogs/plugin_info_dialog.ui + dialogs/save_mesh_attributes_dialog.ui dialogs/save_snapshot_dialog.ui - ui/layerDialog.ui - ui/renametexture.ui - ui/savemaskexporter.ui) + ui/layerDialog.ui) set(CMAKE_AUTOUIC_SEARCH_PATHS ${CMAKE_CURRENT_SOURCE_DIR}/ui) diff --git a/src/meshlab/Info.plist b/src/meshlab/Info.plist index ed6e5145f..2026cf4f6 100644 --- a/src/meshlab/Info.plist +++ b/src/meshlab/Info.plist @@ -68,11 +68,11 @@ CFBundlePackageType APPL CFBundleShortVersionString - 2020.12 + 2021.05 CFBundleSignature ???? CFBundleVersion - 2020.12 + 2021.05 LSMinimumSystemVersion 10.12 NOTE diff --git a/src/meshlab/changetexturename.cpp b/src/meshlab/changetexturename.cpp deleted file mode 100644 index 7c8bb040e..000000000 --- a/src/meshlab/changetexturename.cpp +++ /dev/null @@ -1,74 +0,0 @@ -/**************************************************************************** -* VCGLib o o * -* Visual and Computer Graphics Library o o * -* _ O _ * -* Copyright(C) 2004 \/)\/ * -* Visual Computing Lab /\/| * -* ISTI - Italian National Research Council | * -* \ * -* All rights reserved. * -* * -* This program is free software; you can redistribute it and/or modify * -* it under the terms of the GNU General Public License as published by * -* the Free Software Foundation; either version 2 of the License, or * -* (at your option) any later version. * -* * -* This program is distributed in the hope that it will be useful, * -* but WITHOUT ANY WARRANTY; without even the implied warranty of * -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * -* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) * -* for more details. * -* * -****************************************************************************/ - -#include "ui_renametexture.h" -#include "changetexturename.h" - -#include - -ChangeTextureNameDialog::ChangeTextureNameDialog(QWidget *parent) : QDialog(parent) -{ - InitDialog(); -} - -ChangeTextureNameDialog::ChangeTextureNameDialog(QWidget *parent,std::string oldtexture) : QDialog(parent), texture(oldtexture) -{ - InitDialog(); - ui->newtexturename->setText(QString(texture.c_str())); -} - -void ChangeTextureNameDialog::InitDialog() -{ - ui = new Ui::RenameTextureDialog(); - ChangeTextureNameDialog::ui->setupUi(this); - connect(ui->okButton, SIGNAL(clicked()), this, SLOT(SlotOkButton())); - connect(ui->cancelButton, SIGNAL(clicked()), this, SLOT(SlotCancelButton())); - connect(ui->searchButton,SIGNAL(clicked()),this,SLOT(SlotSearchTextureName())); - ui->newtexturename->setWindowTitle("Rename Texture"); -} - -void ChangeTextureNameDialog::SlotOkButton() -{ - this->texture = ui->newtexturename->text().toStdString(); - ui->newtexturename->setText(QString(texture.c_str())); -} - -void ChangeTextureNameDialog::SlotCancelButton() -{ - this->texture = ""; -} - -void ChangeTextureNameDialog::SlotSearchTextureName() -{ - this->texture = QFileDialog::getOpenFileName(new QWidget(),tr("Open Image File"),".").toStdString(); - if(this->texture.size() > 0) - { - QStringList lists = QString(texture.c_str()).split('/'); - ui->newtexturename->setText(lists[lists.size()-1]); - } -} - -ChangeTextureNameDialog::~ChangeTextureNameDialog() -{ - delete ui; -} diff --git a/src/meshlab/changetexturename.h b/src/meshlab/changetexturename.h deleted file mode 100644 index a6310ffc1..000000000 --- a/src/meshlab/changetexturename.h +++ /dev/null @@ -1,55 +0,0 @@ -/**************************************************************************** -* VCGLib o o * -* Visual and Computer Graphics Library o o * -* _ O _ * -* Copyright(C) 2004 \/)\/ * -* Visual Computing Lab /\/| * -* ISTI - Italian National Research Council | * -* \ * -* All rights reserved. * -* * -* This program is free software; you can redistribute it and/or modify * -* it under the terms of the GNU General Public License as published by * -* the Free Software Foundation; either version 2 of the License, or * -* (at your option) any later version. * -* * -* This program is distributed in the hope that it will be useful, * -* but WITHOUT ANY WARRANTY; without even the implied warranty of * -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * -* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) * -* for more details. * -* * -****************************************************************************/ - -#ifndef __VCGLIB_TEXTURE_RENAME -#define __VCGLIB_TEXTURE_RENAME - -#include - -namespace Ui -{ - class RenameTextureDialog; -} - -class ChangeTextureNameDialog : public QDialog -{ - Q_OBJECT -public: - ChangeTextureNameDialog(QWidget *parent); - ChangeTextureNameDialog(QWidget *parent,std::string oldtexture); - ~ChangeTextureNameDialog(); - - void InitDialog(); - std::string GetTextureName(){return texture;} - -private slots: - void SlotOkButton(); - void SlotCancelButton(); - void SlotSearchTextureName(); - -private: - Ui::RenameTextureDialog* ui; - std::string texture; -};//end class - -#endif diff --git a/src/meshlab/dialogs/filter_script_dialog.cpp b/src/meshlab/dialogs/filter_script_dialog.cpp index a37470935..15238cfac 100644 --- a/src/meshlab/dialogs/filter_script_dialog.cpp +++ b/src/meshlab/dialogs/filter_script_dialog.cpp @@ -209,8 +209,7 @@ void FilterScriptDialog::editOldParameters( const int row ) //fill the parameter set with all the names and descriptions which are lost in the //filter script - RichParameterList newParameterSet; - iFilter->initParameterList(action, *(mainWindow->meshDoc()), newParameterSet); + RichParameterList newParameterSet = iFilter->initParameterList(action, *(mainWindow->meshDoc())); if(newParameterSet.size() == oldParameterSet.size()) { RichParameterList::iterator i = newParameterSet.begin(); diff --git a/src/meshlab/dialogs/plugin_info_dialog.cpp b/src/meshlab/dialogs/plugin_info_dialog.cpp index 3108e7d96..6859183f0 100644 --- a/src/meshlab/dialogs/plugin_info_dialog.cpp +++ b/src/meshlab/dialogs/plugin_info_dialog.cpp @@ -192,6 +192,30 @@ void PluginInfoDialog::populateTreeWidget() formats+="Exporter_"+s+" "; tmplist.push_back(formats); } + for(const FileFormat& f: iopi->importImageFormats()){ + QString formats; + for(const QString& s : f.extensions) + formats+="IMG_Importer_"+s+" "; + tmplist.push_back(formats); + } + for(const FileFormat& f: iopi->exportImageFormats()){ + QString formats; + for(const QString& s: f.extensions) + formats+="IMG_Exporter_"+s+" "; + tmplist.push_back(formats); + } + for(const FileFormat& f: iopi->importProjectFormats()){ + QString formats; + for(const QString& s : f.extensions) + formats+="PRJ_Importer_"+s+" "; + tmplist.push_back(formats); + } + for(const FileFormat& f: iopi->exportProjectFormats()){ + QString formats; + for(const QString& s: f.extensions) + formats+="PRJ_Exporter_"+s+" "; + tmplist.push_back(formats); + } } if (type.isRenderPlugin()){ RenderPlugin* rpi = dynamic_cast(fp); diff --git a/src/meshlab/dialogs/save_mesh_attributes_dialog.cpp b/src/meshlab/dialogs/save_mesh_attributes_dialog.cpp new file mode 100644 index 000000000..174308e71 --- /dev/null +++ b/src/meshlab/dialogs/save_mesh_attributes_dialog.cpp @@ -0,0 +1,304 @@ +/**************************************************************************** +* MeshLab o o * +* A versatile mesh processing toolbox o o * +* _ O _ * +* Copyright(C) 2005-2021 \/)\/ * +* Visual Computing Lab /\/| * +* ISTI - Italian National Research Council | * +* \ * +* All rights reserved. * +* * +* This program is free software; you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation; either version 2 of the License, or * +* (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) * +* for more details. * +* * +****************************************************************************/ + +#include "ui_save_mesh_attributes_dialog.h" +#include "save_mesh_attributes_dialog.h" + +#include +#include + +SaveMeshAttributesDialog::SaveMeshAttributesDialog( + QWidget *parent, + MeshModel *m, + int capability, + int defaultBits, + const RichParameterList& additionalSaveParams, + GLArea* glar): + QDialog(parent), + ui(new Ui::SaveMeshAttributesDialog), + m(m), + capability(capability), + defaultBits(defaultBits), + mask(0), + textureQuality(66), + additionalSaveParametrs(additionalSaveParams), + glar(glar) +{ + ui->setupUi(this); + + ui->renametextureButton->setDisabled(true); + + additionalParametersFrame = new RichParameterListFrame(additionalSaveParametrs, this,glar); + QVBoxLayout *vbox = new QVBoxLayout(this); + vbox->addWidget(additionalParametersFrame); + ui->saveParBox->setLayout(vbox); + QFileInfo fi(m->fullName()); + this->setWindowTitle("Choose Saving Options for: '"+ fi.baseName() +"'"); + // Show the additional parameters only for formats that have some. + if(additionalSaveParametrs.isEmpty()) + ui->saveParBox->hide(); + else + ui->saveParBox->show(); + //all - none + ui->AllButton->setChecked(true); + //ui->NoneButton->setChecked(true); + + if( m->cm.textures.size() == 0 ) + { + ui->check_iom_wedgtexcoord->setDisabled(true); + ui->check_iom_wedgtexcoord->setChecked(false); + } + + textureNames.reserve(m->cm.textures.size()); + for(const std::string& tname : m->cm.textures) + { + textureNames.push_back(tname); + QString item(tname.c_str()); + ui->listTextureName->addItem(item); + } + setMaskCapability(); +} + +SaveMeshAttributesDialog::~SaveMeshAttributesDialog() +{ + delete ui; +} + +void SaveMeshAttributesDialog::selectAllPossibleBits() +{ + on_AllButton_clicked(); + updateMask(); +} + +int SaveMeshAttributesDialog::getNewMask() const +{ + return this->mask; +} + +RichParameterList SaveMeshAttributesDialog::getNewAdditionalSaveParameters() const +{ + return additionalSaveParametrs; +} + +std::vector SaveMeshAttributesDialog::getTextureNames() const +{ + return textureNames; +} + +int SaveMeshAttributesDialog::getTextureQuality() const +{ + return textureQuality; +} + +void SaveMeshAttributesDialog::on_okButton_clicked() +{ + updateMask(); + additionalParametersFrame->writeValuesOnParameterList(additionalSaveParametrs); + textureQuality = ui->textureQualitySpinBox->value(); +} + +void SaveMeshAttributesDialog::on_cancelButton_clicked() +{ + mask=-1; +} + +void SaveMeshAttributesDialog::on_check_help_stateChanged(int) +{ + additionalParametersFrame->toggleHelp(); +} + +void SaveMeshAttributesDialog::on_renametextureButton_clicked() +{ + int row = ui->listTextureName->currentRow(); + //ChangeTextureNameDialog dialog(this, textureNames[row].c_str()); + //dialog.exec(); + bool ok; + QString newtexture = + QInputDialog::getText(this, "New Texture Name", + "Enter the new texture name:", QLineEdit::Normal, + QString::fromStdString(textureNames[row]), &ok); + //dialog.close(); + if(ok && newtexture.size()>0 ) { + textureNames[row] = newtexture.toStdString(); + ui->listTextureName->currentItem()->setText(newtexture); + } +} + +void SaveMeshAttributesDialog::on_listTextureName_itemSelectionChanged() +{ + ui->renametextureButton->setDisabled(false); +} + +void SaveMeshAttributesDialog::on_AllButton_clicked() +{ + //vert + ui->check_iom_vertquality->setChecked(ui->check_iom_vertquality->isEnabled()); + ui->check_iom_vertflags->setChecked(ui->check_iom_vertflags->isEnabled()); + ui->check_iom_vertcolor->setChecked(ui->check_iom_vertcolor->isEnabled()); + ui->check_iom_verttexcoord->setChecked(ui->check_iom_verttexcoord->isEnabled()); + ui->check_iom_vertnormal->setChecked(ui->check_iom_vertnormal->isEnabled()); + ui->check_iom_vertradius->setChecked(ui->check_iom_vertradius->isEnabled()); + + //face + ui->check_iom_facequality->setChecked(ui->check_iom_facequality->isEnabled()); + ui->check_iom_faceflags->setChecked(ui->check_iom_faceflags->isEnabled()); + ui->check_iom_facenormal->setChecked(ui->check_iom_facenormal->isEnabled()); + ui->check_iom_facecolor->setChecked(ui->check_iom_facecolor->isEnabled()); + + //wedg + ui->check_iom_wedgcolor->setChecked(ui->check_iom_wedgcolor->isEnabled()); + ui->check_iom_wedgtexcoord->setChecked(ui->check_iom_wedgtexcoord->isEnabled()); + ui->check_iom_wedgnormal->setChecked(ui->check_iom_wedgnormal->isEnabled()); + + //camera + ui->check_iom_camera->setChecked(ui->check_iom_camera->isEnabled()); +} + +void SaveMeshAttributesDialog::on_NoneButton_clicked() +{ + //vert + ui->check_iom_vertquality->setChecked(false); + ui->check_iom_vertflags->setChecked(false); + ui->check_iom_vertcolor->setChecked(false); + ui->check_iom_verttexcoord->setChecked(false); + ui->check_iom_vertnormal->setChecked(false); + ui->check_iom_vertradius->setChecked(false); + + //face + ui->check_iom_facequality->setChecked(false); + ui->check_iom_faceflags->setChecked(false); + ui->check_iom_facenormal->setChecked(false); + ui->check_iom_facecolor->setChecked(false); + + //wedg + ui->check_iom_wedgcolor->setChecked(false); + ui->check_iom_wedgtexcoord->setChecked(false); + ui->check_iom_wedgnormal->setChecked(false); + + //camera + ui->check_iom_camera->setChecked(false); +} + +void SaveMeshAttributesDialog::setMaskCapability() +{ + //vert + checkAndEnable(ui->check_iom_vertquality, vcg::tri::io::Mask::IOM_VERTQUALITY, capability, defaultBits ); + checkAndEnable(ui->check_iom_vertflags, vcg::tri::io::Mask::IOM_VERTFLAGS, capability, defaultBits); + checkAndEnable(ui->check_iom_vertcolor, vcg::tri::io::Mask::IOM_VERTCOLOR, capability, defaultBits); + checkAndEnable(ui->check_iom_verttexcoord, vcg::tri::io::Mask::IOM_VERTTEXCOORD, capability, defaultBits); + checkAndEnable(ui->check_iom_vertnormal, vcg::tri::io::Mask::IOM_VERTNORMAL, capability, defaultBits); + checkAndEnable(ui->check_iom_vertradius, vcg::tri::io::Mask::IOM_VERTRADIUS, capability, defaultBits); + + // point cloud fix: if a point cloud, probably you'd want to save vertex normals + if ((m->cm.fn == 0) && (m->cm.en == 0)) + ui->check_iom_vertnormal->setChecked(true); + + //face + checkAndEnable(ui->check_iom_facequality, vcg::tri::io::Mask::IOM_FACEQUALITY, capability, defaultBits ); + checkAndEnable(ui->check_iom_faceflags, vcg::tri::io::Mask::IOM_FACEFLAGS, capability, defaultBits ); + checkAndEnable(ui->check_iom_facecolor, vcg::tri::io::Mask::IOM_FACECOLOR, capability, defaultBits ); + checkAndEnable(ui->check_iom_facenormal, vcg::tri::io::Mask::IOM_FACENORMAL, capability, defaultBits ); + + //wedge + checkAndEnable(ui->check_iom_wedgcolor, vcg::tri::io::Mask::IOM_WEDGCOLOR, capability, defaultBits ); + checkAndEnable(ui->check_iom_wedgtexcoord, vcg::tri::io::Mask::IOM_WEDGTEXCOORD, capability, defaultBits ); + checkAndEnable(ui->check_iom_wedgnormal, vcg::tri::io::Mask::IOM_WEDGNORMAL, capability, defaultBits ); + + checkAndEnable(ui->check_iom_polygonal, vcg::tri::io::Mask::IOM_BITPOLYGONAL, capability, defaultBits ); + + //camera THIS ONE HAS TO BE CORRECTED !!!! + //bool camval = m->cm.shot.IsValid(); + //int res = capability & vcg::tri::io::Mask::IOM_CAMERA; + ui->check_iom_camera->setDisabled( ((capability & vcg::tri::io::Mask::IOM_CAMERA)==0) || (m->cm.shot.IsValid() == false)); + ui->check_iom_camera->setChecked ( ((capability & vcg::tri::io::Mask::IOM_CAMERA)!=0) && (m->cm.shot.IsValid())); + + if(capability == 0) + ui->NoneButton->setChecked(true); +} + +/* + there are three things that are looked when setting the initial states of the checkbox of this dialog + - this->capabilityBit + - this->defaultBit + + + setDisabled(true): uncheckable + setDisabled(false) : checkable + + true : when the information is not present or in the Capability or in the MeshModel Mask + false : when the information is present in the Capability and in the Mask MeshModel + + setChecked(true) : checked + setChecked(false): unchecked + + true : the information is present both in the Capability and the MeshModel Mask + false : otherwise. + +*/ +void SaveMeshAttributesDialog::checkAndEnable(QCheckBox *qcb,int bit, int capabilityBits, int defaultBits) +{ + qcb->setEnabled(shouldBeEnabled (bit,capabilityBits, defaultBits) ); + qcb->setChecked(shouldBeChecked (bit,capabilityBits, defaultBits) ); +} + +bool SaveMeshAttributesDialog::shouldBeEnabled(int iobit, int capabilityBits, int /*defaultBits*/) +{ + if( (iobit & capabilityBits) == 0 ) return false; + int mmbit = MeshModel::io2mm(iobit); + if(!m->hasDataMask(mmbit)) return false; + return true; +} + +bool SaveMeshAttributesDialog::shouldBeChecked(int bit, int /*capabilityBits*/, int defaultBits) +{ + if(!m->hasDataMask(MeshModel::io2mm(bit))) return false; + //if( (bit & meshBits) == 0 ) return false; + if( (bit & defaultBits) == 0 ) return false; + return true; +} + +void SaveMeshAttributesDialog::updateMask() +{ + int newmask = 0; + + if( ui->check_iom_vertflags->isChecked() ) { newmask |= vcg::tri::io::Mask::IOM_VERTFLAGS;} + if( ui->check_iom_vertcolor->isChecked() ) { newmask |= vcg::tri::io::Mask::IOM_VERTCOLOR;} + if( ui->check_iom_vertquality->isChecked() ) { newmask |= vcg::tri::io::Mask::IOM_VERTQUALITY;} + if( ui->check_iom_verttexcoord->isChecked() ) { newmask |= vcg::tri::io::Mask::IOM_VERTTEXCOORD;} + if( ui->check_iom_vertnormal->isChecked() ) { newmask |= vcg::tri::io::Mask::IOM_VERTNORMAL;} + if( ui->check_iom_vertradius->isChecked() ) { newmask |= vcg::tri::io::Mask::IOM_VERTRADIUS;} + + if( ui->check_iom_faceflags->isChecked() ) { newmask |= vcg::tri::io::Mask::IOM_FACEFLAGS;} + if( ui->check_iom_facecolor->isChecked() ) { newmask |= vcg::tri::io::Mask::IOM_FACECOLOR;} + if( ui->check_iom_facequality->isChecked() ) { newmask |= vcg::tri::io::Mask::IOM_FACEQUALITY;} + if( ui->check_iom_facenormal->isChecked() ) { newmask |= vcg::tri::io::Mask::IOM_FACENORMAL;} + + if( ui->check_iom_wedgcolor->isChecked() ) { newmask |= vcg::tri::io::Mask::IOM_WEDGCOLOR;} + if( ui->check_iom_wedgtexcoord->isChecked() ) { newmask |= vcg::tri::io::Mask::IOM_WEDGTEXCOORD;} + if( ui->check_iom_wedgnormal->isChecked() ) { newmask |= vcg::tri::io::Mask::IOM_WEDGNORMAL;} + + if( ui->check_iom_camera->isChecked() ) { newmask |= vcg::tri::io::Mask::IOM_CAMERA;} + if( ui->check_iom_polygonal->isChecked() ) { newmask |= vcg::tri::io::Mask::IOM_BITPOLYGONAL;} + + this->mask=newmask; +} diff --git a/src/meshlab/savemaskexporter.h b/src/meshlab/dialogs/save_mesh_attributes_dialog.h similarity index 68% rename from src/meshlab/savemaskexporter.h rename to src/meshlab/dialogs/save_mesh_attributes_dialog.h index 362b36b93..2b85827fc 100644 --- a/src/meshlab/savemaskexporter.h +++ b/src/meshlab/dialogs/save_mesh_attributes_dialog.h @@ -1,14 +1,14 @@ /**************************************************************************** -* VCGLib o o * -* Visual and Computer Graphics Library o o * +* MeshLab o o * +* A versatile mesh processing toolbox o o * * _ O _ * -* Copyright(C) 2004 \/)\/ * +* Copyright(C) 2005-2021 \/)\/ * * Visual Computing Lab /\/| * * ISTI - Italian National Research Council | * * \ * * All rights reserved. * * * -* This program is free software; you can redistribute it and/or modify * +* This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * @@ -43,44 +43,58 @@ namespace Ui { - class MaskExporterDialog; -} + class SaveMeshAttributesDialog; +} -class SaveMaskExporterDialog : public QDialog +class SaveMeshAttributesDialog : public QDialog { Q_OBJECT public: - SaveMaskExporterDialog(QWidget *parent, MeshModel *m, int capability, int defaultBits, RichParameterList *par,GLArea* glar = NULL); - ~SaveMaskExporterDialog(); - - void InitDialog(); - void SetTextureName(); - int GetNewMask(); - void SetMaskCapability(); - void updateMask(); + SaveMeshAttributesDialog( + QWidget* parent, + MeshModel* m, + int capability, + int defaultBits, + const RichParameterList& additionalSaveParams, + GLArea* glar = NULL); + ~SaveMeshAttributesDialog(); -public slots: + void selectAllPossibleBits(); + + int getNewMask() const; + RichParameterList getNewAdditionalSaveParameters() const; + std::vector getTextureNames() const; + int getTextureQuality() const; + +private slots: + void on_okButton_clicked(); + void on_cancelButton_clicked(); void on_check_help_stateChanged(int); - void SlotOkButton(); - void SlotCancelButton(); - void SlotRenameTexture(); - void SlotSelectionTextureName(); - void SlotSelectionNoneButton(); - void SlotSelectionAllButton(); + void on_renametextureButton_clicked(); + void on_listTextureName_itemSelectionChanged(); + void on_AllButton_clicked(); + void on_NoneButton_clicked(); + private: - Ui::MaskExporterDialog* ui; - MeshModel *m; - int mask; - int type; - int capability; - int defaultBits; - RichParameterList *parSet; - RichParameterListFrame *stdParFrame; - GLArea* glar; - + void setMaskCapability(); void checkAndEnable(QCheckBox *qcb,int bit, int capabilityBits, int defaultBits); bool shouldBeEnabled(int bit, int capabilityBits, int defaultBits); bool shouldBeChecked(int bit, int capabilityBits, int defaultBits); + void updateMask(); + + Ui::SaveMeshAttributesDialog* ui; + MeshModel *m; + const int capability; + const int defaultBits; + + int mask; + int textureQuality; + + RichParameterList additionalSaveParametrs; + std::vector textureNames; + + RichParameterListFrame *additionalParametersFrame; + GLArea* glar; };//end class #endif diff --git a/src/meshlab/ui/savemaskexporter.ui b/src/meshlab/dialogs/save_mesh_attributes_dialog.ui similarity index 85% rename from src/meshlab/ui/savemaskexporter.ui rename to src/meshlab/dialogs/save_mesh_attributes_dialog.ui index 35f68d380..995bb1dff 100644 --- a/src/meshlab/ui/savemaskexporter.ui +++ b/src/meshlab/dialogs/save_mesh_attributes_dialog.ui @@ -1,13 +1,13 @@ - MaskExporterDialog - + SaveMeshAttributesDialog + 0 0 687 - 337 + 357 @@ -237,6 +237,53 @@ + + + + QFrame::NoFrame + + + QFrame::Plain + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Texture Quality: + + + + + + + -1 + + + 100 + + + 66 + + + + + + @@ -354,7 +401,7 @@ okButton clicked() - MaskExporterDialog + SaveMeshAttributesDialog accept() @@ -370,7 +417,7 @@ cancelButton clicked() - MaskExporterDialog + SaveMeshAttributesDialog reject() diff --git a/src/meshlab/glarea.cpp b/src/meshlab/glarea.cpp index 61d3c6b17..e98c5a071 100644 --- a/src/meshlab/glarea.cpp +++ b/src/meshlab/glarea.cpp @@ -364,7 +364,7 @@ int GLArea::RenderForSelection(int pickX, int pickY) if (datacont == NULL) return -1; - int sz = int( md()->meshList.size())*5; + int sz = int( md()->meshNumber())*5; GLuint *selectBuf =new GLuint[sz]; glSelectBuffer(sz, selectBuf); glRenderMode(GL_SELECT); @@ -390,7 +390,7 @@ int GLArea::RenderForSelection(int pickX, int pickY) /*if (shared->highPrecisionRendering()) glTranslate(-shared->globalSceneCenter());*/ - foreach(MeshModel * mp, this->md()->meshList) + for(MeshModel * mp : md()->meshIterator()) { glLoadName(mp->id()); @@ -477,7 +477,7 @@ void GLArea::paintEvent(QPaintEvent* /*event*/) MLDefaultMeshDecorators defdec(mw()); - foreach(MeshModel * mp, this->md()->meshList) + for(MeshModel * mp : md()->meshIterator()) { if ((mp != NULL) && (meshVisibilityMap[mp->id()])) { @@ -513,7 +513,7 @@ void GLArea::paintEvent(QPaintEvent* /*event*/) if (datacont == NULL) return; - foreach(MeshModel * mp, this->md()->meshList) + for(MeshModel * mp : md()->meshIterator()) { if (meshVisibilityMap[mp->id()]) { @@ -534,7 +534,7 @@ void GLArea::paintEvent(QPaintEvent* /*event*/) datacont->draw(mp->id(),context()); } } - foreach(MeshModel * mp, this->md()->meshList) + for(MeshModel * mp : md()->meshIterator()) { if (meshVisibilityMap[mp->id()]) { @@ -794,9 +794,9 @@ void GLArea::displayInfo(QPainter *painter) QString col1Text,col0Text; - if(this->md()->size()>0) + if(this->md()->meshNumber()>0) { - if(this->md()->size()==1) + if(this->md()->meshNumber()==1) { QLocale engLocale(QLocale::English, QLocale::UnitedStates); col1Text += QString("Mesh: %1\n").arg(mm()->label()); @@ -852,7 +852,7 @@ void GLArea::renderingFacilityString() renderfacility.clear(); makeCurrent(); - if (md()->size() > 0) + if (md()->meshNumber() > 0) { enum RenderingType { FULL_BO, MIXED, FULL_IMMEDIATE_MODE }; RenderingType rendtype = FULL_IMMEDIATE_MODE; @@ -863,12 +863,12 @@ void GLArea::renderingFacilityString() if (shared != NULL) { int hh = 0; - foreach(MeshModel* meshmod, md()->meshList) + for(MeshModel * meshmod : md()->meshIterator()) { if (shared->isBORenderingAvailable(meshmod->id())) { rendtype = MIXED; - if ((rendtype == MIXED) && (hh == md()->meshList.size() - 1)) + if ((rendtype == MIXED) && (hh == md()->meshNumber() - 1)) rendtype = FULL_BO; } ++hh; @@ -956,45 +956,45 @@ void GLArea::displayHelp() void GLArea::saveSnapshot() { makeCurrent(); - // snap all layers - currSnapLayer=0; + // snap all layers + currSnapLayer=0; - // number of subparts - totalCols=totalRows=ss.resolution; - tileRow=tileCol=0; + // number of subparts + totalCols=totalRows=ss.resolution; + tileRow=tileCol=0; - if(ss.snapAllLayers) - { - while(currSnapLayermd()->meshList.size()) - { - tileRow=tileCol=0; - qDebug("Snapping layer %i",currSnapLayer); + if(ss.snapAllLayers) + { + while(currSnapLayermeshNumber()) + { + tileRow=tileCol=0; + qDebug("Snapping layer %i",currSnapLayer); int mmit = 0; - foreach(MeshModel *mp,this->md()->meshList) { + for(MeshModel * mp : md()->meshIterator()){ if (mmit == currSnapLayer) meshSetVisibility(mp, true); else meshSetVisibility(mp, false); mmit++; - } + } - takeSnapTile=true; + takeSnapTile=true; for (int tilenum = 0; tilenum < (ss.resolution*ss.resolution); tilenum++) repaint(); - currSnapLayer++; - } + currSnapLayer++; + } - //cleanup - foreach(MeshModel *mp,this->md()->meshList) { - meshSetVisibility(mp,true); - } - ss.counter++; - } - else - { - takeSnapTile=true; - update(); - } + //cleanup + for(MeshModel *mp : md()->meshIterator()) { + meshSetVisibility(mp,true); + } + ss.counter++; + } + else + { + takeSnapTile=true; + update(); + } } // Slot called when the current mesh has changed. @@ -1108,7 +1108,7 @@ void GLArea::setCurrentEditAction(QAction *editAction) } else { - foreach(MeshModel* mm, md()->meshList) + for(MeshModel* mm : md()->meshIterator()) { if (mm != NULL) { @@ -1333,7 +1333,7 @@ void GLArea::wheelEvent(QWheelEvent*e) MLSceneGLSharedDataContext* cont = mvc()->sharedDataContext(); if (cont != NULL) { - foreach(MeshModel * mp, this->md()->meshList) + for(MeshModel *mp : md()->meshIterator()) { MLRenderingData dt; cont->getRenderInfoPerMeshView(mp->id(), context(), dt); @@ -1787,7 +1787,7 @@ void GLArea::updateCustomSettingValues( const RichParameterList& rps ) this->update(); } -void GLArea::initGlobalParameterList( RichParameterList * defaultGlobalParamList) +void GLArea::initGlobalParameterList( RichParameterList& defaultGlobalParamList) { GLAreaSetting::initGlobalParameterList(defaultGlobalParamList); } @@ -1796,7 +1796,7 @@ void GLArea::initGlobalParameterList( RichParameterList * defaultGlobalParamList void GLArea::updateMeshSetVisibilities() { meshVisibilityMap.clear(); - foreach(MeshModel * mp, this->md()->meshList) + for(MeshModel *mp : md()->meshIterator()) { //Insert the new pair in the map; If the key is already in the map, its value will be overwritten meshVisibilityMap.insert(mp->id(),mp->visible); @@ -1812,7 +1812,7 @@ void GLArea::updateRasterSetVisibilities() while (i.hasNext()) { i.next(); bool found =false; - foreach(RasterModel * rp, this->md()->rasterList) + for(RasterModel * rp: md()->rasterIterator()) { if(rp->id() == i.key()) { @@ -1824,7 +1824,7 @@ void GLArea::updateRasterSetVisibilities() rasterVisibilityMap.remove(i.key()); } - foreach(RasterModel * rp, this->md()->rasterList) + for(RasterModel * rp: md()->rasterIterator()) { //Insert the new pair in the map;If the key is already in the map, its value will be overwritten rasterVisibilityMap.insert(rp->id(),rp->visible); @@ -1879,7 +1879,7 @@ void GLArea::showRaster(bool resetViewFlag) void GLArea::loadRaster(int id) { lastloadedraster = id; - foreach(RasterModel *rm, this->md()->rasterList) + for(RasterModel *rm: md()->rasterIterator()) if(rm->id()==id) { this->md()->setCurrentRaster(id); diff --git a/src/meshlab/glarea.h b/src/meshlab/glarea.h index 09be0e966..00ccd6f4c 100644 --- a/src/meshlab/glarea.h +++ b/src/meshlab/glarea.h @@ -62,7 +62,7 @@ class GLArea : public QGLWidget public: GLArea(QWidget *parent,MultiViewer_Container *mvcont, RichParameterList *current); ~GLArea(); - static void initGlobalParameterList( RichParameterList * /*globalparam*/); + static void initGlobalParameterList(RichParameterList& /*globalparam*/); private: int id; //the very important unique id of each subwindow. diff --git a/src/meshlab/glarea_setting.cpp b/src/meshlab/glarea_setting.cpp index bf318d008..7a058af21 100644 --- a/src/meshlab/glarea_setting.cpp +++ b/src/meshlab/glarea_setting.cpp @@ -1,30 +1,30 @@ #include "glarea_setting.h" -void GLAreaSetting::initGlobalParameterList( RichParameterList * defaultGlobalParamSet) +void GLAreaSetting::initGlobalParameterList(RichParameterList& defaultGlobalParamSet) { - defaultGlobalParamSet->addParam(RichColor(backgroundBotColorParam(),QColor(128,128,255),"MeshLab Bottom BackGround Color","MeshLab GLarea's BackGround Color(bottom corner)")); - defaultGlobalParamSet->addParam(RichColor(backgroundTopColorParam(),QColor( 0, 0, 0),"MeshLab Top BackGround Color","MeshLab GLarea's BackGround Color(top corner)")); - defaultGlobalParamSet->addParam(RichColor(logAreaColorParam(), QColor(128,16,16),"MeshLab GLarea's Log Area Color","MeshLab GLarea's BackGround Color(bottom corner)")); - defaultGlobalParamSet->addParam(RichColor(textColorParam(),vcg::Color4b::White,"Text Color","Color of the text used in all the Graphics Window (it should be well different from the background color...)")); + defaultGlobalParamSet.addParam(RichColor(backgroundBotColorParam(),QColor(128,128,255),"MeshLab Bottom BackGround Color","MeshLab GLarea's BackGround Color(bottom corner)")); + defaultGlobalParamSet.addParam(RichColor(backgroundTopColorParam(),QColor( 0, 0, 0),"MeshLab Top BackGround Color","MeshLab GLarea's BackGround Color(top corner)")); + defaultGlobalParamSet.addParam(RichColor(logAreaColorParam(), QColor(128,16,16),"MeshLab GLarea's Log Area Color","MeshLab GLarea's BackGround Color(bottom corner)")); + defaultGlobalParamSet.addParam(RichColor(textColorParam(),vcg::Color4b::White,"Text Color","Color of the text used in all the Graphics Window (it should be well different from the background color...)")); - defaultGlobalParamSet->addParam(RichColor(baseLightAmbientColorParam() ,QColor( 32, 32, 32),"MeshLab Base Light Ambient Color","MeshLab GLarea's BackGround Color(bottom corner)")); - defaultGlobalParamSet->addParam(RichColor(baseLightDiffuseColorParam() ,QColor(204,204,204),"MeshLab Base Light Diffuse Color","MeshLab GLarea's BackGround Color(top corner)")); - defaultGlobalParamSet->addParam(RichColor(baseLightSpecularColorParam() ,QColor(255,255,255),"MeshLab Base Light Specular Color","MeshLab GLarea's BackGround Color(bottom corner)")); + defaultGlobalParamSet.addParam(RichColor(baseLightAmbientColorParam() ,QColor( 32, 32, 32),"MeshLab Base Light Ambient Color","MeshLab GLarea's BackGround Color(bottom corner)")); + defaultGlobalParamSet.addParam(RichColor(baseLightDiffuseColorParam() ,QColor(204,204,204),"MeshLab Base Light Diffuse Color","MeshLab GLarea's BackGround Color(top corner)")); + defaultGlobalParamSet.addParam(RichColor(baseLightSpecularColorParam() ,QColor(255,255,255),"MeshLab Base Light Specular Color","MeshLab GLarea's BackGround Color(bottom corner)")); - defaultGlobalParamSet->addParam(RichColor(fancyBLightDiffuseColorParam() ,QColor(255,204,204),"MeshLab Base Light Diffuse Color","MeshLab GLarea's BackGround Color(top corner)")); - defaultGlobalParamSet->addParam(RichColor(fancyFLightDiffuseColorParam() ,QColor(204,204,255),"MeshLab Base Light Diffuse Color","MeshLab GLarea's BackGround Color(top corner)")); + defaultGlobalParamSet.addParam(RichColor(fancyBLightDiffuseColorParam() ,QColor(255,204,204),"MeshLab Base Light Diffuse Color","MeshLab GLarea's BackGround Color(top corner)")); + defaultGlobalParamSet.addParam(RichColor(fancyFLightDiffuseColorParam() ,QColor(204,204,255),"MeshLab Base Light Diffuse Color","MeshLab GLarea's BackGround Color(top corner)")); QStringList textureMinFilterModes = (QStringList() << "Nearest" << "MipMap"); QStringList textureMagFilterModes = (QStringList() << "Nearest" << "Linear"); - defaultGlobalParamSet->addParam(RichEnum(textureMinFilterParam() , 1,textureMinFilterModes,"MeshLab Texture Minification Filtering","MeshLab GLarea's BackGround Color(top corner)")); - defaultGlobalParamSet->addParam(RichEnum(textureMagFilterParam() , 1,textureMagFilterModes,"MeshLab Texture Magnification Filtering","MeshLab GLarea's BackGround Color(top corner)")); + defaultGlobalParamSet.addParam(RichEnum(textureMinFilterParam() , 1,textureMinFilterModes,"MeshLab Texture Minification Filtering","MeshLab GLarea's BackGround Color(top corner)")); + defaultGlobalParamSet.addParam(RichEnum(textureMagFilterParam() , 1,textureMagFilterModes,"MeshLab Texture Magnification Filtering","MeshLab GLarea's BackGround Color(top corner)")); - defaultGlobalParamSet->addParam(RichBool(pointDistanceAttenuationParam() , true,"Perspective Varying Point Size","If true the size of the points is drawn with a size proprtional to the distance from the observer.")); - defaultGlobalParamSet->addParam(RichBool(pointSmoothParam() , false,"Antialiased Point","If true the points are drawn with small circles instead of fast squared dots.")); - defaultGlobalParamSet->addParam(RichFloat(pointSizeParam() , 2.0, "Point Size","The base size of points when drawn")); + defaultGlobalParamSet.addParam(RichBool(pointDistanceAttenuationParam() , true,"Perspective Varying Point Size","If true the size of the points is drawn with a size proprtional to the distance from the observer.")); + defaultGlobalParamSet.addParam(RichBool(pointSmoothParam() , false,"Antialiased Point","If true the points are drawn with small circles instead of fast squared dots.")); + defaultGlobalParamSet.addParam(RichFloat(pointSizeParam() , 2.0, "Point Size","The base size of points when drawn")); - defaultGlobalParamSet->addParam(RichBool(wheelDirectionParam(), false, "Wheel Direction", "If true, inverts the direction of the mouse wheel for zooming in/out in the MeshLab canvas.")); + defaultGlobalParamSet.addParam(RichBool(wheelDirectionParam(), false, "Wheel Direction", "If true, inverts the direction of the mouse wheel for zooming in/out in the MeshLab canvas.")); } diff --git a/src/meshlab/glarea_setting.h b/src/meshlab/glarea_setting.h index 0372db6bb..eb88b555d 100644 --- a/src/meshlab/glarea_setting.h +++ b/src/meshlab/glarea_setting.h @@ -71,7 +71,7 @@ public: void updateGlobalParameterSet(const RichParameterList& rps ); - static void initGlobalParameterList( RichParameterList * defaultGlobalParamSet); + static void initGlobalParameterList(RichParameterList& defaultGlobalParamSet); const RichParameterList *currentGlobalParamSet; }; diff --git a/src/meshlab/layerDialog.cpp b/src/meshlab/layerDialog.cpp index 2fee5cd83..252b61038 100644 --- a/src/meshlab/layerDialog.cpp +++ b/src/meshlab/layerDialog.cpp @@ -223,7 +223,7 @@ void LayerDialog::clickV1() if (isRecording) { visibilityState[0].clear(); - foreach(MeshModel *mp, md->meshList) + for(MeshModel *mp : md->meshIterator()) { visibilityState[0].insert(mp->id(), mp->isVisible()); } @@ -253,7 +253,7 @@ void LayerDialog::clickV2() if (isRecording) { visibilityState[1].clear(); - foreach(MeshModel *mp, md->meshList) + for(MeshModel *mp : md->meshIterator()) { visibilityState[1].insert(mp->id(), mp->isVisible()); } @@ -283,7 +283,7 @@ void LayerDialog::clickV3() if (isRecording) { visibilityState[2].clear(); - foreach(MeshModel *mp, md->meshList) + for(MeshModel *mp : md->meshIterator()) { visibilityState[2].insert(mp->id(), mp->isVisible()); } @@ -313,7 +313,7 @@ void LayerDialog::clickV4() if (isRecording) { visibilityState[3].clear(); - foreach(MeshModel *mp, md->meshList) + for(MeshModel *mp : md->meshIterator()) { visibilityState[3].insert(mp->id(), mp->isVisible()); } @@ -375,7 +375,7 @@ void LayerDialog::meshItemClicked (QTreeWidgetItem * item , int col) // Very useful for comparing meshes if(QApplication::keyboardModifiers() == Qt::ControlModifier) { - foreach(MeshModel *mp, md->meshList) + for(MeshModel *mp : md->meshIterator()) mw->GLA()->meshSetVisibility(mp, false); } @@ -389,7 +389,7 @@ void LayerDialog::meshItemClicked (QTreeWidgetItem * item , int col) // clicking on all of them... if(QApplication::keyboardModifiers() == Qt::AltModifier) { - foreach(MeshModel *mp, md->meshList) + for(MeshModel *mp : md->meshIterator()) { mw->GLA()->meshSetVisibility(mp, true); } @@ -397,7 +397,7 @@ void LayerDialog::meshItemClicked (QTreeWidgetItem * item , int col) if(QApplication::keyboardModifiers() == Qt::ShiftModifier) { - foreach(MeshModel *mp, md->meshList) + for(MeshModel *mp : md->meshIterator()) { mw->GLA()->meshSetVisibility(mp, !mp->visible); } @@ -457,7 +457,7 @@ void LayerDialog::rasterItemClicked (QTreeWidgetItem * item , int col) // if(QApplication::keyboardModifiers() == Qt::ControlModifier) { - foreach(RasterModel *rp, md->rasterList) + for(RasterModel *rp: md->rasterIterator()) { rp->visible = false; } @@ -476,7 +476,7 @@ void LayerDialog::rasterItemClicked (QTreeWidgetItem * item , int col) // clicking on all of them... if(QApplication::keyboardModifiers() == Qt::AltModifier) { - foreach(RasterModel *rp, md->rasterList) + for(RasterModel *rp: md->rasterIterator()) { rp->visible = true; } @@ -484,7 +484,7 @@ void LayerDialog::rasterItemClicked (QTreeWidgetItem * item , int col) if(QApplication::keyboardModifiers() == Qt::ShiftModifier) { - foreach(RasterModel *rp, md->rasterList) + for(RasterModel *rp: md->rasterIterator()) { rp->visible = !rp->visible; } @@ -657,7 +657,7 @@ void LayerDialog::updateTable(const MLSceneGLSharedDataContext::PerMeshRendering updateProjectName(md->docLabel()); QList itms; - for (MeshModel* mmd : md->meshList) + for (MeshModel* mmd : md->meshIterator()) { //Restore mesh visibility according to the current visibility map //very good to keep viewer state consistent @@ -712,7 +712,7 @@ void LayerDialog::updateTable(const MLSceneGLSharedDataContext::PerMeshRendering //} //tabsrelatedtodeletedmeshes.clear(); - if (md->rasterList.size() > 0) + if (md->rasterNumber() > 0) ui->rasterTreeWidget->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding); else ui->rasterTreeWidget->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Ignored); @@ -723,7 +723,7 @@ void LayerDialog::updateTable(const MLSceneGLSharedDataContext::PerMeshRendering //TODO The fourth column is fake... solo per ora, E' per evitare che l'ultimacolonna si allunghi indefinitivamente //mettere una lunghezza fissa e' inutile perche' non so quanto e' lungo il nome. ui->rasterTreeWidget->header()->hide(); - foreach(RasterModel* rmd, md->rasterList) + for(RasterModel* rmd: md->rasterIterator()) { //Restore raster visibility according to the current visibility map //very good to keep viewer state consistent @@ -958,7 +958,7 @@ void LayerDialog::updatePerMeshItemSelectionStatus() } } } - if (md->meshList.size() == 0) + if (md->meshNumber() == 0) _renderingtabcontainer->setTitle(QString()); } @@ -1110,7 +1110,7 @@ void LayerDialog::updatePerMeshItemVisibility() } } - if ((!md->meshList.isEmpty()) && allhidden) + if ((!(md->meshNumber() == 0)) && allhidden) _docitem->setIcon(0,QIcon(":/images/layer_eye_close.png")); else _docitem->setIcon(0,QIcon(":/images/layer_eye_open.png")); diff --git a/src/meshlab/mainwindow.h b/src/meshlab/mainwindow.h index d860b778f..760ed7664 100644 --- a/src/meshlab/mainwindow.h +++ b/src/meshlab/mainwindow.h @@ -29,7 +29,6 @@ #include -#include "common/mainwindow_interface.h" #include "common/plugins/plugin_manager.h" #include @@ -67,7 +66,7 @@ class QToolBar; class MainWindowSetting { public: - static void initGlobalParameterList(RichParameterList* gbllist); + static void initGlobalParameterList(RichParameterList& gbllist); void updateGlobalParameterList(const RichParameterList& rpl ); std::ptrdiff_t maxgpumem; @@ -83,13 +82,16 @@ public: inline static QString perBatchPrimitives() {return "MeshLab::System::perBatchPrimitives";} size_t minpolygonpersmoothrendering; - inline static QString minPolygonNumberPerSmoothRendering() { return "MeshLab::System::minPolygonNumberPerSmoothRendering"; } + inline static QString minFaceNumberPerSmoothRendering() { return "MeshLab::System::minFaceNumberPerSmoothRendering"; } std::ptrdiff_t maxTextureMemory; inline static QString maxTextureMemoryParam() {return "MeshLab::System::maxTextureMemory";} + + bool showPreOpenParameterDialog; + inline static QString showPreOpenParameterDialogParam() {return "MeshLab::System::showPreOpenParameterDialog";} }; -class MainWindow : public QMainWindow, public MainWindowInterface +class MainWindow : public QMainWindow { Q_OBJECT @@ -122,7 +124,7 @@ private slots: public slots: bool importMeshWithLayerManagement(QString fileName=QString()); bool importRaster(const QString& fileImg = QString()); - bool openProject(QString fileName=QString()); + bool openProject(QString fileName=QString(), bool append = false); bool appendProject(QString fileName=QString()); void updateCustomSettings(); void updateLayerDialog(); @@ -150,7 +152,7 @@ private slots: public: bool exportMesh(QString fileName,MeshModel* mod,const bool saveAllPossibleAttributes); - bool loadMesh(const QString& fileName,IOPlugin *pCurrentIOPlugin, const std::list& meshList, std::list& maskList,RichParameterList* prePar,const Matrix44m &mtr=Matrix44m::Identity(), bool isareload = false, MLRenderingData* rendOpt = NULL); + bool loadMesh(const QString& fileName, IOPlugin *pCurrentIOPlugin, const std::list& meshList, std::list& maskList, const RichParameterList& prePar, const Matrix44m &mtr=Matrix44m::Identity(), bool isareload = false, MLRenderingData* rendOpt = NULL); void computeRenderingDataOnLoading(MeshModel* mm,bool isareload, MLRenderingData* rendOpt = NULL); @@ -264,6 +266,7 @@ private: void clearMenu(QMenu* menu); void updateAllPluginsActions(); void createToolBars(); + void loadDefaultSettingsFromPlugins(); void loadMeshLabSettings(); void keyPressEvent(QKeyEvent *); void updateRecentFileActions(); diff --git a/src/meshlab/mainwindow_Init.cpp b/src/meshlab/mainwindow_Init.cpp index 26eed1155..489b67bd5 100644 --- a/src/meshlab/mainwindow_Init.cpp +++ b/src/meshlab/mainwindow_Init.cpp @@ -85,7 +85,7 @@ MainWindow::MainWindow(): catch (const MLException& e) { QMessageBox::warning(this, "Error while loading plugins.", e.what()); } - + //disable previously disabled plugins QStringList disabledPlugins = settings.value("DisabledPlugins").value(); for (MeshLabPlugin* fp : PM.pluginIterator(true)){ @@ -115,7 +115,11 @@ MainWindow::MainWindow(): settings.setValue(MeshLabApplication::versionRegisterKeyName(), MeshLabApplication::appVer()); settings.setValue(MeshLabApplication::wordSizeKeyName(), QSysInfo::WordSize); } - // Now load from the registry the settings and merge the hardwired values got from the PM.loadPlugins with the ones found in the registry. + + //load default params from plugins + loadDefaultSettingsFromPlugins(); + // Now load from the registry the settings and merge the hardwired values + // got from the PM.loadPlugins with the ones found in the registry. loadMeshLabSettings(); mwsettings.updateGlobalParameterList(currentGlobalParams); createActions(); @@ -951,14 +955,40 @@ void MainWindow::updateAllPluginsActions() */ } +void MainWindow::loadDefaultSettingsFromPlugins() +{ + //decorate settings + for (DecoratePlugin* dp : PM.decoratePluginIterator()){ + for(QAction *decoratorAction : dp->actions()) { + dp->initGlobalParameterList(decoratorAction, defaultGlobalParams); + } + } + + //io settings + for (IOPlugin* iop : PM.ioPluginIterator()){ + for (const FileFormat& ff : iop->importFormats()) { + for (const QString& format : ff.extensions) { + RichParameterList tmplist = iop->initPreOpenParameter(format); + if (!tmplist.isEmpty()){ + for (RichParameter& rp : tmplist){ + QString prefixName = "MeshLab::IO::" + format.toUpper() + "::"; + rp.setName(prefixName + rp.name()); + } + defaultGlobalParams.join(tmplist); + } + } + } + } +} + void MainWindow::loadMeshLabSettings() { // I have already loaded the plugins so the default parameters for the settings // of the plugins are already in the . // we just miss the globals default of meshlab itself - MainWindowSetting::initGlobalParameterList(&defaultGlobalParams); - GLArea::initGlobalParameterList(&defaultGlobalParams); + MainWindowSetting::initGlobalParameterList(defaultGlobalParams); + GLArea::initGlobalParameterList(defaultGlobalParams); QSettings settings; QStringList klist = settings.allKeys(); @@ -978,12 +1008,14 @@ void MainWindow::loadMeshLabSettings() bool b = RichParameterAdapter::create(docElem, &rp); if (b && defaultGlobalParams.hasParameter(rp->name())) currentGlobalParams.pushFromQDomElement(docElem); + if (b) + delete rp; } } // 2) eventually fill missing values with the hardwired defaults for (const RichParameter& p : defaultGlobalParams) { - // qDebug("Searching param[%i] %s of the default into the loaded settings. ", ii, qUtf8Printable(defaultGlobalParams.paramList.at(ii)->name)); + // qDebug("Searching param[%i] %s of the default into the loaded settings. ", ii, qUtf8Printable(defaultGlobalParams.paramList.at(ii)->name)); if (!currentGlobalParams.hasParameter(p.name())) { //qDebug("Warning! a default param was not found in the saved settings. This should happen only on the first run..."); RichParameter& v = currentGlobalParams.addParam(p); @@ -1088,7 +1120,7 @@ void MainWindow::checkForUpdates(bool verboseFlag) if (settings.contains(checkForMonthlyAndBetasVar)) checkForMonthlyAndBetasVal = settings.value(checkForMonthlyAndBetasVar).toBool(); if (checkForMonthlyAndBetasVal){ - urlCheck = "https://github.com/cnr-isti-vclab/meshlab/blob/master/ML_VERSION"; + urlCheck = "https://raw.githubusercontent.com/cnr-isti-vclab/meshlab/master/ML_VERSION"; } int totalKV = settings.value("totalKV", 0).toInt(); int loadedMeshCounter = settings.value("loadedMeshCounter", 0).toInt(); @@ -1292,28 +1324,30 @@ int MainWindow::longestActionWidthInAllMenus() return longest; } -void MainWindowSetting::initGlobalParameterList(RichParameterList* gbllist) +void MainWindowSetting::initGlobalParameterList(RichParameterList& gbllist) { - gbllist->addParam(RichInt(maximumDedicatedGPUMem(), 350, "Maximum GPU Memory Dedicated to MeshLab (Mb)", "Maximum GPU Memory Dedicated to MeshLab (megabyte) for the storing of the geometry attributes. The dedicated memory must NOT be all the GPU memory presents on the videocard.")); - gbllist->addParam(RichInt(perBatchPrimitives(), 100000, "Per batch primitives loaded in GPU", "Per batch primitives (vertices and faces) loaded in the GPU memory. It's used in order to do not overwhelm the system memory with an entire temporary copy of a mesh.")); - gbllist->addParam(RichInt(minPolygonNumberPerSmoothRendering(), 50000, "Default Face number per smooth rendering", "Minimum number of faces in order to automatically render a newly created mesh layer with the per vertex normal attribute activated.")); + gbllist.addParam(RichInt(maximumDedicatedGPUMem(), 350, "Maximum GPU Memory Dedicated to MeshLab (Mb)", "Maximum GPU Memory Dedicated to MeshLab (megabyte) for the storing of the geometry attributes. The dedicated memory must NOT be all the GPU memory presents on the videocard.")); + gbllist.addParam(RichInt(perBatchPrimitives(), 100000, "Per batch primitives loaded in GPU", "Per batch primitives (vertices and faces) loaded in the GPU memory. It's used in order to do not overwhelm the system memory with an entire temporary copy of a mesh.")); + gbllist.addParam(RichInt(minFaceNumberPerSmoothRendering(), 5000000, "Default Face number per smooth rendering", "Minimum number of faces in order to automatically render a newly created mesh layer with the per vertex normal attribute activated.")); // glbset->addParam(RichBool(perMeshRenderingToolBar(), true, "Show Per-Mesh Rendering Side ToolBar", "If true the per-mesh rendering side toolbar will be redendered inside the layerdialog.")); if (MeshLabScalarTest::doublePrecision()) - gbllist->addParam(RichBool(highPrecisionRendering(), false, "High Precision Rendering", "If true all the models in the scene will be rendered at the center of the world")); - gbllist->addParam(RichInt(maxTextureMemoryParam(), 256, "Max Texture Memory (in MB)", "The maximum quantity of texture memory allowed to load mesh textures")); + gbllist.addParam(RichBool(highPrecisionRendering(), false, "High Precision Rendering", "If true all the models in the scene will be rendered at the center of the world")); + gbllist.addParam(RichInt(maxTextureMemoryParam(), 256, "Max Texture Memory (in MB)", "The maximum quantity of texture memory allowed to load mesh textures")); + gbllist.addParam(RichBool(showPreOpenParameterDialogParam(), false, "Show Open Parameter Dialog", "If true, each time that a mesh is imported, a dialog asking for extra parameters (if applicable), is shown.")); } void MainWindowSetting::updateGlobalParameterList(const RichParameterList& rpl) { maxgpumem = (std::ptrdiff_t)rpl.getInt(maximumDedicatedGPUMem()) * (float)(1024 * 1024); perbatchprimitives = (size_t)rpl.getInt(perBatchPrimitives()); - minpolygonpersmoothrendering = (size_t)rpl.getInt(minPolygonNumberPerSmoothRendering()); + minpolygonpersmoothrendering = (size_t)rpl.getInt(minFaceNumberPerSmoothRendering()); highprecision = false; if (MeshLabScalarTest::doublePrecision()) highprecision = rpl.getBool(highPrecisionRendering()); maxTextureMemory = (std::ptrdiff_t) rpl.getInt(this->maxTextureMemoryParam()) * (float)(1024 * 1024); + showPreOpenParameterDialog = rpl.getBool(showPreOpenParameterDialogParam()); } void MainWindow::defaultPerViewRenderingData(MLRenderingData& dt) const diff --git a/src/meshlab/mainwindow_RunTime.cpp b/src/meshlab/mainwindow_RunTime.cpp index 5242e8919..ce10552a6 100644 --- a/src/meshlab/mainwindow_RunTime.cpp +++ b/src/meshlab/mainwindow_RunTime.cpp @@ -24,7 +24,6 @@ #include "mainwindow.h" -#include "savemaskexporter.h" #include #include "ml_default_decorators.h" @@ -40,8 +39,6 @@ #include #include -#include -#include #include #include #include @@ -55,6 +52,7 @@ #include "dialogs/filter_script_dialog.h" #include "dialogs/options_dialog.h" #include "dialogs/plugin_info_dialog.h" +#include "dialogs/save_mesh_attributes_dialog.h" #include "dialogs/save_snapshot_dialog.h" using namespace std; @@ -345,7 +343,7 @@ void MainWindow::updateMenus() { bool activeDoc = !(mdiarea->subWindowList().empty()) && (mdiarea->currentSubWindow() != NULL); - bool notEmptyActiveDoc = activeDoc && (meshDoc() != NULL) && !(meshDoc()->meshList.empty()); + bool notEmptyActiveDoc = activeDoc && (meshDoc() != NULL) && !(meshDoc()->meshNumber() == 0); //std::cout << "SubWindowsList empty: " << mdiarea->subWindowList().empty() << " Valid Current Sub Windows: " << (mdiarea->currentSubWindow() != NULL) << " MeshList empty: " << meshDoc()->meshList.empty() << "\n"; @@ -715,27 +713,35 @@ void MainWindow::dropEvent ( QDropEvent * event ) { QList< QUrl > url_list = data->urls(); bool layervis = false; - if (layerDialog != NULL) - { + if (layerDialog != NULL) { layervis = layerDialog->isVisible(); showLayerDlg(false); } - for (int i=0, size=url_list.size(); ikeyboardModifiers () == Qt::ControlModifier ) || ( QApplication::keyboardModifiers () == Qt::ControlModifier )) - { + if( (event->keyboardModifiers () == Qt::ControlModifier ) || ( QApplication::keyboardModifiers () == Qt::ControlModifier )) { this->newProject(); } - - if(path.endsWith("mlp",Qt::CaseInsensitive) || path.endsWith("mlb", Qt::CaseInsensitive) || path.endsWith("aln",Qt::CaseInsensitive) || path.endsWith("out",Qt::CaseInsensitive) || path.endsWith("nvm",Qt::CaseInsensitive) ) + + QString extension = QFileInfo(path).suffix(); + if (PM.isInputProjectFormatSupported(extension)){ openProject(path); - else - { + } + else if (PM.isInputMeshFormatSupported(extension)){ importMesh(path); } + else if (PM.isInputImageFormatSupported(extension)){ + importRaster(path); + } + else { + QMessageBox::warning( + this, "File format not supported", + extension + " file format is not supported by MeshLab."); + } + + } - showLayerDlg(layervis || meshDoc()->meshList.size() > 0); + showLayerDlg(layervis || meshDoc()->meshNumber() > 0); } } @@ -746,9 +752,8 @@ void MainWindow::endEdit() return; - for (int ii = 0; ii < meshDoc()->meshList.size(); ++ii) + for (MeshModel* mm : meshDoc()->meshIterator()) { - MeshModel* mm = meshDoc()->meshList[ii]; if (mm != NULL) addRenderingDataIfNewlyGeneratedMesh(mm->id()); } @@ -798,22 +803,6 @@ void MainWindow::runFilterScript() iFilter->setLog(&meshDoc()->Log); RichParameterList ¶meterSet = pair.second; - for(RichParameter& parameter : parameterSet) { - //if this is a mesh parameter and the index is valid - if(parameter.value().isMesh()) { - RichMesh& md = reinterpret_cast(parameter); - if( md.meshindex < meshDoc()->size() && md.meshindex >= 0 ) { - parameterSet.setValue(md.name(), MeshValue(meshDoc(), md.meshindex)); - } - else { - printf("Meshes loaded: %i, meshes asked for: %i \n", meshDoc()->size(), md.meshindex ); - printf("One of the filters in the script needs more meshes than you have loaded.\n"); - return; - } - } - } - //iFilter->applyFilter( action, *(meshDoc()->mm()), (*ii).second, QCallBack ); - bool created = false; MLSceneGLSharedDataContext* shar = NULL; if (currentViewContainer() != NULL) @@ -842,9 +831,8 @@ void MainWindow::runFilterScript() } else { - for(int ii = 0;ii < meshDoc()->meshList.size();++ii) + for(MeshModel* mm : meshDoc()->meshIterator()) { - MeshModel* mm = meshDoc()->meshList[ii]; MLRenderingData::PRIMITIVE_MODALITY pm = MLPoliciesStandAloneFunctions::bestPrimitiveModalityAccordingToMesh(mm); if ((pm != MLRenderingData::PR_ARITY) && (mm != NULL)) { @@ -1014,53 +1002,47 @@ void MainWindow::updateSharedContextDataAfterFilterExecution(int postcondmask,in //Just to be sure that the filter author didn't forget to add changing tags to the postCondition field if ((mm->hasDataMask(MeshModel::MM_FACECOLOR)) && (fclasses & FilterPlugin::FaceColoring )) postcondmask = postcondmask | MeshModel::MM_FACECOLOR; - + if ((mm->hasDataMask(MeshModel::MM_VERTCOLOR)) && (fclasses & FilterPlugin::VertexColoring )) postcondmask = postcondmask | MeshModel::MM_VERTCOLOR; - + if ((mm->hasDataMask(MeshModel::MM_COLOR)) && (fclasses & FilterPlugin::MeshColoring )) postcondmask = postcondmask | MeshModel::MM_COLOR; - + if ((mm->hasDataMask(MeshModel::MM_FACEQUALITY)) && (fclasses & FilterPlugin::Quality )) postcondmask = postcondmask | MeshModel::MM_FACEQUALITY; - + if ((mm->hasDataMask(MeshModel::MM_VERTQUALITY)) && (fclasses & FilterPlugin::Quality )) postcondmask = postcondmask | MeshModel::MM_VERTQUALITY; - + MLRenderingData dttoberendered; QMap::Iterator existit = meshDoc()->meshDocStateData().find(mm->id()); if (existit != meshDoc()->meshDocStateData().end()) { - shared->getRenderInfoPerMeshView(mm->id(),GLA()->context(),dttoberendered); - int updatemask = MeshModel::MM_NONE; + + //masks differences bitwise operator (^) -> remove the attributes that didn't apparently change + the ones that for sure changed according to the postCondition function + //this operation has been introduced in order to minimize problems with filters that didn't declared properly the postCondition mask + int updatemask = (existit->_mask ^ mm->dataMask()) | postcondmask; bool connectivitychanged = false; if (((unsigned int)mm->cm.VN() != existit->_nvert) || ((unsigned int)mm->cm.FN() != existit->_nface) || bool(postcondmask & MeshModel::MM_UNKNOWN) || bool(postcondmask & MeshModel::MM_VERTNUMBER) || bool(postcondmask & MeshModel::MM_FACENUMBER) || bool(postcondmask & MeshModel::MM_FACEVERT) || bool(postcondmask & MeshModel::MM_VERTFACETOPO) || bool(postcondmask & MeshModel::MM_FACEFACETOPO)) { - updatemask = MeshModel::MM_ALL; connectivitychanged = true; } - else - { - //masks differences bitwise operator (^) -> remove the attributes that didn't apparently change + the ones that for sure changed according to the postCondition function - //this operation has been introduced in order to minimize problems with filters that didn't declared properly the postCondition mask - updatemask = (existit->_mask ^ mm->dataMask()) | postcondmask; - connectivitychanged = false; - } - + MLRenderingData::RendAtts dttoupdate; //1) we convert the meshmodel updating mask to a RendAtts structure MLPoliciesStandAloneFunctions::fromMeshModelMaskToMLRenderingAtts(updatemask,dttoupdate); //2) The correspondent bos to the updated rendering attributes are set to invalid shared->meshAttributesUpdated(mm->id(),connectivitychanged,dttoupdate); - + //3) we took the current rendering modality for the mesh in the active gla MLRenderingData curr; shared->getRenderInfoPerMeshView(mm->id(),GLA()->context(),curr); - + //4) we add to the current rendering modality in the current GLArea just the minimum attributes having been updated // WARNING!!!! There are priority policies // ex1) suppose that the current rendering modality is PR_POINTS and ATT_VERTPOSITION, ATT_VERTNORMAL,ATT_VERTCOLOR @@ -1075,8 +1057,7 @@ void MainWindow::updateSharedContextDataAfterFilterExecution(int postcondmask,in bool wasprimitivemodalitymeaningful = MLPoliciesStandAloneFunctions::isPrimitiveModalityCompatibleWithMeshInfo((existit->_nvert > 0),(existit->_nface > 0),(existit->_nedge > 0),existit->_mask,pm); bool isprimitivemodalitymeaningful = MLPoliciesStandAloneFunctions::isPrimitiveModalityCompatibleWithMesh(mm,pm); bool isworthtobevisualized = MLPoliciesStandAloneFunctions::isPrimitiveModalityWorthToBeActivated(pm,curr.isPrimitiveActive(pm),wasprimitivemodalitymeaningful,isprimitivemodalitymeaningful); - - + MLRenderingData::RendAtts rd; curr.get(pm, rd); MLPoliciesStandAloneFunctions::updatedRendAttsAccordingToPriorities(pm, dttoupdate, rd, rd); @@ -1092,7 +1073,7 @@ void MainWindow::updateSharedContextDataAfterFilterExecution(int postcondmask,in opts._perpoint_mesh_color_enabled = hasmeshcolor; opts._perwire_mesh_color_enabled = hasmeshcolor; opts._persolid_mesh_color_enabled = hasmeshcolor; - + for (MLRenderingData::PRIMITIVE_MODALITY pm = MLRenderingData::PRIMITIVE_MODALITY(0); pm < MLRenderingData::PR_ARITY; pm = MLRenderingData::next(pm)) { MLRenderingData::RendAtts atts; @@ -1105,7 +1086,7 @@ void MainWindow::updateSharedContextDataAfterFilterExecution(int postcondmask,in } MLPoliciesStandAloneFunctions::setPerViewGLOptionsAccordindToWireModality(mm, curr); MLPoliciesStandAloneFunctions::setPerViewGLOptionsPriorities(curr); - + if (mm == meshDoc()->mm()) { /*HORRIBLE TRICK IN ORDER TO HAVE VALID ACTIONS ASSOCIATED WITH THE CURRENT WIRE RENDERING MODALITY*/ @@ -1115,8 +1096,7 @@ void MainWindow::updateSharedContextDataAfterFilterExecution(int postcondmask,in delete fauxaction; /****************************************************************************************************/ } - - + shared->setRenderingDataPerMeshView(mm->id(),GLA()->context(),curr); } else @@ -1133,6 +1113,8 @@ void MainWindow::updateSharedContextDataAfterFilterExecution(int postcondmask,in delete fauxaction; /****************************************************************************************************/ } + if (!mm->cm.textures.empty()) + updateTexture(mm->id()); foreach(GLArea* gla,mvc->viewerList) { if (gla != NULL) @@ -1166,7 +1148,7 @@ void MainWindow::executeFilter(const QAction* action, RichParameterList ¶ms, qApp->setOverrideCursor(QCursor(Qt::WaitCursor)); MainWindow::globalStatusBar()->showMessage("Starting Filter...",5000); int req=iFilter->getRequirements(action); - if (!meshDoc()->meshList.isEmpty()) + if (!(meshDoc()->meshNumber() == 0)) meshDoc()->mm()->updateDataMask(req); qApp->restoreOverrideCursor(); @@ -1209,9 +1191,8 @@ void MainWindow::executeFilter(const QAction* action, RichParameterList ¶ms, } else { - for(int ii = 0;ii < meshDoc()->meshList.size();++ii) + for(MeshModel* mm : meshDoc()->meshIterator()) { - MeshModel* mm = meshDoc()->meshList[ii]; MLRenderingData::PRIMITIVE_MODALITY pm = MLPoliciesStandAloneFunctions::bestPrimitiveModalityAccordingToMesh(mm); if ((pm != MLRenderingData::PR_ARITY) && (mm != NULL)) { @@ -1273,7 +1254,7 @@ void MainWindow::executeFilter(const QAction* action, RichParameterList ¶ms, { if (p.value().isMesh()) { - MeshModel* mm = p.value().getMesh(); + MeshModel* mm = meshDoc()->getMesh(p.value().getMeshId()); if (mm != NULL) tmp.push_back(mm); } @@ -1346,7 +1327,7 @@ void MainWindow::executeFilter(const QAction* action, RichParameterList ¶ms, } qb->reset(); - layerDialog->setVisible(layerDialog->isVisible() || ((newmeshcreated) && (meshDoc()->size() > 0))); + layerDialog->setVisible(layerDialog->isVisible() || ((newmeshcreated) && (meshDoc()->meshNumber() > 0))); updateLayerDialog(); updateMenus(); MultiViewer_Container* mvc = currentViewContainer(); @@ -1588,243 +1569,190 @@ void MainWindow::saveProject() { if (meshDoc() == NULL) return; - //if a mesh has been created by a create filter we must before to save it. Otherwise the project will refer to a mesh without file name path. - foreach(MeshModel * mp, meshDoc()->meshList) - { - if ((mp != NULL) && (mp->fullName().isEmpty())) - { - bool saved = exportMesh(tr(""),mp,false); - if (!saved) - { - QString msg = "Mesh layer " + mp->label() + " cannot be saved on a file.\nProject \"" + meshDoc()->docLabel() + "\" saving has been aborted."; - QMessageBox::warning(this,tr("Project Saving Aborted"),msg); - return; - } - } - } - QFileDialog* saveDiag = new QFileDialog(this,tr("Save Project File"),lastUsedDirectory.path().append(""), tr("MeshLab Project (*.mlp);;MeshLab Binary Project (*.mlb);;Align Project (*.aln)")); -#if defined(Q_OS_WIN) + + QFileDialog* saveDiag = new QFileDialog( + this, + tr("Save Project File"), + lastUsedDirectory.path().append("")); + saveDiag->setNameFilters(PM.outputProjectFormatListDialog()); saveDiag->setOption(QFileDialog::DontUseNativeDialog); -#endif - QCheckBox* saveAllFile = new QCheckBox(QString("Save All Files"),saveDiag); - saveAllFile->setCheckState(Qt::Unchecked); - QCheckBox* onlyVisibleLayers = new QCheckBox(QString("Only Visible Layers"),saveDiag); - onlyVisibleLayers->setCheckState(Qt::Unchecked); - QCheckBox* saveViewState = new QCheckBox(QString("Save View State"), saveDiag); - saveViewState->setCheckState(Qt::Checked); + QCheckBox* saveAllFilesCheckBox = new QCheckBox(QString("Save All Files"),saveDiag); + saveAllFilesCheckBox->setCheckState(Qt::Unchecked); + QCheckBox* onlyVisibleLayersCheckBox = new QCheckBox(QString("Only Visible Layers"),saveDiag); + onlyVisibleLayersCheckBox->setCheckState(Qt::Unchecked); + QCheckBox* saveViewStateCheckBox = new QCheckBox(QString("Save View State"), saveDiag); + saveViewStateCheckBox->setCheckState(Qt::Checked); QGridLayout* layout = qobject_cast(saveDiag->layout()); - if (layout != NULL) - { - layout->addWidget(onlyVisibleLayers, 4, 0); - layout->addWidget(saveViewState, 4, 1); - layout->addWidget(saveAllFile, 4, 2); + if (layout != NULL) { + layout->addWidget(onlyVisibleLayersCheckBox, 4, 0); + layout->addWidget(saveViewStateCheckBox, 4, 1); + layout->addWidget(saveAllFilesCheckBox, 4, 2); } saveDiag->setAcceptMode(QFileDialog::AcceptSave); - saveDiag->exec(); - QStringList files = saveDiag->selectedFiles(); - if (files.size() != 1) - return; - QString fileName = files[0]; - // this change of dir is needed for subsequent textures/materials loading - QFileInfo fi(fileName); - if (fi.isDir()) - return; - if (fi.suffix().isEmpty()) - { - QRegExp reg("\\.\\w+"); - saveDiag->selectedNameFilter().indexOf(reg); - QString ext = reg.cap(); - fileName.append(ext); - fi.setFile(fileName); - } - QDir::setCurrent(fi.absoluteDir().absolutePath()); + int res = saveDiag->exec(); + + if (res == QFileDialog::AcceptSave){ + if (!saveAllFilesCheckBox->isChecked()){ + bool firstNotSaved = true; + //if a mesh has been created by a create filter we must before to save it. + //Otherwise the project will refer to a mesh without file name path. + for(MeshModel * mp : meshDoc()->meshIterator()) { + if ((mp != nullptr) && (mp->fullName().isEmpty())) { + if (firstNotSaved) { + QMessageBox::information(this, "Layer(s) not saved", + "Layers must be saved into files before saving the project.\n" + "Opening save dialog(s) to save the layer(s)..."); + firstNotSaved = false; + } + bool saved = exportMesh(tr(""), mp, false); + if (!saved) { + QString msg = "Mesh layer " + mp->label() + " cannot be saved on a file.\nProject \"" + meshDoc()->docLabel() + "\" saving has been aborted."; + QMessageBox::warning(this,tr("Project Saving Aborted"),msg); + return; + } + } + } + } + + QString fileName = saveDiag->selectedFiles().first(); + // this change of dir is needed for subsequent textures/materials loading + QFileInfo fi(fileName); + if (fi.suffix().isEmpty()) { + QRegExp reg("\\.\\w+"); + saveDiag->selectedNameFilter().indexOf(reg); + QString ext = reg.cap(); + fileName.append(ext); + fi.setFile(fileName); + } + QDir::setCurrent(fi.absoluteDir().absolutePath()); - /*********WARNING!!!!!! CHANGE IT!!! ALSO IN THE OPENPROJECT FUNCTION********/ - meshDoc()->setDocLabel(fileName); - QMdiSubWindow* sub = mdiarea->currentSubWindow(); - if (sub != NULL) - { - sub->setWindowTitle(meshDoc()->docLabel()); - layerDialog->setWindowTitle(meshDoc()->docLabel()); - } - /****************************************************************************/ - - - bool ret; - qDebug("Saving aln file %s\n", qUtf8Printable(fileName)); - if (fileName.isEmpty()) return; - else - { //save path away so we can use it again QString path = fileName; path.truncate(path.lastIndexOf("/")); lastUsedDirectory.setPath(path); - } - if (QString(fi.suffix()).toLower() == "aln") - { - vector meshNameVector; - vector transfVector; - - foreach(MeshModel * mp, meshDoc()->meshList) - { - if((!onlyVisibleLayers->isChecked()) || (mp->visible)) - { - meshNameVector.push_back(qUtf8Printable(mp->relativePathName())); - transfVector.push_back(mp->cm.Tr); - } - } - ret = ALNParser::SaveALN(qUtf8Printable(fileName), meshNameVector, transfVector); - } - else - { - std::map rendOpt; - foreach(MeshModel * mp, meshDoc()->meshList) - { + + std::vector rendData; + for(MeshModel * mp : meshDoc()->meshIterator()) { MLRenderingData ml; getRenderingData(mp->id(), ml); - rendOpt.insert(std::pair(mp->id(), ml)); + rendData.push_back(ml); } - ret = MeshDocumentToXMLFile(*meshDoc(), fileName, onlyVisibleLayers->isChecked(), saveViewState->isChecked(), QString(fi.suffix()).toLower() == "mlb", rendOpt); - } - - if (saveAllFile->isChecked()) - { - for(int ii = 0; ii < meshDoc()->meshList.size();++ii) - { - MeshModel* mp = meshDoc()->meshList[ii]; - if((!onlyVisibleLayers->isChecked()) || (mp->visible)) - { - ret |= exportMesh(mp->fullName(),mp,true); + + try { + if (saveAllFilesCheckBox->isChecked()) { + meshlab::saveAllMeshes(path, *meshDoc(), onlyVisibleLayersCheckBox->isChecked()); } + meshlab::saveProject(fileName, *meshDoc(), onlyVisibleLayersCheckBox->isChecked(), rendData); + /*********WARNING!!!!!! CHANGE IT!!! ALSO IN THE OPENPROJECT FUNCTION********/ + meshDoc()->setDocLabel(fileName); + QMdiSubWindow* sub = mdiarea->currentSubWindow(); + if (sub != nullptr) { + sub->setWindowTitle(meshDoc()->docLabel()); + layerDialog->setWindowTitle(meshDoc()->docLabel()); + } + /****************************************************************************/ + } + catch (const MLException& e) { + QMessageBox::critical( + this, "Meshlab Saving Error", + "Unable to save project file " + fileName + "\nDetails:\n" + e.what()); } } - if(!ret) - QMessageBox::critical(this, tr("Meshlab Saving Error"), QString("Unable to save project file %1\n").arg(fileName)); } -bool MainWindow::openProject(QString fileName) +bool MainWindow::openProject(QString fileName, bool append) { bool visiblelayer = layerDialog->isVisible(); - //showLayerDlg(false); globrendtoolbar->setEnabled(false); + if (fileName.isEmpty()) - fileName = QFileDialog::getOpenFileName(this,tr("Open Project File"), lastUsedDirectory.path(), tr("All Project Files (*.mlp *.mlb *.aln *.out *.nvm);;MeshLab Project (*.mlp);;MeshLab Binary Project (*.mlb);;Align Project (*.aln);;Bundler Output (*.out);;VisualSFM Output (*.nvm)")); - - if (fileName.isEmpty()) return false; - + fileName = + QFileDialog::getOpenFileName( + this, tr("Open Project File"), + lastUsedDirectory.path(), PM.inputProjectFormatListDialog().join(";;")); + + if (fileName.isEmpty()) + return false; + QFileInfo fi(fileName); lastUsedDirectory = fi.absoluteDir(); - if((fi.suffix().toLower()!="aln") && (fi.suffix().toLower()!="mlp") && (fi.suffix().toLower() != "mlb") && (fi.suffix().toLower()!="out") && (fi.suffix().toLower()!="nvm")) - { - QMessageBox::critical(this, tr("Meshlab Opening Error"), "Unknown project file extension"); + + QString extension = fi.suffix(); + PluginManager& pm = meshlab::pluginManagerInstance(); + IOPlugin *ioPlugin = pm.inputProjectPlugin(extension); + + if (ioPlugin == nullptr) { + QMessageBox::critical(this, tr("Meshlab Opening Error"), + "Project " + fileName + " cannot be loaded. Your MeshLab version " + "has not plugin to load " + extension + " file format."); return false; } - + + std::list additionalFilesFormats = + ioPlugin->projectFileRequiresAdditionalFiles( + extension, fileName); + + QStringList filenames; + filenames.push_front(fileName); + for (const FileFormat& ff : additionalFilesFormats){ + QString currentFilterEntry = ff.description + " ("; + for (QString currentExtension : ff.extensions) { + currentExtension = currentExtension.toLower(); + currentFilterEntry.append(QObject::tr(" *.")); + currentFilterEntry.append(currentExtension); + } + currentFilterEntry.append(')'); + QString additionalFile = + QFileDialog::getOpenFileName( + this, tr("Open Additional Project File"), + lastUsedDirectory.path(), currentFilterEntry); + if (!additionalFile.isEmpty()) + filenames.push_back(additionalFile); + else + return false; + } + // Common Part: init a Doc if necessary, and bool activeDoc = (bool) !mdiarea->subWindowList().empty() && mdiarea->currentSubWindow(); - bool activeEmpty = activeDoc && meshDoc()->meshList.empty(); - - if (!activeEmpty) newProject(fileName); - - meshDoc()->setFileName(fileName); + bool activeEmpty = activeDoc && ((meshDoc()->meshNumber() == 0)); + + if (!activeEmpty && !append) + newProject(fileName); + mdiarea->currentSubWindow()->setWindowTitle(fileName); + + meshDoc()->setFileName(fileName); meshDoc()->setDocLabel(fileName); - + meshDoc()->setBusy(true); - + // this change of dir is needed for subsequent textures/materials loading QDir::setCurrent(fi.absoluteDir().absolutePath()); qb->show(); - - if (QString(fi.suffix()).toLower() == "aln") - { - vector rmv; - int retVal = ALNParser::ParseALN(rmv, qUtf8Printable(fileName)); - if(retVal != ALNParser::NoError) { - QMessageBox::critical(this, tr("Meshlab Opening Error"), "Unable to open ALN file"); - return false; - } - - for(const RangeMap& rm : rmv) { - QString relativeToProj = fi.absoluteDir().absolutePath() + "/" + rm.filename.c_str(); - try { - meshlab::loadMeshWithStandardParameters(relativeToProj, *meshDoc(), QCallBack); - meshDoc()->mm()->cm.Tr.Import(rm.transformation); - computeRenderingDataOnLoading(meshDoc()->mm(), false, nullptr); - if (!(meshDoc()->mm()->cm.textures.empty())) - updateTexture(meshDoc()->mm()->id()); - } - catch (const MLException& e){ - QMessageBox::critical(this, "Meshlab Opening Error", e.what()); - } - } + + std::vector meshList; + std::vector rendOptions; + try { + meshList = meshlab::loadProject(filenames, ioPlugin, *meshDoc(), rendOptions, &meshDoc()->Log, QCallBack); } - - if (QString(fi.suffix()).toLower() == "mlp" || QString(fi.suffix()).toLower() == "mlb") - { - std::map rendOpt; - if (!MeshDocumentFromXML(*meshDoc(), fileName, (QString(fi.suffix()).toLower() == "mlb"), rendOpt)) - { - QMessageBox::critical(this, tr("Meshlab Opening Error"), "Unable to open MeshLab Project file"); - return false; - } - GLA()->updateMeshSetVisibilities(); - for (int i=0; imeshList.size(); i++) - { - QString fullPath = meshDoc()->meshList[i]->fullName(); - //meshDoc()->setBusy(true); - Matrix44m trm = this->meshDoc()->meshList[i]->cm.Tr; // save the matrix, because loadMeshClear it... - MLRenderingData* ptr = NULL; - if (rendOpt.find(meshDoc()->meshList[i]->id()) != rendOpt.end()) - ptr = &rendOpt[meshDoc()->meshList[i]->id()]; - if (!loadMeshWithStandardParams(fullPath, this->meshDoc()->meshList[i], trm, false, ptr)) - meshDoc()->delMesh(meshDoc()->meshList[i]); - } + catch (const MLException& e) { + QMessageBox::critical(this, tr("Meshlab Opening Error"), e.what()); + return false; } - - ////// BUNDLER - if (QString(fi.suffix()).toLower() == "out"){ - - QString cameras_filename = fileName; - QString image_list_filename; - QString model_filename; - - image_list_filename = QFileDialog::getOpenFileName( - this, - tr("Open image list file"), - QFileInfo(fileName).absolutePath(), - tr("Bundler images list file (*.txt)")); - if(image_list_filename.isEmpty()) - return false; - - if(!MeshDocumentFromBundler(*meshDoc(),cameras_filename,image_list_filename,model_filename)){ - QMessageBox::critical(this, tr("Meshlab Opening Error"), "Unable to open OUTs file"); - return false; - } - - - //WARNING!!!!! i suppose it's not useful anymore but....... - /*GLA()->setColorMode(GLW::CMPerVert); -GLA()->setDrawMode(GLW::DMPoints);*/ - ///////////////////////////////////////////////////////// + QString warningString = ioPlugin->warningMessageString(); + if (!warningString.isEmpty()){ + QMessageBox::warning(this, "Warning", warningString); } - - //////NVM - if (QString(fi.suffix()).toLower() == "nvm"){ - - QString cameras_filename = fileName; - QString model_filename; - - if(!MeshDocumentFromNvm(*meshDoc(),cameras_filename,model_filename)){ - QMessageBox::critical(this, tr("Meshlab Opening Error"), "Unable to open NVMs file"); - return false; - } - //WARNING!!!!! i suppose it's not useful anymore but....... - /*GLA()->setColorMode(GLW::CMPerVert); -GLA()->setDrawMode(GLW::DMPoints);*/ - ///////////////////////////////////////////////////////// + + for (unsigned int i = 0; i < meshList.size(); i++){ + MLRenderingData* ptr = nullptr; + if (rendOptions.size() == meshList.size()) + ptr = &rendOptions[i]; + computeRenderingDataOnLoading(meshList[i], false, ptr); + if (!(meshList[i]->cm.textures.empty())) + updateTexture(meshList[i]->id()); } - + meshDoc()->setBusy(false); if(this->GLA() == 0) return false; @@ -1839,7 +1767,7 @@ GLA()->setDrawMode(GLW::DMPoints);*/ qb->reset(); saveRecentProjectList(fileName); globrendtoolbar->setEnabled(true); - showLayerDlg(visiblelayer || (meshDoc()->meshList.size() > 0)); + showLayerDlg(visiblelayer || (meshDoc()->meshNumber() > 0)); return true; } @@ -1855,9 +1783,9 @@ bool MainWindow::appendProject(QString fileName) if (fileNameList.isEmpty()) return false; - // Ccheck if we have a doc and if it is empty + // Check if we have a doc and if it is empty bool activeDoc = (bool) !mdiarea->subWindowList().empty() && mdiarea->currentSubWindow(); - if (!activeDoc || meshDoc()->meshList.empty()) // it is wrong to try appending to an empty project, even if it is possible + if (!activeDoc || (meshDoc()->meshNumber() == 0)) // it is wrong to try appending to an empty project, even if it is possible { QMessageBox::critical(this, tr("Meshlab Opening Error"), "Current project is empty, cannot append"); return false; @@ -1866,98 +1794,8 @@ bool MainWindow::appendProject(QString fileName) meshDoc()->setBusy(true); // load all projects - foreach(fileName,fileNameList) - { - QFileInfo fi(fileName); - lastUsedDirectory = fi.absoluteDir(); - - if((fi.suffix().toLower()!="aln") && (fi.suffix().toLower()!="mlp") && (fi.suffix().toLower() != "mlb") && (fi.suffix().toLower() != "out") && (fi.suffix().toLower() != "nvm")) - { - QMessageBox::critical(this, tr("Meshlab Opening Error"), "Unknown project file extension"); - return false; - } - - // this change of dir is needed for subsequent textures/materials loading - QDir::setCurrent(fi.absoluteDir().absolutePath()); - qb->show(); - - if (QString(fi.suffix()).toLower() == "aln") - { - vector rmv; - int retVal = ALNParser::ParseALN(rmv, qUtf8Printable(fileName)); - if(retVal != ALNParser::NoError) { - QMessageBox::critical(this, tr("Meshlab Opening Error"), "Unable to open ALN file"); - return false; - } - - for(const RangeMap& rm : rmv) { - QString relativeToProj = fi.absoluteDir().absolutePath() + "/" + rm.filename.c_str(); - try { - meshlab::loadMeshWithStandardParameters(relativeToProj, *meshDoc(), QCallBack); - meshDoc()->mm()->cm.Tr.Import(rm.transformation); - computeRenderingDataOnLoading(meshDoc()->mm(), false, nullptr); - if (!(meshDoc()->mm()->cm.textures.empty())) - updateTexture(meshDoc()->mm()->id()); - } - catch (const MLException& e){ - QMessageBox::critical(this, "Meshlab Opening Error", e.what()); - } - } - } - - if (QString(fi.suffix()).toLower() == "mlp" || QString(fi.suffix()).toLower() == "mlb") - { - int alreadyLoadedNum = meshDoc()->meshList.size(); - std::map rendOpt; - if (!MeshDocumentFromXML(*meshDoc(),fileName, QString(fi.suffix()).toLower() == "mlb", rendOpt)) - { - QMessageBox::critical(this, tr("Meshlab Opening Error"), "Unable to open MeshLab Project file"); - return false; - } - GLA()->updateMeshSetVisibilities(); - for (int i = alreadyLoadedNum; imeshList.size(); i++) - { - QString fullPath = meshDoc()->meshList[i]->fullName(); - meshDoc()->setBusy(true); - Matrix44m trm = this->meshDoc()->meshList[i]->cm.Tr; // save the matrix, because loadMeshClear it... - MLRenderingData* ptr = NULL; - if (rendOpt.find(meshDoc()->meshList[i]->id()) != rendOpt.end()) - ptr = &rendOpt[meshDoc()->meshList[i]->id()]; - if(!loadMeshWithStandardParams(fullPath,this->meshDoc()->meshList[i],trm, false, ptr)) - meshDoc()->delMesh(meshDoc()->meshList[i]); - } - } - - if (QString(fi.suffix()).toLower() == "out") { - - QString cameras_filename = fileName; - QString image_list_filename; - QString model_filename; - - image_list_filename = QFileDialog::getOpenFileName( - this, - tr("Open image list file"), - QFileInfo(fileName).absolutePath(), - tr("Bundler images list file (*.txt)")); - if (image_list_filename.isEmpty()) - return false; - - if (!MeshDocumentFromBundler(*meshDoc(), cameras_filename, image_list_filename, model_filename)) { - QMessageBox::critical(this, tr("Meshlab Opening Error"), "Unable to open OUTs file"); - return false; - } - } - - if (QString(fi.suffix()).toLower() == "nvm") { - - QString cameras_filename = fileName; - QString model_filename; - - if (!MeshDocumentFromNvm(*meshDoc(), cameras_filename, model_filename)) { - QMessageBox::critical(this, tr("Meshlab Opening Error"), "Unable to open NVMs file"); - return false; - } - } + for(QString fileName: fileNameList) { + openProject(fileName, true); } globrendtoolbar->setEnabled(true); @@ -2035,10 +1873,9 @@ void MainWindow::documentUpdateRequested() { if (meshDoc() == NULL) return; - for (int ii = 0; ii < meshDoc()->meshList.size(); ++ii) + for (MeshModel* mm : meshDoc()->meshIterator()) { - MeshModel* mm = meshDoc()->meshList[ii]; - if (mm != NULL) + if (mm != nullptr) { addRenderingDataIfNewlyGeneratedMesh(mm->id()); updateLayerDialog(); @@ -2123,7 +1960,7 @@ bool MainWindow::importRaster(const QString& fileImg) QStringList fileNameList; if (fileImg.isEmpty()) - fileNameList = QFileDialog::getOpenFileNames(this,tr("Import Mesh"), lastUsedDirectory.path(), PM.inputRasterFormatListDialog().join(";;")); + fileNameList = QFileDialog::getOpenFileNames(this,tr("Import Mesh"), lastUsedDirectory.path(), PM.inputImageFormatListDialog().join(";;")); else fileNameList.push_back(fileImg); @@ -2140,11 +1977,12 @@ bool MainWindow::importRaster(const QString& fileImg) allFileTime.start(); for(const QString& fileName : fileNameList) { - + RasterModel *rm = nullptr; try { QElapsedTimer t; t.start(); - meshlab::loadRaster(fileName, *meshDoc(), QCallBack); + rm = meshDoc()->addNewRaster(); + meshlab::loadRaster(fileName, *rm, &meshDoc()->Log, QCallBack); GLA()->Logf(0, "Opened raster %s in %i msec", qUtf8Printable(fileName), t.elapsed()); GLA()->resetTrackBall(); GLA()->fov = meshDoc()->rm()->shot.GetFovFromFocal(); @@ -2155,6 +1993,7 @@ bool MainWindow::importRaster(const QString& fileImg) GLA()->Logf(0,"All files opened in %i msec",allFileTime.elapsed()); } catch(const MLException& e){ + meshDoc()->delRaster(rm); QMessageBox::warning( this, tr("Opening Failure"), @@ -2173,23 +2012,23 @@ bool MainWindow::importRaster(const QString& fileImg) return true; } -bool MainWindow::loadMesh(const QString& fileName, IOPlugin *pCurrentIOPlugin, const std::list& meshList, std::list& maskList,RichParameterList* prePar, const Matrix44m &mtr, bool isareload, MLRenderingData* rendOpt) +bool MainWindow::loadMesh(const QString& fileName, IOPlugin *pCurrentIOPlugin, const std::list& meshList, std::list& maskList, const RichParameterList& prePar, const Matrix44m &mtr, bool isareload, MLRenderingData* rendOpt) { if ((GLA() == NULL)) return false; - + QFileInfo fi(fileName); QString extension = fi.suffix(); - + // the original directory path before we switch it QString origDir = QDir::current().path(); - + // this change of dir is needed for subsequent textures/materials loading QDir::setCurrent(fi.absoluteDir().absolutePath()); - + // Adjust the file name after changing the directory QString fileNameSansDir = fi.fileName(); - + // retrieving corresponding IO plugin if (pCurrentIOPlugin == 0) { @@ -2200,8 +2039,8 @@ bool MainWindow::loadMesh(const QString& fileName, IOPlugin *pCurrentIOPlugin, c } meshDoc()->setBusy(true); pCurrentIOPlugin->setLog(&meshDoc()->Log); - - unsigned int nMeshes = pCurrentIOPlugin->numberMeshesContainedInFile(extension, fileNameSansDir); + + unsigned int nMeshes = pCurrentIOPlugin->numberMeshesContainedInFile(extension, fileNameSansDir, prePar); if (nMeshes != meshList.size()) { QMessageBox::warning( this, @@ -2213,7 +2052,7 @@ bool MainWindow::loadMesh(const QString& fileName, IOPlugin *pCurrentIOPlugin, c } try { - pCurrentIOPlugin->open(extension, fileNameSansDir, meshList ,maskList,*prePar,QCallBack); + meshlab::loadMesh(fileName, pCurrentIOPlugin, prePar, meshList, maskList, QCallBack); } catch(const MLException& e) { QMessageBox::warning( @@ -2224,8 +2063,7 @@ bool MainWindow::loadMesh(const QString& fileName, IOPlugin *pCurrentIOPlugin, c QDir::setCurrent(origDir); // undo the change of directory before leaving return false; } - - + //std::cout << "Opened mesh: in " << tm.elapsed() << " secs\n"; // After opening the mesh lets ask to the io plugin if this format // requires some optional, or userdriven post-opening processing. @@ -2234,15 +2072,15 @@ bool MainWindow::loadMesh(const QString& fileName, IOPlugin *pCurrentIOPlugin, c //RichParameterSet par; //pCurrentIOPlugin->initOpenParameter(extension, *mm, par); //pCurrentIOPlugin->applyOpenParameter(extension, *mm, par); - + QString err = pCurrentIOPlugin->warningMessageString(); if (!err.isEmpty()) { QMessageBox::warning(this, tr("Opening Problems"), QString("While opening: '%1'\n\n").arg(fileName)+ err); } - + saveRecentFileList(fileName); - + auto itmesh = meshList.begin(); auto itmask = maskList.begin(); for (unsigned int i = 0; i < meshList.size(); ++i){ @@ -2297,12 +2135,11 @@ bool MainWindow::loadMesh(const QString& fileName, IOPlugin *pCurrentIOPlugin, c } updateLayerDialog(); - - + meshDoc()->setBusy(false); - + QDir::setCurrent(origDir); // undo the change of directory before leaving - + return true; } @@ -2356,7 +2193,7 @@ bool MainWindow::importMeshWithLayerManagement(QString fileName) bool res = importMesh(fileName); globrendtoolbar->setEnabled(true); if (layerDialog != NULL) - showLayerDlg(layervisible || meshDoc()->meshList.size()); + showLayerDlg(layervisible || meshDoc()->meshNumber()); setCurrentMeshBestTab(); return res; } @@ -2411,18 +2248,32 @@ bool MainWindow::importMesh(QString fileName) } pCurrentIOPlugin->setLog(&meshDoc()->Log); - RichParameterList prePar; - pCurrentIOPlugin->initPreOpenParameter(extension,prePar); - if(!prePar.isEmpty()) - { - RichParameterListDialog preOpenDialog(this, prePar, tr("Pre-Open Options")); - preOpenDialog.setFocus(); - preOpenDialog.exec(); + RichParameterList prePar = pCurrentIOPlugin->initPreOpenParameter(extension); + if(!prePar.isEmpty()) { + // the user wants to see each time the pre parameters dialog: + if (currentGlobalParams.getBool(MainWindowSetting::showPreOpenParameterDialogParam())){ + RichParameterListDialog preOpenDialog(this, prePar, tr("Pre-Open Options")); + preOpenDialog.setFocus(); + preOpenDialog.exec(); + } + // the user does not want to see the parameter dialog + // need to take the default values from the currentGlobalParams + else { + for (RichParameter& p : prePar){ + QString prefixName = "MeshLab::IO::" + extension.toUpper() + "::"; + if (currentGlobalParams.hasParameter(prefixName + p.name())){ + const RichParameter& cp = currentGlobalParams.getParameterByName(prefixName + p.name()); + p.setValue(cp.value()); + } + else { + qDebug() << "ERROR!!! " + prefixName + p.name() + " not found in global params."; + } + } + } } - prePar.join(currentGlobalParams); //check how many meshes are going to be loaded from the file - unsigned int nMeshes = pCurrentIOPlugin->numberMeshesContainedInFile(extension, fileName); + unsigned int nMeshes = pCurrentIOPlugin->numberMeshesContainedInFile(extension, fileName, prePar); QFileInfo info(fileName); std::list meshList; @@ -2440,7 +2291,8 @@ bool MainWindow::importMesh(QString fileName) try { QElapsedTimer t; t.start(); - meshlab::loadMesh(fileName, pCurrentIOPlugin, prePar, meshList, masks, QCallBack); + std::list unloadedTextures = + meshlab::loadMesh(fileName, pCurrentIOPlugin, prePar, meshList, masks, QCallBack); saveRecentFileList(fileName); updateLayerDialog(); for (MeshModel* mm : meshList) { @@ -2449,22 +2301,15 @@ bool MainWindow::importMesh(QString fileName) updateTexture(mm->id()); } QString warningString = pCurrentIOPlugin->warningMessageString(); + if (unloadedTextures.size() > 0){ + warningString += "\n\nThe following textures have not been loaded: \n"; + for (const std::string& txt : unloadedTextures) + warningString += QString::fromStdString(txt) + "\n"; + } if (!warningString.isEmpty()){ QMessageBox::warning(this, "Meshlab Opening Warning", warningString); } GLA()->Logf(0, "Opened mesh %s in %i msec", qUtf8Printable(fileName), t.elapsed()); - RichParameterList par; - - pCurrentIOPlugin->initOpenParameter(extension, *meshList.front(), par); - - if(!par.isEmpty()) - { - RichParameterListDialog postOpenDialog(this, par, tr("Post-Open Processing")); - postOpenDialog.setFocus(); - postOpenDialog.exec(); - for (MeshModel* mm : meshList) - pCurrentIOPlugin->applyOpenParameter(extension, *mm, par); - } } catch (const MLException& e){ for (MeshModel* mm : meshList) @@ -2509,19 +2354,18 @@ bool MainWindow::loadMeshWithStandardParams(QString& fullPath, MeshModel* mm, co bool ret = false; if (!mm->isVisible()) { - mm->Clear(); + mm->clear(); mm->visible = false; } else - mm->Clear(); + mm->clear(); QFileInfo fi(fullPath); QString extension = fi.suffix(); IOPlugin *pCurrentIOPlugin = PM.inputMeshPlugin(extension); if(pCurrentIOPlugin != NULL) { - RichParameterList prePar; - pCurrentIOPlugin->initPreOpenParameter(extension, prePar); + RichParameterList prePar = pCurrentIOPlugin->initPreOpenParameter(extension); prePar.join(currentGlobalParams); QElapsedTimer t;t.start(); @@ -2529,13 +2373,10 @@ bool MainWindow::loadMeshWithStandardParams(QString& fullPath, MeshModel* mm, co std::list ml; std::list masks; ml.push_back(mm); - bool open = loadMesh(fullPath,pCurrentIOPlugin,ml,masks,&prePar,mtr,isreload, rendOpt); + bool open = loadMesh(fullPath,pCurrentIOPlugin,ml,masks,prePar,mtr,isreload, rendOpt); if(open) { GLA()->Logf(0, "Opened mesh %s in %i msec", qUtf8Printable(fullPath), t.elapsed()); - RichParameterList par; - pCurrentIOPlugin->initOpenParameter(extension, *mm, par); - pCurrentIOPlugin->applyOpenParameter(extension,*mm,par); ret = true; } else @@ -2567,10 +2408,9 @@ void MainWindow::reloadAllMesh() i++; } try { - meshlab::reloadMesh(fileName, meshList, QCallBack); - i = 0; + meshlab::reloadMesh(fileName, meshList, &meshDoc()->Log, QCallBack); for (MeshModel* m : meshList){ - computeRenderingDataOnLoading(m, i++, nullptr); + computeRenderingDataOnLoading(m, true, nullptr); } } catch (const MLException& e) { @@ -2615,10 +2455,9 @@ void MainWindow::reload() try { QElapsedTimer t; t.start(); - meshlab::reloadMesh(fileName, meshList, QCallBack); - i = 0; + meshlab::reloadMesh(fileName, meshList, &meshDoc()->Log, QCallBack); for (MeshModel* m : meshList){ - computeRenderingDataOnLoading(m, i++, nullptr); + computeRenderingDataOnLoading(m, true, nullptr); } GLA()->Log(0, ("File reloaded in " + std::to_string(t.elapsed()) + " msec.").c_str()); } @@ -2650,9 +2489,7 @@ bool MainWindow::exportMesh(QString fileName,MeshModel* mod,const bool saveAllPo QString laylabel = "Save \"" + mod->label() + "\" Layer"; QString ss = fi.absoluteFilePath(); QFileDialog* saveDialog = new QFileDialog(this,laylabel, fi.absolutePath()); -#if defined(Q_OS_WIN) saveDialog->setOption(QFileDialog::DontUseNativeDialog); -#endif saveDialog->setNameFilters(suffixList); saveDialog->setAcceptMode(QFileDialog::AcceptSave); saveDialog->setFileMode(QFileDialog::AnyFile); @@ -2660,17 +2497,16 @@ bool MainWindow::exportMesh(QString fileName,MeshModel* mod,const bool saveAllPo QStringList matchingExtensions=suffixList.filter(defaultExt); if(!matchingExtensions.isEmpty()) saveDialog->selectNameFilter(matchingExtensions.last()); - connect(saveDialog,SIGNAL(filterSelected(const QString&)),this,SLOT(changeFileExtension(const QString&))); + //connect(saveDialog,SIGNAL(filterSelected(const QString&)),this,SLOT(changeFileExtension(const QString&))); - if (fileName.isEmpty()){ + if (fileName.isEmpty()) { saveDialog->selectFile(meshDoc()->mm()->fullName()); int dialogRet = saveDialog->exec(); - if(dialogRet==QDialog::Rejected ) + if(dialogRet==QDialog::Rejected) return false; fileName=saveDialog->selectedFiles ().first(); QFileInfo fni(fileName); - if(fni.suffix().isEmpty()) - { + if(fni.suffix().isEmpty()) { QString ext = saveDialog->selectedNameFilter(); ext.chop(1); ext = ext.right(4); fileName = fileName + ext; @@ -2678,19 +2514,15 @@ bool MainWindow::exportMesh(QString fileName,MeshModel* mod,const bool saveAllPo } } - - bool ret = false; - QStringList fs = fileName.split("."); - if(!fileName.isEmpty() && fs.size() < 2) - { + if(!fileName.isEmpty() && fs.size() < 2) { QMessageBox::warning(this,"Save Error","You must specify file extension!!"); - return ret; + return false; } - - if (!fileName.isEmpty()) - { + + bool saved = true; + if (!fileName.isEmpty()) { //save path away so we can use it again QString path = fileName; path.truncate(path.lastIndexOf("/")); @@ -2702,33 +2534,40 @@ bool MainWindow::exportMesh(QString fileName,MeshModel* mod,const bool saveAllPo QStringListIterator itFilter(suffixList); IOPlugin *pCurrentIOPlugin = PM.outputMeshPlugin(extension); - if (pCurrentIOPlugin == 0) - { + if (pCurrentIOPlugin == 0) { QMessageBox::warning(this, "Unknown type", "File extension not supported!"); return false; } - //MeshIOInterface* pCurrentIOPlugin = meshIOPlugins[idx-1]; pCurrentIOPlugin->setLog(&meshDoc()->Log); int capability=0,defaultBits=0; pCurrentIOPlugin->exportMaskCapability(extension,capability,defaultBits); // optional saving parameters (like ascii/binary encoding) - RichParameterList savePar; + RichParameterList savePar = pCurrentIOPlugin->initSaveParameter(extension,*(mod)); - pCurrentIOPlugin->initSaveParameter(extension,*(mod),savePar); - - SaveMaskExporterDialog maskDialog(new QWidget(),mod,capability,defaultBits,&savePar,this->GLA()); + SaveMeshAttributesDialog maskDialog(this, mod, capability, defaultBits, savePar, this->GLA()); + int quality = 66; if (!saveAllPossibleAttributes) maskDialog.exec(); - else - { - maskDialog.SlotSelectionAllButton(); - maskDialog.updateMask(); + else { + //this is horrible: creating a dialog object but then not showing the + //dialog.. And using it just to select all the possible options.. + //to be removed soon + maskDialog.selectAllPossibleBits(); } - int mask = maskDialog.GetNewMask(); - if (!saveAllPossibleAttributes) - { + int mask = maskDialog.getNewMask(); + savePar = maskDialog.getNewAdditionalSaveParameters(); + quality = maskDialog.getTextureQuality(); + std::vector textureNames = maskDialog.getTextureNames(); + + for (unsigned int i = 0; i < mod->cm.textures.size(); ++i){ + if (textureNames[i].find('.') == std::string::npos){ + textureNames[i] += ".png"; + } + mod->changeTextureName(mod->cm.textures[i], textureNames[i]); + } + if (!saveAllPossibleAttributes) { maskDialog.close(); if(maskDialog.result() == QDialog::Rejected) return false; @@ -2740,26 +2579,29 @@ bool MainWindow::exportMesh(QString fileName,MeshModel* mod,const bool saveAllPo qb->show(); QElapsedTimer tt; tt.start(); qb->reset(); + try { pCurrentIOPlugin->save(extension, fileName, *mod ,mask,savePar,QCallBack); + QFileInfo finfo(fileName); + mod->saveTextures(finfo.absolutePath(), quality, &meshDoc()->Log, QCallBack); GLA()->Logf(GLLogStream::SYSTEM, "Saved Mesh %s in %i msec", qUtf8Printable(fileName), tt.elapsed()); mod->setFileName(fileName); QSettings settings; int savedMeshCounter = settings.value("savedMeshCounter", 0).toInt(); settings.setValue("savedMeshCounter", savedMeshCounter + 1); } - catch(const MLException& e) - { + catch(const MLException& e) { GLA()->Logf(GLLogStream::SYSTEM, "Error Saving Mesh %s", qUtf8Printable(fileName)); QMessageBox::critical(this, tr("Meshlab Saving Error"), e.what()); + saved = false; } qApp->restoreOverrideCursor(); updateLayerDialog(); - if (ret) + if (saved) QDir::setCurrent(fi.absoluteDir().absolutePath()); //set current dir } - return ret; + return saved; } void MainWindow::changeFileExtension(const QString& st) @@ -2949,49 +2791,28 @@ void MainWindow::updateTexture(int meshid) MeshModel* mymesh = meshDoc()->getMesh(meshid); if (mymesh == NULL) return; - + + QString cwd = QDir::currentPath(); + QDir::setCurrent(mymesh->pathName()); + shared->deAllocateTexturesPerMesh(mymesh->id()); int textmemMB = int(mwsettings.maxTextureMemory / ((float) 1024 * 1024)); size_t totalTextureNum = 0; - foreach (MeshModel *mp, meshDoc()->meshList) + for (MeshModel *mp : meshDoc()->meshIterator()) totalTextureNum+=mp->cm.textures.size(); int singleMaxTextureSizeMpx = int(textmemMB/((totalTextureNum != 0)? totalTextureNum : 1)); - bool sometextfailed = false; - QString unexistingtext = "In mesh file " + mymesh->fullName() + " : Failure loading textures:
"; - for(size_t i =0; i< mymesh->cm.textures.size();++i) + + bool sometextnotfound = false; + for(const std::string& textname : mymesh->cm.textures) { - QImage img; - QFileInfo fi(mymesh->cm.textures[i].c_str()); - QFileInfo mfi(mymesh->fullName()); - QString filename = fi.absoluteFilePath(); - bool res = img.load(filename); - if(!res) - { - QString fn2 = mfi.absolutePath() + "/" + fi.fileName(); - res = img.load(fn2); - if(!res) - { - QString errmsg = QString("Failure of loading texture %1").arg(fi.fileName()); - meshDoc()->Log.log(GLLogStream::WARNING,qUtf8Printable(errmsg)); - unexistingtext += "" + fi.fileName() + "
"; - sometextfailed = sometextfailed || !res; - } - } - - /*PLEASE EXPLAIN ME!*********************************************************************************************************************************************************************************/ - //if(!res && filename.endsWith("dds",Qt::CaseInsensitive)) - //{ - // qDebug("DDS binding!"); - // int newTexId = shared->bindTexture(filename); - // shared->txtcont.push_back(newTexId); - //} - /*PLEASE EXPLAIN ME!*********************************************************************************************************************************************************************************/ - - if (!res) + QImage img = mymesh->getTexture(textname); + + if (img.isNull()){ img.load(":/images/dummy.png"); + } GLuint textid = shared->allocateTexturePerMesh(meshid,img,singleMaxTextureSizeMpx); for(int tt = 0;tt < mvc->viewerCounter();++tt) @@ -3001,8 +2822,10 @@ void MainWindow::updateTexture(int meshid) ar->setupTextureEnv(textid); } } - if (sometextfailed) - QMessageBox::warning(this,"Texture file has not been correctly loaded",unexistingtext); + if (sometextnotfound) + QMessageBox::warning(this,"Texture error", "Some texture has not been found. Using dummy texture."); + + QDir::setCurrent(cwd); } void MainWindow::updateProgressBar( const int pos,const QString& text ) @@ -3297,9 +3120,8 @@ void MainWindow::updateRenderingDataAccordingToActionsToAllVisibleLayers(const Q { if (meshDoc() == NULL) return; - for (int ii = 0; ii < meshDoc()->meshList.size(); ++ii) + for (MeshModel* mm : meshDoc()->meshIterator()) { - MeshModel* mm = meshDoc()->meshList[ii]; if ((mm != NULL) && (mm->isVisible())) { updateRenderingDataAccordingToActionsCommonCode(mm->id(), acts); @@ -3327,10 +3149,10 @@ void MainWindow::updateRenderingDataAccordingToActions(int /*meshid*/, MLRenderi } } - for (int hh = 0; hh < meshDoc()->meshList.size(); ++hh) + for (MeshModel* mm : meshDoc()->meshIterator()) { - if (meshDoc()->meshList[hh] != NULL) - updateRenderingDataAccordingToActionsCommonCode(meshDoc()->meshList[hh]->id(), tmpacts); + if (mm != NULL) + updateRenderingDataAccordingToActionsCommonCode(mm->id(), tmpacts); } for (int ii = 0; ii < tmpacts.size(); ++ii) @@ -3382,9 +3204,8 @@ void MainWindow::updateRenderingDataAccordingToActionToAllVisibleLayers(MLRender if (meshDoc() == NULL) return; - for (int ii = 0; ii < meshDoc()->meshList.size(); ++ii) + for (MeshModel* mm : meshDoc()->meshIterator()) { - MeshModel* mm = meshDoc()->meshList[ii]; if ((mm != NULL) && (mm->isVisible())) { updateRenderingDataAccordingToActionCommonCode(mm->id(), act); @@ -3400,9 +3221,8 @@ void MainWindow::updateRenderingDataAccordingToActions(QListmeshList.size(); ++ii) + for (MeshModel* mm : meshDoc()->meshIterator()) { - MeshModel* mm = meshDoc()->meshList[ii]; if (mm != NULL) { foreach(MLRenderingGlobalAction* act, actlist) @@ -3425,7 +3245,7 @@ void MainWindow::updateRenderingDataAccordingToAction(int /*meshid*/, MLRenderin MLRenderingAction* sisteract = NULL; act->createSisterAction(sisteract, NULL); sisteract->setChecked(check); - foreach(MeshModel* mm, meshDoc()->meshList) + for(MeshModel* mm : meshDoc()->meshIterator()) { if (mm != NULL) updateRenderingDataAccordingToActionCommonCode(mm->id(), sisteract); diff --git a/src/meshlab/meshlab.pro b/src/meshlab/meshlab.pro index 4d82fccb1..7b73b69cb 100644 --- a/src/meshlab/meshlab.pro +++ b/src/meshlab/meshlab.pro @@ -32,12 +32,11 @@ HEADERS += \ dialogs/filter_script_dialog.h \ dialogs/options_dialog.h \ dialogs/plugin_info_dialog.h \ + dialogs/save_mesh_attributes_dialog.h \ dialogs/save_snapshot_dialog.h \ dialogs/setting_dialog.h \ multiViewer_Container.h \ glarea_setting.h \ - savemaskexporter.h \ - changetexturename.h \ layerDialog.h \ ml_std_par_dialog.h \ additionalgui.h \ @@ -62,12 +61,11 @@ SOURCES += \ dialogs/filter_script_dialog.cpp \ dialogs/options_dialog.cpp \ dialogs/plugin_info_dialog.cpp \ + dialogs/save_mesh_attributes_dialog.cpp \ dialogs/save_snapshot_dialog.cpp \ dialogs/setting_dialog.cpp \ multiViewer_Container.cpp \ layerDialog.cpp \ - savemaskexporter.cpp \ - changetexturename.cpp \ ml_std_par_dialog.cpp \ additionalgui.cpp \ ml_render_gui.cpp \ @@ -86,10 +84,9 @@ FORMS += \ dialogs/congrats_dialog.ui \ dialogs/filter_script_dialog.ui \ dialogs/plugin_info_dialog.ui \ + dialogs/save_mesh_attributes_dialog.ui \ dialogs/save_snapshot_dialog.ui \ - ui/layerDialog.ui \ - ui/renametexture.ui \ - ui/savemaskexporter.ui + ui/layerDialog.ui RESOURCES += \ meshlab.qrc diff --git a/src/meshlab/ml_std_par_dialog.cpp b/src/meshlab/ml_std_par_dialog.cpp index f14fcd851..6131a6eb3 100644 --- a/src/meshlab/ml_std_par_dialog.cpp +++ b/src/meshlab/ml_std_par_dialog.cpp @@ -33,13 +33,12 @@ bool MeshlabStdDialog::showAutoDialog(FilterPlugin *mfi, MeshModel *mm, MeshDocu curAction = action; curmfi = mfi; curmwi = mwi; - curParSet.clear(); prevParSet.clear(); curModel = mm; curMeshDoc = mdp; curgla = gla; - mfi->initParameterList(action, *mdp, curParSet); + curParSet = mfi->initParameterList(action, *mdp); curmask = mfi->postCondition(action); if (curParSet.isEmpty() && !isPreviewable()) return false; @@ -104,8 +103,7 @@ void MeshlabStdDialog::createFrame() // update the values of the widgets with the values in the paramlist; void MeshlabStdDialog::resetValues() { - curParSet.clear(); - curmfi->initParameterList(curAction, *curMeshDoc, curParSet); + curParSet = curmfi->initParameterList(curAction, *curMeshDoc); assert(qf); assert(qf->isVisible()); diff --git a/src/meshlab/rich_parameter_gui/richparameterwidgets.cpp b/src/meshlab/rich_parameter_gui/richparameterwidgets.cpp index 24d621162..9a1115b98 100644 --- a/src/meshlab/rich_parameter_gui/richparameterwidgets.cpp +++ b/src/meshlab/rich_parameter_gui/richparameterwidgets.cpp @@ -1076,81 +1076,48 @@ MeshWidget::MeshWidget(QWidget *p, const RichMesh& rpar, const RichMesh& rdef) : //defaultMeshIndex = -1; int currentmeshindex = -1; - for(int i=0;imeshList.size();++i) - { - QString shortName = md->meshList.at(i)->label(); + unsigned int i = 0; + for(const MeshModel* mm : md->meshIterator()) { + QString shortName = mm->label(); meshNames.push_back(shortName); - /* if(md->meshList.at(i) == rp->pd->defvalue().getMesh()) - defaultMeshIndex = i;*/ - if(md->meshList.at(i) == rp->value().getMesh()) - { + if((unsigned int) mm->id() == rp->value().getMeshId()) { currentmeshindex = i; - ((RichMesh*)rp)->meshindex = currentmeshindex; } + ++i; } Init(p,currentmeshindex,meshNames); } -MeshModel * MeshWidget::getMesh() -{ - //test to make sure index is in bounds - int index = enumCombo->currentIndex(); - if(index < md->meshList.size() && index > -1) - { - //RichMesh* rm = reinterpret_cast(rp); - //rm->meshindex = index; - return md->meshList.at(enumCombo->currentIndex()); - } - else return NULL; -} - -void MeshWidget::setMesh(MeshModel * newMesh) -{ - for(int i=0; i < md->meshList.size(); ++i) - { - if(md->meshList.at(i) == newMesh) - setIndex(i); - } -} - void MeshWidget::collectWidgetValue() { - //MeshDecoration* dec = reinterpret_cast(rp->pd); - RichMesh* rm = reinterpret_cast(rp); - rm->meshindex = enumCombo->currentIndex(); - rp->setValue(MeshValue(md->meshList.at(rm->meshindex))); + auto it = md->meshBegin(); + std::advance(it, enumCombo->currentIndex()); + rp->setValue(MeshValue((*it)->id())); } void MeshWidget::resetWidgetValue() { int meshindex = -1; - for(int i=0;imeshList.size();++i) - { - if(md->meshList.at(i) == rp->value().getMesh()) - { + unsigned int i = 0; + for(const MeshModel* mm : md->meshIterator()) { + if(mm->id() == rp->value().getMeshId()) { meshindex = i; - //RichMesh* rm = reinterpret_cast(rp); - //rm->meshindex = enumCombo->currentIndex(); } - + ++i; } enumCombo->setCurrentIndex(meshindex); } void MeshWidget::setWidgetValue( const Value& nv ) { - //WARNING!!!!! I HAVE TO THINK CAREFULLY ABOUT THIS FUNCTION!!! - //assert(0); int meshindex = -1; - for(int i=0;imeshList.size();++i) - { - if(md->meshList.at(i) == nv.getMesh()) - { + unsigned int i = 0; + for(const MeshModel* mm : md->meshIterator()) { + if(mm->id() == nv.getMeshId()) { meshindex = i; - //RichMesh* rm = reinterpret_cast(rp); - //rm->meshindex = meshindex; } + ++i; } enumCombo->setCurrentIndex(meshindex); } diff --git a/src/meshlab/rich_parameter_gui/richparameterwidgets.h b/src/meshlab/rich_parameter_gui/richparameterwidgets.h index 71d895f07..c43b00155 100644 --- a/src/meshlab/rich_parameter_gui/richparameterwidgets.h +++ b/src/meshlab/rich_parameter_gui/richparameterwidgets.h @@ -372,7 +372,7 @@ public: class MeshWidget : public ComboWidget { private: - MeshDocument *md; + const MeshDocument *md; public: MeshWidget(QWidget *p, const RichMesh& defaultMesh, const RichMesh& rdef); ~MeshWidget(){}; @@ -380,9 +380,6 @@ public: void collectWidgetValue(); void resetWidgetValue(); void setWidgetValue(const Value& nv); - - MeshModel * getMesh(); - void setMesh(MeshModel * newMesh); }; class IOFileWidget : public RichParameterWidget diff --git a/src/meshlab/savemaskexporter.cpp b/src/meshlab/savemaskexporter.cpp deleted file mode 100644 index 396e42eb1..000000000 --- a/src/meshlab/savemaskexporter.cpp +++ /dev/null @@ -1,281 +0,0 @@ -/**************************************************************************** -* VCGLib o o * -* Visual and Computer Graphics Library o o * -* _ O _ * -* Copyright(C) 2004 \/)\/ * -* Visual Computing Lab /\/| * -* ISTI - Italian National Research Council | * -* \ * -* All rights reserved. * -* * -* This program is free software; you can redistribute it and/or modify * -* it under the terms of the GNU General Public License as published by * -* the Free Software Foundation; either version 2 of the License, or * -* (at your option) any later version. * -* * -* This program is distributed in the hope that it will be useful, * -* but WITHOUT ANY WARRANTY; without even the implied warranty of * -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * -* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) * -* for more details. * -* * -****************************************************************************/ - -#include "ui_savemaskexporter.h" -#include "savemaskexporter.h" -#include "changetexturename.h" - -#include - -SaveMaskExporterDialog::SaveMaskExporterDialog(QWidget *parent,MeshModel *m,int capability,int defaultBits, RichParameterList *_parSet,GLArea* glar): -QDialog(parent),m(m),mask(0),capability(capability),defaultBits(defaultBits),parSet(_parSet),glar(glar) -{ - ui = new Ui::MaskExporterDialog(); - InitDialog(); -} - -void SaveMaskExporterDialog::InitDialog() -{ - SaveMaskExporterDialog::ui->setupUi(this); - connect(ui->okButton, SIGNAL(clicked()), this, SLOT(SlotOkButton())); - connect(ui->cancelButton, SIGNAL(clicked()), this, SLOT(SlotCancelButton())); - connect(ui->renametextureButton,SIGNAL(clicked()),this,SLOT(SlotRenameTexture())); - connect(ui->listTextureName,SIGNAL(itemSelectionChanged()),this,SLOT(SlotSelectionTextureName())); - connect(ui->AllButton,SIGNAL(clicked()),this,SLOT(SlotSelectionAllButton())); - connect(ui->NoneButton,SIGNAL(clicked()),this,SLOT(SlotSelectionNoneButton())); - ui->renametextureButton->setDisabled(true); - - stdParFrame = new RichParameterListFrame(*parSet, this,glar); - QVBoxLayout *vbox = new QVBoxLayout(this); - vbox->addWidget(stdParFrame); - ui->saveParBox->setLayout(vbox); - QFileInfo fi(m->fullName()); - this->setWindowTitle("Choose Saving Options for: '"+ fi.baseName() +"'"); - // Show the additional parameters only for formats that have some. - if(parSet->isEmpty()) ui->saveParBox->hide(); - else ui->saveParBox->show(); - //all - none - ui->AllButton->setChecked(true); - //ui->NoneButton->setChecked(true); - - SetTextureName(); - SetMaskCapability(); -} - -void SaveMaskExporterDialog::SetTextureName() -{ - if( m->cm.textures.size() == 0 ) - { - ui->check_iom_wedgtexcoord->setDisabled(true); - ui->check_iom_wedgtexcoord->setChecked(false); - } - - for(unsigned int i=0;icm.textures.size();i++) - { - QString item(m->cm.textures[i].c_str()); - ui->listTextureName->addItem(item); - } -} - -int SaveMaskExporterDialog::GetNewMask() -{ - return this->mask; -} - -/* - there are three things that are looked when setting the initial states of the checkbox of this dialog - - this->capabilityBit - - this->defaultBit - - - setDisabled(true): uncheckable - setDisabled(false) : checkable - - true : when the information is not present or in the Capability or in the MeshModel Mask - false : when the information is present in the Capability and in the Mask MeshModel - - setChecked(true) : checked - setChecked(false): unchecked - - true : the information is present both in the Capability and the MeshModel Mask - false : otherwise. - -*/ -bool SaveMaskExporterDialog::shouldBeChecked(int bit, int /*capabilityBits*/, int defaultBits) -{ - if(!m->hasDataMask(MeshModel::io2mm(bit))) return false; - //if( (bit & meshBits) == 0 ) return false; - if( (bit & defaultBits) == 0 ) return false; - return true; -} - -bool SaveMaskExporterDialog::shouldBeEnabled(int iobit, int capabilityBits, int /*defaultBits*/) -{ - if( (iobit & capabilityBits) == 0 ) return false; - int mmbit = MeshModel::io2mm(iobit); - if(!m->hasDataMask(mmbit)) return false; - return true; -} - -void SaveMaskExporterDialog::checkAndEnable(QCheckBox *qcb,int bit, int capabilityBits, int defaultBits) -{ - qcb->setEnabled(shouldBeEnabled (bit,capabilityBits, defaultBits) ); - qcb->setChecked(shouldBeChecked (bit,capabilityBits, defaultBits) ); -} - -void SaveMaskExporterDialog::SetMaskCapability() -{ - //vert - checkAndEnable(ui->check_iom_vertquality, vcg::tri::io::Mask::IOM_VERTQUALITY, capability, defaultBits ); - checkAndEnable(ui->check_iom_vertflags, vcg::tri::io::Mask::IOM_VERTFLAGS, capability, defaultBits); - checkAndEnable(ui->check_iom_vertcolor, vcg::tri::io::Mask::IOM_VERTCOLOR, capability, defaultBits); - checkAndEnable(ui->check_iom_verttexcoord, vcg::tri::io::Mask::IOM_VERTTEXCOORD, capability, defaultBits); - checkAndEnable(ui->check_iom_vertnormal, vcg::tri::io::Mask::IOM_VERTNORMAL, capability, defaultBits); - checkAndEnable(ui->check_iom_vertradius, vcg::tri::io::Mask::IOM_VERTRADIUS, capability, defaultBits); - - // point cloud fix: if a point cloud, probably you'd want to save vertex normals - if ((m->cm.fn == 0) && (m->cm.en == 0)) - ui->check_iom_vertnormal->setChecked(true); - - //face - checkAndEnable(ui->check_iom_facequality, vcg::tri::io::Mask::IOM_FACEQUALITY, capability, defaultBits ); - checkAndEnable(ui->check_iom_faceflags, vcg::tri::io::Mask::IOM_FACEFLAGS, capability, defaultBits ); - checkAndEnable(ui->check_iom_facecolor, vcg::tri::io::Mask::IOM_FACECOLOR, capability, defaultBits ); - checkAndEnable(ui->check_iom_facenormal, vcg::tri::io::Mask::IOM_FACENORMAL, capability, defaultBits ); - - //wedge - checkAndEnable(ui->check_iom_wedgcolor, vcg::tri::io::Mask::IOM_WEDGCOLOR, capability, defaultBits ); - checkAndEnable(ui->check_iom_wedgtexcoord, vcg::tri::io::Mask::IOM_WEDGTEXCOORD, capability, defaultBits ); - checkAndEnable(ui->check_iom_wedgnormal, vcg::tri::io::Mask::IOM_WEDGNORMAL, capability, defaultBits ); - - checkAndEnable(ui->check_iom_polygonal, vcg::tri::io::Mask::IOM_BITPOLYGONAL, capability, defaultBits ); - - //camera THIS ONE HAS TO BE CORRECTED !!!! - //bool camval = m->cm.shot.IsValid(); - //int res = capability & vcg::tri::io::Mask::IOM_CAMERA; - ui->check_iom_camera->setDisabled( ((capability & vcg::tri::io::Mask::IOM_CAMERA)==0) || (m->cm.shot.IsValid() == false)); - ui->check_iom_camera->setChecked ( ((capability & vcg::tri::io::Mask::IOM_CAMERA)!=0) && (m->cm.shot.IsValid())); - - if(capability == 0) - ui->NoneButton->setChecked(true); -} - - -void SaveMaskExporterDialog::updateMask() -{ - int newmask = 0; - - if( ui->check_iom_vertflags->isChecked() ) { newmask |= vcg::tri::io::Mask::IOM_VERTFLAGS;} - if( ui->check_iom_vertcolor->isChecked() ) { newmask |= vcg::tri::io::Mask::IOM_VERTCOLOR;} - if( ui->check_iom_vertquality->isChecked() ) { newmask |= vcg::tri::io::Mask::IOM_VERTQUALITY;} - if( ui->check_iom_verttexcoord->isChecked() ) { newmask |= vcg::tri::io::Mask::IOM_VERTTEXCOORD;} - if( ui->check_iom_vertnormal->isChecked() ) { newmask |= vcg::tri::io::Mask::IOM_VERTNORMAL;} - if( ui->check_iom_vertradius->isChecked() ) { newmask |= vcg::tri::io::Mask::IOM_VERTRADIUS;} - - if( ui->check_iom_faceflags->isChecked() ) { newmask |= vcg::tri::io::Mask::IOM_FACEFLAGS;} - if( ui->check_iom_facecolor->isChecked() ) { newmask |= vcg::tri::io::Mask::IOM_FACECOLOR;} - if( ui->check_iom_facequality->isChecked() ) { newmask |= vcg::tri::io::Mask::IOM_FACEQUALITY;} - if( ui->check_iom_facenormal->isChecked() ) { newmask |= vcg::tri::io::Mask::IOM_FACENORMAL;} - - if( ui->check_iom_wedgcolor->isChecked() ) { newmask |= vcg::tri::io::Mask::IOM_WEDGCOLOR;} - if( ui->check_iom_wedgtexcoord->isChecked() ) { newmask |= vcg::tri::io::Mask::IOM_WEDGTEXCOORD;} - if( ui->check_iom_wedgnormal->isChecked() ) { newmask |= vcg::tri::io::Mask::IOM_WEDGNORMAL;} - - if( ui->check_iom_camera->isChecked() ) { newmask |= vcg::tri::io::Mask::IOM_CAMERA;} - if( ui->check_iom_polygonal->isChecked() ) { newmask |= vcg::tri::io::Mask::IOM_BITPOLYGONAL;} - - for(unsigned int i=0;icm.textures.size();i++) - m->cm.textures[i] = ui->listTextureName->item(i)->text().toStdString(); - this->mask=newmask; -} - -//slot -void SaveMaskExporterDialog::SlotOkButton() -{ - updateMask(); - stdParFrame->writeValuesOnParameterList(*parSet); -} - -void SaveMaskExporterDialog::SlotCancelButton() -{ - this->mask=-1; -} - -void SaveMaskExporterDialog::SlotRenameTexture() -{ - int row = ui->listTextureName->currentRow(); - ChangeTextureNameDialog dialog(this,m->cm.textures[row].c_str()); - dialog.exec(); - std::string newtexture = dialog.GetTextureName(); - dialog.close(); - if(newtexture.size()>0) - { - QStringList lists = QString(newtexture.c_str()).split('/'); - (ui->listTextureName->currentItem())->setText(lists[lists.size()-1]); - } -} - -void SaveMaskExporterDialog::SlotSelectionTextureName() -{ - ui->renametextureButton->setDisabled(false); -} - -void SaveMaskExporterDialog::SlotSelectionAllButton() -{ - //vert - ui->check_iom_vertquality->setChecked(ui->check_iom_vertquality->isEnabled()); - ui->check_iom_vertflags->setChecked(ui->check_iom_vertflags->isEnabled()); - ui->check_iom_vertcolor->setChecked(ui->check_iom_vertcolor->isEnabled()); - ui->check_iom_verttexcoord->setChecked(ui->check_iom_verttexcoord->isEnabled()); - ui->check_iom_vertnormal->setChecked(ui->check_iom_vertnormal->isEnabled()); - ui->check_iom_vertradius->setChecked(ui->check_iom_vertradius->isEnabled()); - - //face - ui->check_iom_facequality->setChecked(ui->check_iom_facequality->isEnabled()); - ui->check_iom_faceflags->setChecked(ui->check_iom_faceflags->isEnabled()); - ui->check_iom_facenormal->setChecked(ui->check_iom_facenormal->isEnabled()); - ui->check_iom_facecolor->setChecked(ui->check_iom_facecolor->isEnabled()); - - //wedg - ui->check_iom_wedgcolor->setChecked(ui->check_iom_wedgcolor->isEnabled()); - ui->check_iom_wedgtexcoord->setChecked(ui->check_iom_wedgtexcoord->isEnabled()); - ui->check_iom_wedgnormal->setChecked(ui->check_iom_wedgnormal->isEnabled()); - - //camera - ui->check_iom_camera->setChecked(ui->check_iom_camera->isEnabled()); -} - -void SaveMaskExporterDialog::SlotSelectionNoneButton() -{ - //vert - ui->check_iom_vertquality->setChecked(false); - ui->check_iom_vertflags->setChecked(false); - ui->check_iom_vertcolor->setChecked(false); - ui->check_iom_verttexcoord->setChecked(false); - ui->check_iom_vertnormal->setChecked(false); - ui->check_iom_vertradius->setChecked(false); - - //face - ui->check_iom_facequality->setChecked(false); - ui->check_iom_faceflags->setChecked(false); - ui->check_iom_facenormal->setChecked(false); - ui->check_iom_facecolor->setChecked(false); - - //wedg - ui->check_iom_wedgcolor->setChecked(false); - ui->check_iom_wedgtexcoord->setChecked(false); - ui->check_iom_wedgnormal->setChecked(false); - - //camera - ui->check_iom_camera->setChecked(false); -} - -void SaveMaskExporterDialog::on_check_help_stateChanged(int) -{ - stdParFrame->toggleHelp(); -} - -SaveMaskExporterDialog::~SaveMaskExporterDialog() -{ - delete ui; -} diff --git a/src/meshlab/ui/renametexture.ui b/src/meshlab/ui/renametexture.ui deleted file mode 100644 index 36f706fa8..000000000 --- a/src/meshlab/ui/renametexture.ui +++ /dev/null @@ -1,182 +0,0 @@ - - - - - RenameTextureDialog - - - - 0 - 0 - 473 - 71 - - - - Dialog - - - - - 10 - 10 - 351 - 17 - - - - Qt::Horizontal - - - - - - 10 - 10 - 238 - 23 - - - - Qt::Horizontal - - - - - - 10 - 10 - 391 - 17 - - - - Qt::Horizontal - - - - - - 10 - 60 - 351 - 33 - - - - - - - 10 - 30 - 367 - 23 - - - - Qt::Horizontal - - - - - - 390 - 40 - 71 - 23 - - - - OK - - - - - - 320 - 40 - 71 - 23 - - - - Cancel - - - - - - 82 - 10 - 291 - 21 - - - - - - - - - - 10 - 10 - 67 - 21 - - - - <html><head><meta name="qrichtext" content="1" /></head><body style=" white-space: pre-wrap; font-family:MS Shell Dlg; font-weight:400; font-style:normal; text-decoration:none;"><p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Texture Name</p></body></html> - - - - - - 380 - 10 - 81 - 23 - - - - Search Texture - - - - - - - - okButton - clicked() - RenameTextureDialog - accept() - - - 278 - 253 - - - 96 - 254 - - - - - cancelButton - clicked() - RenameTextureDialog - reject() - - - 369 - 253 - - - 179 - 282 - - - - - diff --git a/src/meshlab_mini.pro b/src/meshlab_mini.pro index b83daf984..1afdab097 100644 --- a/src/meshlab_mini.pro +++ b/src/meshlab_mini.pro @@ -19,7 +19,6 @@ message("DISTRIB_DIRECTORY: "$$MESHLAB_DISTRIB_DIRECTORY) SUBDIRS = \ #sub projects names common \ meshlab \ - meshlabserver \ io_base \ # a few basic file formats (ply, obj, off), without this you cannot open anything decorate_base \ filter_measure \ @@ -27,14 +26,12 @@ SUBDIRS = \ #sub projects names common.subdir = common meshlab.subdir = meshlab -meshlabserver.subdir = meshlabserver io_base.subdir = meshlabplugins/io_base decorate_base.subdir = meshlabplugins/decorate_base filter_measure.subdir = meshlabplugins/filter_measure filter_meshing.subdir = meshlabplugins/filter_meshing meshlab.depends = common -meshlabserver.depends = common io_base.depends = common decorate_base.depends = common filter_measure.depends = common diff --git a/src/meshlabplugins/decorate_base/decorate_base.cpp b/src/meshlabplugins/decorate_base/decorate_base.cpp index 1ea883924..0ec7d5f63 100644 --- a/src/meshlabplugins/decorate_base/decorate_base.cpp +++ b/src/meshlabplugins/decorate_base/decorate_base.cpp @@ -95,7 +95,7 @@ void DecorateBasePlugin::decorateDoc(const QAction* a, MeshDocument &md, const R // draw all visible mesh cameras if(rm->getBool(ShowMeshCameras())) { - foreach(MeshModel *meshm, md.meshList) + for(MeshModel *meshm : md.meshIterator()) { if (meshm != md.mm() || (!showCameraDetails)) // non-selected meshes, only draw { @@ -108,14 +108,14 @@ void DecorateBasePlugin::decorateDoc(const QAction* a, MeshDocument &md, const R } } - if (md.meshList.size() == 0) + if (md.meshNumber() == 0) this->realTimeLog("Show Mesh Camera", md.mm()->label(), "There are no Mesh Layers"); } // draw all visible raster cameras if(rm->getBool(ShowRasterCameras())) { - foreach(RasterModel *raster, md.rasterList) + for(RasterModel *raster: md.rasterIterator()) { if(raster != md.rm() || !showCameraDetails ) // non-selected raster, only draw { @@ -128,7 +128,7 @@ void DecorateBasePlugin::decorateDoc(const QAction* a, MeshDocument &md, const R } } - if (md.rasterList.size() == 0) + if (md.rasterNumber() == 0) this->realTimeLog("Show Raster Camera", md.mm()->label(), "There are no Rasters"); } } break; diff --git a/src/meshlabplugins/decorate_raster_proj/decorate_raster_proj.cpp b/src/meshlabplugins/decorate_raster_proj/decorate_raster_proj.cpp index b0cf431be..7669c841e 100644 --- a/src/meshlabplugins/decorate_raster_proj/decorate_raster_proj.cpp +++ b/src/meshlabplugins/decorate_raster_proj/decorate_raster_proj.cpp @@ -240,7 +240,7 @@ void DecorateRasterProjPlugin::updateCurrentMesh(MeshDocument &m, QMap tmpScene = m_Scene; m_Scene.clear(); - foreach( MeshModel *md, m.meshList ) + for( MeshModel *md : m.meshIterator() ) { QMap::iterator t = tmpScene.find( md->id() ); if( t != tmpScene.end() ) diff --git a/src/meshlabplugins/decorate_shadow/shadow_mapping.cpp b/src/meshlabplugins/decorate_shadow/shadow_mapping.cpp index 5a6923762..3b3db43d1 100644 --- a/src/meshlabplugins/decorate_shadow/shadow_mapping.cpp +++ b/src/meshlabplugins/decorate_shadow/shadow_mapping.cpp @@ -145,7 +145,7 @@ void ShadowMapping::runShader(MeshDocument& md, GLArea* gla){ atts[MLRenderingData::ATT_NAMES::ATT_FACENORMAL] = true; dt.set(MLRenderingData::PR_SOLID, atts); - foreach(MeshModel *m, md.meshList) + for(MeshModel *m: md.meshIterator()) { if ((m != NULL) && (m->visible)) { @@ -182,7 +182,7 @@ void ShadowMapping::runShader(MeshDocument& md, GLArea* gla){ glUniform1i(loc, 0); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - foreach(MeshModel *m, md.meshList) + for(MeshModel *m: md.meshIterator()) { if ((m != NULL) && (m->visible)) { diff --git a/src/meshlabplugins/decorate_shadow/ssao.cpp b/src/meshlabplugins/decorate_shadow/ssao.cpp index f43f701ce..e5f963743 100644 --- a/src/meshlabplugins/decorate_shadow/ssao.cpp +++ b/src/meshlabplugins/decorate_shadow/ssao.cpp @@ -132,8 +132,8 @@ void SSAO::runShader(MeshDocument& md, GLArea* gla) mProj.transposeInPlace(); mInverseProj = vcg::Inverse(mProj); - glDrawBuffer(GL_COLOR_ATTACHMENT0); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glDrawBuffer(GL_COLOR_ATTACHMENT0); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); MLRenderingData dt; MLRenderingData::RendAtts atts; atts[MLRenderingData::ATT_NAMES::ATT_VERTPOSITION] = true; @@ -141,14 +141,14 @@ void SSAO::runShader(MeshDocument& md, GLArea* gla) atts[MLRenderingData::ATT_NAMES::ATT_FACENORMAL] = true; dt.set(MLRenderingData::PR_SOLID, atts); - foreach(MeshModel *m, md.meshList) + for(MeshModel *m: md.meshIterator()) { if ((m != NULL) && (m->visible)) { ctx->drawAllocatedAttributesSubset(m->id(), gla->context(), dt); } } - glUseProgram(0); + glUseProgram(0); /***********************************************************/ //SSAO PASS diff --git a/src/meshlabplugins/decorate_shadow/variance_shadow_mapping.cpp b/src/meshlabplugins/decorate_shadow/variance_shadow_mapping.cpp index a0d1e0058..92fd9f09c 100644 --- a/src/meshlabplugins/decorate_shadow/variance_shadow_mapping.cpp +++ b/src/meshlabplugins/decorate_shadow/variance_shadow_mapping.cpp @@ -103,7 +103,7 @@ void VarianceShadowMapping::runShader(MeshDocument& md, GLArea* gla) atts[MLRenderingData::ATT_NAMES::ATT_FACENORMAL] = true; dt.set(MLRenderingData::PR_SOLID, atts); - foreach(MeshModel *m, md.meshList) + for(MeshModel *m: md.meshIterator()) { if ((m != NULL) && (m->visible)) { @@ -144,7 +144,7 @@ void VarianceShadowMapping::runShader(MeshDocument& md, GLArea* gla) glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - foreach(MeshModel *m, md.meshList) + for(MeshModel *m: md.meshIterator()) { if ((m != NULL) && (m->visible)) { diff --git a/src/meshlabplugins/decorate_shadow/variance_shadow_mapping_blur.cpp b/src/meshlabplugins/decorate_shadow/variance_shadow_mapping_blur.cpp index 9fb6378d7..755649d6e 100644 --- a/src/meshlabplugins/decorate_shadow/variance_shadow_mapping_blur.cpp +++ b/src/meshlabplugins/decorate_shadow/variance_shadow_mapping_blur.cpp @@ -106,14 +106,14 @@ void VarianceShadowMappingBlur::runShader(MeshDocument& md, GLArea* gla){ atts[MLRenderingData::ATT_NAMES::ATT_FACENORMAL] = true; dt.set(MLRenderingData::PR_SOLID, atts); - foreach(MeshModel *m, md.meshList) - { - if ((m != NULL) && (m->visible)) - { + for(MeshModel *m: md.meshIterator()) + { + if ((m != NULL) && (m->visible)) + { ctx->drawAllocatedAttributesSubset(m->id(),gla->context(),dt); - } - } - glDisable(GL_POLYGON_OFFSET_FILL); + } + } + glDisable(GL_POLYGON_OFFSET_FILL); this->renderingFromLightUnsetup(); @@ -188,7 +188,7 @@ void VarianceShadowMappingBlur::runShader(MeshDocument& md, GLArea* gla){ glPushAttrib(GL_COLOR_BUFFER_BIT); glColorMask(GL_TRUE,GL_TRUE,GL_TRUE,GL_FALSE); // to avoid the fact that when saving a snapshot we get semitransparent shadowed areas. - foreach(MeshModel *m, md.meshList) + for(MeshModel *m: md.meshIterator()) { if ((m != NULL) && (m->visible)) { diff --git a/src/meshlabplugins/edit_align/edit_align.cpp b/src/meshlabplugins/edit_align/edit_align.cpp index 2884b0bf7..57afe108f 100644 --- a/src/meshlabplugins/edit_align/edit_align.cpp +++ b/src/meshlabplugins/edit_align/edit_align.cpp @@ -114,23 +114,23 @@ void EditAlignPlugin::suggestedRenderingData(MeshModel & /*m*/, MLRenderingData& bool EditAlignPlugin::startEdit(MeshDocument& md, GLArea * gla, MLSceneGLSharedDataContext* cont) { - _md=&md; - _gla= gla; + _md=&md; + _gla= gla; _shared = cont; - if ((_gla == NULL) || (_shared == NULL) || (md.meshList.size() < 1)) + if ((_gla == NULL) || (_shared == NULL) || (md.meshNumber() < 1)) return false; //mainW->addDockWidget(Qt::LeftDockWidgetArea,alignDialog); mode = ALIGN_IDLE; - int numOfMeshes = _md->meshList.size(); - meshTree.clear(); - foreach(MeshModel *mm, _md->meshList) - { + int numOfMeshes = _md->meshNumber(); + meshTree.clear(); + for(MeshModel *mm: _md->meshIterator()) + { - // assigns random color: if less than 50 meshes, color is truly unique, and the less meshes, the more different they will be - // if above 50, truly unique color would generate too similar colors, so total number of unique color - // is capped to 50 and the color reused, id that are close will have different color anyway + // assigns random color: if less than 50 meshes, color is truly unique, and the less meshes, the more different they will be + // if above 50, truly unique color would generate too similar colors, so total number of unique color + // is capped to 50 and the color reused, id that are close will have different color anyway if (mm != NULL) { if (numOfMeshes < 50) @@ -139,12 +139,12 @@ bool EditAlignPlugin::startEdit(MeshDocument& md, GLArea * gla, MLSceneGLSharedD mm->cm.C() = Color4b::Scatter(51, mm->id() % 50, .2f, .7f); mm->updateDataMask(MeshModel::MM_COLOR); // meshTree.nodeList.push_back(new MeshNode(mm)); - meshTree.nodeMap[mm->id()]=new MeshNode(mm); + meshTree.nodeMap[mm->id()]=new MeshNode(mm); } - } + } -//for(QMap::iterator it = _gla->rendermodemap.begin();it != _gla->rendermodemap.end();++it) -// it.value().colorMode=GLW::CMPerMesh; +// for(QMap::iterator it = _gla->rendermodemap.begin();it != _gla->rendermodemap.end();++it) +// it.value().colorMode=GLW::CMPerMesh; _gla->setCursor(QCursor(QPixmap(":/images/cur_align.png"),1,1)); if(alignDialog==0) diff --git a/src/meshlabplugins/edit_mutualcorrs/edit_mutualcorrs.cpp b/src/meshlabplugins/edit_mutualcorrs/edit_mutualcorrs.cpp index 1c40a733d..ad5124c50 100644 --- a/src/meshlabplugins/edit_mutualcorrs/edit_mutualcorrs.cpp +++ b/src/meshlabplugins/edit_mutualcorrs/edit_mutualcorrs.cpp @@ -71,7 +71,7 @@ void EditMutualCorrsPlugin::mouseReleaseEvent(QMouseEvent * event, MeshModel &/* void EditMutualCorrsPlugin::decorate(MeshModel &m, GLArea *gla, QPainter *p) { - if (gla->md()->rasterList.size() == 0 || !gla->isRaster()) + if (gla->md()->rasterNumber() == 0 || !gla->isRaster()) { return; } @@ -204,7 +204,7 @@ bool EditMutualCorrsPlugin::startEdit(MeshModel & /*m*/, GLArea *gla, MLSceneGLS { mutualcorrsDialog = new edit_mutualcorrsDialog(gla->window(), this); - if (glArea->md()->rasterList.size() == 0 || !glArea->isRaster()) + if (glArea->md()->rasterNumber() == 0 || !glArea->isRaster()) { QMessageBox::warning(gla, tr("Mutual Correspondences"), tr("You need at least a raster layer, and to be in Current Raster View mode!"), QMessageBox::Ok); return false; @@ -469,7 +469,7 @@ void EditMutualCorrsPlugin::saveToFile() // export reference list + picked point QTextStream openFileTS(&openFile); openFileTS << "-------RASTER ALIGNMENT DATA---------" << "\n"; - openFileTS << "3D Model: " << glArea->md()->mm()->relativePathName() << "\n"; + openFileTS << "3D Model: " << glArea->md()->mm()->relativePathName(glArea->md()->pathName()) << "\n"; openFileTS << "Raster: " << glArea->md()->rm()->currentPlane->fullPathFileName << "\n"; // writing reference diff --git a/src/meshlabplugins/edit_referencing/edit_referencing.cpp b/src/meshlabplugins/edit_referencing/edit_referencing.cpp index e5dd22429..dca6b7aae 100644 --- a/src/meshlabplugins/edit_referencing/edit_referencing.cpp +++ b/src/meshlabplugins/edit_referencing/edit_referencing.cpp @@ -343,9 +343,9 @@ bool EditReferencingPlugin::startEdit(MeshModel & m, GLArea * gla, MLSceneGLShar status_error = ""; // reading current transformations for all layers - layersOriginalTransf.resize(glArea->md()->meshList.size()); + layersOriginalTransf.resize(glArea->md()->meshNumber()); int lind = 0; - foreach(MeshModel *mmp, glArea->md()->meshList) + for(MeshModel *mmp: glArea->md()->meshIterator()) { layersOriginalTransf[lind].Import(mmp->cm.Tr); lind++; @@ -808,30 +808,30 @@ void EditReferencingPlugin::calculateMatrix() void EditReferencingPlugin::applyMatrix() { - status_error = ""; + status_error = ""; - Matrix44m newMat; + Matrix44m newMat; - newMat.Import(transfMatrix); + newMat.Import(transfMatrix); - if(referencingDialog->ui->cbApplyToAll->checkState() == Qt::Checked) - { + if(referencingDialog->ui->cbApplyToAll->checkState() == Qt::Checked) + { int lind = 0; - foreach(MeshModel *mmp, glArea->md()->meshList) - { - if(mmp->visible) - { + for(MeshModel *mmp: glArea->md()->meshIterator()) + { + if(mmp->visible) + { mmp->cm.Tr = newMat * layersOriginalTransf[lind]; - } + } lind++; - } - } - else - { + } + } + else + { glArea->mm()->cm.Tr = newMat * originalTransf; - } + } - glArea->update(); + glArea->update(); } void EditReferencingPlugin::updateDistances() @@ -997,7 +997,7 @@ void EditReferencingPlugin::applyScale() if (referencingDialog->ui->cbApplyToAll->checkState() == Qt::Checked) { int lind = 0; - foreach(MeshModel *mmp, glArea->md()->meshList) + for(MeshModel *mmp: glArea->md()->meshIterator()) { if (mmp->visible) { diff --git a/src/meshlabplugins/filter_ao/filter_ao.cpp b/src/meshlabplugins/filter_ao/filter_ao.cpp index ca5e8b917..bf51531ab 100644 --- a/src/meshlabplugins/filter_ao/filter_ao.cpp +++ b/src/meshlabplugins/filter_ao/filter_ao.cpp @@ -123,10 +123,11 @@ FilterPlugin::FilterClass AmbientOcclusionPlugin::getClass(const QAction * /*fil //return MeshFilterInterface::FilterClass(MeshFilterInterface::FaceColoring | MeshFilterInterface::VertexColoring); }; -void AmbientOcclusionPlugin::initParameterList(const QAction *action, MeshModel & /*m*/, RichParameterList &parlst) +RichParameterList AmbientOcclusionPlugin::initParameterList(const QAction *action, const MeshModel & /*m*/) { - switch(ID(action)) - { + RichParameterList parlst; + switch(ID(action)) + { case FP_AMBIENT_OCCLUSION: parlst.addParam(RichEnum("occMode", 0, QStringList() << "per-Vertex" << "per-Face (deprecated)", tr("Occlusion mode:"), tr("Occlusion may be calculated per-vertex or per-face, color and quality will be saved in the chosen component."))); parlst.addParam(RichFloat("dirBias",0,"Directional Bias [0..1]","The balance between a uniform and a directionally biased set of lighting direction
:" @@ -134,15 +135,17 @@ void AmbientOcclusionPlugin::initParameterList(const QAction *action, MeshModel " - 1 means that all the light cames from the specified cone of directions
" " - other values mix the two set of lighting directions ")); parlst.addParam(RichInt ("reqViews",AMBOCC_DEFAULT_NUM_VIEWS,"Requested views", "Number of different views uniformly placed around the mesh. More views means better accuracy at the cost of increased calculation time")); - parlst.addParam(RichPoint3f("coneDir",Point3f(0,1,0),"Lighting Direction", "Number of different views placed around the mesh. More views means better accuracy at the cost of increased calculation time")); + parlst.addParam(RichPoint3f("coneDir",Point3m(0,1,0),"Lighting Direction", "Number of different views placed around the mesh. More views means better accuracy at the cost of increased calculation time")); parlst.addParam(RichFloat("coneAngle",30,"Cone amplitude", "Number of different views uniformly placed around the mesh. More views means better accuracy at the cost of increased calculation time")); parlst.addParam(RichBool("useGPU",AMBOCC_USEGPU_BY_DEFAULT,"Use GPU acceleration","Only works for per-vertex AO. In order to use GPU-Mode, your hardware must support FBOs, FP32 Textures and Shaders. Normally increases the performance by a factor of 4x-5x")); //parlst.addParam(RichBool("useVBO",AMBOCC_USEVBO_BY_DEFAULT,"Use VBO if supported","By using VBO, Meshlab loads all the vertex structure in the VRam, greatly increasing rendering speed (for both CPU and GPU mode). Disable it if problem occurs")); parlst.addParam(RichInt ("depthTexSize",AMBOCC_DEFAULT_TEXTURE_SIZE,"Depth texture size(should be 2^n)", "Defines the depth texture size used to compute occlusion from each point of view. Higher values means better accuracy usually with low impact on performance")); - break; + break; default: break; // do not add any parameter for the other filters - } + } + return parlst; } + std::map AmbientOcclusionPlugin::applyFilter(const QAction * filter, const RichParameterList & par, MeshDocument &md, unsigned int& /*postConditionMask*/, vcg::CallBackPos *cb) { if (ID(filter) == FP_AMBIENT_OCCLUSION) { diff --git a/src/meshlabplugins/filter_ao/filter_ao.h b/src/meshlabplugins/filter_ao/filter_ao.h index 1646fa982..48beeae25 100644 --- a/src/meshlabplugins/filter_ao/filter_ao.h +++ b/src/meshlabplugins/filter_ao/filter_ao.h @@ -76,7 +76,7 @@ public: bool requiresGLContext(const QAction* action) const; FilterClass getClass(const QAction* filter) const; - void initParameterList(const QAction*, MeshModel &/*m*/, RichParameterList & /*parent*/); + RichParameterList initParameterList(const QAction*, const MeshModel &/*m*/); std::map applyFilter(const QAction* action, const RichParameterList & /*parent*/, MeshDocument &md, unsigned int& postConditionMask, vcg::CallBackPos * cb); void initTextures(void); void initGL(vcg::CallBackPos *cb,unsigned int numVertices); diff --git a/src/meshlabplugins/filter_camera/filter_camera.cpp b/src/meshlabplugins/filter_camera/filter_camera.cpp index 52b08599e..c9ca054b8 100644 --- a/src/meshlabplugins/filter_camera/filter_camera.cpp +++ b/src/meshlabplugins/filter_camera/filter_camera.cpp @@ -74,13 +74,13 @@ QString FilterCameraPlugin::filterName(ActionIDType filterId) const QString FilterCameraPlugin::filterInfo(ActionIDType filterId) const { switch(filterId) { - case FP_SET_MESH_CAMERA : return QString("This filter allows one to set a shot for the current mesh"); - case FP_SET_RASTER_CAMERA : return QString("This filter allows one to set a shot for the current mesh"); - case FP_QUALITY_FROM_CAMERA : return QString("Compute vertex quality using the camera definition, according to viewing angle or distance"); - case FP_CAMERA_ROTATE : return QString("Rotate the camera, or all the cameras of the project. The selected raster is the reference if viewpoint rotation is selected."); - case FP_CAMERA_SCALE : return QString("Scale the camera, or all the cameras of the project. The selected raster is the reference if viewpoint scaling is selected."); - case FP_CAMERA_TRANSLATE : return QString("Translate the camera, or all the cameras of the project."); - case FP_CAMERA_TRANSFORM : return QString("Transform the camera extrinsics, or all the cameras of the project."); + case FP_SET_MESH_CAMERA : return QString("This filter allows one to set a shot for the current mesh"); + case FP_SET_RASTER_CAMERA : return QString("This filter allows one to set a shot for the current mesh"); + case FP_QUALITY_FROM_CAMERA : return QString("Compute vertex quality using the camera definition, according to viewing angle or distance"); + case FP_CAMERA_ROTATE : return QString("Rotate the camera, or all the cameras of the project. The selected raster is the reference if viewpoint rotation is selected."); + case FP_CAMERA_SCALE : return QString("Scale the camera, or all the cameras of the project. The selected raster is the reference if viewpoint scaling is selected."); + case FP_CAMERA_TRANSLATE : return QString("Translate the camera, or all the cameras of the project."); + case FP_CAMERA_TRANSFORM : return QString("Transform the camera extrinsics, or all the cameras of the project."); case FP_ORIENT_NORMALS_WITH_CAMERAS:return QString("Reorient vertex normals using cameras. For this filter to work the mesh needs to have the attribute 'correspondences' which is only created when loading Bundler files (.out projects)"); default : assert(0); } @@ -88,8 +88,9 @@ QString FilterCameraPlugin::filterInfo(ActionIDType filterId) const } // This function define the needed parameters for each filter. -void FilterCameraPlugin::initParameterList(const QAction *action, MeshDocument &/*m*/, RichParameterList & parlst) +RichParameterList FilterCameraPlugin::initParameterList(const QAction *action, const MeshDocument &/*m*/) { + RichParameterList parlst; Shotm defShot; switch(ID(action)) { @@ -111,8 +112,8 @@ void FilterCameraPlugin::initParameterList(const QAction *action, MeshDocument & rotCenter.push_back("custom point"); parlst.addParam(RichEnum("rotCenter", 0, rotCenter, tr("Center of rotation:"), tr("Choose a method"))); parlst.addParam(RichDynamicFloat("angle",0,-360,360,"Rotation Angle","Angle of rotation (in degree). If snapping is enabled this value is rounded according to the snap value")); - parlst.addParam(RichPoint3f("customAxis",Point3f(0,0,0),"Custom axis","This rotation axis is used only if the 'custom axis' option is chosen.")); - parlst.addParam(RichPoint3f("customCenter",Point3f(0,0,0),"Custom center","This rotation center is used only if the 'custom point' option is chosen.")); + parlst.addParam(RichPoint3f("customAxis",Point3m(0,0,0),"Custom axis","This rotation axis is used only if the 'custom axis' option is chosen.")); + parlst.addParam(RichPoint3f("customCenter",Point3m(0,0,0),"Custom center","This rotation center is used only if the 'custom point' option is chosen.")); parlst.addParam(RichBool ("toallRaster", false, "Apply to all active Raster layers", "Apply the same scaling to all the active Raster layers: it is taken into account only if 'Raster Camera' is selected")); parlst.addParam(RichBool ("toall", false, "Apply to all active Raster and visible Mesh layers", "Apply the same scaling to all the layers, including any visible 3D layer")); } @@ -128,7 +129,7 @@ void FilterCameraPlugin::initParameterList(const QAction *action, MeshDocument & scaleCenter.push_back("camera viewpoint"); scaleCenter.push_back("custom point"); parlst.addParam(RichEnum("scaleCenter", 0, scaleCenter, tr("Center of scaling:"), tr("Choose a method"))); - parlst.addParam(RichPoint3f("customCenter",Point3f(0,0,0),"Custom center","This scaling center is used only if the 'custom point' option is chosen.")); + parlst.addParam(RichPoint3f("customCenter",Point3m(0,0,0),"Custom center","This scaling center is used only if the 'custom point' option is chosen.")); parlst.addParam(RichFloat("scale", 1.0, "Scale factor", "The scale factor that has to be applied to the camera")); parlst.addParam(RichBool ("toallRaster", false, "Apply to all active Raster layers", "Apply the same scaling to all the active Raster layers: it is taken into account only if 'Raster Camera' is selected")); parlst.addParam(RichBool ("toall", false, "Apply to all active Raster and visible Mesh layers", "Apply the same scaling to all the layers, including any visible 3D layer")); @@ -158,8 +159,7 @@ void FilterCameraPlugin::initParameterList(const QAction *action, MeshDocument & behaviour.push_back("The matrix is the transformation to apply to the extrinsics"); behaviour.push_back("The matrix represent the new extrinsics"); - Matrix44m mat; mat.SetIdentity(); - parlst.addParam(RichMatrix44f("TransformMatrix",mat,"")); + parlst.addParam(RichMatrix44f("TransformMatrix",Matrix44m::Identity(),"")); parlst.addParam(RichEnum("camera", 0, shotType, tr("Camera type"), tr("Choose the camera to scale"))); parlst.addParam(RichEnum("behaviour", 0, behaviour, tr("Matrix semantic"), tr("What the matrix is used for"))); parlst.addParam(RichBool ("toallRaster", false, "Apply to all active Raster layers", "Apply the same scaling to all the active Raster layers: it is taken into account only if 'Raster Camera' is selected")); @@ -182,16 +182,17 @@ void FilterCameraPlugin::initParameterList(const QAction *action, MeshDocument & break; default: break; // do not add any parameter for the other filters } + return parlst; } // Core Function doing the actual mesh processing. std::map FilterCameraPlugin::applyFilter(const QAction *filter, const RichParameterList & par, MeshDocument &md, unsigned int& /*postConditionMask*/, vcg::CallBackPos * /*cb*/) { - MeshModel* mesh = md.mm(); + MeshModel* currentMesh = md.mm(); CMeshO* cm = NULL; - if (mesh != NULL) - cm = &(mesh->cm); - RasterModel *rm = md.rm(); + if (currentMesh != NULL) + cm = &(currentMesh->cm); + RasterModel *currentRaster = md.rm(); switch(ID(filter)) { case FP_CAMERA_ROTATE : @@ -225,11 +226,11 @@ std::map FilterCameraPlugin::applyFilter(const QAction *f switch(par.getEnum("camera")) { case 0: - if (rm == NULL) + if (currentRaster == NULL) { throw MLException("You need a Raster Model to apply this filter!"); } - tranVec=rm->shot.Extrinsics.Tra(); + tranVec=currentRaster->shot.Extrinsics.Tra(); break; case 1: if (cm == NULL) @@ -255,43 +256,43 @@ std::map FilterCameraPlugin::applyFilter(const QAction *f Matrix44m transf=trTran*trRot*trTranInv; if (par.getBool("toall")) { - for (int i=0; ivisible) + if (mm->visible) { - md.meshList[i]->cm.Tr=transf * md.meshList[i]->cm.Tr; - tri::UpdatePosition::Matrix(md.meshList[i]->cm, md.meshList[i]->cm.Tr); + mm->cm.Tr=transf * mm->cm.Tr; + tri::UpdatePosition::Matrix(mm->cm, mm->cm.Tr); //tri::UpdateNormal::PerVertexMatrix(md.meshList[i]->cm,md.meshList[i]->cm.Tr); //tri::UpdateNormal::PerFaceMatrix(md.meshList[i]->cm,md.meshList[i]->cm.Tr); - tri::UpdateBounding::Box(md.meshList[i]->cm); - md.meshList[i]->cm.shot.ApplyRigidTransformation(transf); - md.meshList[i]->cm.Tr.SetIdentity(); + tri::UpdateBounding::Box(mm->cm); + mm->cm.shot.ApplyRigidTransformation(transf); + mm->cm.Tr.SetIdentity(); } } - for (int i=0; ivisible) - md.rasterList[i]->shot.ApplyRigidTransformation(transf); + if (rm->visible) + rm->shot.ApplyRigidTransformation(transf); } } else if (par.getBool("toallRaster") && (par.getEnum("camera")==0)) { - for (int i=0; ivisible) - md.rasterList[i]->shot.ApplyRigidTransformation(transf); + if (rm->visible) + rm->shot.ApplyRigidTransformation(transf); } } else switch(par.getEnum("camera")) { case 0: { - if (rm == NULL) + if (currentRaster == NULL) { throw MLException("You need a Raster Model to apply this filter!"); } - rm->shot.ApplyRigidTransformation(transf); + currentRaster->shot.ApplyRigidTransformation(transf); break; } case 1: @@ -326,11 +327,11 @@ std::map FilterCameraPlugin::applyFilter(const QAction *f switch(par.getEnum("camera")) { case 0: - if (rm == NULL) + if (currentRaster == NULL) { throw MLException("You need a Raster Model to apply this filter!"); } - tranVec=rm->shot.Extrinsics.Tra(); + tranVec=currentRaster->shot.Extrinsics.Tra(); break; case 1: if (cm == NULL) @@ -351,41 +352,41 @@ std::map FilterCameraPlugin::applyFilter(const QAction *f trTranInv.SetTranslate(-tranVec); if (par.getBool("toall")) { - for (int i=0; ivisible) + if (mm->visible) { - md.meshList[i]->cm.Tr=trTran*trScale*trTranInv; - tri::UpdatePosition::Matrix(md.meshList[i]->cm, md.meshList[i]->cm.Tr); + mm->cm.Tr=trTran*trScale*trTranInv; + tri::UpdatePosition::Matrix(mm->cm, mm->cm.Tr); //tri::UpdateNormal::PerVertexMatrix(md.meshList[i]->cm,md.meshList[i]->cm.Tr); //tri::UpdateNormal::PerFaceMatrix(md.meshList[i]->cm,md.meshList[i]->cm.Tr); - tri::UpdateBounding::Box(md.meshList[i]->cm); - md.meshList[i]->cm.Tr.SetIdentity(); - md.meshList[i]->cm.shot.ApplyRigidTransformation(trTran); - md.meshList[i]->cm.shot.RescalingWorld(trScale[0][0], false); - md.meshList[i]->cm.shot.ApplyRigidTransformation(trTranInv); + tri::UpdateBounding::Box(mm->cm); + mm->cm.Tr.SetIdentity(); + mm->cm.shot.ApplyRigidTransformation(trTran); + mm->cm.shot.RescalingWorld(trScale[0][0], false); + mm->cm.shot.ApplyRigidTransformation(trTranInv); } } - for (int i=0; ivisible) + if (rm->visible) { - md.rasterList[i]->shot.ApplyRigidTransformation(trTran); - md.rasterList[i]->shot.RescalingWorld(trScale[0][0], false); - md.rasterList[i]->shot.ApplyRigidTransformation(trTranInv); + rm->shot.ApplyRigidTransformation(trTran); + rm->shot.RescalingWorld(trScale[0][0], false); + rm->shot.ApplyRigidTransformation(trTranInv); } } } else if (par.getBool("toallRaster") && (par.getEnum("camera")==0)) { - for (int i=0; ivisible) + if (rm->visible) { - md.rasterList[i]->shot.ApplyRigidTransformation(trTran); - md.rasterList[i]->shot.RescalingWorld(trScale[0][0], false); - md.rasterList[i]->shot.ApplyRigidTransformation(trTranInv); + rm->shot.ApplyRigidTransformation(trTran); + rm->shot.RescalingWorld(trScale[0][0], false); + rm->shot.ApplyRigidTransformation(trTranInv); } } } @@ -393,13 +394,13 @@ std::map FilterCameraPlugin::applyFilter(const QAction *f { case 0: { - if (rm == NULL) + if (currentRaster == NULL) { throw MLException("You need a Raster Model to apply this filter!"); } - rm->shot.ApplyRigidTransformation(trTran); - rm->shot.RescalingWorld(Scale, false); - rm->shot.ApplyRigidTransformation(trTranInv); + currentRaster->shot.ApplyRigidTransformation(trTran); + currentRaster->shot.RescalingWorld(Scale, false); + currentRaster->shot.ApplyRigidTransformation(trTranInv); break; } case 1: @@ -431,11 +432,11 @@ std::map FilterCameraPlugin::applyFilter(const QAction *f switch(par.getEnum("camera")) { case 0: - if (rm == NULL) + if (currentRaster == NULL) { throw MLException("You need a Raster Model to apply this filter!"); } - trTran.SetTranslate(-rm->shot.Extrinsics.Tra()); + trTran.SetTranslate(-currentRaster->shot.Extrinsics.Tra()); break; case 1: if (cm == NULL) @@ -448,43 +449,43 @@ std::map FilterCameraPlugin::applyFilter(const QAction *f } if (par.getBool("toall")) { - for (int i=0; ivisible) + if (mm->visible) { - md.meshList[i]->cm.Tr=trTran; - tri::UpdatePosition::Matrix(md.meshList[i]->cm, md.meshList[i]->cm.Tr); + mm->cm.Tr=trTran; + tri::UpdatePosition::Matrix(mm->cm, mm->cm.Tr); //tri::UpdateNormal::PerVertexMatrix(md.meshList[i]->cm,md.meshList[i]->cm.Tr); //tri::UpdateNormal::PerFaceMatrix(md.meshList[i]->cm,md.meshList[i]->cm.Tr); - tri::UpdateBounding::Box(md.meshList[i]->cm); - md.meshList[i]->cm.Tr.SetIdentity(); - md.meshList[i]->cm.shot.ApplyRigidTransformation(trTran); + tri::UpdateBounding::Box(mm->cm); + mm->cm.Tr.SetIdentity(); + mm->cm.shot.ApplyRigidTransformation(trTran); } } - for (int i=0; ivisible) - md.rasterList[i]->shot.ApplyRigidTransformation(trTran); + if (rm->visible) + rm->shot.ApplyRigidTransformation(trTran); } } else if (par.getBool("toallRaster") && (par.getEnum("camera")==0)) { - for (int i=0; ivisible) - md.rasterList[i]->shot.ApplyRigidTransformation(trTran); + if (rm->visible) + rm->shot.ApplyRigidTransformation(trTran); } } else switch(par.getEnum("camera")) { case 0: { - if (rm == NULL) + if (currentRaster == NULL) { throw MLException("You need a Raster Model to apply this filter!"); } - rm->shot.ApplyRigidTransformation(trTran); + currentRaster->shot.ApplyRigidTransformation(trTran); break; } case 1: @@ -508,12 +509,12 @@ std::map FilterCameraPlugin::applyFilter(const QAction *f mat = par.getMatrix44("TransformMatrix"); if(par.getEnum("behaviour") == 1) { - if (rm == NULL) + if (currentRaster == NULL) { throw MLException("You need a Raster Model to apply this filter!"); } - inv = rm->shot.Extrinsics.Rot(); - tra = inv * rm->shot.Extrinsics.Tra(); + inv = currentRaster->shot.Extrinsics.Rot(); + tra = inv * currentRaster->shot.Extrinsics.Tra(); inv[0][3] = -tra[0]; inv[1][3] = -tra[1]; inv[2][3] = -tra[2]; @@ -523,42 +524,42 @@ std::map FilterCameraPlugin::applyFilter(const QAction *f if (par.getBool("toall")) { - for (int i=0; ivisible) + if (mm->visible) { - md.meshList[i]->cm.Tr = mat; - tri::UpdatePosition::Matrix(md.meshList[i]->cm, md.meshList[i]->cm.Tr); + mm->cm.Tr = mat; + tri::UpdatePosition::Matrix(mm->cm, mm->cm.Tr); //tri::UpdateNormal::PerFaceMatrix(md.meshList[i]->cm,md.meshList[i]->cm.Tr); - tri::UpdateBounding::Box(md.meshList[i]->cm); - md.meshList[i]->cm.Tr.SetIdentity(); - md.meshList[i]->cm.shot.ApplySimilarity(mat); + tri::UpdateBounding::Box(mm->cm); + mm->cm.Tr.SetIdentity(); + mm->cm.shot.ApplySimilarity(mat); } } - for (int i=0; ivisible) - md.rasterList[i]->shot.ApplySimilarity(mat); + if (rm->visible) + rm->shot.ApplySimilarity(mat); } } else if (par.getBool("toallRaster") && (par.getEnum("camera")==0)) { - for (int i=0; ivisible) - md.rasterList[i]->shot.ApplySimilarity(mat); + if (rm->visible) + rm->shot.ApplySimilarity(mat); } } else switch(par.getEnum("camera")) { case 0: { - if (rm == NULL) + if (currentRaster == NULL) { throw MLException("You need a Raster Model to apply this filter!"); } - rm->shot.ApplyRigidTransformation(mat); + currentRaster->shot.ApplyRigidTransformation(mat); break; } case 1: @@ -577,19 +578,19 @@ std::map FilterCameraPlugin::applyFilter(const QAction *f case FP_SET_RASTER_CAMERA : { - if (rm == NULL) + if (currentRaster == NULL) { throw MLException("You need a Raster Model to apply this filter!"); } Shotm shotGot=par.getShotf("Shot"); - rm->shot = shotGot; - float ratio=(float)rm->currentPlane->image.height()/(float)shotGot.Intrinsics.ViewportPx[1]; - rm->shot.Intrinsics.ViewportPx[0]=rm->currentPlane->image.width(); - rm->shot.Intrinsics.ViewportPx[1]=rm->currentPlane->image.height(); - rm->shot.Intrinsics.PixelSizeMm[1]/=ratio; - rm->shot.Intrinsics.PixelSizeMm[0]/=ratio; - rm->shot.Intrinsics.CenterPx[0]=(int)((float)rm->shot.Intrinsics.ViewportPx[0]/2.0); - rm->shot.Intrinsics.CenterPx[1]=(int)((float)rm->shot.Intrinsics.ViewportPx[1]/2.0); + currentRaster->shot = shotGot; + float ratio=(float)currentRaster->currentPlane->image.height()/(float)shotGot.Intrinsics.ViewportPx[1]; + currentRaster->shot.Intrinsics.ViewportPx[0]=currentRaster->currentPlane->image.width(); + currentRaster->shot.Intrinsics.ViewportPx[1]=currentRaster->currentPlane->image.height(); + currentRaster->shot.Intrinsics.PixelSizeMm[1]/=ratio; + currentRaster->shot.Intrinsics.PixelSizeMm[0]/=ratio; + currentRaster->shot.Intrinsics.CenterPx[0]=(int)((float)currentRaster->shot.Intrinsics.ViewportPx[0]/2.0); + currentRaster->shot.Intrinsics.CenterPx[1]=(int)((float)currentRaster->shot.Intrinsics.ViewportPx[1]/2.0); } break; case FP_SET_MESH_CAMERA : @@ -656,9 +657,11 @@ std::map FilterCameraPlugin::applyFilter(const QAction *f for(CMeshO::VertexIterator vi= cm->vert.begin(); vi != cm->vert.end();++vi) { unsigned int camera_id = ch[*vi][0].id_img; - if (md.rasterList[camera_id] != NULL) + auto it = md.rasterBegin(); + std::advance(it, camera_id); + if (it != md.rasterEnd() && *it != nullptr) { - Point3m n=md.rasterList[camera_id]->shot.GetViewPoint()-(*vi).P() ; + Point3m n=(*it)->shot.GetViewPoint()-(*vi).P() ; if( n*(*vi).cN()<0) (*vi). N()=-(*vi).cN(); } diff --git a/src/meshlabplugins/filter_camera/filter_camera.h b/src/meshlabplugins/filter_camera/filter_camera.h index a69b45709..cb268fb5a 100644 --- a/src/meshlabplugins/filter_camera/filter_camera.h +++ b/src/meshlabplugins/filter_camera/filter_camera.h @@ -51,7 +51,7 @@ public: virtual QString filterName(ActionIDType filter) const; virtual QString filterInfo(ActionIDType filter) const; virtual FilterClass getClass(const QAction*) const; - virtual void initParameterList(const QAction*, MeshDocument &/*m*/, RichParameterList & /*parent*/); + virtual RichParameterList initParameterList(const QAction*, const MeshDocument &/*m*/); std::map applyFilter(const QAction* action, const RichParameterList & /*parent*/, MeshDocument &md, unsigned int& postConditionMask, vcg::CallBackPos * cb); FilterArity filterArity(const QAction* act) const; }; diff --git a/src/meshlabplugins/filter_clean/cleanfilter.cpp b/src/meshlabplugins/filter_clean/cleanfilter.cpp index 5ad5a2b00..1ee1db963 100644 --- a/src/meshlabplugins/filter_clean/cleanfilter.cpp +++ b/src/meshlabplugins/filter_clean/cleanfilter.cpp @@ -212,19 +212,20 @@ int CleanFilter::postCondition(const QAction* action) const case FP_REMOVE_DUPLICATE_FACE: case FP_REMOVE_FOLD_FACE: case FP_REMOVE_NON_MANIF_EDGE: - case FP_REMOVE_NON_MANIF_EDGE_SPLIT: case FP_REMOVE_NON_MANIF_VERT: case FP_REMOVE_UNREFERENCED_VERTEX: case FP_REMOVE_DUPLICATED_VERTEX: - case FP_REMOVE_FACE_ZERO_AREA: return MeshModel::MM_GEOMETRY_AND_TOPOLOGY_CHANGE; + case FP_REMOVE_FACE_ZERO_AREA: + case FP_REMOVE_NON_MANIF_EDGE_SPLIT: return MeshModel::MM_GEOMETRY_AND_TOPOLOGY_CHANGE; case FP_COMPACT_VERT: case FP_COMPACT_FACE: return MeshModel::MM_NONE; // only internal vector storage should change, nothing more } return MeshModel::MM_ALL; } -void CleanFilter::initParameterList(const QAction *action,MeshDocument &md, RichParameterList & parlst) +RichParameterList CleanFilter::initParameterList(const QAction *action, const MeshDocument &md) { + RichParameterList parlst; pair qualityRange; switch(ID(action)) { @@ -264,19 +265,21 @@ void CleanFilter::initParameterList(const QAction *action,MeshDocument &md, Rich "Repeat", true, "Iterate until convergence", "Iterates the algorithm until it reaches convergence")); break; case FP_REMOVE_NON_MANIF_VERT : - parlst.addParam(RichFloat("VertDispRatio", 0, "Vertex Displacement Ratio", "When a vertex is split it is moved along the average vector going from its position to the baricyenter of the FF connected faces sharing it")); + parlst.addParam(RichFloat("VertDispRatio", 0, "Vertex Displacement Ratio", "This parameter denote the ratio ⍺ of displacement of a vertex. When a vertex v is split, it is moved towards the barycenter b of the FF connected faces sharing it of a (v-b)*⍺. When ⍺ is zero vertex is not displaced. When ⍺ is 0.5 the new vertex is half away toward the barycenter of the face. Reasonable values are in the [0 .. 0.1] range. ")); break; default: break; // do not add any parameter for the other filters } + return parlst; } -std::map CleanFilter::applyFilter(const QAction *filter, const RichParameterList & par, MeshDocument &md, unsigned int& /*postConditionMask*/, vcg::CallBackPos * cb) +std::map CleanFilter::applyFilter(const QAction *filter, const RichParameterList & par, MeshDocument &md, unsigned int& postConditionMask, vcg::CallBackPos * cb) { MeshModel &m=*(md.mm()); switch(ID(filter)) { case FP_BALL_PIVOTING: { + vcg::tri::Allocator::CompactEveryVector(m.cm); Scalarm Radius = par.getAbsPerc("BallRadius"); Scalarm Clustering = par.getFloat("Clustering") / 100.0f; Scalarm CreaseThr = math::ToRad(par.getFloat("CreaseThr")); @@ -305,7 +308,7 @@ std::map CleanFilter::applyFilter(const QAction *filter, int delvert = tri::Clean::RemoveUnreferencedVertex(m.cm); log("Removed %d unreferenced vertices", delvert); } - m.UpdateBoxAndNormals(); + m.updateBoxAndNormals(); }break; case FP_REMOVE_ISOLATED_COMPLEXITY: { @@ -317,7 +320,7 @@ std::map CleanFilter::applyFilter(const QAction *filter, int delvert = tri::Clean::RemoveUnreferencedVertex(m.cm); log("Removed %d unreferenced vertices", delvert); } - m.UpdateBoxAndNormals(); + m.updateBoxAndNormals(); } break; case FP_REMOVE_WRT_Q: @@ -343,7 +346,7 @@ std::map CleanFilter::applyFilter(const QAction *filter, m.clearDataMask(MeshModel::MM_FACEFACETOPO); log("Deleted %i vertices and %i faces with a quality lower than %f", deletedVN,deletedFN,val); - m.UpdateBoxAndNormals(); + m.updateBoxAndNormals(); } break; case FP_REMOVE_TVERTEX_COLLAPSE : @@ -392,21 +395,23 @@ std::map CleanFilter::applyFilter(const QAction *filter, m.updateDataMask(MeshModel::MM_FACECOLOR); int total = tri::Clean::RemoveFaceFoldByFlip(m.cm); log("Successfully flipped %d folded faces", total); - m.UpdateBoxAndNormals(); + m.updateBoxAndNormals(); } break; case FP_REMOVE_NON_MANIF_EDGE : { int total = tri::Clean::RemoveNonManifoldFace(m.cm); log("Successfully removed %d non-manifold faces", total); - m.UpdateBoxAndNormals(); + m.updateBoxAndNormals(); } break; case FP_REMOVE_NON_MANIF_EDGE_SPLIT : { int total = tri::Clean::SplitManifoldComponents(m.cm); log("Successfully split the mesh into %d edge manifold components", total); - m.UpdateBoxAndNormals(); + m.updateBoxAndNormals(); + if (m.hasDataMask(MeshModel::MM_WEDGTEXCOORD)) + postConditionMask = MeshModel::MM_GEOMETRY_AND_TOPOLOGY_CHANGE | MeshModel::MM_WEDGTEXCOORD; } break; case FP_REMOVE_NON_MANIF_VERT : @@ -414,7 +419,7 @@ std::map CleanFilter::applyFilter(const QAction *filter, Scalarm threshold = par.getFloat("VertDispRatio"); int total = tri::Clean::SplitNonManifoldVertex(m.cm,threshold); log("Successfully split %d non manifold vertices faces", total); - m.UpdateBoxAndNormals(); + m.updateBoxAndNormals(); } break; case FP_REMOVE_FACE_ZERO_AREA: @@ -428,14 +433,14 @@ std::map CleanFilter::applyFilter(const QAction *filter, { int delvert = tri::Clean::RemoveUnreferencedVertex(m.cm); log("Removed %d unreferenced vertices", delvert); - if (delvert != 0) m.UpdateBoxAndNormals(); + if (delvert != 0) m.updateBoxAndNormals(); } break; case FP_REMOVE_DUPLICATED_VERTEX: { int delvert = tri::Clean::RemoveDuplicateVertex(m.cm); log("Removed %d duplicated vertices", delvert); - if (delvert != 0) m.UpdateBoxAndNormals(); + if (delvert != 0) m.updateBoxAndNormals(); m.clearDataMask(MeshModel::MM_FACEFACETOPO); m.clearDataMask(MeshModel::MM_VERTFACETOPO); } break; diff --git a/src/meshlabplugins/filter_clean/cleanfilter.h b/src/meshlabplugins/filter_clean/cleanfilter.h index 3f858f92f..58d522b36 100644 --- a/src/meshlabplugins/filter_clean/cleanfilter.h +++ b/src/meshlabplugins/filter_clean/cleanfilter.h @@ -64,14 +64,14 @@ class CleanFilter : public QObject, public FilterPlugin ~CleanFilter(); QString pluginName() const; - virtual QString filterName(ActionIDType filter) const; - virtual QString filterInfo(ActionIDType filter) const; + QString filterName(ActionIDType filter) const; + QString filterInfo(ActionIDType filter) const; - virtual FilterClass getClass(const QAction*) const; - virtual int getRequirements(const QAction*); + FilterClass getClass(const QAction*) const; + int getRequirements(const QAction*); int postCondition(const QAction* ) const; int getPreConditions(const QAction *) const { return MeshModel::MM_NONE; } - virtual void initParameterList(const QAction*, MeshDocument &/*m*/, RichParameterList & /*parent*/); + RichParameterList initParameterList(const QAction*, const MeshDocument &/*m*/); std::map applyFilter(const QAction* action, const RichParameterList & /*parent*/, MeshDocument &md, unsigned int& postConditionMask, vcg::CallBackPos * cb); FilterArity filterArity(const QAction *) const {return SINGLE_MESH;} }; diff --git a/src/meshlabplugins/filter_color_projection/filter_color_projection.cpp b/src/meshlabplugins/filter_color_projection/filter_color_projection.cpp index 0c89d12fe..38e642246 100644 --- a/src/meshlabplugins/filter_color_projection/filter_color_projection.cpp +++ b/src/meshlabplugins/filter_color_projection/filter_color_projection.cpp @@ -47,7 +47,7 @@ using namespace vcg; #define CheckError(x,y); if ((x)) {throw MLException((y));} -static QString extractFilenameWOExt(MeshModel* mm) +static QString extractFilenameWOExt(const MeshModel* mm) { QFileInfo fi(mm->fullName()); return fi.baseName(); @@ -76,9 +76,12 @@ QString FilterColorProjectionPlugin::pluginName() const QString FilterColorProjectionPlugin::filterName(ActionIDType filterId) const { switch(filterId) { - case FP_SINGLEIMAGEPROJ : return QString("Project current raster color to current mesh"); - case FP_MULTIIMAGETRIVIALPROJ : return QString("Project active rasters color to current mesh"); - case FP_MULTIIMAGETRIVIALPROJTEXTURE : return QString("Project active rasters color to current mesh, filling the texture"); + case FP_SINGLEIMAGEPROJ : + return QString("Project current raster color to current mesh"); + case FP_MULTIIMAGETRIVIALPROJ : + return QString("Project active rasters color to current mesh"); + case FP_MULTIIMAGETRIVIALPROJTEXTURE : + return QString("Project active rasters color to current mesh, filling the texture"); default : assert(0); } return NULL; @@ -122,8 +125,9 @@ bool FilterColorProjectionPlugin::requiresGLContext(const QAction* action) const // This function define the needed parameters for each filter. -void FilterColorProjectionPlugin::initParameterList(const QAction *action, MeshDocument &md, RichParameterList & parlst) +RichParameterList FilterColorProjectionPlugin::initParameterList(const QAction *action, const MeshDocument &md) { + RichParameterList parlst; switch(ID(action)) { case FP_SINGLEIMAGEPROJ : @@ -229,6 +233,7 @@ void FilterColorProjectionPlugin::initParameterList(const QAction *action, MeshD default: break; // do not add any parameter for the other filters } + return parlst; } // Core Function doing the actual mesh processing. @@ -237,41 +242,40 @@ std::map FilterColorProjectionPlugin::applyFilter(const Q if (glContext != nullptr){ //CMeshO::FaceIterator fi; CMeshO::VertexIterator vi; - + RenderHelper *rendermanager=NULL; switch(ID(filter)) { - + ////--------------------------- project single trivial ---------------------------------- - + case FP_SINGLEIMAGEPROJ : { bool use_depth = par.getBool("usedepth"); bool onselection = par.getBool("onselection"); Scalarm eta = par.getFloat("deptheta"); QColor blank = par.getColor("blankColor"); - - + Scalarm depth=0; // depth of point (distance from camera) Scalarm pdepth=0; // depth value of projected point (from depth map) - + // get current raster and model RasterModel *raster = md.rm(); MeshModel *model = md.mm(); - + // no projection if camera not valid if(!raster || !raster->shot.IsValid()) { throw MLException("Raster or camera not valid."); } - + // the mesh has to be correctly transformed before mapping tri::UpdatePosition::Matrix(model->cm,model->cm.Tr,true); tri::UpdateBounding::Box(model->cm); // making context current glContext->makeCurrent(); - + if(use_depth) { // init rendermanager @@ -285,14 +289,14 @@ std::map FilterColorProjectionPlugin::applyFilter(const Q //if( rendermanager->initializeMeshBuffers(model, cb) != 0 ) // return false; //Log("init Buffers"); - + // render depth rendermanager->renderScene(raster->shot, model, RenderHelper::FLAT, glContext); } - + // unmaking context current glContext->doneCurrent(); - + qDebug("Viewport %i %i",raster->shot.Intrinsics.ViewportPx[0],raster->shot.Intrinsics.ViewportPx[1]); for(vi=model->cm.vert.begin();vi!=model->cm.vert.end();++vi) { @@ -301,10 +305,10 @@ std::map FilterColorProjectionPlugin::applyFilter(const Q Point2m pp = raster->shot.Project((*vi).P()); // pray is the vector from the point-to-be-colored to the camera center Point3m pray = (raster->shot.GetViewPoint() - (*vi).P()).Normalize(); - + if ((blank.red() != 0) || (blank.green() != 0) || (blank.blue() != 0) || (blank.alpha() != 0)) (*vi).C() = vcg::Color4b(blank.red(), blank.green(), blank.blue(), blank.alpha()); - + //if inside image if(pp[0]>0 && pp[1]>0 && pp[0]shot.Intrinsics.ViewportPx[0] && pp[1]shot.Intrinsics.ViewportPx[1]) { @@ -315,7 +319,7 @@ std::map FilterColorProjectionPlugin::applyFilter(const Q depth = raster->shot.Depth((*vi).P()); pdepth = rendermanager->depth->getval(int(pp[0]), int(pp[1]));//rendermanager->depth[(int(pp[1]) * raster->shot.Intrinsics.ViewportPx[0]) + int(pp[0])]; } - + if(!use_depth || (depth <= (pdepth + eta))) { QRgb pcolor = raster->currentPlane->image.pixel(pp[0],raster->shot.Intrinsics.ViewportPx[1] - pp[1]); @@ -325,21 +329,20 @@ std::map FilterColorProjectionPlugin::applyFilter(const Q } } } - + // the mesh has to return to its original position tri::UpdatePosition::Matrix(model->cm,Inverse(model->cm.Tr),true); tri::UpdateBounding::Box(model->cm); - + // delete rendermanager if(rendermanager != NULL) delete rendermanager; } break; - - + ////--------------------------- project multi trivial ---------------------------------- - + case FP_MULTIIMAGETRIVIALPROJ : { bool onselection = par.getBool("onselection"); @@ -350,35 +353,35 @@ std::map FilterColorProjectionPlugin::applyFilter(const Q bool usesilhouettes = par.getBool("usesilhouettes"); bool usealphamask = par.getBool("usealpha"); QColor blank = par.getColor("blankColor"); - + Scalarm depth=0; // depth of point (distance from camera) Scalarm pdepth=0; // depth value of projected point (from depth map) double pweight; // pixel weight MeshModel *model; bool do_project; int cam_ind; - + // min max depth for depth weight normalization float allcammaxdepth; float allcammindepth; - + // max image size for border weight normalization float allcammaximagesize; - + // accumulation buffers for colors and weights int buff_ind; double *weights; double *acc_red; double *acc_grn; double *acc_blu; - + // get current model model = md.mm(); - + // the mesh has to be correctly transformed before mapping tri::UpdatePosition::Matrix(model->cm,model->cm.Tr,true); tri::UpdateBounding::Box(model->cm); - + // init accumulation buffers for colors and weights log("init color accumulation buffers"); weights = new double[model->cm.vn]; @@ -392,47 +395,49 @@ std::map FilterColorProjectionPlugin::applyFilter(const Q acc_grn[buff_ind] = 0.0; acc_blu[buff_ind] = 0.0; } - + // calculate accuratenear/far for all cameras std::vector my_near; std::vector my_far; calculateNearFarAccurate(md, &my_near, &my_far); - + allcammaxdepth = -1000000; allcammindepth = 1000000; allcammaximagesize = -1000000; - for(cam_ind = 0; cam_ind < md.rasterList.size(); cam_ind++) + cam_ind = 0; + for(RasterModel* rm : md.rasterIterator()) { if(my_far[cam_ind] > allcammaxdepth) allcammaxdepth = my_far[cam_ind]; if(my_near[cam_ind] < allcammindepth) allcammindepth = my_near[cam_ind]; - - float imgdiag = sqrt(double(md.rasterList[cam_ind]->shot.Intrinsics.ViewportPx[0] * md.rasterList[cam_ind]->shot.Intrinsics.ViewportPx[1])); + + float imgdiag = sqrt(double(rm->shot.Intrinsics.ViewportPx[0] * rm->shot.Intrinsics.ViewportPx[1])); if (imgdiag > allcammaximagesize) allcammaximagesize = imgdiag; + cam_ind++; } - + //-- cycle all cameras cam_ind = 0; - for(RasterModel *raster : md.rasterList){ + for(RasterModel *raster : md.rasterIterator()){ if(raster->visible) { do_project = true; - + // no drawing if camera not valid if(!raster->shot.IsValid()) do_project = false; - + // no drawing if raster is not active //if(!raster->shot.IsValid()) // do_project = false; - + if(do_project) { // making context current glContext->makeCurrent(); - + // delete & reinit rendermanager if(rendermanager != NULL) delete rendermanager; @@ -445,15 +450,15 @@ std::map FilterColorProjectionPlugin::applyFilter(const Q /*if( rendermanager->initializeMeshBuffers(model, cb) != 0 ) return false; Log("init Buffers");*/ - + // render normal & depth rendermanager->renderScene(raster->shot, model, RenderHelper::NORMAL, glContext, my_near[cam_ind]*0.5, my_far[cam_ind]*1.25); - + // unmaking context current glContext->doneCurrent(); - + buff_ind=0; - + // If should be used silhouette weighting, it is needed to compute depth discontinuities // and per-pixel distance from detected borders on the entire image here // the weight is then applied later, per-vertex, when needed @@ -463,20 +468,20 @@ std::map FilterColorProjectionPlugin::applyFilter(const Q { silhouette_buff = new floatbuffer(); silhouette_buff->init(rendermanager->depth->sx, rendermanager->depth->sy); - + silhouette_buff->applysobel(rendermanager->depth); //sprintf(dumpFileName,"Abord%i.pfm",cam_ind); //silhouette_buff->dumppfm(dumpFileName); - + silhouette_buff->initborder(rendermanager->depth); //sprintf(dumpFileName,"Bbord%i.pfm",cam_ind); //silhouette_buff->dumppfm(dumpFileName); - + maxsildist = silhouette_buff->distancefield(); //sprintf(dumpFileName,"Cbord%i.pfm",cam_ind); //silhouette_buff->dumppfm(dumpFileName); } - + for(vi=model->cm.vert.begin();vi!=model->cm.vert.end();++vi) { if(!(*vi).IsD() && (!onselection || (*vi).IsS())) @@ -485,45 +490,45 @@ std::map FilterColorProjectionPlugin::applyFilter(const Q Point2m pp = raster->shot.Project((*vi).P()); // pray is the vector from the point-to-be-colored to the camera center Point3m pray = (raster->shot.GetViewPoint() - (*vi).P()).Normalize(); - + //if inside image if(pp[0]>=0 && pp[1]>=0 && pp[0]shot.Intrinsics.ViewportPx[0] && pp[1]shot.Intrinsics.ViewportPx[1]) { if((pray.dot(-raster->shot.Axis(2))) <= 0.0) { - + depth = raster->shot.Depth((*vi).P()); pdepth = rendermanager->depth->getval(int(pp[0]), int(pp[1])); // rendermanager->depth[(int(pp[1]) * raster->shot.Intrinsics.ViewportPx[0]) + int(pp[0])]; - + if(depth <= (pdepth + eta)) { // determine color QRgb pcolor = raster->currentPlane->image.pixel(pp[0],raster->shot.Intrinsics.ViewportPx[1] - pp[1]); // determine weight pweight = 1.0; - + if(useangle) { Point3m pixnorm = (*vi).N(); Point3m viewaxis = raster->shot.GetViewPoint() - (*vi).P(); pixnorm.Normalize(); viewaxis.Normalize(); - + float ang = abs(pixnorm * viewaxis); ang = min(1.0f, ang); - + pweight *= ang; } - + if(usedistance) { float distw = depth; distw = 1.0 - (distw - (allcammindepth*0.99)) / ((allcammaxdepth*1.01) - (allcammindepth*0.99)); - + pweight *= distw; pweight *= distw; } - + if(useborders) { double xdist = 1.0 - (abs(pp[0] - (raster->shot.Intrinsics.ViewportPx[0] / 2.0)) / (raster->shot.Intrinsics.ViewportPx[0] / 2.0)); @@ -531,10 +536,10 @@ std::map FilterColorProjectionPlugin::applyFilter(const Q double borderw = min (xdist , ydist); //borderw = min(1.0,borderw); //debug debug //borderw = max(0.0,borderw); //debug debug - + pweight *= borderw; } - + if(usesilhouettes) { // here the silhouette weight is applied, but it is calculated before, on a per-image basis @@ -542,15 +547,15 @@ std::map FilterColorProjectionPlugin::applyFilter(const Q silw = silhouette_buff->getval(int(pp[0]), int(pp[1])) / maxsildist; //silw = min(1.0f,silw); //debug debug //silw = max(0.0f,silw); //debug debug - + pweight *= silw; } - + if(usealphamask) //alpha channel of image is an additional mask { pweight *= (qAlpha(pcolor) / 255.0); } - + weights[buff_ind] += pweight; acc_red[buff_ind] += (qRed(pcolor) * pweight / 255.0); acc_grn[buff_ind] += (qGreen(pcolor) * pweight / 255.0); @@ -562,16 +567,16 @@ std::map FilterColorProjectionPlugin::applyFilter(const Q buff_ind++; } cam_ind ++; - + if(usesilhouettes) { delete silhouette_buff; } - + } // end foreach camera } // end foreach camera } - + buff_ind = 0; for(vi=model->cm.vert.begin();vi!=model->cm.vert.end();++vi) { @@ -592,33 +597,33 @@ std::map FilterColorProjectionPlugin::applyFilter(const Q } buff_ind++; } - + // the mesh has to return to its original position tri::UpdatePosition::Matrix(model->cm,Inverse(model->cm.Tr),true); tri::UpdateBounding::Box(model->cm); - + // delete rendermanager if(rendermanager != NULL) delete rendermanager; - + // delete accumulation buffers delete[] weights; delete[] acc_red; delete[] acc_grn; delete[] acc_blu; - + } break; - - + + case FP_MULTIIMAGETRIVIALPROJTEXTURE : { - + if(!tri::HasPerWedgeTexCoord(md.mm()->cm)) { throw MLException("Error: nothing have been done. Mesh has no Texture Coordinates."); } - + //bool onselection = par.getBool("onselection"); int texsize = par.getInt("texsize"); bool dorefill = par.getBool("dorefill"); @@ -629,31 +634,31 @@ std::map FilterColorProjectionPlugin::applyFilter(const Q bool usesilhouettes = par.getBool("usesilhouettes"); bool usealphamask = par.getBool("usealpha"); QString textName = par.getString("textName"); - + int textW = texsize; int textH = texsize; - + Scalarm depth=0; // depth of point (distance from camera) Scalarm pdepth=0; // depth value of projected point (from depth map) double pweight; // pixel weight MeshModel *model; bool do_project; int cam_ind; - + // min max depth for depth weight normalization float allcammaxdepth; float allcammindepth; - + // max image size for border weight normalization float allcammaximagesize; - + // get the working model model = md.mm(); - + // the mesh has to be correctly transformed before mapping tri::UpdatePosition::Matrix(model->cm,model->cm.Tr,true); tri::UpdateBounding::Box(model->cm); - + // texture file name QString filePath(model->fullName()); filePath = filePath.left(std::max(filePath.lastIndexOf('\\'),filePath.lastIndexOf('/'))+1); @@ -663,13 +668,13 @@ std::map FilterColorProjectionPlugin::applyFilter(const Q if (!textName.endsWith(".png", Qt::CaseInsensitive)) textName.append(".png"); filePath.append(textName); - + // Image creation CheckError(textW <= 0, "Texture Width has an incorrect value"); CheckError(textH <= 0, "Texture Height has an incorrect value"); QImage img(QSize(textW,textH), QImage::Format_ARGB32); img.fill(qRgba(0,0,0,0)); // transparent black - + // Compute (texture-space) border edges if(dorefill) { @@ -677,25 +682,25 @@ std::map FilterColorProjectionPlugin::applyFilter(const Q tri::UpdateTopology::FaceFaceFromTexCoord(model->cm); tri::UpdateFlags::FaceBorderFromFF(model->cm); } - + // create a list of to-be-filled texels and accumulators // storing texel 2d coords, texel mesh-space point, texel mesh normal - + vector texels; texels.clear(); texels.reserve(textW*textH); // just to avoid the 2x reallocate rule... - + vector accums; accums.clear(); accums.reserve(textW*textH); // just to avoid the 2x reallocate rule... - + // Rasterizing triangles in the list of voxels TexFillerSampler tfs(img); tfs.texelspointer = &texels; tfs.accumpointer = &accums; tfs.InitCallback(cb, model->cm.fn, 0, 80); tri::SurfaceSampling::Texture(model->cm,tfs,textW,textH,true); - + // Revert alpha values for border edge pixels to 255 cb(81, "Cleaning up texture ..."); for (int y=0; y FilterColorProjectionPlugin::applyFilter(const Q img.setPixel(x,y, px | 0xff000000); } } - + // calculate accuratenear/far for all cameras std::vector my_near; std::vector my_far; calculateNearFarAccurate(md, &my_near, &my_far); - + allcammaxdepth = -1000000; allcammindepth = 1000000; allcammaximagesize = -1000000; - for(cam_ind = 0; cam_ind < md.rasterList.size(); cam_ind++) + cam_ind = 0; + for(RasterModel* rm : md.rasterIterator()) { if(my_far[cam_ind] > allcammaxdepth) allcammaxdepth = my_far[cam_ind]; if(my_near[cam_ind] < allcammindepth) allcammindepth = my_near[cam_ind]; - - float imgdiag = sqrt(double(md.rasterList[cam_ind]->shot.Intrinsics.ViewportPx[0] * md.rasterList[cam_ind]->shot.Intrinsics.ViewportPx[1])); + + float imgdiag = sqrt(double(rm->shot.Intrinsics.ViewportPx[0] * rm->shot.Intrinsics.ViewportPx[1])); if (imgdiag > allcammaximagesize) allcammaximagesize = imgdiag; + cam_ind++; } - + //-- cycle all cameras cam_ind = 0; - for(RasterModel *raster : md.rasterList) + for(RasterModel *raster : md.rasterIterator()) { if(raster->visible) { do_project = true; - + // no drawing if camera not valid if(!raster->shot.IsValid()) do_project = false; - + // no drawing if raster is not active //if(!raster->shot.IsValid()) // do_project = false; - + if(do_project) { // making context current glContext->makeCurrent(); - + // delete & reinit rendermanager if(rendermanager != NULL) delete rendermanager; @@ -761,13 +768,13 @@ std::map FilterColorProjectionPlugin::applyFilter(const Q /*if( rendermanager->initializeMeshBuffers(model, cb) != 0 ) return false; Log("init Buffers");*/ - + // render normal & depth rendermanager->renderScene(raster->shot, model, RenderHelper::NORMAL, glContext, my_near[cam_ind]*0.5, my_far[cam_ind]*1.25); - + // unmaking context current glContext->doneCurrent(); - + // If should be used silhouette weighting, it is needed to compute depth discontinuities // and per-pixel distance from detected borders on the entire image here // the weight is then applied later, per-vertex, when needed @@ -777,74 +784,74 @@ std::map FilterColorProjectionPlugin::applyFilter(const Q { silhouette_buff = new floatbuffer(); silhouette_buff->init(rendermanager->depth->sx, rendermanager->depth->sy); - + silhouette_buff->applysobel(rendermanager->depth); //sprintf(dumpFileName,"Abord%i.bmp",cam_ind); //silhouette_buff->dumpbmp(dumpFileName); - + silhouette_buff->initborder(rendermanager->depth); //sprintf(dumpFileName,"Bbord%i.bmp",cam_ind); //silhouette_buff->dumpbmp(dumpFileName); - + maxsildist = silhouette_buff->distancefield(); //sprintf(dumpFileName,"Cbord%i.bmp",cam_ind); //silhouette_buff->dumpbmp(dumpFileName); } - + for(size_t texcount=0; texcount < texels.size(); texcount++) { Point2m pp = raster->shot.Project(texels[texcount].meshpoint); // pray is the vector from the point-to-be-colored to the camera center Point3m pray = (raster->shot.GetViewPoint() - texels[texcount].meshpoint).Normalize(); - + //if inside image if(pp[0]>0 && pp[1]>0 && pp[0]shot.Intrinsics.ViewportPx[0] && pp[1]shot.Intrinsics.ViewportPx[1]) { if((pray.dot(-raster->shot.Axis(2))) <= 0.0) { - + depth = raster->shot.Depth(texels[texcount].meshpoint); pdepth = rendermanager->depth->getval(int(pp[0]), int(pp[1])); // rendermanager->depth[(int(pp[1]) * raster->shot.Intrinsics.ViewportPx[0]) + int(pp[0])]; - + if(depth <= (pdepth + eta)) { // determine color QRgb pcolor = raster->currentPlane->image.pixel(pp[0],raster->shot.Intrinsics.ViewportPx[1] - pp[1]); // determine weight pweight = 1.0; - + if(useangle) { Point3m pixnorm = texels[texcount].meshnormal; pixnorm.Normalize(); - + Point3m viewaxis = raster->shot.GetViewPoint() - texels[texcount].meshpoint; viewaxis.Normalize(); - + float ang = abs(pixnorm * viewaxis); ang = min(1.0f, ang); - + pweight *= ang; } - + if(usedistance) { float distw = depth; distw = 1.0 - (distw - (allcammindepth*0.99)) / ((allcammaxdepth*1.01) - (allcammindepth*0.99)); - + pweight *= distw; pweight *= distw; } - + if(useborders) { double xdist = 1.0 - (abs(pp[0] - (raster->shot.Intrinsics.ViewportPx[0] / 2.0)) / (raster->shot.Intrinsics.ViewportPx[0] / 2.0)); double ydist = 1.0 - (abs(pp[1] - (raster->shot.Intrinsics.ViewportPx[1] / 2.0)) / (raster->shot.Intrinsics.ViewportPx[1] / 2.0)); double borderw = min (xdist , ydist); - + pweight *= borderw; } - + if(usesilhouettes) { // here the silhouette weight is applied, but it is calculated before, on a per-image basis @@ -852,12 +859,12 @@ std::map FilterColorProjectionPlugin::applyFilter(const Q silw = silhouette_buff->getval(int(pp[0]), int(pp[1])) / maxsildist; pweight *= silw; } - + if(usealphamask) //alpha channel of image is an additional mask { pweight *= (qAlpha(pcolor) / 255.0); } - + accums[texcount].weights += pweight; accums[texcount].acc_red += (qRed(pcolor) * pweight / 255.0); accums[texcount].acc_grn += (qGreen(pcolor) * pweight / 255.0); @@ -865,20 +872,20 @@ std::map FilterColorProjectionPlugin::applyFilter(const Q } } } - + } // end foreach texel cam_ind ++; - + if(usesilhouettes) { delete silhouette_buff; } - + } // end if(do_project) - + } } // end foreach camera - + // for each texel.... divide accumulated values by weight and write to texture for(size_t texcount=0; texcount < texels.size(); texcount++) { @@ -887,44 +894,39 @@ std::map FilterColorProjectionPlugin::applyFilter(const Q float texel_red = accums[texcount].acc_red / accums[texcount].weights; float texel_green = accums[texcount].acc_grn / accums[texcount].weights; float texel_blue = accums[texcount].acc_blu / accums[texcount].weights; - + img.setPixel(texels[texcount].texcoord.X(), img.height() - 1 - texels[texcount].texcoord.Y(), qRgba(texel_red*255.0, texel_green*255.0, texel_blue*255.0, 255)); } - else // if no projected data available, black (to be refilled later on + else // if no projected data available, black (to be refilled later on { img.setPixel(texels[texcount].texcoord.X(), img.height() - 1 - texels[texcount].texcoord.Y(), qRgba(0, 0, 0, 0)); } } - + // cleaning texels.clear(); accums.clear(); - + // PullPush if(dorefill) { cb(85, "Filling texture holes..."); - + PullPush(img, qRgba(0,0,0,0)); // atlas gaps } - + // Undo topology changes if(dorefill) { tri::UpdateTopology::FaceFace(model->cm); tri::UpdateFlags::FaceBorderFromFF(model->cm); } - - // Save texture - cb(90, "Saving texture ..."); - CheckError(!img.save(filePath), "Texture file cannot be saved"); - log( "Texture \"%s\" Created", filePath.toStdString().c_str()); - assert(QFile(filePath).exists()); - + // Assign texture - model->cm.textures.clear(); - model->cm.textures.push_back(textName.toStdString()); - + cb(90, "Assigning texture ..."); + model->clearTextures(); + model->addTexture(textName.toStdString(), img); + // the mesh has to return to its original position tri::UpdatePosition::Matrix(model->cm,Inverse(model->cm.Tr),true); tri::UpdateBounding::Box(model->cm); @@ -981,7 +983,7 @@ int FilterColorProjectionPlugin::calculateNearFarAccurate(MeshDocument &md, std: if(near_acc != NULL) { near_acc->clear(); - near_acc->resize(md.rasterList.size()); + near_acc->resize(md.rasterNumber()); } else return -1; @@ -989,13 +991,13 @@ int FilterColorProjectionPlugin::calculateNearFarAccurate(MeshDocument &md, std: if(far_acc != NULL) { far_acc->clear(); - far_acc->resize(md.rasterList.size()); + far_acc->resize(md.rasterNumber()); } else return -1; // init near and far vectors - for(rasterindex = 0; rasterindex < md.rasterList.size(); rasterindex++) + for(unsigned int rasterindex = 0; rasterindex < md.rasterNumber(); rasterindex++) { (*near_acc)[rasterindex] = 1000000; (*far_acc)[rasterindex] = -1000000; @@ -1011,7 +1013,7 @@ int FilterColorProjectionPlugin::calculateNearFarAccurate(MeshDocument &md, std: { // check against all cameras rasterindex = 0; - foreach(RasterModel *raster, md.rasterList) + for(RasterModel *raster: md.rasterIterator()) { if(raster->shot.IsValid()) { @@ -1036,7 +1038,7 @@ int FilterColorProjectionPlugin::calculateNearFarAccurate(MeshDocument &md, std: } } - for(rasterindex = 0; rasterindex < md.rasterList.size(); rasterindex++) // set to 0 0 invalid and "strange" cameras + for(unsigned rasterindex = 0; rasterindex < md.rasterNumber(); rasterindex++) // set to 0 0 invalid and "strange" cameras { if ( ((*near_acc)[rasterindex] == 1000000) || ((*far_acc)[rasterindex] == -1000000) ) { diff --git a/src/meshlabplugins/filter_color_projection/filter_color_projection.h b/src/meshlabplugins/filter_color_projection/filter_color_projection.h index 51000bc71..0643990c7 100644 --- a/src/meshlabplugins/filter_color_projection/filter_color_projection.h +++ b/src/meshlabplugins/filter_color_projection/filter_color_projection.h @@ -44,7 +44,7 @@ class FilterColorProjectionPlugin : public QObject, public FilterPlugin int postCondition( const QAction* ) const; FilterClass getClass(const QAction*) const; - void initParameterList(const QAction*, MeshDocument &/*m*/, RichParameterList & /*parent*/); + RichParameterList initParameterList(const QAction*, const MeshDocument &/*m*/); int getRequirements(const QAction*); bool requiresGLContext(const QAction* action) const; std::map applyFilter(const QAction* action, const RichParameterList & /*parent*/, MeshDocument &md, unsigned int& postConditionMask, vcg::CallBackPos * cb); diff --git a/src/meshlabplugins/filter_colorproc/filter_colorproc.cpp b/src/meshlabplugins/filter_colorproc/filter_colorproc.cpp index c18ea126b..08be43af0 100644 --- a/src/meshlabplugins/filter_colorproc/filter_colorproc.cpp +++ b/src/meshlabplugins/filter_colorproc/filter_colorproc.cpp @@ -189,8 +189,9 @@ int FilterColorProc::getRequirements(const QAction *action) assert(0); } -void FilterColorProc::initParameterList(const QAction *a, MeshDocument& md, RichParameterList & par) +RichParameterList FilterColorProc::initParameterList(const QAction *a, const MeshDocument& md) { + RichParameterList par; switch(ID(a)) { case CP_FILLING: @@ -380,6 +381,7 @@ void FilterColorProc::initParameterList(const QAction *a, MeshDocument& md, Rich default: break; // do not add any parameter for the other filters } + return par; } std::map FilterColorProc::applyFilter(const QAction *filter, const RichParameterList &par, MeshDocument &md, unsigned int& /*postConditionMask*/, vcg::CallBackPos *cb) @@ -452,13 +454,13 @@ std::map FilterColorProc::applyFilter(const QAction *filt if (all_levels) { - foreach(MeshModel *mm, md.meshList) + for(MeshModel *mm: md.meshIterator()) if (mm->isVisible()) - vcg::tri::UpdateColor::PerVertexLevels(mm->cm, gamma, in_min, in_max, out_min, out_max, rgbMask, selected); + vcg::tri::UpdateColor::PerVertexLevels(mm->cm, gamma, in_min, in_max, out_min, out_max, rgbMask, selected); } else { - vcg::tri::UpdateColor::PerVertexLevels(m->cm, gamma, in_min, in_max, out_min, out_max, rgbMask, selected); + vcg::tri::UpdateColor::PerVertexLevels(m->cm, gamma, in_min, in_max, out_min, out_max, rgbMask, selected); } break; } @@ -518,9 +520,9 @@ std::map FilterColorProc::applyFilter(const QAction *filt if(seed==0) seed = time(NULL); math::MarsenneTwisterRNG myrnd(seed); - int numOfMeshes = md.meshList.size(); + int numOfMeshes = md.meshNumber(); int id = myrnd.generate(numOfMeshes); - foreach(MeshModel *mm, md.meshList) + for(MeshModel *mm: md.meshIterator()) { if (mm->isVisible()) mm->cm.C()=Color4b::Scatter(numOfMeshes,id); @@ -864,7 +866,7 @@ std::map FilterColorProc::applyFilter(const QAction *filt case CP_MESH_TO_FACE: { - foreach(MeshModel *mmi, md.meshList) + for(MeshModel *mmi: md.meshIterator()) { if (mmi->visible) { diff --git a/src/meshlabplugins/filter_colorproc/filter_colorproc.h b/src/meshlabplugins/filter_colorproc/filter_colorproc.h index 57e200dbf..7334eefa0 100644 --- a/src/meshlabplugins/filter_colorproc/filter_colorproc.h +++ b/src/meshlabplugins/filter_colorproc/filter_colorproc.h @@ -77,7 +77,7 @@ public: virtual int getRequirements(const QAction*); - virtual void initParameterList(const QAction*, MeshDocument&, RichParameterList & /*parent*/); + virtual RichParameterList initParameterList(const QAction*, const MeshDocument&); std::map applyFilter(const QAction* action, const RichParameterList & /*parent*/, MeshDocument &md, unsigned int& postConditionMask, vcg::CallBackPos * cb); int postCondition(const QAction* filter) const; int getPreConditions(const QAction *) const; diff --git a/src/meshlabplugins/filter_create/filter_create.cpp b/src/meshlabplugins/filter_create/filter_create.cpp index b5d4e7976..fcc8c5166 100644 --- a/src/meshlabplugins/filter_create/filter_create.cpp +++ b/src/meshlabplugins/filter_create/filter_create.cpp @@ -76,7 +76,7 @@ QString FilterCreate::filterName(ActionIDType filterId) const case CR_FITPLANE: return QString("Fit a plane to selection"); default : assert(0); } - return NULL; + return ""; } // Info() must return the longer string describing each filtering action @@ -98,7 +98,7 @@ QString FilterCreate::filterInfo(ActionIDType filterId) const case CR_FITPLANE: return QString("Create a quad on the plane fitting the selection"); default : assert(0); } - return NULL; + return ""; } // This function define the needed parameters for each filter. Return true if the filter has some parameters @@ -108,20 +108,23 @@ QString FilterCreate::filterInfo(ActionIDType filterId) const // - the string shown in the dialog // - the default value // - a possibly long string describing the meaning of that parameter (shown as a popup help in the dialog) -void FilterCreate::initParameterList(const QAction *action, MeshModel & /*m*/, RichParameterList & parlst) +RichParameterList FilterCreate::initParameterList(const QAction *action, const MeshModel & /*m*/) { + RichParameterList parlst; switch(ID(action)) { case CR_SPHERE : parlst.addParam(RichFloat("radius",1,"Radius","Radius of the sphere")); - parlst.addParam(RichInt("subdiv",3,"Subdiv. Level","Number of the recursive subdivision of the surface. Default is 3 (a sphere approximation composed by 1280 faces).
" - "Admitted values are in the range 0 (an icosahedron) to 8 (a 1.3 MegaTris approximation of a sphere)")); + parlst.addParam(RichInt("subdiv",3,"Subdiv. Level", + "Number of the recursive subdivision of the surface. Default is 3 (a sphere approximation composed by 1280 faces).
" + "Admitted values are in the range 0 (an icosahedron) to 8 (a 1.3 MegaTris approximation of a sphere)")); break; case CR_SPHERE_CAP : parlst.addParam(RichFloat("angle",60,"Angle","Angle of the cone subtending the cap. It must be < 180")); - parlst.addParam(RichInt("subdiv",3,"Subdiv. Level","Number of the recursive subdivision of the surface. Default is 3 (a sphere approximation composed by 1280 faces).
" - "Admitted values are in the range 0 (an icosahedron) to 8 (a 1.3 MegaTris approximation of a sphere)")); + parlst.addParam(RichInt("subdiv",3,"Subdiv. Level", + "Number of the recursive subdivision of the surface. Default is 3 (a sphere approximation composed by 1280 faces).
" + "Admitted values are in the range 0 (an icosahedron) to 8 (a 1.3 MegaTris approximation of a sphere)")); break; case CR_ANNULUS : parlst.addParam(RichFloat("internalRadius",0.5f,"Internal Radius","Internal Radius of the annulus")); @@ -134,12 +137,11 @@ void FilterCreate::initParameterList(const QAction *action, MeshModel & /*m*/, R QStringList() << "Montecarlo" << "Poisson Sampling" << "DiscoBall" << "Octahedron" << "Fibonacci", tr("Generation Technique:"), tr("Generation Technique:" - "Montecarlo: The points are randomly generated with an uniform distribution.
" - "Poisson Disk: The points are to follow a poisson disk distribution.
" - "Disco Ball Dave Rusin's disco ball algorithm for the regular placement of points on a sphere is used.
" - "Recursive Octahedron Points are generated on the vertex of a recursively subdivided octahedron
" - "Fibonacci . " - ))); + "Montecarlo: The points are randomly generated with an uniform distribution.
" + "Poisson Disk: The points are to follow a poisson disk distribution.
" + "Disco Ball Dave Rusin's disco ball algorithm for the regular placement of points on a sphere is used.
" + "Recursive Octahedron Points are generated on the vertex of a recursively subdivided octahedron
" + "Fibonacci . "))); break; case CR_BOX : @@ -167,13 +169,14 @@ void FilterCreate::initParameterList(const QAction *action, MeshModel & /*m*/, R QStringList() << "quasi-Straight Fit" << "Best Fit" << "XZ Parallel" << "YZ Parallel" << "YX Parallel", tr("Plane orientation"), tr("Orientation:" - "quasi-Straight Fit: The fitting plane will be oriented (as much as possible) straight with the axeses.
" - "Best Fit: The fitting plane will be oriented and sized trying to best fit to the selected area.
" - "-- Parallel: The fitting plane will be oriented with a side parallel with the chosen plane. WARNING: do not use if the selection is exactly parallel to a plane.
" - ))); + "quasi-Straight Fit: The fitting plane will be oriented (as much as possible) straight with the axeses.
" + "Best Fit: The fitting plane will be oriented and sized trying to best fit to the selected area.
" + "-- Parallel: The fitting plane will be oriented with a side parallel with the chosen plane. WARNING: do not use if the selection is exactly parallel to a plane.
"))); break; - default : return; + default : + ; } + return parlst; } // The Real Core Function doing the actual mesh processing. @@ -445,7 +448,6 @@ std::map FilterCreate::applyFilter(const QAction *filter, m->cm.Clear(); std::vector sampleVec; - switch(sphereGenTech) { case 0: // Montecarlo @@ -533,8 +535,10 @@ std::map FilterCreate::applyFilter(const QAction *filter, }//CASE FILTER - tri::UpdateBounding::Box(m->cm); - tri::UpdateNormal::PerVertexNormalizedPerFaceNormalized(m->cm); + if (m != nullptr){ + tri::UpdateBounding::Box(m->cm); + tri::UpdateNormal::PerVertexNormalizedPerFaceNormalized(m->cm); + } return std::map(); } diff --git a/src/meshlabplugins/filter_create/filter_create.h b/src/meshlabplugins/filter_create/filter_create.h index b7b624d8b..5993b77cb 100644 --- a/src/meshlabplugins/filter_create/filter_create.h +++ b/src/meshlabplugins/filter_create/filter_create.h @@ -53,7 +53,7 @@ public: QString filterName(ActionIDType filter) const; QString filterInfo(ActionIDType filter) const; FilterClass getClass(const QAction*) const; - void initParameterList(const QAction*, MeshModel &/*m*/, RichParameterList & /*parent*/); + RichParameterList initParameterList(const QAction*, const MeshModel &/*m*/); std::map applyFilter(const QAction* action, const RichParameterList & /*parent*/, MeshDocument &md, unsigned int& postConditionMask, vcg::CallBackPos * cb); QString filterScriptFunctionName(ActionIDType filterID); FilterArity filterArity(const QAction *) const {return NONE;} diff --git a/src/meshlabplugins/filter_createiso/filter_createiso.cpp b/src/meshlabplugins/filter_createiso/filter_createiso.cpp index 9f1fbf81f..be188d8da 100644 --- a/src/meshlabplugins/filter_createiso/filter_createiso.cpp +++ b/src/meshlabplugins/filter_createiso/filter_createiso.cpp @@ -117,15 +117,17 @@ std::map FilterCreateIso::applyFilter(const QAction *filt printf("[MARCHING CUBES] Building mesh..."); MyMarchingCubes mc(m.cm, walker); walker.BuildMesh(m.cm, volume, mc, (gridSize*gridSize)/10,cb); - m.UpdateBoxAndNormals(); + m.updateBoxAndNormals(); } else { wrongActionCalled(filter); } return std::map(); } -void FilterCreateIso::initParameterList(const QAction *action,MeshModel & /*m*/, RichParameterList & parlst) + +RichParameterList FilterCreateIso::initParameterList(const QAction *action, const MeshModel & /*m*/) { + RichParameterList parlst; switch(ID(action)) { case FP_CREATEISO : @@ -133,6 +135,7 @@ void FilterCreateIso::initParameterList(const QAction *action,MeshModel & /*m*/, break; default: break; // do not add any parameter for the other filters } + return parlst; } diff --git a/src/meshlabplugins/filter_createiso/filter_createiso.h b/src/meshlabplugins/filter_createiso/filter_createiso.h index 01f4ad910..a475b59b6 100644 --- a/src/meshlabplugins/filter_createiso/filter_createiso.h +++ b/src/meshlabplugins/filter_createiso/filter_createiso.h @@ -56,12 +56,12 @@ class FilterCreateIso : public QObject, public FilterPlugin ~FilterCreateIso(); QString pluginName() const; - virtual QString filterName(ActionIDType filter) const; - virtual QString filterInfo(ActionIDType filter) const; + QString filterName(ActionIDType filter) const; + QString filterInfo(ActionIDType filter) const; - virtual FilterClass getClass(const QAction*) const; - virtual int getRequirements(const QAction*); - virtual void initParameterList(const QAction*, MeshModel &/*m*/, RichParameterList & /*parent*/); + FilterClass getClass(const QAction*) const; + int getRequirements(const QAction*); + RichParameterList initParameterList(const QAction*, const MeshModel &/*m*/); std::map applyFilter(const QAction* action, const RichParameterList & /*parent*/, MeshDocument &md, unsigned int& postConditionMask, vcg::CallBackPos * cb); FilterArity filterArity(const QAction*) const {return NONE;} diff --git a/src/meshlabplugins/filter_dirt/dirt_utils.cpp b/src/meshlabplugins/filter_dirt/dirt_utils.cpp index c1ff816f1..ad2d3d0a7 100644 --- a/src/meshlabplugins/filter_dirt/dirt_utils.cpp +++ b/src/meshlabplugins/filter_dirt/dirt_utils.cpp @@ -217,9 +217,9 @@ CMeshO::CoordType StepForward(CMeshO::CoordType p,CMeshO::CoordType v,Scalarm m, void DrawDust(MeshModel *base_mesh,MeshModel *cloud_mesh){ if(tri::HasPerWedgeTexCoord(base_mesh->cm) && base_mesh->cm.textures.size()>0){ - QImage img; + QImage img = base_mesh->getTexture(base_mesh->cm.textures[0]); //QFileInfo text_file=QFileInfo(base_mesh->cm.textures[0].c_str()); - img.load(base_mesh->cm.textures[0].c_str()); + //img.load(base_mesh->cm.textures[0].c_str()); QPainter painter(&img); Scalarm w=img.width(); Scalarm h=img.height(); @@ -242,10 +242,7 @@ void DrawDust(MeshModel *base_mesh,MeshModel *cloud_mesh){ dbc=p0*bc[0]+p1*bc[1]+p2*bc[2]; painter.drawPoint(dbc[0],dbc[1]); } - QString path=QDir::currentPath()+"/dirt_texture.png"; - img.save(path,"PNG"); - base_mesh->cm.textures.clear(); - base_mesh->cm.textures.push_back(path.toStdString()); + base_mesh->setTexture(base_mesh->cm.textures[0], img); } } diff --git a/src/meshlabplugins/filter_dirt/filter_dirt.cpp b/src/meshlabplugins/filter_dirt/filter_dirt.cpp index aa1e4237f..9d4c49c2d 100644 --- a/src/meshlabplugins/filter_dirt/filter_dirt.cpp +++ b/src/meshlabplugins/filter_dirt/filter_dirt.cpp @@ -99,8 +99,9 @@ QString FilterDirt::filterInfo(ActionIDType filterId) const } } -void FilterDirt::initParameterList(const QAction* filter,MeshDocument & /*md*/, RichParameterList &par){ - +RichParameterList FilterDirt::initParameterList(const QAction* filter, const MeshDocument & /*md*/) +{ + RichParameterList par; switch(ID(filter)){ case FP_DIRT:{ @@ -126,6 +127,7 @@ void FilterDirt::initParameterList(const QAction* filter,MeshDocument & /*md*/, break; } } + return par; } int FilterDirt::getRequirements(const QAction * /*action*/) @@ -186,7 +188,7 @@ std::map FilterDirt::applyFilter(const QAction *filter, c break; } case FP_CLOUD_MOVEMENT:{ - if(md.size()!=2){ + if(md.meshNumber()!=2){ throw MLException("This filter requires two mesh"); } diff --git a/src/meshlabplugins/filter_dirt/filter_dirt.h b/src/meshlabplugins/filter_dirt/filter_dirt.h index 5a83d48df..d3a4467af 100644 --- a/src/meshlabplugins/filter_dirt/filter_dirt.h +++ b/src/meshlabplugins/filter_dirt/filter_dirt.h @@ -64,7 +64,7 @@ public: virtual int getRequirements(const QAction*); virtual bool autoDialog(QAction *) {return true;} // virtual void initParameterSet(QAction* filter,MeshModel &,RichParameterSet &){}; - virtual void initParameterList(const QAction*, MeshDocument &/*m*/, RichParameterList & /*parent*/); + RichParameterList initParameterList(const QAction*, const MeshDocument &/*m*/); std::map applyFilter(const QAction* action, const RichParameterList & /*parent*/, MeshDocument &md, unsigned int& postConditionMask, vcg::CallBackPos * cb); virtual int postCondition(const QAction*) const; virtual FilterClass getClass (const QAction *) const; diff --git a/src/meshlabplugins/filter_fractal/filter_fractal.cpp b/src/meshlabplugins/filter_fractal/filter_fractal.cpp index 89267f68b..2934354d5 100644 --- a/src/meshlabplugins/filter_fractal/filter_fractal.cpp +++ b/src/meshlabplugins/filter_fractal/filter_fractal.cpp @@ -169,8 +169,9 @@ QString FilterFractal::filterInfo(ActionIDType filterId) const return description; } -void FilterFractal::initParameterList(const QAction* filter,MeshDocument &md, RichParameterList &par) +RichParameterList FilterFractal::initParameterList(const QAction* filter, const MeshDocument &md) { + RichParameterList par; switch(ID(filter)) { case CR_FRACTAL_TERRAIN: @@ -181,9 +182,10 @@ void FilterFractal::initParameterList(const QAction* filter,MeshDocument &md, Ri initParameterSetForCratersGeneration(md, par); break; } + return par; } -void FilterFractal::initParameterSetForFractalDisplacement(const QAction *filter, MeshDocument &md, RichParameterList &par) +void FilterFractal::initParameterSetForFractalDisplacement(const QAction *filter, const MeshDocument &md, RichParameterList &par) { bool terrain_filter = (ID(filter) == CR_FRACTAL_TERRAIN); @@ -213,18 +215,16 @@ void FilterFractal::initParameterSetForFractalDisplacement(const QAction *filter par.addParam(RichBool("saveAsQuality", false, "Save as vertex quality", "Saves the perturbation value as vertex quality.")); } -void FilterFractal::initParameterSetForCratersGeneration(MeshDocument &md, RichParameterList &par) +void FilterFractal::initParameterSetForCratersGeneration(const MeshDocument &md, RichParameterList &par) { - int meshCount = md.meshList.size(); - // tries to detect the target mesh - MeshModel* target = md.mm(); - MeshModel* samples = md.mm(); - MeshModel* tmpMesh; + const MeshModel* target = md.mm(); + const MeshModel* samples = md.mm(); + const MeshModel* tmpMesh; if (samples->cm.fn != 0){ // this is probably not the samples layer - for(int i=0; icm.fn == 0) { samples = tmpMesh; @@ -233,8 +233,8 @@ void FilterFractal::initParameterSetForCratersGeneration(MeshDocument &md, RichP } } - par.addParam(RichMesh("target_mesh", target, &md, "Target mesh:", "The mesh on which craters will be generated.")); - par.addParam(RichMesh("samples_mesh", samples, &md, "Samples layer:", "The samples that represent the central points of craters.")); + par.addParam(RichMesh("target_mesh", target->id(), &md, "Target mesh:", "The mesh on which craters will be generated.")); + par.addParam(RichMesh("samples_mesh", samples->id(), &md, "Samples layer:", "The samples that represent the central points of craters.")); par.addParam(RichInt("seed", 0, "Seed:", "The seed with which the random number generator is initialized. The random generator generates radius and depth for each crater into the given range.")); par.addParam(RichInt("smoothingSteps", 5, "Normals smoothing steps:", "Vertex normals are smoothed this number of times before generating craters.")); @@ -304,15 +304,15 @@ std::map FilterFractal::applyFilter( break; case FP_CRATERS: { - if (md.meshList.size() < 2) { + if (md.meshNumber() < 2) { throw MLException("There must be at least two layers to apply the craters generation filter."); } - CMeshO* samples = &(par.getMesh("samples_mesh")->cm); + CMeshO* samples = &(md.getMesh(par.getMeshId("samples_mesh"))->cm); if (samples->face.size() > 0) { throw MLException("The sample layer selected should be a points cloud."); } - CMeshO* target = &(par.getMesh("target_mesh")->cm); + CMeshO* target = &(md.getMesh(par.getMeshId("target_mesh"))->cm); if (samples == target) { throw MLException("The sample layer and the target layer must be different."); } @@ -330,7 +330,7 @@ std::map FilterFractal::applyFilter( } // reads parameters - CratersUtils::CratersArgs args(par.getMesh("target_mesh"), par.getMesh("samples_mesh"), par.getEnum("rbf"), + CratersUtils::CratersArgs args(md.getMesh(par.getMeshId("target_mesh")), md.getMesh(par.getMeshId("samples_mesh")), par.getEnum("rbf"), par.getInt("seed"), minRadius, maxRadius, minDepth, maxDepth, par.getInt("smoothingSteps"), par.getBool("save_as_quality"), par.getBool("invert"), par.getBool("ppNoise"), par.getBool("successiveImpacts"), diff --git a/src/meshlabplugins/filter_fractal/filter_fractal.h b/src/meshlabplugins/filter_fractal/filter_fractal.h index c9ac9f6cd..18535ce42 100644 --- a/src/meshlabplugins/filter_fractal/filter_fractal.h +++ b/src/meshlabplugins/filter_fractal/filter_fractal.h @@ -46,15 +46,15 @@ class FilterFractal : public QObject, public FilterPlugin QString filterInfo(ActionIDType filter) const; int getRequirements(const QAction*); - void initParameterList(const QAction*, MeshDocument &, RichParameterList &); + RichParameterList initParameterList(const QAction*, const MeshDocument &); std::map applyFilter(const QAction* action, const RichParameterList & /*parent*/, MeshDocument &md, unsigned int& postConditionMask, vcg::CallBackPos * cb); int postCondition(const QAction *action) const; FilterClass getClass(const QAction*) const; FilterArity filterArity(const QAction* act) const; private: - void initParameterSetForFractalDisplacement (const QAction*, MeshDocument &, RichParameterList &); - void initParameterSetForCratersGeneration (MeshDocument &md, RichParameterList &par); + void initParameterSetForFractalDisplacement (const QAction*, const MeshDocument &, RichParameterList &); + void initParameterSetForCratersGeneration (const MeshDocument &md, RichParameterList &par); enum {CR_FRACTAL_TERRAIN, FP_FRACTAL_MESH, FP_CRATERS}; }; diff --git a/src/meshlabplugins/filter_func/filter_func.cpp b/src/meshlabplugins/filter_func/filter_func.cpp index 968cc75d7..6fc9fd3e8 100644 --- a/src/meshlabplugins/filter_func/filter_func.cpp +++ b/src/meshlabplugins/filter_func/filter_func.cpp @@ -254,9 +254,9 @@ int FilterFunctionPlugin::getRequirements(const QAction *action) // - the string shown in the dialog // - the default value // - a possibly long string describing the meaning of that parameter (shown as a popup help in the dialog) -void FilterFunctionPlugin::initParameterList(const QAction *action,MeshModel &m, RichParameterList & parlst) +RichParameterList FilterFunctionPlugin::initParameterList(const QAction *action,const MeshModel &) { - Q_UNUSED(m); + RichParameterList parlst; switch(ID(action)) { case FF_VERT_SELECTION : @@ -369,6 +369,7 @@ void FilterFunctionPlugin::initParameterList(const QAction *action,MeshModel &m, default: break; // do not add any parameter for the other filters } + return parlst; } // The Real Core Function doing the actual mesh processing. @@ -981,7 +982,7 @@ std::map FilterFunctionPlugin::applyFilter( // Matrix44m rot; rot.SetRotateDeg(180,Point3m(0,1,0)); Matrix44m rot; rot.SetScale(-1,1,-1); tri::UpdatePosition::Matrix(m.cm,rot,false); - m.UpdateBoxAndNormals(); + m.updateBoxAndNormals(); } break; case FF_ISOSURFACE : @@ -1066,7 +1067,7 @@ std::map FilterFunctionPlugin::applyFilter( // and the new vertex is chosen with MidPointCustom created above vcg::tri::RefineE, CustomEdge > (m.cm, mid, edge, false, cb); - m.UpdateBoxAndNormals(); + m.updateBoxAndNormals(); m.clearDataMask( MeshModel::MM_VERTMARK); //vcg::tri::UpdateNormal::PerVertexNormalizedPerFace(m.cm); } diff --git a/src/meshlabplugins/filter_func/filter_func.h b/src/meshlabplugins/filter_func/filter_func.h index 2a6175b8e..9e5186dd2 100644 --- a/src/meshlabplugins/filter_func/filter_func.h +++ b/src/meshlabplugins/filter_func/filter_func.h @@ -76,11 +76,11 @@ public: ~FilterFunctionPlugin(); QString pluginName() const; - virtual QString filterName(ActionIDType filter) const; - virtual QString filterInfo(ActionIDType filter) const; - virtual FilterClass getClass(const QAction*) const; - virtual int postCondition(const QAction *action) const; - virtual void initParameterList(const QAction*, MeshModel &/*m*/, RichParameterList & /*parent*/); + QString filterName(ActionIDType filter) const; + QString filterInfo(ActionIDType filter) const; + FilterClass getClass(const QAction*) const; + int postCondition(const QAction *action) const; + RichParameterList initParameterList(const QAction*, const MeshModel &/*m*/); virtual int getRequirements(const QAction*); std::map applyFilter( const QAction* action, diff --git a/src/meshlabplugins/filter_geodesic/filter_geodesic.cpp b/src/meshlabplugins/filter_geodesic/filter_geodesic.cpp index bed89d6a5..c77c43dad 100644 --- a/src/meshlabplugins/filter_geodesic/filter_geodesic.cpp +++ b/src/meshlabplugins/filter_geodesic/filter_geodesic.cpp @@ -232,8 +232,9 @@ std::map FilterGeodesic::applyFilter(const QAction *filte return std::map(); } -void FilterGeodesic::initParameterList(const QAction *action,MeshModel &m, RichParameterList & parlst) +RichParameterList FilterGeodesic::initParameterList(const QAction *action, const MeshModel &m) { + RichParameterList parlst; switch(ID(action)) { case FP_QUALITY_POINT_GEODESIC : @@ -245,7 +246,7 @@ void FilterGeodesic::initParameterList(const QAction *action,MeshModel &m, RichP break; default: break; // do not add any parameter for the other filters } - return; + return parlst; } int FilterGeodesic::postCondition(const QAction * filter) const diff --git a/src/meshlabplugins/filter_geodesic/filter_geodesic.h b/src/meshlabplugins/filter_geodesic/filter_geodesic.h index 5b6bac0e5..207bc90c8 100644 --- a/src/meshlabplugins/filter_geodesic/filter_geodesic.h +++ b/src/meshlabplugins/filter_geodesic/filter_geodesic.h @@ -57,7 +57,7 @@ class FilterGeodesic : public QObject, public FilterPlugin FilterClass getClass(const QAction*) const; int getRequirements(const QAction*); std::map applyFilter(const QAction* action, const RichParameterList & /*parent*/, MeshDocument &md, unsigned int& postConditionMask, vcg::CallBackPos * cb); - void initParameterList(const QAction*, MeshModel &/*m*/, RichParameterList & /*parent*/); + RichParameterList initParameterList(const QAction*, const MeshModel &/*m*/); int postCondition(const QAction * filter) const; FilterArity filterArity(const QAction*) const {return SINGLE_MESH;} }; diff --git a/src/meshlabplugins/filter_img_patch_param/VisibleSet.cpp b/src/meshlabplugins/filter_img_patch_param/VisibleSet.cpp index 8245cd284..8db54f678 100644 --- a/src/meshlabplugins/filter_img_patch_param/VisibleSet.cpp +++ b/src/meshlabplugins/filter_img_patch_param/VisibleSet.cpp @@ -29,12 +29,11 @@ -VisibleSet::VisibleSet( - glw::Context &ctx, +VisibleSet::VisibleSet(glw::Context &ctx, MLPluginGLContext* plugctx, int meshid, CMeshO &mesh, - QList &rasterList, + std::list& rasterList, int weightMask) : m_Mesh(mesh), m_FaceVis(mesh.fn), @@ -48,7 +47,7 @@ VisibleSet::VisibleSet( float depthMin = std::numeric_limits::max(); m_DepthMax = -std::numeric_limits::max(); - for(RasterModel *rm: qAsConst(rasterList)) { + for(RasterModel *rm: rasterList) { CMeshO::ScalarType zNear, zFar; GlShot< Shotm >::GetNearFarPlanes( rm->shot, mesh.bbox, zNear, zFar ); @@ -66,7 +65,7 @@ VisibleSet::VisibleSet( m_DepthRangeInv = 1.0f / (m_DepthMax-depthMin); - for( RasterModel *rm : qAsConst(rasterList)) + for( RasterModel *rm : rasterList) { visibility.setRaster( rm ); visibility.checkVisibility(); diff --git a/src/meshlabplugins/filter_img_patch_param/VisibleSet.h b/src/meshlabplugins/filter_img_patch_param/VisibleSet.h index 75709f1d3..9035ced6f 100644 --- a/src/meshlabplugins/filter_img_patch_param/VisibleSet.h +++ b/src/meshlabplugins/filter_img_patch_param/VisibleSet.h @@ -81,7 +81,7 @@ private: public: VisibleSet( glw::Context &ctx,MLPluginGLContext* plugctx,int meshid, CMeshO &mesh, - QList &rasterList, + std::list &rasterList, int weightMask ); float getWeight( const RasterModel *rm, CFaceO &f ); diff --git a/src/meshlabplugins/filter_img_patch_param/filter_img_patch_param.cpp b/src/meshlabplugins/filter_img_patch_param/filter_img_patch_param.cpp index 430df354e..9f86be535 100644 --- a/src/meshlabplugins/filter_img_patch_param/filter_img_patch_param.cpp +++ b/src/meshlabplugins/filter_img_patch_param/filter_img_patch_param.cpp @@ -140,10 +140,11 @@ FilterPlugin::FilterClass FilterImgPatchParamPlugin::getClass(const QAction *act //} -void FilterImgPatchParamPlugin::initParameterList(const QAction *act, - MeshDocument &/*md*/, - RichParameterList &par ) +RichParameterList FilterImgPatchParamPlugin::initParameterList( + const QAction *act, + const MeshDocument &/*md*/) { + RichParameterList par; switch( ID(act) ) { case FP_PATCH_PARAM_AND_TEXTURING: @@ -203,6 +204,7 @@ void FilterImgPatchParamPlugin::initParameterList(const QAction *act, break; } } + return par; } @@ -237,8 +239,8 @@ std::map FilterImgPatchParamPlugin::applyFilter( CMeshO &mesh = md.mm()->cm; std::list initialShots; - QList activeRasters; - for(RasterModel *rm : qAsConst(md.rasterList)) { + std::list activeRasters; + for(RasterModel *rm : md.rasterIterator()) { initialShots.push_back(rm->shot); rm->shot.ApplyRigidTransformation( vcg::Inverse(mesh.Tr) ); if( rm->visible ) @@ -316,11 +318,8 @@ std::map FilterImgPatchParamPlugin::applyFilter( log( "TEXTURE PAINTING: %.3f sec.", 0.001f*t.elapsed() ); QImage tex = painter.getTexture(); - if( tex.save(texName) ) - { - mesh.textures.clear(); - mesh.textures.push_back( texName.toStdString() ); - } + md.mm()->clearTextures(); + md.mm()->addTexture(texName.toStdString(), tex); } } if (!retValue) @@ -336,7 +335,7 @@ std::map FilterImgPatchParamPlugin::applyFilter( for( CMeshO::VertexIterator vi=mesh.vert.begin(); vi!=mesh.vert.end(); ++vi ) vi->Q() = 0.0f; - foreach( RasterModel *rm, activeRasters ) + for( RasterModel *rm: activeRasters ) { visibility.setRaster( rm ); visibility.checkVisibility(); @@ -347,7 +346,7 @@ std::map FilterImgPatchParamPlugin::applyFilter( if( par.getBool("normalizeQuality") ) { - const float normFactor = 1.0f / md.rasterList.size(); + const float normFactor = 1.0f / md.rasterNumber(); for( CMeshO::VertexIterator vi=mesh.vert.begin(); vi!=mesh.vert.end(); ++vi ) vi->Q() *= normFactor; } @@ -363,7 +362,7 @@ std::map FilterImgPatchParamPlugin::applyFilter( for( CMeshO::FaceIterator fi=mesh.face.begin(); fi!=mesh.face.end(); ++fi ) fi->Q() = 0.0f; - foreach( RasterModel *rm, activeRasters ) + for( RasterModel *rm: activeRasters ) { visibility.setRaster( rm ); visibility.checkVisibility(); @@ -374,7 +373,7 @@ std::map FilterImgPatchParamPlugin::applyFilter( if( par.getBool("normalizeQuality") ) { - const float normFactor = 1.0f / md.rasterList.size(); + const float normFactor = 1.0f / md.rasterNumber(); for( CMeshO::FaceIterator fi=mesh.face.begin(); fi!=mesh.face.end(); ++fi ) fi->Q() *= normFactor; } @@ -385,7 +384,7 @@ std::map FilterImgPatchParamPlugin::applyFilter( wrongActionCalled(act); } - foreach( RasterModel *rm, md.rasterList ) + for( RasterModel *rm: md.rasterIterator() ) { rm->shot = *initialShots.begin(); initialShots.erase( initialShots.begin() ); @@ -624,11 +623,11 @@ int FilterImgPatchParamPlugin::extractPatches( RasterPatchMap &patches, PatchVec &nullPatches, CMeshO &mesh, VisibleSet &faceVis, - QList &rasterList ) + std::list &rasterList ) { int nbPatches = 0; - foreach( RasterModel *rm, rasterList ) + for( RasterModel *rm: rasterList ) patches[rm] = PatchVec(); for( CMeshO::FaceIterator fSeed=mesh.face.begin(); fSeed!=mesh.face.end(); ++fSeed ) @@ -917,7 +916,7 @@ void FilterImgPatchParamPlugin::patchBasedTextureParameterization( PatchVec &nullPatches, int meshid, CMeshO &mesh, - QList &rasterList, + std::list &rasterList, const RichParameterList &par) { // Computes the visibility set for all mesh faces. It contains the set of all images diff --git a/src/meshlabplugins/filter_img_patch_param/filter_img_patch_param.h b/src/meshlabplugins/filter_img_patch_param/filter_img_patch_param.h index 27325a20b..3433bab38 100644 --- a/src/meshlabplugins/filter_img_patch_param/filter_img_patch_param.h +++ b/src/meshlabplugins/filter_img_patch_param/filter_img_patch_param.h @@ -74,7 +74,7 @@ class FilterImgPatchParamPlugin : public QObject, public FilterPlugin PatchVec &nullPatches, CMeshO &mesh, VisibleSet &faceVis, - QList &rasterList); + std::list& rasterList); void constructPatchBoundary( Patch &p, @@ -97,7 +97,7 @@ class FilterImgPatchParamPlugin : public QObject, public FilterPlugin PatchVec &nullPatches, int meshid, CMeshO &mesh, - QList &rasterList, + std::list& rasterList, const RichParameterList& par); float computeTotalPatchArea(const RasterPatchMap& patches ); @@ -109,17 +109,16 @@ public: ~FilterImgPatchParamPlugin(); QString pluginName() const; - virtual QString filterName( ActionIDType id ) const; - virtual QString filterInfo( ActionIDType id ) const; + QString filterName( ActionIDType id ) const; + QString filterInfo( ActionIDType id ) const; - virtual FilterClass getClass(const QAction* act ) const; + FilterClass getClass(const QAction* act ) const; - virtual void initParameterList( + RichParameterList initParameterList( const QAction* act, - MeshDocument &md, - RichParameterList &par ); + const MeshDocument &md); - virtual int getRequirements(const QAction* act ); + int getRequirements(const QAction* act ); bool requiresGLContext(const QAction* action) const; //virtual int postCondition( QAction *act ) const; diff --git a/src/meshlabplugins/filter_isoparametrization/filter_isoparametrization.cpp b/src/meshlabplugins/filter_isoparametrization/filter_isoparametrization.cpp index 24c3f2953..83bde12a4 100644 --- a/src/meshlabplugins/filter_isoparametrization/filter_isoparametrization.cpp +++ b/src/meshlabplugins/filter_isoparametrization/filter_isoparametrization.cpp @@ -99,9 +99,9 @@ int FilterIsoParametrization::getRequirements(const QAction *) return MeshModel::MM_NONE; } -void FilterIsoParametrization::initParameterList(const QAction *a, MeshDocument& md, RichParameterList & par) +RichParameterList FilterIsoParametrization::initParameterList(const QAction *a, const MeshDocument& md) { - + RichParameterList par; switch(ID(a)) { case ISOP_PARAM: @@ -153,10 +153,11 @@ void FilterIsoParametrization::initParameterList(const QAction *a, MeshDocument& } case ISOP_TRANSFER: { - par.addParam(RichMesh ("sourceMesh",md.mm(),&md, "Source Mesh", "The mesh already having an Isoparameterization")); - par.addParam(RichMesh ("targetMesh",md.mm(),&md, "Target Mesh", "The mesh to be Isoparameterized")); + par.addParam(RichMesh ("sourceMesh",md.mm()->id(),&md, "Source Mesh", "The mesh already having an Isoparameterization")); + par.addParam(RichMesh ("targetMesh",md.mm()->id(),&md, "Target Mesh", "The mesh to be Isoparameterized")); } } + return par; } void FilterIsoParametrization::PrintStats(CMeshO *mesh) @@ -333,7 +334,7 @@ std::map FilterIsoParametrization::applyFilter( mm->updateDataMask(MeshModel::MM_FACEFACETOPO); mm->updateDataMask(MeshModel::MM_VERTFACETOPO); PrintStats(rem); - mm->UpdateBoxAndNormals(); + mm->updateBoxAndNormals(); break; } case ISOP_DIAMPARAM : @@ -414,8 +415,8 @@ std::map FilterIsoParametrization::applyFilter( // } case ISOP_TRANSFER: { - MeshModel *mmtrg = par.getMesh("targetMesh"); - MeshModel *mmsrc = par.getMesh("sourceMesh"); + MeshModel *mmtrg = md.getMesh(par.getMeshId("targetMesh")); + MeshModel *mmsrc = md.getMesh(par.getMeshId("sourceMesh")); CMeshO *trgMesh=&mmtrg->cm; CMeshO *srcMesh=&mmsrc->cm; diff --git a/src/meshlabplugins/filter_isoparametrization/filter_isoparametrization.h b/src/meshlabplugins/filter_isoparametrization/filter_isoparametrization.h index 1a3798d3b..5c46c8aa9 100644 --- a/src/meshlabplugins/filter_isoparametrization/filter_isoparametrization.h +++ b/src/meshlabplugins/filter_isoparametrization/filter_isoparametrization.h @@ -54,7 +54,7 @@ public: virtual int getRequirements(const QAction*); - virtual void initParameterList(const QAction*, MeshDocument&, RichParameterList & /*parent*/); + RichParameterList initParameterList(const QAction*, const MeshDocument&); std::map applyFilter( const QAction* action, const RichParameterList & parameters, diff --git a/src/meshlabplugins/filter_layer/filter_layer.cpp b/src/meshlabplugins/filter_layer/filter_layer.cpp index d053f1a89..e4eaa9347 100644 --- a/src/meshlabplugins/filter_layer/filter_layer.cpp +++ b/src/meshlabplugins/filter_layer/filter_layer.cpp @@ -116,10 +116,11 @@ QString FilterLayerPlugin::filterInfo(ActionIDType filterId) const } // This function define the needed parameters for each filter. -void FilterLayerPlugin::initParameterList(const QAction *action, MeshDocument &md, RichParameterList & parlst) +RichParameterList FilterLayerPlugin::initParameterList(const QAction *action, const MeshDocument &md) { - MeshModel *mm=md.mm(); - RasterModel *rm=md.rm(); + RichParameterList parlst; + const MeshModel *mm=md.mm(); + const RasterModel *rm=md.rm(); switch(ID(action)) { case FP_SPLITSELECTEDVERTICES: @@ -157,11 +158,11 @@ void FilterLayerPlugin::initParameterList(const QAction *action, MeshDocument &m "New Label for the raster")); break; case FP_SELECTCURRENT : - parlst.addParam(RichMesh ("layer",md.mm(),&md, "Layer Name", + parlst.addParam(RichMesh ("layer",md.mm()->id(),&md, "Layer Name", "The name of the current layer")); break; case FP_MESH_VISIBILITY : - parlst.addParam(RichMesh ("layer",md.mm(),&md, "Layer Name", "The name of the layer that has to change visibility. If second parameter is not empty, this parameter is ignored")); + parlst.addParam(RichMesh ("layer",md.mm()->id(),&md, "Layer Name", "The name of the layer that has to change visibility. If second parameter is not empty, this parameter is ignored")); parlst.addParam(RichString("lName", "", "Substring match", "Apply visibility to all layers with name substring matching the entered string. If not empty, the first parameter is ignored.")); parlst.addParam(RichBool ("isMeshVisible", true, "Visible", "It makes the selected layer(s) visible or invisible.")); break; @@ -178,6 +179,7 @@ void FilterLayerPlugin::initParameterList(const QAction *action, MeshDocument &m break; default: break; // do not add any parameter for the other filters } + return parlst; } // Core Function doing the actual mesh processing. @@ -208,20 +210,20 @@ std::map FilterLayerPlugin::applyFilter( } break; - case FP_SELECTCURRENT: md.setCurrent(par.getMesh("layer")); break; + case FP_SELECTCURRENT: md.setCurrent(md.getMesh(par.getMeshId("layer"))); break; case FP_MESH_VISIBILITY: { QString match = par.getString("lName"); if (match == "") { - MeshModel *mm = par.getMesh("layer"); + MeshModel *mm = md.getMesh(par.getMeshId("layer")); if (mm) md.setVisible(mm->id(), par.getBool("isMeshVisible")); } else { - foreach(MeshModel *mmp, md.meshList) + for(MeshModel *mmp: md.meshIterator()) { if (mmp->label().contains(match)) md.setVisible(mmp->id(), par.getBool("isMeshVisible")); @@ -237,7 +239,7 @@ std::map FilterLayerPlugin::applyFilter( case FP_DELETE_NON_VISIBLE_MESH: { - foreach(MeshModel *mmp, md.meshList) + for(MeshModel *mmp: md.meshIterator()) { if (!mmp->visible) md.delMesh(mmp); @@ -248,7 +250,7 @@ std::map FilterLayerPlugin::applyFilter( case FP_DELETE_NON_SELECTED_RASTER: { - foreach(RasterModel *rmp, md.rasterList) + for(RasterModel *rmp: md.rasterIterator()) { if (!rmp->visible) md.delRaster(rmp); @@ -281,16 +283,16 @@ std::map FilterLayerPlugin::applyFilter( tri::UpdateSelection::VertexClear(currentModel->cm); currentModel->clearDataMask(MeshModel::MM_FACEFACETOPO); - log("Moved %i vertices to layer %i, deleted %i faces", numVertSel, delfaces, md.meshList.size()); + log("Moved %i vertices to layer %i, deleted %i faces", numVertSel, currentModel->id(), delfaces); } - else // keep original faces + else // keep original faces { - log("Copied %i vertices to layer %i", numVertSel, md.meshList.size()); + log("Copied %i vertices to layer %i", numVertSel, currentModel->id()); } vcg::tri::UpdateFlags::VertexClear(destModel->cm, CMeshO::VertexType::SELECTED); // init new layer - destModel->UpdateBoxAndNormals(); + destModel->updateBoxAndNormals(); destModel->cm.Tr = currentModel->cm.Tr; destModel->updateDataMask(currentModel); } break; @@ -326,17 +328,17 @@ std::map FilterLayerPlugin::applyFilter( tri::UpdateSelection::FaceClear(currentModel->cm); currentModel->clearDataMask(MeshModel::MM_FACEFACETOPO); - log("Moved %i faces and %i vertices to layer %i", numFacesSel, numVertSel, md.meshList.size()); + log("Moved %i faces and %i vertices to layer %i", numFacesSel, numVertSel, currentModel->id()); } else // keep original faces { - log("Copied %i faces and %i vertices to layer %i", numFacesSel, numVertSel, md.meshList.size()); + log("Copied %i faces and %i vertices to layer %i", numFacesSel, numVertSel, currentModel->id()); } vcg::tri::UpdateFlags::VertexClear(destModel->cm, CMeshO::VertexType::SELECTED); vcg::tri::UpdateFlags::FaceClear(destModel->cm, CMeshO::FaceType::SELECTED); // init new layer - destModel->UpdateBoxAndNormals(); + destModel->updateBoxAndNormals(); destModel->cm.Tr = currentModel->cm.Tr; destModel->updateDataMask(currentModel); } break; @@ -349,10 +351,14 @@ std::map FilterLayerPlugin::applyFilter( destModel->updateDataMask(currentModel); tri::Append::Mesh(destModel->cm, currentModel->cm); - log("Duplicated current model to layer %i", md.meshList.size()); + for (const std::string& tex: destModel->cm.textures) { + destModel->addTexture(tex, currentModel->getTexture(tex)); + } + + log("Duplicated current model to layer %i", destModel->id()); // init new layer - destModel->UpdateBoxAndNormals(); + destModel->updateBoxAndNormals(); destModel->cm.Tr = currentModel->cm.Tr; } break; @@ -368,14 +374,14 @@ std::map FilterLayerPlugin::applyFilter( QList toBeDeletedList; int cnt=0; - foreach(MeshModel *mmp, md.meshList) + for(MeshModel *mmp: md.meshIterator()) { ++cnt; if(mmp->visible || !mergeVisible) { if (mmp != destModel) { - cb(cnt*100/md.meshList.size(), "Merging layers..."); + cb(cnt*100/md.meshNumber(), "Merging layers..."); tri::UpdatePosition::Matrix(mmp->cm,mmp->cm.Tr,true); toBeDeletedList.push_back(mmp); if(!alsoUnreferenced) @@ -404,7 +410,7 @@ std::map FilterLayerPlugin::applyFilter( log( "Removed %d duplicated vertices", delvert); } - destModel->UpdateBoxAndNormals(); + destModel->updateBoxAndNormals(); log("Merged all the layers to single mesh of %i vertices",md.mm()->cm.vn); } break; @@ -430,7 +436,7 @@ std::map FilterLayerPlugin::applyFilter( tri::Append::Mesh(destModel->cm, cm, true); // init new layer - destModel->UpdateBoxAndNormals(); + destModel->updateBoxAndNormals(); destModel->cm.Tr = currentModel->cm.Tr; } } break; @@ -452,26 +458,26 @@ std::map FilterLayerPlugin::applyFilter( } int active = 0; - for (int i = 0; i < md.rasterList.size(); i++) + for (RasterModel* rm : md.rasterIterator()) { - if (md.rasterList[i]->visible) + if (rm->visible) active++; } fprintf(outfile, "# Bundle file v0.3\n"); fprintf(outfile, "%d %d\n", active, 0); - for (int i = 0; i < md.rasterList.size(); i++) + for (RasterModel* rm : md.rasterIterator()) { - if (md.rasterList[i]->visible) + if (rm->visible) { - fprintf(outfile, "%f %d %d\n", md.rasterList[i]->shot.Intrinsics.FocalMm / md.rasterList[i]->shot.Intrinsics.PixelSizeMm[0], 0, 0); + fprintf(outfile, "%f %d %d\n", rm->shot.Intrinsics.FocalMm / rm->shot.Intrinsics.PixelSizeMm[0], 0, 0); - Matrix44m mat = md.rasterList[i]->shot.Extrinsics.Rot(); + Matrix44m mat = rm->shot.Extrinsics.Rot(); Matrix33m Rt = Matrix33m(Matrix44m(mat), 3); - Point3f pos = Rt * md.rasterList[i]->shot.Extrinsics.Tra(); + Point3f pos = Rt * rm->shot.Extrinsics.Tra(); Rt.Transpose(); fprintf(outfile, "%f %f %f\n", Rt[0][0], Rt[1][0], Rt[2][0]); @@ -508,22 +514,23 @@ std::map FilterLayerPlugin::applyFilter( xmlWriter.writeStartElement("chunk"); xmlWriter.writeStartElement("sensors"); - for (int i = 0; i < md.rasterList.size(); i++) + unsigned int i = 0; + for (RasterModel* rm : md.rasterIterator()) { - if (md.rasterList[i]->visible) + if (rm->visible) { float focal, pixelX, pixelY; - if (md.rasterList[i]->shot.Intrinsics.FocalMm > 1000) + if (rm->shot.Intrinsics.FocalMm > 1000) { - focal = md.rasterList[i]->shot.Intrinsics.FocalMm / 500; - pixelX = md.rasterList[i]->shot.Intrinsics.PixelSizeMm[0] / 500; - pixelY = md.rasterList[i]->shot.Intrinsics.PixelSizeMm[1] / 500; + focal = rm->shot.Intrinsics.FocalMm / 500; + pixelX = rm->shot.Intrinsics.PixelSizeMm[0] / 500; + pixelY = rm->shot.Intrinsics.PixelSizeMm[1] / 500; } else { - focal = md.rasterList[i]->shot.Intrinsics.FocalMm; - pixelX = md.rasterList[i]->shot.Intrinsics.PixelSizeMm[0]; - pixelY = md.rasterList[i]->shot.Intrinsics.PixelSizeMm[1]; + focal = rm->shot.Intrinsics.FocalMm; + pixelX = rm->shot.Intrinsics.PixelSizeMm[0]; + pixelY = rm->shot.Intrinsics.PixelSizeMm[1]; } xmlWriter.writeStartElement("sensor"); @@ -531,8 +538,8 @@ std::map FilterLayerPlugin::applyFilter( xmlWriter.writeAttribute("label", "unknown"+QString::number(i)); xmlWriter.writeAttribute("type", "frame"); xmlWriter.writeStartElement("resolution"); - xmlWriter.writeAttribute("width", QString::number(md.rasterList[i]->shot.Intrinsics.ViewportPx[0])); - xmlWriter.writeAttribute("height", QString::number(md.rasterList[i]->shot.Intrinsics.ViewportPx[1])); + xmlWriter.writeAttribute("width", QString::number(rm->shot.Intrinsics.ViewportPx[0])); + xmlWriter.writeAttribute("height", QString::number(rm->shot.Intrinsics.ViewportPx[1])); xmlWriter.writeEndElement(); xmlWriter.writeStartElement("property"); xmlWriter.writeAttribute("name", "pixel_width"); @@ -554,13 +561,13 @@ std::map FilterLayerPlugin::applyFilter( xmlWriter.writeAttribute("type", "frame"); xmlWriter.writeAttribute("class", "adjusted"); xmlWriter.writeStartElement("resolution"); - xmlWriter.writeAttribute("width", QString::number(md.rasterList[i]->shot.Intrinsics.ViewportPx[0])); - xmlWriter.writeAttribute("height", QString::number(md.rasterList[i]->shot.Intrinsics.ViewportPx[1])); + xmlWriter.writeAttribute("width", QString::number(rm->shot.Intrinsics.ViewportPx[0])); + xmlWriter.writeAttribute("height", QString::number(rm->shot.Intrinsics.ViewportPx[1])); xmlWriter.writeEndElement(); - xmlWriter.writeTextElement("fx", QString::number(md.rasterList[i]->shot.Intrinsics.FocalMm / md.rasterList[i]->shot.Intrinsics.PixelSizeMm[0])); - xmlWriter.writeTextElement("fy", QString::number(md.rasterList[i]->shot.Intrinsics.FocalMm / md.rasterList[i]->shot.Intrinsics.PixelSizeMm[1])); - xmlWriter.writeTextElement("cx", QString::number(md.rasterList[i]->shot.Intrinsics.CenterPx[0])); - xmlWriter.writeTextElement("cy", QString::number(md.rasterList[i]->shot.Intrinsics.CenterPx[1])); + xmlWriter.writeTextElement("fx", QString::number(rm->shot.Intrinsics.FocalMm / rm->shot.Intrinsics.PixelSizeMm[0])); + xmlWriter.writeTextElement("fy", QString::number(rm->shot.Intrinsics.FocalMm / rm->shot.Intrinsics.PixelSizeMm[1])); + xmlWriter.writeTextElement("cx", QString::number(rm->shot.Intrinsics.CenterPx[0])); + xmlWriter.writeTextElement("cy", QString::number(rm->shot.Intrinsics.CenterPx[1])); xmlWriter.writeTextElement("k1", "0"); xmlWriter.writeTextElement("k2", "0"); xmlWriter.writeTextElement("p1", "0"); @@ -568,20 +575,22 @@ std::map FilterLayerPlugin::applyFilter( xmlWriter.writeEndElement(); xmlWriter.writeEndElement(); } + ++i; } xmlWriter.writeEndElement(); xmlWriter.writeStartElement("cameras"); - for (int i = 0; i < md.rasterList.size(); i++) + i = 0; + for (RasterModel* rm : md.rasterIterator()) { - if (md.rasterList[i]->visible) + if (rm->visible) { xmlWriter.writeStartElement("camera"); xmlWriter.writeAttribute("id", QString::number(i)); - xmlWriter.writeAttribute("label", md.rasterList[i]->currentPlane->shortName()); + xmlWriter.writeAttribute("label", rm->currentPlane->shortName()); xmlWriter.writeAttribute("sensor_id", QString::number(i)); xmlWriter.writeAttribute("enabled", "true"); - Matrix44m mat = md.rasterList[i]->shot.Extrinsics.Rot(); - Point3f pos = md.rasterList[i]->shot.Extrinsics.Tra(); + Matrix44m mat = rm->shot.Extrinsics.Rot(); + Point3f pos = rm->shot.Extrinsics.Tra(); QString transform= QString::number(mat[0][0]); transform.append(" " + QString::number(-mat[1][0])); transform.append(" " + QString::number(-mat[2][0])); @@ -602,6 +611,7 @@ std::map FilterLayerPlugin::applyFilter( xmlWriter.writeTextElement("transform", transform); xmlWriter.writeEndElement(); } + ++i; } xmlWriter.writeEndElement(); xmlWriter.writeEndDocument(); @@ -640,9 +650,9 @@ std::map FilterLayerPlugin::applyFilter( ///// Check if the number of active rasters and cameras is the same unsigned active = 0; - for (int i = 0; i < md.rasterList.size(); i++) + for (RasterModel* rm : md.rasterIterator()) { - if (md.rasterList[i]->visible) + if (rm->visible) active++; } @@ -652,47 +662,51 @@ std::map FilterLayerPlugin::applyFilter( } //// Import cameras - for (uint i = 0; i < num_cams; ++i) + unsigned int i = 0; + for (RasterModel* rm : md.rasterIterator()) { - float f, k1, k2; - float R[16] = { 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,1 }; - vcg::Point3f t; + if (rm->visible) { + float f, k1, k2; + float R[16] = { 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,1 }; + vcg::Point3f t; - fgets(line, 100, fp);; if (line[0] == '\0') throw MLException("Error while parsing " + fileName);; - sscanf(line, "%f %f %f", &f, &k1, &k2); + fgets(line, 100, fp);; if (line[0] == '\0') throw MLException("Error while parsing " + fileName);; + sscanf(line, "%f %f %f", &f, &k1, &k2); - fgets(line, 100, fp);; if (line[0] == '\0') throw MLException("Error while parsing " + fileName);; - sscanf(line, "%f %f %f", &(R[0]), &(R[1]), &(R[2])); R[3] = 0; - fgets(line, 100, fp);; if (line[0] == '\0') throw MLException("Error while parsing " + fileName);; - sscanf(line, "%f %f %f", &(R[4]), &(R[5]), &(R[6])); R[7] = 0; - fgets(line, 100, fp);; if (line[0] == '\0') throw MLException("Error while parsing " + fileName);; - sscanf(line, "%f %f %f", &(R[8]), &(R[9]), &(R[10])); R[11] = 0; + fgets(line, 100, fp);; if (line[0] == '\0') throw MLException("Error while parsing " + fileName);; + sscanf(line, "%f %f %f", &(R[0]), &(R[1]), &(R[2])); R[3] = 0; + fgets(line, 100, fp);; if (line[0] == '\0') throw MLException("Error while parsing " + fileName);; + sscanf(line, "%f %f %f", &(R[4]), &(R[5]), &(R[6])); R[7] = 0; + fgets(line, 100, fp);; if (line[0] == '\0') throw MLException("Error while parsing " + fileName);; + sscanf(line, "%f %f %f", &(R[8]), &(R[9]), &(R[10])); R[11] = 0; - fgets(line, 100, fp);; if (line[0] == '\0') throw MLException("Error while parsing " + fileName);; - sscanf(line, "%f %f %f", &(t[0]), &(t[1]), &(t[2])); + fgets(line, 100, fp);; if (line[0] == '\0') throw MLException("Error while parsing " + fileName);; + sscanf(line, "%f %f %f", &(t[0]), &(t[1]), &(t[2])); - Matrix44f matF(R); - Matrix44m mat; - mat.Import(matF); + Matrix44f matF(R); + Matrix44m mat; + mat.Import(matF); - Matrix33m Rt = Matrix33m(Matrix44m(mat), 3); - Rt.Transpose(); + Matrix33m Rt = Matrix33m(Matrix44m(mat), 3); + Rt.Transpose(); - Point3f pos = Rt * Point3f(t[0], t[1], t[2]); + Point3f pos = Rt * Point3f(t[0], t[1], t[2]); - md.rasterList[i]->shot.Extrinsics.SetTra(Point3f(-pos[0], -pos[1], -pos[2])); - md.rasterList[i]->shot.Extrinsics.SetRot(mat); + rm->shot.Extrinsics.SetTra(Point3f(-pos[0], -pos[1], -pos[2])); + rm->shot.Extrinsics.SetRot(mat); - md.rasterList[i]->shot.Intrinsics.FocalMm = f; - md.rasterList[i]->shot.Intrinsics.k[0] = 0.0;//k1; To be uncommented when distortion is taken into account reliably - md.rasterList[i]->shot.Intrinsics.k[1] = 0.0;//k2; - md.rasterList[i]->shot.Intrinsics.PixelSizeMm = vcg::Point2f(1, 1); - QSize size; - QImageReader sizeImg(md.rasterList[i]->currentPlane->fullPathFileName); - size = sizeImg.size(); - md.rasterList[i]->shot.Intrinsics.ViewportPx = vcg::Point2i(size.width(), size.height()); - md.rasterList[i]->shot.Intrinsics.CenterPx[0] = (int)((double)md.rasterList[i]->shot.Intrinsics.ViewportPx[0] / 2.0f); - md.rasterList[i]->shot.Intrinsics.CenterPx[1] = (int)((double)md.rasterList[i]->shot.Intrinsics.ViewportPx[1] / 2.0f); + rm->shot.Intrinsics.FocalMm = f; + rm->shot.Intrinsics.k[0] = 0.0;//k1; To be uncommented when distortion is taken into account reliably + rm->shot.Intrinsics.k[1] = 0.0;//k2; + rm->shot.Intrinsics.PixelSizeMm = vcg::Point2f(1, 1); + QSize size; + QImageReader sizeImg(rm->currentPlane->fullPathFileName); + size = sizeImg.size(); + rm->shot.Intrinsics.ViewportPx = vcg::Point2i(size.width(), size.height()); + rm->shot.Intrinsics.CenterPx[0] = (int)((double)rm->shot.Intrinsics.ViewportPx[0] / 2.0f); + rm->shot.Intrinsics.CenterPx[1] = (int)((double)rm->shot.Intrinsics.ViewportPx[1] / 2.0f); + } + ++i; } } else if ((fi.suffix().toLower() == "xml")) @@ -787,33 +801,33 @@ std::map FilterLayerPlugin::applyFilter( int sensor_id = n.attributes().namedItem("sensor_id").nodeValue().toInt(); QString name = n.attributes().namedItem("label").nodeValue(); - int rasterId = -1; - for (int i = 0; i < md.rasterList.size(); i++) + RasterModel* rasterId = nullptr; + for (RasterModel* rm : md.rasterIterator()) { - if (md.rasterList[i]->currentPlane->shortName() == name) + if (rm->currentPlane->shortName() == name) { - rasterId = i; + rasterId = rm; break; } } QDomNode node = n.firstChild(); - while (!node.isNull() && rasterId != -1) + while (!node.isNull() && rasterId != nullptr) { if (QString::compare(node.nodeName(), "transform") == 0) { - md.rasterList[rasterId]->shot.Intrinsics.FocalMm = shots[sensor_id].Intrinsics.FocalMm; - md.rasterList[rasterId]->shot.Intrinsics.ViewportPx[0] = shots[sensor_id].Intrinsics.ViewportPx[0]; - md.rasterList[rasterId]->shot.Intrinsics.ViewportPx[1] = shots[sensor_id].Intrinsics.ViewportPx[1]; - md.rasterList[rasterId]->shot.Intrinsics.CenterPx[0] = shots[sensor_id].Intrinsics.CenterPx[0]; - md.rasterList[rasterId]->shot.Intrinsics.CenterPx[1] = shots[sensor_id].Intrinsics.CenterPx[1]; - md.rasterList[rasterId]->shot.Intrinsics.PixelSizeMm[0] = shots[sensor_id].Intrinsics.PixelSizeMm[0]; - md.rasterList[rasterId]->shot.Intrinsics.PixelSizeMm[1] = shots[sensor_id].Intrinsics.PixelSizeMm[1]; + rasterId->shot.Intrinsics.FocalMm = shots[sensor_id].Intrinsics.FocalMm; + rasterId->shot.Intrinsics.ViewportPx[0] = shots[sensor_id].Intrinsics.ViewportPx[0]; + rasterId->shot.Intrinsics.ViewportPx[1] = shots[sensor_id].Intrinsics.ViewportPx[1]; + rasterId->shot.Intrinsics.CenterPx[0] = shots[sensor_id].Intrinsics.CenterPx[0]; + rasterId->shot.Intrinsics.CenterPx[1] = shots[sensor_id].Intrinsics.CenterPx[1]; + rasterId->shot.Intrinsics.PixelSizeMm[0] = shots[sensor_id].Intrinsics.PixelSizeMm[0]; + rasterId->shot.Intrinsics.PixelSizeMm[1] = shots[sensor_id].Intrinsics.PixelSizeMm[1]; QStringList values = node.toElement().text().split(" ", QString::SkipEmptyParts); - Matrix44m mat = md.rasterList[i]->shot.Extrinsics.Rot(); - Point3f pos = md.rasterList[i]->shot.Extrinsics.Tra(); + Matrix44m mat = rasterId->shot.Extrinsics.Rot(); + Point3f pos = rasterId->shot.Extrinsics.Tra(); mat[0][0] = values[0].toFloat(); mat[1][0] = -values[1].toFloat(); @@ -827,8 +841,8 @@ std::map FilterLayerPlugin::applyFilter( mat[1][2] = -values[9].toFloat(); mat[2][2] = -values[10].toFloat(); pos[2] = values[11].toFloat(); - md.rasterList[i]->shot.Extrinsics.SetRot(mat); - md.rasterList[i]->shot.Extrinsics.SetTra(pos); + rasterId->shot.Extrinsics.SetRot(mat); + rasterId->shot.Extrinsics.SetTra(pos); } node = node.nextSibling(); } diff --git a/src/meshlabplugins/filter_layer/filter_layer.h b/src/meshlabplugins/filter_layer/filter_layer.h index 64dd00bc6..17e1ef666 100644 --- a/src/meshlabplugins/filter_layer/filter_layer.h +++ b/src/meshlabplugins/filter_layer/filter_layer.h @@ -56,10 +56,10 @@ public: FilterLayerPlugin(); QString pluginName() const; - virtual QString filterName(ActionIDType filter) const; - virtual QString filterInfo(ActionIDType filter) const; - virtual FilterClass getClass(const QAction*) const; - virtual void initParameterList(const QAction*, MeshDocument &/*m*/, RichParameterList & /*parent*/); + QString filterName(ActionIDType filter) const; + QString filterInfo(ActionIDType filter) const; + FilterClass getClass(const QAction*) const; + RichParameterList initParameterList(const QAction*, const MeshDocument &/*m*/); std::map applyFilter( const QAction* action, const RichParameterList & parameters, diff --git a/src/meshlabplugins/filter_measure/filter_measure.cpp b/src/meshlabplugins/filter_measure/filter_measure.cpp index 404de64e5..f28b2ff95 100644 --- a/src/meshlabplugins/filter_measure/filter_measure.cpp +++ b/src/meshlabplugins/filter_measure/filter_measure.cpp @@ -155,8 +155,9 @@ int FilterMeasurePlugin::getPreConditions(const QAction* action) const } } -void FilterMeasurePlugin::initParameterList(const QAction *action, MeshModel &m, RichParameterList & parlst) +RichParameterList FilterMeasurePlugin::initParameterList(const QAction *action, const MeshModel &m) { + RichParameterList parlst; switch (ID(action)) { case PER_VERTEX_QUALITY_HISTOGRAM: parlst.addParam(RichFloat("HistMin", vcg::tri::Stat::ComputePerVertexQualityMinMax(m.cm).first, "Hist Min", "The vertex are displaced of a vector whose norm is bounded by this value")); @@ -173,6 +174,7 @@ void FilterMeasurePlugin::initParameterList(const QAction *action, MeshModel &m, default: break; } + return parlst; } std::map FilterMeasurePlugin::applyFilter( diff --git a/src/meshlabplugins/filter_measure/filter_measure.h b/src/meshlabplugins/filter_measure/filter_measure.h index e66c7e4a9..816a94eb0 100644 --- a/src/meshlabplugins/filter_measure/filter_measure.h +++ b/src/meshlabplugins/filter_measure/filter_measure.h @@ -53,7 +53,7 @@ public: FilterClass getClass(const QAction*) const; FilterArity filterArity(const QAction*) const; int getPreConditions(const QAction *action) const; - void initParameterList(const QAction* , MeshModel& m, RichParameterList& parlst); + RichParameterList initParameterList(const QAction* , const MeshModel& m); std::map applyFilter( const QAction* action, const RichParameterList & parameters, diff --git a/src/meshlabplugins/filter_mesh_booleans/CMakeLists.txt b/src/meshlabplugins/filter_mesh_booleans/CMakeLists.txt new file mode 100644 index 000000000..60aec9cb2 --- /dev/null +++ b/src/meshlabplugins/filter_mesh_booleans/CMakeLists.txt @@ -0,0 +1,14 @@ +# Copyright 2019, 2020, Visual Computing Lab, ISTI - Italian National Research Council + +if (TARGET external-boost AND TARGET external-cgal AND TARGET external-libigl) + set(SOURCES filter_mesh_booleans.cpp) + + set(HEADERS filter_mesh_booleans.h) + + add_meshlab_plugin(filter_mesh_booleans ${SOURCES} ${HEADERS}) + + target_link_libraries(filter_mesh_booleans PRIVATE external-boost external-cgal external-libigl) +else() + message( + STATUS "Skipping filter_mesh_booleans - don't know about boost, cgal or libigl on this system.") +endif() diff --git a/src/meshlabplugins/filter_mesh_booleans/filter_mesh_booleans.cpp b/src/meshlabplugins/filter_mesh_booleans/filter_mesh_booleans.cpp new file mode 100644 index 000000000..41f1a2d22 --- /dev/null +++ b/src/meshlabplugins/filter_mesh_booleans/filter_mesh_booleans.cpp @@ -0,0 +1,662 @@ +/**************************************************************************** +* MeshLab o o * +* A versatile mesh processing toolbox o o * +* _ O _ * +* Copyright(C) 2005-2021 \/)\/ * +* Visual Computing Lab /\/| * +* ISTI - Italian National Research Council | * +* \ * +* All rights reserved. * +* * +* This program is free software; you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation; either version 2 of the License, or * +* (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) * +* for more details. * +* * +****************************************************************************/ + +#include "filter_mesh_booleans.h" + +#include + +/** + * @brief + * Constructor usually performs only two simple tasks of filling the two lists + * - typeList: with all the possible id of the filtering actions + * - actionList with the corresponding actions. + * If you want to add icons to your filtering actions you can do here by construction the QActions accordingly + */ +FilterMeshBooleans::FilterMeshBooleans() +{ + typeList = { + MESH_INTERSECTION, + MESH_UNION, + MESH_DIFFERENCE, + MESH_XOR}; + + for(const ActionIDType& tt : typeList) + actionList.push_back(new QAction(filterName(tt), this)); +} + +QString FilterMeshBooleans::pluginName() const +{ + return "FilterMeshBoolean"; +} + +QString FilterMeshBooleans::vendor() const +{ + return "CNR-ISTI-VCLab"; +} + +/** + * @brief ST() must return the very short string describing each filtering action + * (this string is used also to define the menu entry) + * @param filterId: the id of the filter + * @return the name of the filter + */ +QString FilterMeshBooleans::filterName(ActionIDType filterId) const +{ + switch(filterId) { + case MESH_INTERSECTION : + return "Mesh Boolean: Intersection"; + case MESH_UNION: + return "Mesh Boolean: Union"; + case MESH_DIFFERENCE: + return "Mesh Boolean: Difference"; + case MESH_XOR: + return "Mesh Boolean: Symmetric Difference (XOR)"; + default : + assert(0); + return ""; + } +} + + +/** + * @brief // Info() must return the longer string describing each filtering action + * (this string is used in the About plugin dialog) + * @param filterId: the id of the filter + * @return an info string of the filter + */ +QString FilterMeshBooleans::filterInfo(ActionIDType filterId) const +{ + QString description = + "This filter extecutes an exact boolean %1 between two meshes.
" + "The filter uses the original code provided in the " + "libigl library.
" + "The implementation refers to the following paper:
" + "Qingnan Zhou, Eitan Grinspun, Denis Zorin, Alec Jacobson,
" + "\"Mesh Arrangements for Solid Geometry\"
"; + switch(filterId) { + case MESH_INTERSECTION : + return description.arg("intersection"); + case MESH_UNION: + return description.arg("union"); + case MESH_DIFFERENCE: + return description.arg("difference"); + case MESH_XOR: + return description.arg("symmetric difference (XOR)"); + default : + assert(0); + return "Unknown Filter"; + } +} + +/** + * @brief The FilterClass describes in which generic class of filters it fits. + * This choice affect the submenu in which each filter will be placed + * More than a single class can be chosen. + * @param a: the action of the filter + * @return the class od the filter + */ +FilterMeshBooleans::FilterClass FilterMeshBooleans::getClass(const QAction *a) const +{ + switch(ID(a)) { + case MESH_INTERSECTION : + case MESH_UNION: + case MESH_DIFFERENCE: + case MESH_XOR: + return FilterPlugin::FilterClass(FilterPlugin::FilterClass(FilterPlugin::Layer + FilterPlugin::Remeshing)); + default : + assert(0); + return FilterPlugin::Generic; + } +} + +/** + * @brief FilterSamplePlugin::filterArity + * @return + */ +FilterPlugin::FilterArity FilterMeshBooleans::filterArity(const QAction*) const +{ + return FIXED; +} + +/** + * @brief FilterSamplePlugin::getPreConditions + * @return + */ +//int FilterMeshBooleans::getPreConditions(const QAction*) const +//{ +// return MeshModel::MM_NONE; +//} + +/** + * @brief FilterSamplePlugin::postCondition + * @return + */ +//int FilterMeshBooleans::postCondition(const QAction*) const +//{ +// return MeshModel::MM_VERTCOORD | MeshModel::MM_FACENORMAL | MeshModel::MM_VERTNORMAL; +//} + +/** + * @brief This function define the needed parameters for each filter. Return true if the filter has some parameters + * it is called every time, so you can set the default value of parameters according to the mesh + * For each parameter you need to define, + * - the name of the parameter, + * - the default value + * - the string shown in the dialog + * - a possibly long string describing the meaning of that parameter (shown as a popup help in the dialog) + * @param action + * @param m + * @param parlst + */ +RichParameterList FilterMeshBooleans::initParameterList( + const QAction *action, + const MeshDocument& md) +{ + RichParameterList parlst; + switch(ID(action)) { + case MESH_INTERSECTION : + case MESH_UNION: + case MESH_DIFFERENCE: + case MESH_XOR: + { + const MeshModel *target = md.mm(); + //looking for a second mesh different that the current one + for (const MeshModel * t : md.meshIterator()){ + if (t != md.mm()) { + target = t; + break; + } + } + + parlst.addParam(RichMesh( + "first_mesh", md.mm()->id(), &md, "First Mesh", + "The first operand of the boolean operation")); + parlst.addParam(RichMesh( + "second_mesh", target->id(), &md, "Second Mesh", + "The second operand of the boolean operation")); + + parlst.addParam(RichBool( + "transfer_face_color", false, + "Transfer face color", "Save the color of the birth face to the faces of resulting mesh.")); + + parlst.addParam(RichBool( + "transfer_face_quality", false, + "Transfer face quality", "Save the quality of the birth face to the faces of resulting mesh.")); + + parlst.addParam(RichBool( + "transfer_vert_color", false, + "Transfer vertex color", + "Save the color of the birth vertex to the faces of resulting mesh. For newly created vertices, " + "a simple average of the neighbours is computed.")); + + parlst.addParam(RichBool( + "transfer_vert_quality", false, + "Transfer vertex quality", + "Save the quality of the birth vertex to the faces of resulting mesh. For newly created vertices, " + "a simple average of the neighbours is computed.")); + } + break; + default : + assert(0); + } + return parlst; +} + +/** + * @brief The Real Core Function doing the actual mesh processing. + * @param action + * @param md: an object containing all the meshes and rasters of MeshLab + * @param par: the set of parameters of each filter + * @param cb: callback object to tell MeshLab the percentage of execution of the filter + * @return true if the filter has been applied correctly, false otherwise + */ +std::map FilterMeshBooleans::applyFilter( + const QAction * action, + const RichParameterList & par, + MeshDocument &md, + unsigned int& /*postConditionMask*/, + vcg::CallBackPos *) +{ + bool transfFaceQuality = par.getBool("transfer_face_quality"); + bool transfFaceColor = par.getBool("transfer_face_color"); + bool transfVertQuality = par.getBool("transfer_vert_quality"); + bool transfVertColor = par.getBool("transfer_vert_color"); + + + switch(ID(action)) { + case MESH_INTERSECTION : + booleanOperation( + md, + *md.getMesh(par.getMeshId("first_mesh")), + *md.getMesh(par.getMeshId("second_mesh")), + igl::MESH_BOOLEAN_TYPE_INTERSECT, + transfFaceQuality, + transfFaceColor, + transfVertQuality, + transfVertColor); + break; + case MESH_UNION: + booleanOperation( + md, + *md.getMesh(par.getMeshId("first_mesh")), + *md.getMesh(par.getMeshId("second_mesh")), + igl::MESH_BOOLEAN_TYPE_UNION, + transfFaceQuality, + transfFaceColor, + transfVertQuality, + transfVertColor); + break; + case MESH_DIFFERENCE: + booleanOperation( + md, + *md.getMesh(par.getMeshId("first_mesh")), + *md.getMesh(par.getMeshId("second_mesh")), + igl::MESH_BOOLEAN_TYPE_MINUS, + transfFaceQuality, + transfFaceColor, + transfVertQuality, + transfVertColor); + break; + case MESH_XOR: + booleanOperation( + md, + *md.getMesh(par.getMeshId("first_mesh")), + *md.getMesh(par.getMeshId("second_mesh")), + igl::MESH_BOOLEAN_TYPE_XOR, + transfFaceQuality, + transfFaceColor, + transfVertQuality, + transfVertColor); + break; + default : + wrongActionCalled(action); + } + return std::map(); +} + +/** + * @brief Puts coords and triangle indices of m into V and F matrices + * @param m + * @param V + * @param F + */ +void FilterMeshBooleans::CMeshOToEigen(const CMeshO& m, Eigen::MatrixX3d& V, Eigen::MatrixX3i& F) +{ + vcg::tri::RequireVertexCompactness(m); + vcg::tri::RequireFaceCompactness(m); + V.resize(m.VN(), 3); + for (int i = 0; i < m.VN(); i++){ + for (int j = 0; j < 3; j++){ + V(i,j) = m.vert[i].P()[j]; + } + } + F.resize(m.FN(), 3); + for (int i = 0; i < m.FN(); i++){ + for (int j = 0; j < 3; j++){ + F(i,j) = (int) vcg::tri::Index(m,m.face[i].cV(j)); + } + } +} + +/** + * @brief Returns a CMeshO containing the triangle mesh contained in V and F + * @param V + * @param F + * @return + */ +CMeshO FilterMeshBooleans::EigenToCMeshO(const Eigen::MatrixX3d& V, const Eigen::MatrixX3i& F) +{ + CMeshO m; + CMeshO::VertexIterator vi = + vcg::tri::Allocator::AddVertices(m, V.rows()); + std::vector ivp(V.rows()); + for (unsigned int i = 0; i < V.rows(); ++i, ++vi) { + ivp[i] = &*vi; + vi->P() = CMeshO::CoordType(V(i,0), V(i,1), V(i,2)); + } + + CMeshO::FaceIterator fi = + vcg::tri::Allocator::AddFaces(m, F.rows()); + for (unsigned int i = 0; i < F.rows(); ++i, ++fi) { + for (unsigned int j = 0; j < 3; j++){ + if ((unsigned int)F(i,j) >= ivp.size()) { + throw MLException( + "Error while creating mesh: bad vertex index " + + QString::number(F(i,j)) + " in face " + + QString::number(i) + "; vertex " + QString::number(j) + "."); + } + } + fi->V(0)=ivp[F(i,0)]; + fi->V(1)=ivp[F(i,1)]; + fi->V(2)=ivp[F(i,2)]; + } + vcg::tri::UpdateNormal::PerFace(m); + vcg::tri::UpdateNormal::PerVertex(m); + + return m; +} + +/** + * @brief Executes the boolean operation between m1 and m2, and puts the result + * as a new mesh into md. + * @param md: mesh document + * @param m1: first mesh + * @param m2: second mesh + * @param op: type of boolean operation + * @param transfQuality: if true, face quality will be transferred in the res mesh + * @param transfColor: if true, face color will be transferred in the res mesh + */ +void FilterMeshBooleans::booleanOperation( + MeshDocument& md, + const MeshModel& m1, + const MeshModel& m2, + int op, + bool transfFaceQuality, + bool transfFaceColor, + bool transfVertQuality, + bool transfVertColor) +{ + QString name; + switch (op) { + case igl::MESH_BOOLEAN_TYPE_INTERSECT: + name = "intersection"; + break; + case igl::MESH_BOOLEAN_TYPE_MINUS: + name = "difference"; + break; + case igl::MESH_BOOLEAN_TYPE_XOR: + name = "xor"; + break; + case igl::MESH_BOOLEAN_TYPE_UNION: + name = "union"; + break; + default: + throw MLException("Boolean Operation not found! Please report this issue on https://github.com/cnr-isti-vclab/meshlab/issues"); + } + + Eigen::MatrixX3d V1, V2, VR; + Eigen::MatrixX3i F1, F2, FR; + Eigen::VectorXi indices; //mapping indices for birth faces + + //vcg to eigen meshes + CMeshOToEigen(m1.cm, V1, F1); + CMeshOToEigen(m2.cm, V2, F2); + + bool result = igl::copyleft::cgal::mesh_boolean(V1, F1, V2, F2, (igl::MeshBooleanType)op, VR, FR, indices); + + if (!result){ + throw MLException( + "Mesh inputs must induce a piecewise constant winding number field.
" + "Make sure that both the input mesh are watertight (closed)."); + } + else { + //everything ok, create new mesh into md + MeshModel* mesh = md.addNewMesh("", name); + mesh->cm = EigenToCMeshO(VR, FR); + + //if transfer option enabled + if (transfFaceColor || transfFaceQuality) + transferFaceAttributes(*mesh, indices, m1, m2, transfFaceQuality, transfFaceColor); + if (transfVertColor || transfVertQuality) + transferVertexAttributes(*mesh, indices, m1, m2, transfVertQuality, transfVertColor); + } +} + +/** + * @brief Allows to transfer face attributes from m1 and m2 to res, depending on the + * birth faces indices. + * + * If one mesh does not have the required attribute, a default value will be + * placed in the result: + * - quality: 0 + * - color: 128,128,128 + * + * @param res + * @param indices + * @param m1 + * @param m2 + * @param quality: if true, face quality will be transferred + * @param color: if true, face color will be transferred + */ +void FilterMeshBooleans::transferFaceAttributes( + MeshModel& res, + const Eigen::VectorXi& faceIndices, + const MeshModel& m1, + const MeshModel& m2, + bool quality, + bool color) +{ + //checking if m1 and m2 have quality and color + bool m1HasQuality = true, m1HasColor = true, m2HasQuality = true, m2HasColor = true; + if (quality){ + res.updateDataMask(MeshModel::MM_FACEQUALITY); + if (!m1.hasDataMask(MeshModel::MM_FACEQUALITY)) + m1HasQuality = false; + if (!m2.hasDataMask(MeshModel::MM_FACEQUALITY)) + m2HasQuality = false; + } + if (color) { + res.updateDataMask(MeshModel::MM_FACECOLOR); + if (!m1.hasDataMask(MeshModel::MM_FACECOLOR)) + m1HasColor = false; + if (!m2.hasDataMask(MeshModel::MM_FACECOLOR)) + m2HasColor = false; + } + + //for each index in the birth faces vector + for (unsigned int i = 0; i < faceIndices.size(); ++i){ + bool fromM1 = true; + unsigned int mIndex = faceIndices[i]; + + //if the index is >= FN of m1, it means that the index is of m2 + if (faceIndices[i] >= m1.cm.FN()){ + fromM1 = false; + mIndex -= m1.cm.FN(); + } + + //if we need to transfer quality + if (quality){ + Scalarm q = 0; //default quality value + if (fromM1 && m1HasQuality) + q = m1.cm.face[mIndex].Q(); + if (!fromM1 && m2HasQuality) + q = m2.cm.face[mIndex].Q(); + res.cm.face[i].Q() = q; + } + + //if we need to transfer color + if (color) { + vcg::Color4b c(128, 128, 128, 255); //default color value + if (fromM1 && m1HasColor) + c = m1.cm.face[mIndex].C(); + if (!fromM1 && m2HasColor) + c = m2.cm.face[mIndex].C(); + res.cm.face[i].C() = c; + } + } +} + +/** + * @brief Allows to transfer vertex attributes from m1 and m2 to res, depending on the + * birth faces indices. + * + * If one mesh does not have the required attribute, a default value will be + * placed in the result: + * - quality: 0 + * - color: 128,128,128 + * + * @param res + * @param indices + * @param m1 + * @param m2 + * @param quality: if true, vertex quality will be transferred + * @param color: if true, vertex color will be transferred + */ +void FilterMeshBooleans::transferVertexAttributes( + MeshModel& res, + const Eigen::VectorXi& faceIndices, + const MeshModel& m1, + const MeshModel& m2, + bool quality, + bool color) +{ + res.updateDataMask(MeshModel::MM_VERTFACETOPO); + vcg::tri::UpdateTopology::VertexFace(res.cm); + + //checking if m1 and m2 have quality and color + bool m1HasQuality = true, m1HasColor = true, m2HasQuality = true, m2HasColor = true; + if (quality){ + res.updateDataMask(MeshModel::MM_VERTQUALITY); + if (!m1.hasDataMask(MeshModel::MM_VERTQUALITY)) + m1HasQuality = false; + if (!m2.hasDataMask(MeshModel::MM_VERTQUALITY)) + m2HasQuality = false; + } + if (color) { + res.updateDataMask(MeshModel::MM_VERTCOLOR); + if (!m1.hasDataMask(MeshModel::MM_VERTCOLOR)) + m1HasColor = false; + if (!m2.hasDataMask(MeshModel::MM_VERTCOLOR)) + m2HasColor = false; + } + + //vertIndices construction + Eigen::VectorXi vertIndices(res.cm.VN()); + vertIndices.setConstant(-1); + + for (unsigned int i = 0; i < faceIndices.size(); ++i){ + bool fromM1 = true; + unsigned int mIndex = faceIndices[i]; + + //if the index is >= FN of m1, it means that the index is of m2 + if (faceIndices[i] >= m1.cm.FN()){ + fromM1 = false; + mIndex -= m1.cm.FN(); + } + + CMeshO::ConstFacePointer fBirth; + CMeshO::FacePointer fRes = &(res.cm.face[i]); + if (fromM1) + fBirth = &(m1.cm.face[mIndex]); + else + fBirth = &(m2.cm.face[mIndex]); + + for (unsigned int j = 0; j < 3; ++j){ + CMeshO::VertexPointer vp = fRes->V(j); + unsigned int vi = vcg::tri::Index(res.cm, vp); + if (vertIndices[vi] == -1){ + //look if there is an equal vertex in fBirth + for (unsigned k = 0; k < 3; ++k){ + if (fRes->V(j)->P() == fBirth->V(k)->P()){ + unsigned int birthVertIndex; + if (fromM1) + birthVertIndex = vcg::tri::Index(m1.cm, fBirth->V(k)); + else + birthVertIndex = vcg::tri::Index(m2.cm, fBirth->V(k)) + m1.cm.VN(); + vertIndices[vi] = birthVertIndex; + } + } + } + } + } + + //update birth vertices + for (unsigned int i = 0; i < vertIndices.size(); ++i){ + bool fromM1 = false; + bool fromM2 = false; + + int mIndex = vertIndices[i]; + if (vertIndices[i] >= m1.cm.VN()){ + fromM2 = true; + mIndex -= m1.cm.VN(); + } + else if (vertIndices[i] >= 0) { + fromM1 = true; + } + + //if we need to transfer quality + if (quality){ + Scalarm q = 0; //default quality value + if (fromM1 && m1HasQuality) + q = m1.cm.vert[mIndex].Q(); + if (!fromM1 && m2HasQuality) + q = m2.cm.vert[mIndex].Q(); + res.cm.vert[i].Q() = q; + } + + //if we need to transfer color + if (color) { + vcg::Color4b c(128, 128, 128, 255); //default color value + if (fromM1 && m1HasColor) + c = m1.cm.vert[mIndex].C(); + if (fromM2 && m2HasColor) + c = m2.cm.vert[mIndex].C(); + res.cm.vert[i].C() = c; + } + } + + //update newly created vertices + for (unsigned int i = 0; i < vertIndices.size(); ++i){ + if (vertIndices[i] == -1){ + //base values + unsigned int avgr=0, avgg=0, avgb=0, avga=0; + Scalarm avgq=0; + unsigned int nAdjs = 0; + + CMeshO::VertexPointer vp = &res.cm.vert[i]; + vcg::face::VFIterator fadjit(vp); + //for each incident face fadj to vp + for (; !fadjit.End(); ++fadjit){ + for (unsigned int j = 0; j < 3; j++){ + //get each vertex to f + CMeshO::VertexPointer vadj = fadjit.F()->V(j); + unsigned int vi = vcg::tri::Index(res.cm, vadj); + //if the vertex is not i and it is not newly created + if (vi != i && vertIndices[vi] != -1) { + nAdjs++; + //if we need to transfer color + if (color) { + avgr += res.cm.vert[vi].C()[0]; + avgg += res.cm.vert[vi].C()[1]; + avgb += res.cm.vert[vi].C()[2]; + avga += res.cm.vert[vi].C()[3]; + } + if (quality){ + avgq += res.cm.vert[vi].Q(); + } + } + } + } + if (nAdjs != 0){ + if (color) { + res.cm.vert[i].C() = vcg::Color4b(avgr/nAdjs, avgg/nAdjs, avgb/nAdjs, avga/nAdjs); + } + if (quality){ + res.cm.vert[i].Q() = avgq / nAdjs; + } + } + } + } +} + +MESHLAB_PLUGIN_NAME_EXPORTER(FilterMeshBooleans) diff --git a/src/meshlabplugins/filter_mesh_booleans/filter_mesh_booleans.h b/src/meshlabplugins/filter_mesh_booleans/filter_mesh_booleans.h new file mode 100644 index 000000000..403a1ee2f --- /dev/null +++ b/src/meshlabplugins/filter_mesh_booleans/filter_mesh_booleans.h @@ -0,0 +1,114 @@ +/**************************************************************************** +* MeshLab o o * +* A versatile mesh processing toolbox o o * +* _ O _ * +* Copyright(C) 2005-2021 \/)\/ * +* Visual Computing Lab /\/| * +* ISTI - Italian National Research Council | * +* \ * +* All rights reserved. * +* * +* This program is free software; you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation; either version 2 of the License, or * +* (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) * +* for more details. * +* * +****************************************************************************/ + +#ifndef MESHLAB_FILTER_MESH_BOOLEANS_H +#define MESHLAB_FILTER_MESH_BOOLEANS_H + +// from meshlab common, include the abstract class file of filter plugins +#include + +/** + * @brief The FilterExamplePlugin class + * This is a simple and useless example of a MeshLab filter plugin. + * + * You can use this class as a base to start and coding your plugin! + * + * You can change the name of the class. Just be sure that the class + * inherits from the QObject class (needed to make the plugin a Qt plugin) + * and the FilterPlugin class. + * + * Check the cpp file for the explanation of each member function of the class and + * whether they are mandatory to be implemented. + */ +class FilterMeshBooleans : public QObject, public FilterPlugin +{ + Q_OBJECT + MESHLAB_PLUGIN_IID_EXPORTER(FILTER_PLUGIN_IID) + Q_INTERFACES(FilterPlugin) + +public: + //enum used to give an ID to every filter implemented in the plugin + enum FileterIds { + MESH_INTERSECTION, + MESH_UNION, + MESH_DIFFERENCE, + MESH_XOR}; + + FilterMeshBooleans(); + + QString pluginName() const; + QString vendor() const; + + QString filterName(ActionIDType filter) const; + QString filterInfo(ActionIDType filter) const; + FilterClass getClass(const QAction* a) const; + FilterArity filterArity(const QAction*) const; + //int getPreConditions(const QAction *) const; + //int postCondition(const QAction* ) const; + RichParameterList initParameterList(const QAction*, const MeshDocument &/*m*/); + std::map applyFilter( + const QAction* action, + const RichParameterList & params, + MeshDocument &md, + unsigned int& postConditionMask, + vcg::CallBackPos * cb); + +private: + //conversion functions + static void CMeshOToEigen( + const CMeshO& m, + Eigen::MatrixX3d& V, + Eigen::MatrixX3i& F); + static CMeshO EigenToCMeshO( + const Eigen::MatrixX3d& V, + const Eigen::MatrixX3i& F); + + //generic boolean operation function + static void booleanOperation( + MeshDocument& md, + const MeshModel& m1, + const MeshModel& m2, + int op, + bool transfFaceQuality, + bool transfFaceColor, + bool transfVertQuality, + bool transfVertColor); + + //transfer functions + static void transferFaceAttributes( + MeshModel& res, + const Eigen::VectorXi& faceIndices, + const MeshModel& m1, + const MeshModel& m2, + bool quality, + bool color); + static void transferVertexAttributes( + MeshModel& res, + const Eigen::VectorXi& faceIndices, + const MeshModel& m1, + const MeshModel& m2, + bool quality, + bool color); +}; + +#endif //MESHLAB_FILTER_MESH_BOOLEANS_H diff --git a/src/meshlabplugins/filter_meshing/meshfilter.cpp b/src/meshlabplugins/filter_meshing/meshfilter.cpp index 304dd5612..86f191e59 100644 --- a/src/meshlabplugins/filter_meshing/meshfilter.cpp +++ b/src/meshlabplugins/filter_meshing/meshfilter.cpp @@ -350,8 +350,9 @@ QString ExtraMeshFilterPlugin::filterInfo(ActionIDType filterID) const // return // true if has some parameters // false is has no params -void ExtraMeshFilterPlugin::initParameterList(const QAction * action, MeshModel & m, RichParameterList & parlst) +RichParameterList ExtraMeshFilterPlugin::initParameterList(const QAction * action, const MeshModel & m) { + RichParameterList parlst; float maxVal; QStringList curvCalcMethods; QStringList curvColorMethods; @@ -556,7 +557,7 @@ void ExtraMeshFilterPlugin::initParameterList(const QAction * action, MeshModel traslMethod.push_back("Center on Layer BBox"); traslMethod.push_back("Set new Origin"); parlst.addParam(RichEnum("traslMethod", 0, traslMethod, tr("Transformation:"), tr("[XYZ translation] adds X,Y and Z offset to Layer transformation, [Center on BBox] moves Layer Origin to the Bounding Box center, [Set new Origin] moves Layer Origin to a specific point"))); - Box3m &bb=m.cm.bbox; + const Box3m &bb=m.cm.bbox; parlst.addParam(RichDynamicFloat("axisX",0,-5.0*bb.Diag(),5.0*bb.Diag(),"X Axis","when using [XYZ translation], amount of translation along the X axis (in model units)")); parlst.addParam(RichDynamicFloat("axisY",0,-5.0*bb.Diag(),5.0*bb.Diag(),"Y Axis","when using [XYZ translation], amount of translation along the Y axis (in model units)")); parlst.addParam(RichDynamicFloat("axisZ",0,-5.0*bb.Diag(),5.0*bb.Diag(),"Z Axis","when using [XYZ translation], amount of translation along the Z axis (in model units)")); @@ -642,6 +643,7 @@ void ExtraMeshFilterPlugin::initParameterList(const QAction * action, MeshModel default: break; } + return parlst; } @@ -667,9 +669,9 @@ void ApplyTransform(MeshDocument &md, const Matrix44m &tr, bool toAllFlag, bool if(freeze) Freeze(m); } - for (int i = 0; i < md.rasterList.size(); i++) - if (md.rasterList[0]->visible) - md.rasterList[i]->shot.ApplyRigidTransformation(tr); + for (RasterModel* rm : md.rasterIterator()) + if (rm->visible) + rm->shot.ApplyRigidTransformation(tr); } else { @@ -774,7 +776,7 @@ std::map ExtraMeshFilterPlugin::applyFilter( m.clearDataMask(MeshModel::MM_VERTFACETOPO); } - m.UpdateBoxAndNormals(); + m.updateBoxAndNormals(); } break; case FP_REORIENT: @@ -788,7 +790,7 @@ std::map ExtraMeshFilterPlugin::applyFilter( tri::Clean::OrientCoherentlyMesh(m.cm, oriented,orientable); tri::UpdateTopology::FaceFace(m.cm); tri::UpdateTopology::TestFaceFace(m.cm); - m.UpdateBoxAndNormals(); + m.updateBoxAndNormals(); } break; case FP_CLUSTERING: @@ -802,7 +804,7 @@ std::map ExtraMeshFilterPlugin::applyFilter( ClusteringGrid.AddMesh(m.cm); ClusteringGrid.ExtractMesh(m.cm); - m.UpdateBoxAndNormals(); + m.updateBoxAndNormals(); m.clearDataMask(MeshModel::MM_FACEFACETOPO); } break; @@ -815,7 +817,7 @@ std::map ExtraMeshFilterPlugin::applyFilter( tri::Clean::FlipMesh(m.cm,onlySelected); else flipped = tri::Clean::FlipNormalOutside(m.cm); - m.UpdateBoxAndNormals(); + m.updateBoxAndNormals(); m.clearDataMask(MeshModel::MM_FACEFACETOPO); } break; @@ -903,7 +905,7 @@ std::map ExtraMeshFilterPlugin::applyFilter( tri::Allocator::CompactFaceVector(m.cm); } - m.UpdateBoxAndNormals(); + m.updateBoxAndNormals(); tri::UpdateNormal::NormalizePerFace(m.cm); tri::UpdateNormal::PerVertexFromCurrentFaceNormal(m.cm); tri::UpdateNormal::NormalizePerVertex(m.cm); @@ -939,7 +941,7 @@ std::map ExtraMeshFilterPlugin::applyFilter( lastq_Selected = par.getBool("Selected"); QuadricTexSimplification(m.cm,TargetFaceNum,lastq_Selected, pp, cb); - m.UpdateBoxAndNormals(); + m.updateBoxAndNormals(); tri::UpdateNormal::NormalizePerFace(m.cm); tri::UpdateNormal::PerVertexFromCurrentFaceNormal(m.cm); tri::UpdateNormal::NormalizePerVertex(m.cm); @@ -954,7 +956,7 @@ std::map ExtraMeshFilterPlugin::applyFilter( tri::Clean::RemoveUnreferencedVertex(m.cm); tri::Allocator::CompactEveryVector(m.cm); - m.UpdateBoxAndNormals(); + m.updateBoxAndNormals(); CMeshO toProjectCopy; @@ -1001,7 +1003,7 @@ std::map ExtraMeshFilterPlugin::applyFilter( log(excp.what()); throw MLException(excp.what()); } - m.UpdateBoxAndNormals(); + m.updateBoxAndNormals(); // m.clearDataMask(MeshModel::MM_GEOMETRY_AND_TOPOLOGY_CHANGE | MeshModel::MM_FACEFACETOPO | MeshModel::MM_VERTQUALITY | MeshModel::MM_FACEMARK | MeshModel::MM_FACEFLAG); @@ -1372,7 +1374,7 @@ std::map ExtraMeshFilterPlugin::applyFilter( outputValues["closed_holes"] = holeCnt; outputValues["new_faces"] = (int)(m.cm.fn-OriginalSize); assert(tri::Clean::IsFFAdjacencyConsistent(m.cm)); - m.UpdateBoxAndNormals(); + m.updateBoxAndNormals(); // hole filling filter does not correctly update the border flags (but the topology is still ok!) if(NewFaceSelectedFlag) @@ -1400,7 +1402,9 @@ std::map ExtraMeshFilterPlugin::applyFilter( MeshModel *um=md.addNewMesh("","Unrolled Mesh"); um->updateDataMask(&m); - um->cm.textures = m.cm.textures; + for (const std::string& tex: m.cm.textures) { + um->addTexture(tex, m.getTexture(tex)); + } float avgZ=0; CMeshO::VertexIterator vi; // First loop duplicate accordingly the vertices. @@ -1477,7 +1481,7 @@ std::map ExtraMeshFilterPlugin::applyFilter( loopIndex++; } } - m.UpdateBoxAndNormals(); + m.updateBoxAndNormals(); } break; case FP_REFINE_HALF_CATMULL: @@ -1535,7 +1539,7 @@ std::map ExtraMeshFilterPlugin::applyFilter( case FP_MAKE_PURE_TRI: { vcg::tri::BitQuadCreation::MakeBitTriOnly(m.cm); - m.UpdateBoxAndNormals(); + m.updateBoxAndNormals(); m.clearDataMask(MeshModel::MM_POLYGONAL); } break; @@ -1621,7 +1625,7 @@ std::map ExtraMeshFilterPlugin::applyFilter( // new layer QString newLayerName = QFileInfo(m.shortName()).baseName() + "_perimeter"; MeshModel* perimeter = md.addNewMesh("", newLayerName, true); - perimeter->Clear(); + perimeter->clear(); Matrix44m rotM = m.cm.Tr; rotM.SetColumn(3, Point3m(0.0, 0.0, 0.0)); @@ -1719,7 +1723,7 @@ std::map ExtraMeshFilterPlugin::applyFilter( { MeshModel* cap2= md.addNewMesh("",sectionName+"_filled"); tri::CapEdgeMesh(cap->cm, cap2->cm); - cap2->UpdateBoxAndNormals(); + cap2->updateBoxAndNormals(); } if(par.getBool("splitSurfaceWithSection")) @@ -1758,8 +1762,8 @@ std::map ExtraMeshFilterPlugin::applyFilter( if(!(*vi).IsD() && (*vi).IsS()) tri::Allocator::DeleteVertex(underM->cm,*vi); - underM->UpdateBoxAndNormals(); - overM->UpdateBoxAndNormals(); + underM->updateBoxAndNormals(); + overM->updateBoxAndNormals(); } } diff --git a/src/meshlabplugins/filter_meshing/meshfilter.h b/src/meshlabplugins/filter_meshing/meshfilter.h index ef0cf52f2..35b642920 100644 --- a/src/meshlabplugins/filter_meshing/meshfilter.h +++ b/src/meshlabplugins/filter_meshing/meshfilter.h @@ -88,7 +88,7 @@ public: QString filterInfo(ActionIDType filter) const; FilterClass getClass(const QAction*) const; - void initParameterList(const QAction*, MeshModel &/*m*/, RichParameterList & /*parent*/); + RichParameterList initParameterList(const QAction*, const MeshModel &/*m*/); std::map applyFilter( const QAction* action, const RichParameterList & parameters, diff --git a/src/meshlabplugins/filter_mls/mlsplugin.cpp b/src/meshlabplugins/filter_mls/mlsplugin.cpp index 9fc247421..fbd4a366f 100644 --- a/src/meshlabplugins/filter_mls/mlsplugin.cpp +++ b/src/meshlabplugins/filter_mls/mlsplugin.cpp @@ -179,10 +179,11 @@ QString MlsPlugin::filterInfo(ActionIDType filterId) const // - the string shown in the dialog // - the default value // - a possibly long string describing the meaning of that parameter (shown as a popup help in the dialog) -void MlsPlugin::initParameterList(const QAction* action, MeshDocument& md, RichParameterList& parlst) +RichParameterList MlsPlugin::initParameterList(const QAction* action, const MeshDocument& md) { + RichParameterList parlst; int id = ID(action); - MeshModel *target = md.mm(); + const MeshModel *target = md.mm(); if (id == FP_SELECT_SMALL_COMPONENTS) { @@ -195,7 +196,7 @@ void MlsPlugin::initParameterList(const QAction* action, MeshDocument& md, RichP false, "Select only non closed components", "")); - return; + return parlst; } else if (id == FP_RADIUS_FROM_DENSITY) { @@ -203,14 +204,14 @@ void MlsPlugin::initParameterList(const QAction* action, MeshDocument& md, RichP 16, "Number of neighbors", "Number of neighbors used to estimate the local density. Larger values lead to smoother variations.")); - return; + return parlst; } if ((id & _PROJECTION_)) { - parlst.addParam(RichMesh( "ControlMesh", target,&md, "Point set", + parlst.addParam(RichMesh( "ControlMesh", target->id(),&md, "Point set", "The point set (or mesh) which defines the MLS surface.")); - parlst.addParam(RichMesh( "ProxyMesh", target, &md, "Proxy Mesh", + parlst.addParam(RichMesh( "ProxyMesh", target->id(), &md, "Proxy Mesh", "The mesh that will be projected/resampled onto the MLS surface.")); } if ((id & _PROJECTION_) || (id & _COLORIZE_)) @@ -313,6 +314,7 @@ void MlsPlugin::initParameterList(const QAction* action, MeshDocument& md, RichP "The resolution of the grid on which we run the marching cubes." "This marching cube is memory friendly, so you can safely set large values up to 1000 or even more.")); } + return parlst; } int MlsPlugin::getRequirements(const QAction *) @@ -410,10 +412,10 @@ std::map MlsPlugin::applyFilter( MeshModel* pPoints = 0; if (id & _PROJECTION_) { - if (par.getMesh("ControlMesh") == par.getMesh("ProxyMesh")) + if (par.getMeshId("ControlMesh") == par.getMeshId("ProxyMesh")) { // clone the control mesh - MeshModel* ref = par.getMesh("ControlMesh"); + MeshModel* ref = md.getMesh(par.getMeshId("ControlMesh")); pPoints = md.addNewMesh("","TempMesh"); pPoints->updateDataMask(ref); vcg::tri::Append::Mesh(pPoints->cm, ref->cm); // the last true means "copy all vertices" @@ -421,7 +423,7 @@ std::map MlsPlugin::applyFilter( pPoints->cm.Tr = ref->cm.Tr; } else - pPoints = par.getMesh("ControlMesh"); + pPoints = md.getMesh(par.getMeshId("ControlMesh")); } else // for curvature pPoints = md.mm(); @@ -464,7 +466,7 @@ std::map MlsPlugin::applyFilter( if (id & _PROJECTION_) { - mesh = par.getMesh("ProxyMesh"); + mesh = md.getMesh(par.getMeshId("ProxyMesh")); bool selectionOnly = par.getBool("SelectionOnly"); if (selectionOnly) @@ -614,13 +616,13 @@ std::map MlsPlugin::applyFilter( } delete mls; - if ( (id & _PROJECTION_) && par.getMesh("ControlMesh")!=pPoints) + if ( (id & _PROJECTION_) && md.getMesh(par.getMeshId("ControlMesh"))!=pPoints) { md.delMesh(pPoints); } if (mesh) - mesh->UpdateBoxAndNormals(); + mesh->updateBoxAndNormals(); } // end MLS based stuff diff --git a/src/meshlabplugins/filter_mls/mlsplugin.h b/src/meshlabplugins/filter_mls/mlsplugin.h index 487fb267e..a26632dee 100644 --- a/src/meshlabplugins/filter_mls/mlsplugin.h +++ b/src/meshlabplugins/filter_mls/mlsplugin.h @@ -63,11 +63,11 @@ public: MlsPlugin(); QString pluginName() const; - virtual QString filterName(ActionIDType filter) const; - virtual QString filterInfo(ActionIDType filter) const; + QString filterName(ActionIDType filter) const; + QString filterInfo(ActionIDType filter) const; FilterClass getClass(const QAction *a) const; - virtual void initParameterList(const QAction*, MeshDocument &md, RichParameterList &parent); - virtual int getRequirements(const QAction* action); + RichParameterList initParameterList(const QAction*, const MeshDocument &md); + int getRequirements(const QAction* action); std::map applyFilter( const QAction* action, const RichParameterList & parameters, diff --git a/src/meshlabplugins/filter_mutualglobal/filter_mutualglobal.cpp b/src/meshlabplugins/filter_mutualglobal/filter_mutualglobal.cpp index db4b10e3e..b992f3682 100644 --- a/src/meshlabplugins/filter_mutualglobal/filter_mutualglobal.cpp +++ b/src/meshlabplugins/filter_mutualglobal/filter_mutualglobal.cpp @@ -114,8 +114,9 @@ bool FilterMutualGlobal::requiresGLContext(const QAction* action) const // - the string shown in the dialog // - the default value // - a possibly long string describing the meaning of that parameter (shown as a popup help in the dialog) -void FilterMutualGlobal::initParameterList(const QAction *action,MeshDocument & md, RichParameterList & parlst) +RichParameterList FilterMutualGlobal::initParameterList(const QAction *action, const MeshDocument &) { + RichParameterList parlst; QStringList rendList; switch(ID(action)) { case FP_IMAGE_GLOBALIGN : @@ -167,6 +168,7 @@ void FilterMutualGlobal::initParameterList(const QAction *action,MeshDocument & default : assert(0); } + return parlst; } // The Real Core Function doing the actual mesh processing. @@ -194,9 +196,9 @@ std::map FilterMutualGlobal::applyFilter( myVec.push_back(md.mm()->cm.vert[i].P()); } std::vector oldShots; - for (int r=0; rshot); + oldShots.push_back(rm->shot); } log("Sampled has %i vertices",myVec.size()); @@ -206,7 +208,7 @@ std::map FilterMutualGlobal::applyFilter( switch(ID(action)) { case FP_IMAGE_GLOBALIGN : /// Building of the graph of images - if (md.rasterList.size()==0) + if (md.rasterNumber()==0) { log("You need a Raster Model to apply this filter!"); throw MLException("You need a Raster Model to apply this filter!"); @@ -235,9 +237,9 @@ std::map FilterMutualGlobal::applyFilter( if (diffshot); + oldShots.push_back(rm->shot); } } } @@ -263,15 +265,17 @@ float FilterMutualGlobal::calcShotsDifference(MeshDocument &md, std::vector distances; for (int i=0; ishot.Project(points[i]); - if(pp[0]>0 && pp[1]>0 && pp[0]shot.Intrinsics.ViewportPx[0] && pp[1]shot.Intrinsics.ViewportPx[1]) + vcg::Point2f pp=rm->shot.Project(points[i]); + if(pp[0]>0 && pp[1]>0 && pp[0]shot.Intrinsics.ViewportPx[0] && pp[1]shot.Intrinsics.ViewportPx[1]) { vcg::Point2f ppOld=oldShots[j].Project(points[i]); vcg::Point2f d=pp-ppOld; distances.push_back(vcg::math::Sqrt( d[0]*d[0] + d[1]*d[1] )); } + ++j; } } float totErr=0.0; @@ -362,88 +366,89 @@ bool FilterMutualGlobal::preAlignment(MeshDocument &md, const RichParameterList { Solver solver; MutualInfo mutual; - if (md.rasterList.size()==0) + if (md.rasterNumber()==0) { - log("You need a Raster Model to apply this filter!"); - return false; + log("You need a Raster Model to apply this filter!"); + return false; } else { - alignset.mesh=&md.mm()->cm; + alignset.mesh=&md.mm()->cm; - solver.optimize_focal=par.getBool("Estimate Focal"); - solver.fine_alignment=par.getBool("Fine"); + solver.optimize_focal=par.getBool("Estimate Focal"); + solver.fine_alignment=par.getBool("Fine"); - int rendmode= par.getEnum("RenderingMode"); + int rendmode= par.getEnum("RenderingMode"); - switch(rendmode){ - case 0: - alignset.mode=AlignSet::COMBINE; - break; - case 1: - alignset.mode=AlignSet::NORMALMAP; - break; - case 2: - alignset.mode=AlignSet::COLOR; - break; - case 3: - alignset.mode=AlignSet::SPECULAR; - break; - case 4: - alignset.mode=AlignSet::SILHOUETTE; - break; - case 5: - alignset.mode=AlignSet::SPECAMB; - break; - default: - alignset.mode=AlignSet::COMBINE; - break; - } + switch(rendmode){ + case 0: + alignset.mode=AlignSet::COMBINE; + break; + case 1: + alignset.mode=AlignSet::NORMALMAP; + break; + case 2: + alignset.mode=AlignSet::COLOR; + break; + case 3: + alignset.mode=AlignSet::SPECULAR; + break; + case 4: + alignset.mode=AlignSet::SILHOUETTE; + break; + case 5: + alignset.mode=AlignSet::SPECAMB; + break; + default: + alignset.mode=AlignSet::COMBINE; + break; + } - vcg::Point3f *vertices = new vcg::Point3f[alignset.mesh->vn]; - vcg::Point3f *normals = new vcg::Point3f[alignset.mesh->vn]; - vcg::Color4b *colors = new vcg::Color4b[alignset.mesh->vn]; - unsigned int *indices = new unsigned int[alignset.mesh->fn*3]; + vcg::Point3f *vertices = new vcg::Point3f[alignset.mesh->vn]; + vcg::Point3f *normals = new vcg::Point3f[alignset.mesh->vn]; + vcg::Color4b *colors = new vcg::Color4b[alignset.mesh->vn]; + unsigned int *indices = new unsigned int[alignset.mesh->fn*3]; - for(int i = 0; i < alignset.mesh->vn; i++) { - vertices[i] = alignset.mesh->vert[i].P(); - normals[i] = alignset.mesh->vert[i].N(); - colors[i] = alignset.mesh->vert[i].C(); - } + for(int i = 0; i < alignset.mesh->vn; i++) { + vertices[i] = alignset.mesh->vert[i].P(); + normals[i] = alignset.mesh->vert[i].N(); + colors[i] = alignset.mesh->vert[i].C(); + } - for(int i = 0; i < alignset.mesh->fn; i++) - for(int k = 0; k < 3; k++) - indices[k+i*3] = alignset.mesh->face[i].V(k) - &*alignset.mesh->vert.begin(); + for(int i = 0; i < alignset.mesh->fn; i++) + for(int k = 0; k < 3; k++) + indices[k+i*3] = alignset.mesh->face[i].V(k) - &*alignset.mesh->vert.begin(); - glBindBufferARB(GL_ARRAY_BUFFER_ARB, alignset.vbo); - glBufferDataARB(GL_ARRAY_BUFFER_ARB, alignset.mesh->vn*sizeof(vcg::Point3f), - vertices, GL_STATIC_DRAW_ARB); - glBindBufferARB(GL_ARRAY_BUFFER_ARB, alignset.nbo); - glBufferDataARB(GL_ARRAY_BUFFER_ARB, alignset.mesh->vn*sizeof(vcg::Point3f), - normals, GL_STATIC_DRAW_ARB); - glBindBufferARB(GL_ARRAY_BUFFER_ARB, alignset.cbo); - glBufferDataARB(GL_ARRAY_BUFFER_ARB, alignset.mesh->vn*sizeof(vcg::Color4b), - colors, GL_STATIC_DRAW_ARB); - glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); + glBindBufferARB(GL_ARRAY_BUFFER_ARB, alignset.vbo); + glBufferDataARB(GL_ARRAY_BUFFER_ARB, alignset.mesh->vn*sizeof(vcg::Point3f), + vertices, GL_STATIC_DRAW_ARB); + glBindBufferARB(GL_ARRAY_BUFFER_ARB, alignset.nbo); + glBufferDataARB(GL_ARRAY_BUFFER_ARB, alignset.mesh->vn*sizeof(vcg::Point3f), + normals, GL_STATIC_DRAW_ARB); + glBindBufferARB(GL_ARRAY_BUFFER_ARB, alignset.cbo); + glBufferDataARB(GL_ARRAY_BUFFER_ARB, alignset.mesh->vn*sizeof(vcg::Color4b), + colors, GL_STATIC_DRAW_ARB); + glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); - glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, alignset.ibo); - glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, alignset.mesh->fn*3*sizeof(unsigned int), - indices, GL_STATIC_DRAW_ARB); - glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); + glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, alignset.ibo); + glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, alignset.mesh->fn*3*sizeof(unsigned int), + indices, GL_STATIC_DRAW_ARB); + glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); - // it is safe to delete after copying data to VBO - delete []vertices; - delete []normals; - delete []colors; - delete []indices; + // it is safe to delete after copying data to VBO + delete []vertices; + delete []normals; + delete []colors; + delete []indices; - for (int r=0; rvisible) + unsigned int r = 0; + for (RasterModel* rm : md.rasterIterator()) { - alignset.image=&md.rasterList[r]->currentPlane->image; - alignset.shot=md.rasterList[r]->shot; + if(rm->visible) + { + alignset.image=&rm->currentPlane->image; + alignset.shot=rm->shot; alignset.resize(800); @@ -451,27 +456,29 @@ bool FilterMutualGlobal::preAlignment(MeshDocument &md, const RichParameterList alignset.shot.Intrinsics.CenterPx[0]=(int)(alignset.shot.Intrinsics.ViewportPx[0]/2); if (solver.fine_alignment) - solver.optimize(&alignset, &mutual, alignset.shot); + solver.optimize(&alignset, &mutual, alignset.shot); else { - solver.iterative(&alignset, &mutual, alignset.shot); - log("Vado di rough",r); + solver.iterative(&alignset, &mutual, alignset.shot); + log("Vado di rough",r); } - md.rasterList[r]->shot=alignset.shot; - float ratio=(float)md.rasterList[r]->currentPlane->image.height()/(float)alignset.shot.Intrinsics.ViewportPx[1]; - md.rasterList[r]->shot.Intrinsics.ViewportPx[0]=md.rasterList[r]->currentPlane->image.width(); - md.rasterList[r]->shot.Intrinsics.ViewportPx[1]=md.rasterList[r]->currentPlane->image.height(); - md.rasterList[r]->shot.Intrinsics.PixelSizeMm[1]/=ratio; - md.rasterList[r]->shot.Intrinsics.PixelSizeMm[0]/=ratio; - md.rasterList[r]->shot.Intrinsics.CenterPx[0]=(int)((float)md.rasterList[r]->shot.Intrinsics.ViewportPx[0]/2.0); - md.rasterList[r]->shot.Intrinsics.CenterPx[1]=(int)((float)md.rasterList[r]->shot.Intrinsics.ViewportPx[1]/2.0); + rm->shot=alignset.shot; + float ratio=(float)rm->currentPlane->image.height()/(float)alignset.shot.Intrinsics.ViewportPx[1]; + rm->shot.Intrinsics.ViewportPx[0]=rm->currentPlane->image.width(); + rm->shot.Intrinsics.ViewportPx[1]=rm->currentPlane->image.height(); + rm->shot.Intrinsics.PixelSizeMm[1]/=ratio; + rm->shot.Intrinsics.PixelSizeMm[0]/=ratio; + rm->shot.Intrinsics.CenterPx[0]=(int)((float)rm->shot.Intrinsics.ViewportPx[0]/2.0); + rm->shot.Intrinsics.CenterPx[1]=(int)((float)rm->shot.Intrinsics.ViewportPx[1]/2.0); log("Image %d completed",r); - } - else - log("Image %d skipped",r); + } + else{ + log("Image %d skipped",r); + } + ++r; } } @@ -543,13 +550,14 @@ std::vector FilterMutualGlobal::CalcPairs(MeshDocument &md, bool glob //alignset.mode=AlignSet::PROJIMG; //this->glContext->makeCurrent(); - for (int r=0; rvisible) + if(rm->visible) { AlignPair pair; - alignset.image=&md.rasterList[r]->currentPlane->image; - alignset.shot=md.rasterList[r]->shot; + alignset.image=&rm->currentPlane->image; + alignset.shot=rm->shot; //this->initGL(); alignset.resize(800); @@ -565,13 +573,14 @@ std::vector FilterMutualGlobal::CalcPairs(MeshDocument &md, bool glob QImage covered=alignset.comb; std::vector weightList; - for (int p=0; pshot; - alignset.imagePro=&md.rasterList[p]->currentPlane->image; + alignset.shotPro=pm->shot; + alignset.imagePro=&pm->currentPlane->image; alignset.ProjectedImageChanged(*alignset.imagePro); float countTot=0.0; float countCol=0.0; @@ -593,18 +602,19 @@ std::vector FilterMutualGlobal::CalcPairs(MeshDocument &md, bool glob } } } - pair.area=countCol/countTot; + pair.area=countCol/countTot; - if (pair.area>0.2) - { - pair.mutual=mutual.info(alignset.wt,alignset.ht,alignset.target,alignset.render); - pair.imageId=r; - pair.projId=p; - pair.weight=pair.area*pair.mutual; - weightList.push_back(pair); + if (pair.area>0.2) + { + pair.mutual=mutual.info(alignset.wt,alignset.ht,alignset.target,alignset.render); + pair.imageId=r; + pair.projId=p; + pair.weight=pair.area*pair.mutual; + weightList.push_back(pair); - } + } } + ++p; } log("Image %d completed",r); @@ -623,8 +633,6 @@ std::vector FilterMutualGlobal::CalcPairs(MeshDocument &md, bool glob } else { - - std::sort(weightList.begin(), weightList.end(), orderingW()); ///////////////////////////////////////7 @@ -632,8 +640,8 @@ std::vector FilterMutualGlobal::CalcPairs(MeshDocument &md, bool glob { int p=weightList[i].projId; alignset.mode=AlignSet::PROJIMG; - alignset.shotPro=md.rasterList[p]->shot; - alignset.imagePro=&md.rasterList[p]->currentPlane->image; + alignset.shotPro=rm->shot; + alignset.imagePro=&rm->currentPlane->image; alignset.ProjectedImageChanged(*alignset.imagePro); float countTot=0.0; float countCol=0.0; @@ -660,31 +668,32 @@ std::vector FilterMutualGlobal::CalcPairs(MeshDocument &md, bool glob } } } - pair.area=countCol/countTot; - /*covered.save("covered.jpg"); - alignset.rend.save("rend.jpg"); - alignset.comb.save("comb.jpg");*/ + pair.area=countCol/countTot; + /*covered.save("covered.jpg"); + alignset.rend.save("rend.jpg"); + alignset.comb.save("comb.jpg");*/ - pair.area*=countCov/countTot; - pair.mutual=mutual.info(alignset.wt,alignset.ht,alignset.target,alignset.render); - pair.imageId=r; - pair.projId=p; - pair.weight=weightList[i].weight; - list.push_back(pair); - log("Area %3.2f, Mutual %3.2f",pair.area,pair.mutual); - } + pair.area*=countCov/countTot; + pair.mutual=mutual.info(alignset.wt,alignset.ht,alignset.target,alignset.render); + pair.imageId=r; + pair.projId=p; + pair.weight=weightList[i].weight; + list.push_back(pair); + log("Area %3.2f, Mutual %3.2f",pair.area,pair.mutual); + } } } - } -////////////////////////////////////////////////////// + ++r; + } + ////////////////////////////////////////////////////// - log("Tot arcs %d, Valid arcs %d",(md.rasterList.size())*(md.rasterList.size()-1),list.size()); + log("Tot arcs %d, Valid arcs %d",(md.rasterNumber())*(md.rasterNumber()-1),list.size()); - //emit md.rasterSetChanged(); + //emit md.rasterSetChanged(); //this->glContext->doneCurrent(); return list; @@ -694,7 +703,7 @@ std::vector FilterMutualGlobal::CreateGraphs(MeshDocument &md, std::ve { std::vector Gr; SubGraph allNodes; - int numNodes=md.rasterList.size(); + int numNodes=md.rasterNumber(); for (int s=0; s FilterMutualGlobal::CreateGraphs(MeshDocument &md, std::ve { SubGraph graph; graph.id=i; + auto rmit = md.rasterBegin(); for (int j=0; j FilterMutualGlobal::CreateGraphs(MeshDocument &md, std::ve { Node n; double mut=0.0; double are=0.00001; - if(md.rasterList[j]->visible) + if((*rmit)->visible) n.active=false; else n.active=true; @@ -805,6 +815,7 @@ std::vector FilterMutualGlobal::CreateGraphs(MeshDocument &md, std::ve graph.nodes.push_back(n); log("Node %d of %d: not used",j,numNodes); } + ++rmit; } Gr.push_back(graph); } @@ -896,15 +907,19 @@ bool FilterMutualGlobal::AlignNode(MeshDocument &md, Node node) alignset.mode=AlignSet::NODE; //alignset.node=&node; - alignset.image=&md.rasterList[node.id]->currentPlane->image; - alignset.shot=md.rasterList[node.id]->shot; + auto it= md.rasterBegin(); std::advance(it, node.id); + RasterModel* rm = *it; + alignset.image=&rm->currentPlane->image; + alignset.shot=rm->shot; alignset.mesh=&md.mm()->cm; for (int l=0; lcurrentPlane->image); - alignset.arcShots.push_back(&md.rasterList[node.arcs[l].projId]->shot); + auto lit = md.rasterBegin(); std::advance(lit, node.arcs[l].projId); + RasterModel* lrm =*lit; + alignset.arcImages.push_back(&lrm->currentPlane->image); + alignset.arcShots.push_back(&lrm->shot); alignset.arcMI.push_back(node.arcs[l].mutual); } @@ -913,17 +928,21 @@ bool FilterMutualGlobal::AlignNode(MeshDocument &md, Node node) return true; else if(alignset.arcImages.size()==1) { - alignset.arcImages.push_back(&md.rasterList[node.arcs[0].projId]->currentPlane->image); - alignset.arcShots.push_back(&md.rasterList[node.arcs[0].projId]->shot); + auto lit = md.rasterBegin(); std::advance(lit, node.arcs[0].projId); + RasterModel* lrm =*lit; + alignset.arcImages.push_back(&lrm->currentPlane->image); + alignset.arcShots.push_back(&lrm->shot); alignset.arcMI.push_back(node.arcs[0].mutual); - alignset.arcImages.push_back(&md.rasterList[node.arcs[0].projId]->currentPlane->image); - alignset.arcShots.push_back(&md.rasterList[node.arcs[0].projId]->shot); + alignset.arcImages.push_back(&lrm->currentPlane->image); + alignset.arcShots.push_back(&lrm->shot); alignset.arcMI.push_back(node.arcs[0].mutual); } else if(alignset.arcImages.size()==2) { - alignset.arcImages.push_back(&md.rasterList[node.arcs[0].projId]->currentPlane->image); - alignset.arcShots.push_back(&md.rasterList[node.arcs[0].projId]->shot); + auto lit = md.rasterBegin(); std::advance(lit, node.arcs[0].projId); + RasterModel* lrm =*lit; + alignset.arcImages.push_back(&lrm->currentPlane->image); + alignset.arcShots.push_back(&lrm->shot); alignset.arcMI.push_back(node.arcs[0].mutual); } @@ -942,14 +961,14 @@ bool FilterMutualGlobal::AlignNode(MeshDocument &md, Node node) unsigned int *indices = new unsigned int[alignset.mesh->fn*3]; for(int i = 0; i < alignset.mesh->vn; i++) { - vertices[i] = alignset.mesh->vert[i].P(); - normals[i] = alignset.mesh->vert[i].N(); - colors[i] = alignset.mesh->vert[i].C(); + vertices[i] = alignset.mesh->vert[i].P(); + normals[i] = alignset.mesh->vert[i].N(); + colors[i] = alignset.mesh->vert[i].C(); } for(int i = 0; i < alignset.mesh->fn; i++) - for(int k = 0; k < 3; k++) - indices[k+i*3] = alignset.mesh->face[i].V(k) - &*alignset.mesh->vert.begin(); + for(int k = 0; k < 3; k++) + indices[k+i*3] = alignset.mesh->face[i].V(k) - &*alignset.mesh->vert.begin(); glBindBufferARB(GL_ARRAY_BUFFER_ARB, alignset.vbo); glBufferDataARB(GL_ARRAY_BUFFER_ARB, alignset.mesh->vn*sizeof(vcg::Point3f), @@ -989,14 +1008,14 @@ bool FilterMutualGlobal::AlignNode(MeshDocument &md, Node node) //md.rasterList[node.id]->shot=alignset.shot; - md.rasterList[node.id]->shot=alignset.shot; - float ratio=(float)md.rasterList[node.id]->currentPlane->image.height()/(float)alignset.shot.Intrinsics.ViewportPx[1]; - md.rasterList[node.id]->shot.Intrinsics.ViewportPx[0]=md.rasterList[node.id]->currentPlane->image.width(); - md.rasterList[node.id]->shot.Intrinsics.ViewportPx[1]=md.rasterList[node.id]->currentPlane->image.height(); - md.rasterList[node.id]->shot.Intrinsics.PixelSizeMm[1]/=ratio; - md.rasterList[node.id]->shot.Intrinsics.PixelSizeMm[0]/=ratio; - md.rasterList[node.id]->shot.Intrinsics.CenterPx[0]=(int)((float)md.rasterList[node.id]->shot.Intrinsics.ViewportPx[0]/2.0); - md.rasterList[node.id]->shot.Intrinsics.CenterPx[1]=(int)((float)md.rasterList[node.id]->shot.Intrinsics.ViewportPx[1]/2.0); + rm->shot=alignset.shot; + float ratio=(float)rm->currentPlane->image.height()/(float)alignset.shot.Intrinsics.ViewportPx[1]; + rm->shot.Intrinsics.ViewportPx[0]=rm->currentPlane->image.width(); + rm->shot.Intrinsics.ViewportPx[1]=rm->currentPlane->image.height(); + rm->shot.Intrinsics.PixelSizeMm[1]/=ratio; + rm->shot.Intrinsics.PixelSizeMm[0]/=ratio; + rm->shot.Intrinsics.CenterPx[0]=(int)((float)rm->shot.Intrinsics.ViewportPx[0]/2.0); + rm->shot.Intrinsics.CenterPx[1]=(int)((float)rm->shot.Intrinsics.ViewportPx[1]/2.0); //this->glContext->doneCurrent(); //emit md.rasterSetChanged(); for (int l=0; lfn*3]; for(int i = 0; i < alignset.mesh->vn; i++) { - vertices[i] = alignset.mesh->vert[i].P(); - normals[i] = alignset.mesh->vert[i].N(); - colors[i] = alignset.mesh->vert[i].C(); + vertices[i] = alignset.mesh->vert[i].P(); + normals[i] = alignset.mesh->vert[i].N(); + colors[i] = alignset.mesh->vert[i].C(); } for(int i = 0; i < alignset.mesh->fn; i++) - for(int k = 0; k < 3; k++) - indices[k+i*3] = alignset.mesh->face[i].V(k) - &*alignset.mesh->vert.begin(); + for(int k = 0; k < 3; k++) + indices[k+i*3] = alignset.mesh->face[i].V(k) - &*alignset.mesh->vert.begin(); glBindBufferARB(GL_ARRAY_BUFFER_ARB, alignset.vbo); glBufferDataARB(GL_ARRAY_BUFFER_ARB, alignset.mesh->vn*sizeof(vcg::Point3f), @@ -1066,11 +1085,12 @@ bool FilterMutualGlobal::UpdateGraph(MeshDocument &md, SubGraph graph, int n) ////////////////// int imageId=graph.nodes[h].arcs[l].imageId; int imageProj=graph.nodes[h].arcs[l].projId; - + auto it= md.rasterBegin(); std::advance(it, imageId); + RasterModel* rm = *it; //this->glContext->makeCurrent(); - alignset.image=&md.rasterList[imageId]->currentPlane->image; - alignset.shot=md.rasterList[imageId]->shot; + alignset.image=&rm->currentPlane->image; + alignset.shot=rm->shot; //this->initGL(); alignset.resize(800); @@ -1087,8 +1107,8 @@ bool FilterMutualGlobal::UpdateGraph(MeshDocument &md, SubGraph graph, int n) alignset.comb=alignset.rend;*/ alignset.mode=AlignSet::PROJIMG; - alignset.shotPro=md.rasterList[imageProj]->shot; - alignset.imagePro=&md.rasterList[imageProj]->currentPlane->image; + alignset.shotPro=rm->shot; + alignset.imagePro=&rm->currentPlane->image; alignset.ProjectedImageChanged(*alignset.imagePro); float countTot=0.0; float countCol=0.0; diff --git a/src/meshlabplugins/filter_mutualglobal/filter_mutualglobal.h b/src/meshlabplugins/filter_mutualglobal/filter_mutualglobal.h index 073eebf0e..40ac56b2d 100644 --- a/src/meshlabplugins/filter_mutualglobal/filter_mutualglobal.h +++ b/src/meshlabplugins/filter_mutualglobal/filter_mutualglobal.h @@ -54,7 +54,7 @@ public: QString filterName(ActionIDType filter) const; QString filterInfo(ActionIDType filter) const; - void initParameterList(const QAction*, MeshDocument & md, RichParameterList & /*parent*/); + RichParameterList initParameterList(const QAction*, const MeshDocument & md); std::map applyFilter( const QAction* action, const RichParameterList & parameters, diff --git a/src/meshlabplugins/filter_mutualinfo/filter_mutualinfo.cpp b/src/meshlabplugins/filter_mutualinfo/filter_mutualinfo.cpp index 0250d00e7..b954f7e0a 100644 --- a/src/meshlabplugins/filter_mutualinfo/filter_mutualinfo.cpp +++ b/src/meshlabplugins/filter_mutualinfo/filter_mutualinfo.cpp @@ -96,8 +96,9 @@ FilterPlugin::FilterArity FilterMutualInfoPlugin::filterArity(const QAction*) co return SINGLE_MESH; } -void FilterMutualInfoPlugin::initParameterList(const QAction *action,MeshDocument & /*md*/, RichParameterList & parlst) +RichParameterList FilterMutualInfoPlugin::initParameterList(const QAction *action, const MeshDocument & /*md*/) { + RichParameterList parlst; QStringList rendList; rendList.push_back("Combined"); rendList.push_back("Normal map"); @@ -119,6 +120,7 @@ void FilterMutualInfoPlugin::initParameterList(const QAction *action,MeshDocumen default : assert(0); } + return parlst; } std::map FilterMutualInfoPlugin::applyFilter( @@ -169,7 +171,7 @@ void FilterMutualInfoPlugin::imageMutualInfoAlign( throw MLException("Error: shot not valid. Press 'Get Shot' button before applying!"); } - if (md.rasterList.size()==0) { + if (md.rasterNumber()==0) { log(GLLogStream::FILTER, "You need a Raster Model to apply this filter!"); throw MLException("You need a Raster Model to apply this filter!"); } diff --git a/src/meshlabplugins/filter_mutualinfo/filter_mutualinfo.h b/src/meshlabplugins/filter_mutualinfo/filter_mutualinfo.h index 58b47581b..d76ffe372 100644 --- a/src/meshlabplugins/filter_mutualinfo/filter_mutualinfo.h +++ b/src/meshlabplugins/filter_mutualinfo/filter_mutualinfo.h @@ -48,7 +48,7 @@ public: FilterClass getClass(const QAction* a) const; bool requiresGLContext(const QAction* action) const; FilterArity filterArity(const QAction*) const; - void initParameterList(const QAction*, MeshDocument &, RichParameterList & /*parent*/); + RichParameterList initParameterList(const QAction*, const MeshDocument &); std::map applyFilter( const QAction* action, const RichParameterList & parameters, diff --git a/src/meshlabplugins/filter_plymc/filter_plymc.cpp b/src/meshlabplugins/filter_plymc/filter_plymc.cpp index fe9b9d1a0..22deb8d4a 100644 --- a/src/meshlabplugins/filter_plymc/filter_plymc.cpp +++ b/src/meshlabplugins/filter_plymc/filter_plymc.cpp @@ -101,8 +101,9 @@ PlyMCPlugin::FilterClass PlyMCPlugin::getClass(const QAction *a) const // - the string shown in the dialog // - the default value // - a possibly long string describing the meaning of that parameter (shown as a popup help in the dialog) -void PlyMCPlugin::initParameterList(const QAction *action,MeshModel &m, RichParameterList & parlst) +RichParameterList PlyMCPlugin::initParameterList(const QAction *action,const MeshModel &m) { + RichParameterList parlst; switch(ID(action)) { case FP_PLYMC : @@ -120,6 +121,7 @@ void PlyMCPlugin::initParameterList(const QAction *action,MeshModel &m, RichPara break; default: break; // do not add any parameter for the other filters } + return parlst; } // The Real Core Function doing the actual mesh processing. @@ -163,7 +165,7 @@ std::map PlyMCPlugin::applyFilter( p.FullyPreprocessedFlag=true; p.MergeColor=p.VertSplatFlag=par.getBool("mergeColor"); p.SimplificationFlag = par.getBool("simplification"); - foreach(MeshModel*mm, md.meshList) + for(MeshModel*mm: md.meshIterator()) { if(mm->visible) { @@ -212,7 +214,7 @@ std::map PlyMCPlugin::applyFilter( tri::io::ImporterPLY::Open(mp->cm,name.c_str(),loadMask); if(p.MergeColor) mp->updateDataMask(MeshModel::MM_VERTCOLOR); mp->updateDataMask(MeshModel::MM_VERTQUALITY); - mp->UpdateBoxAndNormals(); + mp->updateBoxAndNormals(); } } diff --git a/src/meshlabplugins/filter_plymc/filter_plymc.h b/src/meshlabplugins/filter_plymc/filter_plymc.h index 748dad027..aaaf8ec81 100644 --- a/src/meshlabplugins/filter_plymc/filter_plymc.h +++ b/src/meshlabplugins/filter_plymc/filter_plymc.h @@ -43,7 +43,7 @@ public: QString pluginName() const; virtual QString filterName(ActionIDType filter) const; virtual QString filterInfo(ActionIDType filter) const; - virtual void initParameterList(const QAction*, MeshModel &/*m*/, RichParameterList & /*parent*/); + virtual RichParameterList initParameterList(const QAction*, const MeshModel &/*m*/); std::map applyFilter( const QAction* action, const RichParameterList & parameters, diff --git a/src/meshlabplugins/filter_qhull/filter_qhull.cpp b/src/meshlabplugins/filter_qhull/filter_qhull.cpp index 1b3991f8a..a95046c26 100644 --- a/src/meshlabplugins/filter_qhull/filter_qhull.cpp +++ b/src/meshlabplugins/filter_qhull/filter_qhull.cpp @@ -135,8 +135,9 @@ QhullPlugin::FilterClass QhullPlugin::getClass(const QAction *a) const // - the string shown in the dialog // - the default value // - a possibly long string describing the meaning of that parameter (shown as a popup help in the dialog) -void QhullPlugin::initParameterList(const QAction *action,MeshModel &m, RichParameterList & parlst) +RichParameterList QhullPlugin::initParameterList(const QAction *action,const MeshModel &m) { + RichParameterList parlst; switch(ID(action)) { case FP_QHULL_CONVEX_HULL : { @@ -195,6 +196,7 @@ void QhullPlugin::initParameterList(const QAction *action,MeshModel &m, RichPara } default: break; // do not add any parameter for the other filters } + return parlst; } // The Real Core Function doing the actual mesh processing. @@ -214,7 +216,7 @@ std::map QhullPlugin::applyFilter( pm.updateDataMask(MeshModel::MM_FACEFACETOPO); bool result = vcg::tri::ConvexHull::ComputeConvexHull(m.cm, pm.cm); pm.clearDataMask(MeshModel::MM_FACEFACETOPO); - pm.UpdateBoxAndNormals(); + pm.updateBoxAndNormals(); if (!result) throw MLException("Failed computing convex hull."); } break; @@ -283,7 +285,7 @@ std::map QhullPlugin::applyFilter( //vcg::tri::UpdateBounding::Box(pm.cm); //vcg::tri::UpdateNormal::PerVertexNormalizedPerFace(pm.cm); - pm.UpdateBoxAndNormals(); + pm.updateBoxAndNormals(); int curlong, totlong; /* memory remaining after qh_memfreeshort */ qh_freeqhull(!qh_ALL); @@ -313,7 +315,7 @@ std::map QhullPlugin::applyFilter( if(result){ //vcg::tri::UpdateBounding::Box(pm.cm); //vcg::tri::UpdateNormal::PerVertexNormalizedPerFace(pm.cm); - pm.UpdateBoxAndNormals(); + pm.updateBoxAndNormals(); log("Successfully created a mesh of %i vert and %i faces",pm.cm.vn,pm.cm.fn); @@ -363,7 +365,7 @@ std::map QhullPlugin::applyFilter( if(result){ //vcg::tri::UpdateBounding::Box(pm.cm); //vcg::tri::UpdateNormal::PerVertexNormalizedPerFace(pm.cm); - pm.UpdateBoxAndNormals(); + pm.updateBoxAndNormals(); log("Successfully created a mesh of %i vert and %i faces",pm.cm.vn,pm.cm.fn); log("Alpha = %f ",alpha); //m.cm.Clear(); diff --git a/src/meshlabplugins/filter_qhull/filter_qhull.h b/src/meshlabplugins/filter_qhull/filter_qhull.h index cff105e09..5ed01bb3e 100644 --- a/src/meshlabplugins/filter_qhull/filter_qhull.h +++ b/src/meshlabplugins/filter_qhull/filter_qhull.h @@ -56,16 +56,16 @@ public: ~QhullPlugin(); QString pluginName() const; - virtual QString filterName(ActionIDType filter) const; - virtual QString filterInfo(ActionIDType filter) const; - virtual void initParameterList(const QAction*, MeshModel &/*m*/, RichParameterList & /*parent*/); + QString filterName(ActionIDType filter) const; + QString filterInfo(ActionIDType filter) const; + RichParameterList initParameterList(const QAction*, const MeshModel &/*m*/); std::map applyFilter( const QAction* action, const RichParameterList & parameters, MeshDocument &md, unsigned int& postConditionMask, vcg::CallBackPos * cb); - virtual FilterClass getClass(const QAction*) const; + FilterClass getClass(const QAction*) const; FilterArity filterArity(const QAction *) const {return SINGLE_MESH;} }; diff --git a/src/meshlabplugins/filter_quality/filterqualitymapper.cpp b/src/meshlabplugins/filter_quality/filterqualitymapper.cpp index 6f8f90d02..55104469c 100644 --- a/src/meshlabplugins/filter_quality/filterqualitymapper.cpp +++ b/src/meshlabplugins/filter_quality/filterqualitymapper.cpp @@ -63,7 +63,13 @@ QString QualityMapperFilter::filterName(ActionIDType filterId) const QString QualityMapperFilter::filterInfo(ActionIDType filterId) const { switch(filterId) { - case FP_QUALITY_MAPPER : return QString("The filter maps quality levels into colors using a colorband built from a transfer function (may be loaded from an external file) and colorizes the mesh vertices. The minimum, medium and maximum quality values can be set by user to obtain a custom quality range for mapping"); + case FP_QUALITY_MAPPER : + return QString( + "The filter maps quality levels into colors using a colorband " + "built from a transfer function (may be loaded from an external " + "file) and colorizes the mesh vertices. The minimum, medium and " + "maximum quality values can be set by user to obtain a custom " + "quality range for mapping"); default : assert(0); } return QString(""); @@ -73,8 +79,8 @@ FilterPlugin::FilterClass QualityMapperFilter::getClass(const QAction *a) const { switch(ID(a)) { - case FP_QUALITY_MAPPER : return FilterPlugin::Quality; - default : assert(0); return FilterPlugin::Generic; + case FP_QUALITY_MAPPER : return FilterPlugin::Quality; + default : assert(0); return FilterPlugin::Generic; } } @@ -86,9 +92,10 @@ FilterPlugin::FilterClass QualityMapperFilter::getClass(const QAction *a) const // - the string shown in the dialog // - the default value // - a possibly long string describing the meaning of that parameter (shown as a popup help in the dialog) -void QualityMapperFilter::initParameterList(const QAction *action,MeshModel &m, RichParameterList & parlst) +RichParameterList QualityMapperFilter::initParameterList(const QAction *action,const MeshModel &m) { - switch(ID(action)) { + RichParameterList parlst; + switch(ID(action)) { case FP_QUALITY_MAPPER : { _meshMinMaxQuality = tri::Stat::ComputePerVertexQualityMinMax(m.cm); @@ -121,6 +128,7 @@ void QualityMapperFilter::initParameterList(const QAction *action,MeshModel &m, break; default: break; // do not add any parameter for the other filters } + return parlst; } // The Real Core Function doing the actual mesh processing. diff --git a/src/meshlabplugins/filter_quality/filterqualitymapper.h b/src/meshlabplugins/filter_quality/filterqualitymapper.h index 6e07205fb..dd9bf97a3 100644 --- a/src/meshlabplugins/filter_quality/filterqualitymapper.h +++ b/src/meshlabplugins/filter_quality/filterqualitymapper.h @@ -70,18 +70,18 @@ public: QualityMapperFilter(); QString pluginName() const; - virtual QString filterName(ActionIDType filter) const; - virtual QString filterInfo(ActionIDType filter) const; + QString filterName(ActionIDType filter) const; + QString filterInfo(ActionIDType filter) const; int getPreConditions(const QAction *) const; int postCondition(const QAction* ) const; - virtual void initParameterList(const QAction*, MeshModel &/*m*/, RichParameterList & /*parent*/); + RichParameterList initParameterList(const QAction*, const MeshModel &/*m*/); std::map applyFilter( const QAction* action, const RichParameterList & parameters, MeshDocument &md, unsigned int& postConditionMask, vcg::CallBackPos * cb); - virtual FilterClass getClass(const QAction*) const; + FilterClass getClass(const QAction*) const; FilterArity filterArity(const QAction *) const {return SINGLE_MESH;} }; diff --git a/src/meshlabplugins/filter_sample/filter_sample.cpp b/src/meshlabplugins/filter_sample/filter_sample.cpp index 64c974a3e..52a1120c7 100644 --- a/src/meshlabplugins/filter_sample/filter_sample.cpp +++ b/src/meshlabplugins/filter_sample/filter_sample.cpp @@ -138,8 +138,9 @@ int FilterSamplePlugin::postCondition(const QAction*) const * @param m * @param parlst */ -void FilterSamplePlugin::initParameterList(const QAction *action,MeshModel &m, RichParameterList & parlst) +RichParameterList FilterSamplePlugin::initParameterList(const QAction *action,const MeshModel &m) { + RichParameterList parlst; switch(ID(action)) { case FP_MOVE_VERTEX : parlst.addParam(RichBool ("UpdateNormals", true, "Recompute normals", "Toggle the recomputation of the normals after the random displacement.\n\nIf disabled the face normals will remains unchanged resulting in a visually pleasant effect.")); @@ -148,6 +149,7 @@ void FilterSamplePlugin::initParameterList(const QAction *action,MeshModel &m, R default : assert(0); } + return parlst; } /** diff --git a/src/meshlabplugins/filter_sample/filter_sample.h b/src/meshlabplugins/filter_sample/filter_sample.h index 14c1e8337..4aaa6e6ea 100644 --- a/src/meshlabplugins/filter_sample/filter_sample.h +++ b/src/meshlabplugins/filter_sample/filter_sample.h @@ -61,7 +61,7 @@ public: FilterArity filterArity(const QAction*) const; int getPreConditions(const QAction *) const; int postCondition(const QAction* ) const; - void initParameterList(const QAction*, MeshModel &/*m*/, RichParameterList & /*parent*/); + RichParameterList initParameterList(const QAction*, const MeshModel &/*m*/); std::map applyFilter( const QAction* action, const RichParameterList & parameters, diff --git a/src/meshlabplugins/filter_sample_dyn/filter_sample_dyn.cpp b/src/meshlabplugins/filter_sample_dyn/filter_sample_dyn.cpp index 78073154f..ffa33eef8 100644 --- a/src/meshlabplugins/filter_sample_dyn/filter_sample_dyn.cpp +++ b/src/meshlabplugins/filter_sample_dyn/filter_sample_dyn.cpp @@ -96,8 +96,9 @@ FilterPlugin::FilterClass ExtraSampleDynPlugin::getClass(const QAction *) const // when the user press apply the current stored state is updated. // when the user press close the mesh state is restored to the one before the startup of the filter. -void ExtraSampleDynPlugin::initParameterList(const QAction *action,MeshModel &/*m*/, RichParameterList & parlst) +RichParameterList ExtraSampleDynPlugin::initParameterList(const QAction *action,const MeshModel &/*m*/) { + RichParameterList parlst; switch(ID(action)) { case FP_VERTEX_COLOR_NOISE : parlst.addParam(RichColor ("baseColor", @@ -118,6 +119,7 @@ void ExtraSampleDynPlugin::initParameterList(const QAction *action,MeshModel &/* default: break; // do not add any parameter for the other filters } + return parlst; } // The Real Core Function doing the actual mesh processing. diff --git a/src/meshlabplugins/filter_sample_dyn/filter_sample_dyn.h b/src/meshlabplugins/filter_sample_dyn/filter_sample_dyn.h index ae6d33787..6b4f280f0 100644 --- a/src/meshlabplugins/filter_sample_dyn/filter_sample_dyn.h +++ b/src/meshlabplugins/filter_sample_dyn/filter_sample_dyn.h @@ -41,12 +41,12 @@ class ExtraSampleDynPlugin : public QObject, public FilterPlugin virtual ~ExtraSampleDynPlugin(); QString pluginName() const; - virtual QString filterName(ActionIDType filter) const; - virtual QString filterInfo(ActionIDType filter) const; - virtual void initParameterList(const QAction*, MeshModel &/*m*/, RichParameterList & /*parent*/); - virtual int postCondition(const QAction* ) const {return MeshModel::MM_VERTCOLOR;}; + QString filterName(ActionIDType filter) const; + QString filterInfo(ActionIDType filter) const; + RichParameterList initParameterList(const QAction*, const MeshModel &/*m*/); + int postCondition(const QAction* ) const {return MeshModel::MM_VERTCOLOR;}; std::map applyFilter(const QAction* action, const RichParameterList & /*parent*/, MeshDocument &md, unsigned int& postConditionMask, vcg::CallBackPos * cb); - virtual FilterClass getClass(const QAction*) const; + FilterClass getClass(const QAction*) const; FilterArity filterArity(const QAction *) const {return SINGLE_MESH;} }; diff --git a/src/meshlabplugins/filter_sample_gpu/filter_sample_gpu.cpp b/src/meshlabplugins/filter_sample_gpu/filter_sample_gpu.cpp index ad430550d..c34f6eb71 100644 --- a/src/meshlabplugins/filter_sample_gpu/filter_sample_gpu.cpp +++ b/src/meshlabplugins/filter_sample_gpu/filter_sample_gpu.cpp @@ -107,10 +107,9 @@ ExtraSampleGPUPlugin::FilterClass ExtraSampleGPUPlugin::getClass(const QAction * // - the string shown in the dialog // - the default value // - a possibly long string describing the meaning of that parameter (shown as a popup help in the dialog) -void ExtraSampleGPUPlugin::initParameterList(const QAction * action, MeshModel & m, RichParameterList & parlst) +RichParameterList ExtraSampleGPUPlugin::initParameterList(const QAction * action, const MeshModel &) { - (void)m; - + RichParameterList parlst; switch(ID(action)) { case FP_GPU_EXAMPLE : @@ -124,6 +123,7 @@ void ExtraSampleGPUPlugin::initParameterList(const QAction * action, MeshModel & } default : assert(0); } + return parlst; } // The Real Core Function doing the actual mesh processing. diff --git a/src/meshlabplugins/filter_sample_gpu/filter_sample_gpu.h b/src/meshlabplugins/filter_sample_gpu/filter_sample_gpu.h index 2321f9877..8bf55534b 100644 --- a/src/meshlabplugins/filter_sample_gpu/filter_sample_gpu.h +++ b/src/meshlabplugins/filter_sample_gpu/filter_sample_gpu.h @@ -49,9 +49,9 @@ public: ExtraSampleGPUPlugin(); - QString pluginName() const; - FilterArity filterArity(const QAction *) const {return SINGLE_MESH;} - void initParameterList(const QAction* action, MeshModel &m, RichParameterList & parlst); + QString pluginName() const; + FilterArity filterArity(const QAction *) const {return SINGLE_MESH;} + RichParameterList initParameterList(const QAction* action, const MeshModel &m); QString filterName(ActionIDType filter) const; QString pythonFilterName(ActionIDType filterId) const; diff --git a/src/meshlabplugins/filter_sampling/filter_sampling.cpp b/src/meshlabplugins/filter_sampling/filter_sampling.cpp index a68b45786..098ed7f8d 100644 --- a/src/meshlabplugins/filter_sampling/filter_sampling.cpp +++ b/src/meshlabplugins/filter_sampling/filter_sampling.cpp @@ -409,7 +409,7 @@ QString FilterDocSampling::filterInfo(ActionIDType filterId) const case FP_MONTECARLO_SAMPLING : return QString("Create a new layer populated with a point sampling of the current mesh; samples are generated in a randomly uniform way, or with a distribution biased by the per-vertex quality values of the mesh."); case FP_STRATIFIED_SAMPLING : return QString("Create a new layer populated with a point sampling of the current mesh; to generate multiple samples inside a triangle each triangle is subdivided according to various stratified strategies. Distribution is often biased by triangle shape."); case FP_CLUSTERED_SAMPLING : return QString("Create a new layer populated with a subsampling of the vertices of the current mesh; the subsampling is driven by a simple one-per-gridded cell strategy."); - case FP_POINTCLOUD_SIMPLIFICATION : return QString("Create a new layer populated with a simplified version of the current point cloud."); + case FP_POINTCLOUD_SIMPLIFICATION : return QString("Create a new layer populated with a simplified version of the current point cloud. The simplification is performed by subsampling the original point cloud using a Poisson Disk strategy."); case FP_POISSONDISK_SAMPLING : return QString("Create a new layer populated with a point sampling of the current mesh;" "samples are generated according to a Poisson-disk distribution, using the algorithm described in:
" "'Efficient and Flexible Sampling with Blue Noise Properties of Triangular Meshes'
" @@ -462,8 +462,9 @@ int FilterDocSampling::getRequirements(const QAction *action) // - the string shown in the dialog // - the default value // - a possibly long string describing the meaning of that parameter (shown as a popup help in the dialog) -void FilterDocSampling::initParameterList(const QAction *action, MeshDocument & md, RichParameterList & parlst) +RichParameterList FilterDocSampling::initParameterList(const QAction *action, const MeshDocument & md) { + RichParameterList parlst; switch(ID(action)) { case FP_MONTECARLO_SAMPLING : parlst.addParam(RichInt ("SampleNum", md.mm()->cm.vn, @@ -541,7 +542,7 @@ void FilterDocSampling::initParameterList(const QAction *action, MeshDocument & parlst.addParam(RichBool("ApproximateGeodesicDistance", false, "Approximate Geodesic Distance", "If true Poisson Disc distances are computed using an approximate geodesic distance, e.g. an euclidean distance weighted by a function of the difference between the normals of the two points.")); parlst.addParam(RichBool("Subsample", false, "Base Mesh Subsampling", "If true the original vertices of the base mesh are used as base set of points. In this case the SampleNum should be obviously much smaller than the original vertex number.
Note that this option is very useful in the case you want to subsample a dense point cloud.")); parlst.addParam(RichBool("RefineFlag", false, "Refine Existing Samples", "If true the vertices of the below mesh are used as starting vertices, and they will utterly refined by adding more and more points until possible. ")); - parlst.addParam(RichMesh("RefineMesh", md.mm(),&md, "Samples to be refined", "Used only if the above option is checked. ")); + parlst.addParam(RichMesh("RefineMesh", md.mm()->id(),&md, "Samples to be refined", "Used only if the above option is checked. ")); parlst.addParam(RichBool("BestSampleFlag", true, "Best Sample Heuristic", "If true it will use a simple heuristic for choosing the samples. At a small cost (it can slow a bit the process) it usually improve the maximality of the generated sampling. ")); parlst.addParam(RichInt("BestSamplePool", 10, "Best Sample Pool Size", "Used only if the Best Sample Flag is true. It control the number of attempt that it makes to get the best sample. It is reasonable that it is smaller than the Montecarlo oversampling factor.")); parlst.addParam(RichBool("ExactNumFlag", false, "Exact number of samples", "If requested it will try to do a dicotomic search for the best poisson disk radius that will generate the requested number of samples with a tolerance of the 0.5%. Obviously it takes much longer.")); @@ -562,13 +563,17 @@ void FilterDocSampling::initParameterList(const QAction *action, MeshDocument & case FP_HAUSDORFF_DISTANCE: { - MeshModel *vertexMesh = md.mm(); - foreach(vertexMesh, md.meshList) - if (vertexMesh != md.mm()) break; + const MeshModel *vertexMesh = md.mm(); + for(const MeshModel * vm: md.meshIterator()){ + if (vm != md.mm()) { + vertexMesh = vm; + break; + } + } - parlst.addParam(RichMesh("SampledMesh", md.mm(), &md, "Sampled Mesh", + parlst.addParam(RichMesh("SampledMesh", md.mm()->id(), &md, "Sampled Mesh", "The mesh whose surface is sampled. For each sample we search the closest point on the Target Mesh.")); - parlst.addParam(RichMesh("TargetMesh", vertexMesh, &md, "Target Mesh", + parlst.addParam(RichMesh("TargetMesh", vertexMesh->id(), &md, "Target Mesh", "The mesh that is sampled for the comparison.")); parlst.addParam(RichBool("SaveSample", false, "Save Samples", "Save the position and distance of all the used samples on both the two surfaces, creating two new layers with two point clouds representing the used samples.")); @@ -584,17 +589,21 @@ void FilterDocSampling::initParameterList(const QAction *action, MeshDocument & "The desired number of samples. It can be smaller or larger than the mesh size, and according to the chosen sampling strategy it will try to adapt.")); parlst.addParam(RichAbsPerc("MaxDist", md.mm()->cm.bbox.Diag() / 2.0, 0.0f, md.bbox().Diag(), tr("Max Distance"), tr("Sample points for which we do not find anything within this distance are rejected and not considered neither for averaging nor for max."))); - } break; + } break; - case FP_DISTANCE_REFERENCE: - { - MeshModel *vertexMesh = md.mm(); - foreach(vertexMesh, md.meshList) - if (vertexMesh != md.mm()) break; + case FP_DISTANCE_REFERENCE: + { + const MeshModel *vertexMesh = md.mm(); + for(const MeshModel * vm: md.meshIterator()){ + if (vm != md.mm()) { + vertexMesh = vm; + break; + } + } - parlst.addParam(RichMesh("MeasureMesh", md.mm(), &md, "Measured Mesh/PointCloud", + parlst.addParam(RichMesh("MeasureMesh", md.mm()->id(), &md, "Measured Mesh/PointCloud", "The Mesh/Pointcloud that is measured, vertex by vertex, computing distance from the REFERENCE mesh/pointcloud.")); - parlst.addParam(RichMesh("RefMesh", vertexMesh, &md, "Reference Mesh/PointCloud", + parlst.addParam(RichMesh("RefMesh", vertexMesh->id(), &md, "Reference Mesh/PointCloud", "The Mesh/Pointcloud that is used as a reference, to measure distance from.")); parlst.addParam(RichBool("SignedDist", true, "Compute Signed Distance", @@ -604,15 +613,18 @@ void FilterDocSampling::initParameterList(const QAction *action, MeshDocument & tr("Max Distance [abs]"), tr("Search is interrupted when nothing is found within this distance range [+maxDistance -maxDistance]."))); } break; - case FP_VERTEX_RESAMPLING: - { - MeshModel *vertexMesh= md.mm(); - foreach (vertexMesh, md.meshList) - if (vertexMesh != md.mm()) break; + case FP_VERTEX_RESAMPLING: + { + const MeshModel *vertexMesh= md.mm(); + for (const MeshModel* vm: md.meshIterator()) + if (vm != md.mm()) { + vertexMesh = vm; + break; + } - parlst.addParam(RichMesh ("SourceMesh", md.mm(),&md, "Source Mesh", + parlst.addParam(RichMesh ("SourceMesh", md.mm()->id(),&md, "Source Mesh", "The mesh that contains the source data that we want to transfer.")); - parlst.addParam(RichMesh ("TargetMesh", vertexMesh,&md, "Target Mesh", + parlst.addParam(RichMesh ("TargetMesh", vertexMesh->id(),&md, "Target Mesh", "The mesh whose vertices will receive the data from the source.")); parlst.addParam(RichBool ("GeomTransfer", false, "Transfer Geometry", "if enabled, the position of each vertex of the target mesh will be snapped onto the corresponding closest point on the source mesh")); @@ -656,20 +668,27 @@ void FilterDocSampling::initParameterList(const QAction *action, MeshDocument & "In this case you have to choose a not zero Offset and a double surface is built around the original surface, inside and outside. " "Is useful to convrt thin floating surfaces into solid, thick meshes.. t")); } break; - case FP_VORONOI_COLORING : - case FP_DISK_COLORING : - { - MeshModel *colorMesh= md.mm(); - foreach (colorMesh, md.meshList) // Search a mesh with some faces.. - if (colorMesh->cm.fn>0) break; - MeshModel *vertexMesh; - foreach (vertexMesh, md.meshList) // Search another mesh - if (vertexMesh != colorMesh) break; + case FP_VORONOI_COLORING : + case FP_DISK_COLORING : + { + const MeshModel *colorMesh= md.mm(); + for (const MeshModel* colm: md.meshIterator()) // Search a mesh with some faces.. + if (colm->cm.fn>0){ + colorMesh = colm; + break; + } - parlst.addParam(RichMesh ("ColoredMesh", colorMesh,&md, "To be Colored Mesh", + const MeshModel *vertexMesh= md.mm(); + for (const MeshModel* vm : md.meshIterator()) // Search another mesh + if (vm != colorMesh) { + vertexMesh = vm; + break; + } + + parlst.addParam(RichMesh ("ColoredMesh", colorMesh->id(),&md, "To be Colored Mesh", "The mesh whose surface is colored. For each vertex of this mesh we decide the color according the below parameters.")); - parlst.addParam(RichMesh ("VertexMesh", vertexMesh,&md, "Vertex Mesh", + parlst.addParam(RichMesh ("VertexMesh", vertexMesh->id(),&md, "Vertex Mesh", "The mesh whose vertices are used as seed points for the color computation. These seeds point are projected onto the above mesh.")); if(ID(action) == FP_DISK_COLORING) { float Diag = md.mm()->cm.bbox.Diag(); @@ -696,6 +715,7 @@ void FilterDocSampling::initParameterList(const QAction *action, MeshDocument & } break; default: break; // do not add any parameter for the other filters } + return parlst; } std::map FilterDocSampling::applyFilter( @@ -751,7 +771,7 @@ std::map FilterDocSampling::applyFilter( if(RecoverColor && curMM->cm.textures.size()>0) { - mps.tex= new QImage(curMM->cm.textures[0].c_str()); + mps.tex= new QImage(curMM->getTexture(curMM->cm.textures[0])); if(mps.texSamplingWidth==0) mps.texSamplingWidth = mps.tex->width(); if(mps.texSamplingHeight==0) mps.texSamplingHeight = mps.tex->height(); } @@ -995,7 +1015,7 @@ std::map FilterDocSampling::applyFilter( if(par.getBool("RefineFlag")) { pp.preGenFlag=true; - pp.preGenMesh=&(par.getMesh("RefineMesh")->cm); + pp.preGenMesh=&(md.getMesh(par.getMeshId("RefineMesh"))->cm); } pp.geodesicDistanceFlag=par.getBool("ApproximateGeodesicDistance"); pp.bestSampleChoiceFlag=par.getBool("BestSampleFlag"); @@ -1014,8 +1034,8 @@ std::map FilterDocSampling::applyFilter( case FP_HAUSDORFF_DISTANCE : { - MeshModel* mm0 = par.getMesh("SampledMesh"); // surface where we choose the random samples - MeshModel* mm1 = par.getMesh("TargetMesh"); // surface that is sought for the closest point to each sample. + MeshModel* mm0 = md.getMesh(par.getMeshId("SampledMesh")); // surface where we choose the random samples + MeshModel* mm1 = md.getMesh(par.getMeshId("TargetMesh")); // surface that is sought for the closest point to each sample. bool saveSampleFlag=par.getBool("SaveSample"); bool sampleVert=par.getBool("SampleVert"); bool sampleEdge=par.getBool("SampleEdge"); @@ -1107,8 +1127,8 @@ std::map FilterDocSampling::applyFilter( case FP_DISTANCE_REFERENCE: { - MeshModel* mm0 = par.getMesh("MeasureMesh"); // this mesh gets measured. - MeshModel* mm1 = par.getMesh("RefMesh"); // this is the reference mesh + MeshModel* mm0 = md.getMesh(par.getMeshId("MeasureMesh")); // this mesh gets measured. + MeshModel* mm1 = md.getMesh(par.getMeshId("RefMesh")); // this is the reference mesh bool useSigned = par.getBool("SignedDist"); Scalarm maxDistABS = par.getAbsPerc("MaxDist"); @@ -1151,8 +1171,8 @@ std::map FilterDocSampling::applyFilter( case FP_VERTEX_RESAMPLING : { - MeshModel* srcMesh = par.getMesh("SourceMesh"); // mesh whose attribute are read - MeshModel* trgMesh = par.getMesh("TargetMesh"); // this whose surface is sought for the closest point to each sample. + MeshModel* srcMesh = md.getMesh(par.getMeshId("SourceMesh")); // mesh whose attribute are read + MeshModel* trgMesh = md.getMesh(par.getMeshId("TargetMesh")); // this whose surface is sought for the closest point to each sample. Scalarm upperbound = par.getAbsPerc("UpperBound"); // maximum distance to stop search bool onlySelected = par.getBool("onSelected"); bool colorT = par.getBool("ColorTransfer"); @@ -1261,8 +1281,8 @@ std::map FilterDocSampling::applyFilter( case FP_VORONOI_COLORING : { - MeshModel* mmM = par.getMesh("ColoredMesh"); // surface where we choose the random samples - MeshModel* mmV = par.getMesh("VertexMesh"); // surface that is sought for the closest point to each sample. + MeshModel* mmM = md.getMesh(par.getMeshId("ColoredMesh")); // surface where we choose the random samples + MeshModel* mmV = md.getMesh(par.getMeshId("VertexMesh")); // surface that is sought for the closest point to each sample. bool backwardFlag = par.getBool("backward"); tri::Clean::RemoveUnreferencedVertex(mmM->cm); @@ -1286,8 +1306,8 @@ std::map FilterDocSampling::applyFilter( case FP_DISK_COLORING : { - MeshModel* mmM = par.getMesh("ColoredMesh"); - MeshModel* mmV = par.getMesh("VertexMesh"); + MeshModel* mmM = md.getMesh(par.getMeshId("ColoredMesh")); + MeshModel* mmV = md.getMesh(par.getMeshId("VertexMesh")); typedef vcg::SpatialHashTable SampleSHT; SampleSHT sht; tri::EmptyTMark markerFunctor; diff --git a/src/meshlabplugins/filter_sampling/filter_sampling.h b/src/meshlabplugins/filter_sampling/filter_sampling.h index 73e2793f5..4cd61aeb4 100644 --- a/src/meshlabplugins/filter_sampling/filter_sampling.h +++ b/src/meshlabplugins/filter_sampling/filter_sampling.h @@ -54,7 +54,7 @@ public: QString pluginName() const; QString filterName(ActionIDType filter) const; QString filterInfo(ActionIDType filter) const; - void initParameterList(const QAction*, MeshDocument &/*m*/, RichParameterList & /*parent*/); + RichParameterList initParameterList(const QAction*, const MeshDocument &/*m*/); std::map applyFilter( const QAction* action, const RichParameterList & parameters, diff --git a/src/meshlabplugins/filter_screened_poisson/filter_screened_poisson.cpp b/src/meshlabplugins/filter_screened_poisson/filter_screened_poisson.cpp index bcc8bcfbf..87f758968 100644 --- a/src/meshlabplugins/filter_screened_poisson/filter_screened_poisson.cpp +++ b/src/meshlabplugins/filter_screened_poisson/filter_screened_poisson.cpp @@ -183,7 +183,7 @@ std::map FilterScreenedPoissonPlugin::applyFilter( MeshModelPointStream meshStream(md.mm()->cm); _Execute >(&meshStream,md.mm()->cm.bbox,pm->cm,pp,cb); } - pm->UpdateBoxAndNormals(); + pm->updateBoxAndNormals(); md.setVisible(pm->id(),true); md.setCurrentMesh(pm->id()); if(currDirChanged) @@ -195,11 +195,11 @@ std::map FilterScreenedPoissonPlugin::applyFilter( return std::map(); } -void FilterScreenedPoissonPlugin::initParameterList( +RichParameterList FilterScreenedPoissonPlugin::initParameterList( const QAction* filter, - MeshModel&, - RichParameterList& parlist) + const MeshModel&) { + RichParameterList parlist; if (ID(filter) == FP_SCREENED_POISSON) { parlist.addParam(RichBool("visibleLayer", false, "Merge all visible layers", "Enabling this flag means that all the visible layers will be used for providing the points.")); parlist.addParam(RichInt("depth", 8, "Reconstruction Depth", "This integer is the maximum depth of the tree that will be used for surface reconstruction. Running at depth d corresponds to solving on a voxel grid whose resolution is no larger than 2^d x 2^d x 2^d. Note that since the reconstructor adapts the octree to the sampling density, the specified reconstruction depth is only an upper bound. The default value for this parameter is 8.")); @@ -212,6 +212,7 @@ void FilterScreenedPoissonPlugin::initParameterList( parlist.addParam(RichBool("confidence", false, "Confidence Flag", "Enabling this flag tells the reconstructor to use the quality as confidence information; this is done by scaling the unit normals with the quality values. When the flag is not enabled, all normals are normalized to have unit-length prior to reconstruction.")); parlist.addParam(RichBool("preClean", false, "Pre-Clean", "Enabling this flag force a cleaning pre-pass on the data removing all unreferenced vertices or vertices with null normals.")); } + return parlist; } int FilterScreenedPoissonPlugin::postCondition(const QAction* filter) const diff --git a/src/meshlabplugins/filter_screened_poisson/filter_screened_poisson.h b/src/meshlabplugins/filter_screened_poisson/filter_screened_poisson.h index 42d670a5b..1837dc759 100644 --- a/src/meshlabplugins/filter_screened_poisson/filter_screened_poisson.h +++ b/src/meshlabplugins/filter_screened_poisson/filter_screened_poisson.h @@ -54,7 +54,7 @@ public: unsigned int& postConditionMask, vcg::CallBackPos * cb); - void initParameterList(const QAction* a, MeshModel&, RichParameterList& parlist); + RichParameterList initParameterList(const QAction* a, const MeshModel&); int postCondition(const QAction* filter) const; FilterArity filterArity(const QAction*) const; }; diff --git a/src/meshlabplugins/filter_sdfgpu/filter_sdfgpu.cpp b/src/meshlabplugins/filter_sdfgpu/filter_sdfgpu.cpp index 99a57e9c9..3eff92c86 100644 --- a/src/meshlabplugins/filter_sdfgpu/filter_sdfgpu.cpp +++ b/src/meshlabplugins/filter_sdfgpu/filter_sdfgpu.cpp @@ -39,8 +39,9 @@ QString SdfGpuPlugin::pluginName() const return "FilterSDFGPU"; } -void SdfGpuPlugin::initParameterList(const QAction *action, MeshModel &/*m*/, RichParameterList &par) +RichParameterList SdfGpuPlugin::initParameterList(const QAction *action, const MeshModel &/*m*/) { + RichParameterList par; QStringList onPrimitive; onPrimitive.push_back("On vertices"); onPrimitive.push_back("On Faces"); par.addParam( RichEnum("onPrimitive", 0, onPrimitive, "Metric:", "Choose whether to trace rays from faces or from vertices. " )); @@ -92,6 +93,7 @@ void SdfGpuPlugin::initParameterList(const QAction *action, MeshModel &/*m*/, Ri "For each ray that we trace, we take multiple depth values near the point of intersection and we output only the median of these values. " "Some mesh can benefit from this additional calculation. ")); } + return par; } QString SdfGpuPlugin::filterName(ActionIDType filterId) const diff --git a/src/meshlabplugins/filter_sdfgpu/filter_sdfgpu.h b/src/meshlabplugins/filter_sdfgpu/filter_sdfgpu.h index d64fe0aa7..5e2c06904 100644 --- a/src/meshlabplugins/filter_sdfgpu/filter_sdfgpu.h +++ b/src/meshlabplugins/filter_sdfgpu/filter_sdfgpu.h @@ -47,7 +47,7 @@ class SdfGpuPlugin : public QObject, public FilterPlugin vcg::CallBackPos * cb); //Parameters init for user interface - virtual void initParameterList(const QAction* action, MeshModel &m, RichParameterList &parlst); + RichParameterList initParameterList(const QAction* action, const MeshModel &m); //Draw the mesh void fillFrameBuffer(bool front, MeshModel* mm); diff --git a/src/meshlabplugins/filter_select/meshselect.cpp b/src/meshlabplugins/filter_select/meshselect.cpp index 62dce0ccf..5ccbfb28e 100644 --- a/src/meshlabplugins/filter_select/meshselect.cpp +++ b/src/meshlabplugins/filter_select/meshselect.cpp @@ -192,10 +192,11 @@ QString SelectionFilterPlugin::filterInfo(ActionIDType filterId) const return QString("Unknown filter"); } -void SelectionFilterPlugin::initParameterList(const QAction *action, MeshModel &m, RichParameterList &parlst) +RichParameterList SelectionFilterPlugin::initParameterList(const QAction *action, const MeshModel &m) { - switch(ID(action)) - { + RichParameterList parlst; + switch(ID(action)) + { case FP_SELECT_FACES_BY_EDGE: { float maxVal = m.cm.bbox.Diag()/2.0f; @@ -302,6 +303,7 @@ void SelectionFilterPlugin::initParameterList(const QAction *action, MeshModel & parlst.addParam(RichBool("allLayers", false, "Apply to all visible Layers", "If selected, the filter will be applied to all visible mesh Layers.")); } break; } + return parlst; } std::map SelectionFilterPlugin::applyFilter( @@ -332,7 +334,7 @@ std::map SelectionFilterPlugin::applyFilter( tri::Allocator::DeleteVertex(m.cm, *vi); m.clearDataMask(MeshModel::MM_FACEFACETOPO); m.clearDataMask(MeshModel::MM_VERTFACETOPO); - m.UpdateBoxAndNormals(); + m.updateBoxAndNormals(); log("Deleted %i vertices, %i faces.", vvn - m.cm.vn, ffn - m.cm.fn); } break; @@ -349,7 +351,7 @@ std::map SelectionFilterPlugin::applyFilter( tri::Allocator::DeleteFace(ml->cm, *fi); ml->clearDataMask(MeshModel::MM_FACEFACETOPO); ml->clearDataMask(MeshModel::MM_VERTFACETOPO); - ml->UpdateBoxAndNormals(); + ml->updateBoxAndNormals(); log("Layer %i: deleted all %i faces.", ml->id(), ffn - ml->cm.fn); } } @@ -361,7 +363,7 @@ std::map SelectionFilterPlugin::applyFilter( tri::Allocator::DeleteFace(m.cm, *fi); m.clearDataMask(MeshModel::MM_FACEFACETOPO); m.clearDataMask(MeshModel::MM_VERTFACETOPO); - m.UpdateBoxAndNormals(); + m.updateBoxAndNormals(); log("Deleted all %i faces.", ffn - m.cm.fn); } } break; @@ -375,7 +377,7 @@ std::map SelectionFilterPlugin::applyFilter( tri::Allocator::DeleteFace(m.cm, *fi); m.clearDataMask(MeshModel::MM_FACEFACETOPO); m.clearDataMask(MeshModel::MM_VERTFACETOPO); - m.UpdateBoxAndNormals(); + m.updateBoxAndNormals(); log("Deleted %i faces.", ffn - m.cm.fn); } break; @@ -394,7 +396,7 @@ std::map SelectionFilterPlugin::applyFilter( tri::Allocator::DeleteVertex(m.cm, *vi); m.clearDataMask(MeshModel::MM_FACEFACETOPO); m.clearDataMask(MeshModel::MM_VERTFACETOPO); - m.UpdateBoxAndNormals(); + m.updateBoxAndNormals(); log("Deleted %i faces, %i vertices.", ffn - m.cm.fn, vvn - m.cm.vn); } break; diff --git a/src/meshlabplugins/filter_select/meshselect.h b/src/meshlabplugins/filter_select/meshselect.h index 301f310e4..5b9611cd3 100644 --- a/src/meshlabplugins/filter_select/meshselect.h +++ b/src/meshlabplugins/filter_select/meshselect.h @@ -70,11 +70,11 @@ public: SelectionFilterPlugin(); //~SelectionFilterPlugin(); QString pluginName() const; - virtual QString filterInfo(ActionIDType filter) const; - virtual QString filterName(ActionIDType filter) const; + QString filterInfo(ActionIDType filter) const; + QString filterName(ActionIDType filter) const; - virtual FilterClass getClass(const QAction*) const; - void initParameterList(const QAction* action, MeshModel &m, RichParameterList &parlst); + FilterClass getClass(const QAction*) const; + RichParameterList initParameterList(const QAction* action, const MeshModel &m); int getPreConditions(const QAction*) const; int postCondition(const QAction* ) const; int getRequirements(const QAction*); diff --git a/src/meshlabplugins/filter_sketchfab/filter_sketchfab.cpp b/src/meshlabplugins/filter_sketchfab/filter_sketchfab.cpp index 00f05ac4c..0f8c424ca 100644 --- a/src/meshlabplugins/filter_sketchfab/filter_sketchfab.cpp +++ b/src/meshlabplugins/filter_sketchfab/filter_sketchfab.cpp @@ -98,8 +98,9 @@ int FilterSketchFabPlugin::postCondition(const QAction*) const return MeshModel::MM_NONE; } -void FilterSketchFabPlugin::initParameterList(const QAction* action, MeshModel&, RichParameterList& parlst) +RichParameterList FilterSketchFabPlugin::initParameterList(const QAction* action, const MeshModel&) { + RichParameterList parlst; QSettings settings; QVariant v = settings.value("SketchFab Code"); QString sketchFabAPIValue; @@ -123,6 +124,7 @@ void FilterSketchFabPlugin::initParameterList(const QAction* action, MeshModel&, default : assert(0); } + return parlst; } std::map FilterSketchFabPlugin::applyFilter( diff --git a/src/meshlabplugins/filter_sketchfab/filter_sketchfab.h b/src/meshlabplugins/filter_sketchfab/filter_sketchfab.h index c249d933a..25facde33 100644 --- a/src/meshlabplugins/filter_sketchfab/filter_sketchfab.h +++ b/src/meshlabplugins/filter_sketchfab/filter_sketchfab.h @@ -46,7 +46,7 @@ public: FilterArity filterArity(const QAction* a) const; int getPreConditions(const QAction*) const; int postCondition(const QAction* ) const; - void initParameterList(const QAction*, MeshModel &/*m*/, RichParameterList & /*parent*/); + RichParameterList initParameterList(const QAction*, const MeshModel &/*m*/); std::map applyFilter( const QAction* action, const RichParameterList & parameters, diff --git a/src/meshlabplugins/filter_ssynth/filter_ssynth.cpp b/src/meshlabplugins/filter_ssynth/filter_ssynth.cpp index 8f13fbf52..b78eceaab 100644 --- a/src/meshlabplugins/filter_ssynth/filter_ssynth.cpp +++ b/src/meshlabplugins/filter_ssynth/filter_ssynth.cpp @@ -57,23 +57,24 @@ QString FilterSSynth::filterInfo(ActionIDType filterId) const } } -void FilterSSynth::initParameterList(const QAction* /*filter*/,MeshDocument &/*md*/, RichParameterList &par) +RichParameterList FilterSSynth::initParameterList(const QAction* /*filter*/,const MeshDocument &/*md*/) { + RichParameterList par; par.addParam(RichString("grammar","set maxdepth 40 R1 R2 rule R1 { { x 1 rz 6 ry 6 s 0.99 } R1 { s 2 } sphere } rule R2 {{ x -1 rz 6 ry 6 s 0.99 } R2 { s 2 } sphere} ","Eisen Script grammar","Write a grammar according to Eisen Script specification and using the primitives box, sphere, mesh, dot and triangle ")); par.addParam(RichInt("seed",1,"seed for random construction","Seed needed to build the mesh")); par.addParam(RichInt("sphereres",1,"set maximum resolution of sphere primitives, it must be included between 1 and 4","increasing the resolution of the spheres will improve the quality of the mesh ")); - return; + return par; } void FilterSSynth::openX3D(const QString &fileName, MeshModel &m, int& mask, vcg::CallBackPos *cb, QWidget* /*parent*/) { vcg::tri::io::AdditionalInfoX3D* info = NULL; /*int result = */vcg::tri::io::ImporterX3D::LoadMask(fileName.toStdString().c_str(), info); - m.Enable(info->mask); + m.enable(info->mask); /*result = */vcg::tri::io::ImporterX3D::Open(m.cm, fileName.toStdString().c_str(), info, cb); /*vcg::tri::UpdateBounding::Box(m.cm); vcg::tri::UpdateNormal::PerVertexNormalizedPerFaceNormalized(m.cm);*/ - m.UpdateBoxAndNormals(); + m.updateBoxAndNormals(); mask=info->mask; delete(info); } @@ -224,11 +225,14 @@ void FilterSSynth::save(const QString &formatName, const QString &/*fileName*/, void FilterSSynth::exportMaskCapability(const QString &/*format*/, int &/*capability*/, int &/*defaultBits*/) const {} -void FilterSSynth::initPreOpenParameter(const QString &/*formatName*/, RichParameterList &parlst){ +RichParameterList FilterSSynth::initPreOpenParameter(const QString &/*formatName*/) const +{ + RichParameterList parlst; parlst.addParam(RichInt(tr("seed"),1,tr("Seed for random mesh generation"),tr("write a seed for the random generation of the mesh"))); parlst.addParam(RichInt("maxrec",0,"set the maximum recursion","the mesh is built recursively according to the productions of the grammar, so a limit is needed. If set to 0 meshlab will generate the mesh according to the maximum recursion set in the file")); parlst.addParam(RichInt("sphereres",1,"set maximum resolution of sphere primitives, it must be included between 1 and 4","increasing the resolution of the spheres will improve the quality of the mesh ")); parlst.addParam(RichInt("maxobj",0,"set the maximum number of object to be rendered","you can set a limit to the maximum number of primitives rendered. If set to 0 meshlab will generate the mesh according to the input file")); + return parlst; } QString FilterSSynth::GetTemplate(int sphereres){ diff --git a/src/meshlabplugins/filter_ssynth/filter_ssynth.h b/src/meshlabplugins/filter_ssynth/filter_ssynth.h index 74ad4f6a9..e5a18e0df 100644 --- a/src/meshlabplugins/filter_ssynth/filter_ssynth.h +++ b/src/meshlabplugins/filter_ssynth/filter_ssynth.h @@ -40,26 +40,25 @@ class FilterSSynth : public QObject, public IOPlugin, public FilterPlugin{ FilterSSynth(); ~FilterSSynth(){} QString pluginName() const; - virtual QString filterName(ActionIDType filter) const; - virtual QString filterInfo(ActionIDType filter) const; - virtual int getRequirements(const QAction*); - virtual void initParameterList(const QAction* /*filter*/,MeshModel &,RichParameterList &){}; - virtual void initParameterList(const QAction*, MeshDocument &/*m*/, RichParameterList & /*parent*/); + QString filterName(ActionIDType filter) const; + QString filterInfo(ActionIDType filter) const; + int getRequirements(const QAction*); + RichParameterList initParameterList(const QAction*, const MeshDocument &/*m*/); std::map applyFilter( const QAction* action, const RichParameterList & parameters, MeshDocument &md, unsigned int& postConditionMask, vcg::CallBackPos * cb); - virtual FilterClass getClass(const QAction* filter) const; + FilterClass getClass(const QAction* filter) const; void setAttributes(CMeshO::VertexIterator &vi, CMeshO &m); static void openX3D(const QString &fileName, MeshModel &m, int& mask, vcg::CallBackPos *cb, QWidget *parent=0); - virtual int postCondition(const QAction* filter) const; + int postCondition(const QAction* filter) const; std::list importFormats() const; std::list exportFormats() const; - virtual void exportMaskCapability(const QString &format, int &capability, int &defaultBits) const; - void initPreOpenParameter(const QString &formatName, RichParameterList &parlst); + void exportMaskCapability(const QString &format, int &capability, int &defaultBits) const; + RichParameterList initPreOpenParameter(const QString&formatName) const; void open(const QString &formatName, const QString &fileName, MeshModel &m, int& mask, const RichParameterList & par, vcg::CallBackPos *cb); void save(const QString &formatName, const QString &fileName, MeshModel &m, const int mask, const RichParameterList &, vcg::CallBackPos *cb); FilterPlugin::FilterArity filterArity(const QAction *) const {return NONE;} diff --git a/src/meshlabplugins/filter_texture/filter_texture.cpp b/src/meshlabplugins/filter_texture/filter_texture.cpp index 3613e3adc..3e246676a 100644 --- a/src/meshlabplugins/filter_texture/filter_texture.cpp +++ b/src/meshlabplugins/filter_texture/filter_texture.cpp @@ -32,10 +32,15 @@ #include #include #include +#include #include using namespace vcg; +// ERROR CHECKING UTILITY +#define CheckError(x,y); if ((x)) {throw MLException((y));} +/////////////////////////////////////////////////////// + FilterTexturePlugin::FilterTexturePlugin() { typeList = { @@ -90,7 +95,7 @@ QString FilterTexturePlugin::filterInfo(ActionIDType filterId) const case FP_UV_VERTEX_TO_WEDGE : return QString("Converts per Vertex Texture Coordinates to per Wedge Texture Coordinates. It does not merge superfluous vertices..."); case FP_BASIC_TRIANGLE_MAPPING : return QString("Builds a trivial triangle-by-triangle parametrization.
Two methods are provided, the first maps all triangles into equal sized triangles, while the second one adapt the size of the triangles in texture space to their original size."); case FP_PLANAR_MAPPING : return QString("Builds a trivial flat-plane parametrization."); - case FP_SET_TEXTURE : return QString("Set a texture associated with current mesh parametrization.
" "If the texture provided exists, then it will be simply associated to the current mesh; else a dummy texture will be created and saved in the same directory of the mesh if exists, or in the default system picture directory."); + case FP_SET_TEXTURE : return QString("Set a texture associated with current mesh parametrization.
" "If the texture provided exists, then it will be simply associated to the current mesh; else the filter will fail with no further actions."); case FP_COLOR_TO_TEXTURE : return QString("Fills the specified texture using per-vertex color data of the mesh."); case FP_TRANSFER_TO_TEXTURE : return QString("Transfer texture color, vertex color or normal from one mesh the texture of another mesh. This may be useful to restore detail lost in simplification, or resample a texture in a different parametrization."); case FP_TEX_TO_VCOLOR_TRANSFER : return QString("Generates Vertex Color values picking color from a texture (same mesh or another mesh)."); @@ -174,12 +179,14 @@ FilterTexturePlugin::FilterClass FilterTexturePlugin::getClass(const QAction *a) return FilterPlugin::Generic; } -static QString extractFilenameTexture(MeshModel* mm) +static QString extractFilenameTexture(const MeshModel* mm) { + if (mm->fullName().isEmpty()){ + return "texture.png"; + } QFileInfo fi(mm->fullName()); QString fileName = fi.baseName().append("_tex.png"); - fileName = fileName.append(".png"); - fileName = fi.absolutePath() + "/" + fileName; + //fileName = fi.absolutePath() + "/" + fileName; return fileName; } @@ -190,9 +197,18 @@ static QString extractFilenameTexture(MeshModel* mm) // - the string shown in the dialog // - the default value // - a possibly long string describing the meaning of that parameter (shown as a popup help in the dialog) -void FilterTexturePlugin::initParameterList(const QAction *action, MeshDocument &md, RichParameterList & parlst) +RichParameterList FilterTexturePlugin::initParameterList(const QAction *action, const MeshDocument &md) { + RichParameterList parlst; + const MeshModel* trg = md.mm(); + for (const MeshModel* tmp : md.meshIterator()){ + if (tmp != trg && tmp != nullptr){ + trg = tmp; + break; + } + } QString fileName = extractFilenameTexture(md.mm()); + QString trgFileName = extractFilenameTexture(trg); switch(ID(action)) { case FP_VORONOI_ATLAS : parlst.addParam(RichInt("regionNum", 10, "Approx. Region Num", "An estimation of the number of regions that must be generated. Smaller regions could lead to parametrizations with smaller distortion.")); @@ -211,41 +227,37 @@ void FilterTexturePlugin::initParameterList(const QAction *action, MeshDocument parlst.addParam(RichInt("border", 2, "Inter-Triangle border (px)", "Specifies how many pixels to be left between triangles in parametrization domain")); parlst.addParam(RichEnum("method", 1, QStringList("Basic") << "Space-optimizing", "Method", "Choose space optimizing to map smaller faces into smaller triangles in parametrizazion domain")); break; - case FP_SET_TEXTURE : { + case FP_SET_TEXTURE : parlst.addParam(RichOpenFile("textName", fileName, QStringList{"*.png", "*.jpg", "*.jpeg", "*.dds"},"Texture file", "If the file exists it will be associated to the mesh else a dummy one will be created")); - parlst.addParam(RichInt("textDim", 1024, "Texture Dimension (px)", "If the named texture doesn't exists the dummy one will be squared with this size")); - } break; case FP_COLOR_TO_TEXTURE : { parlst.addParam(RichString("textName", fileName, "Texture file", "The texture file to be created")); parlst.addParam(RichInt("textW", 1024, "Texture width (px)", "The texture width")); parlst.addParam(RichInt("textH", 1024, "Texture height (px)", "The texture height")); parlst.addParam(RichBool("overwrite", false, "Overwrite texture", "if current mesh has a texture will be overwritten (with provided texture dimension)")); - parlst.addParam(RichBool("assign", false, "Assign texture", "assign the newly created texture")); parlst.addParam(RichBool("pullpush", true, "Fill texture", "if enabled the unmapped texture space is colored using a pull push filling algorithm, if false is set to black")); } break; case FP_TRANSFER_TO_TEXTURE : { - parlst.addParam(RichMesh ("sourceMesh",md.mm(),&md, "Source Mesh", + parlst.addParam(RichMesh ("sourceMesh",md.mm()->id(),&md, "Source Mesh", "The mesh that contains the source data that we want to transfer")); - parlst.addParam(RichMesh ("targetMesh",md.mm(),&md, "Target Mesh", + parlst.addParam(RichMesh ("targetMesh",trg->id(),&md, "Target Mesh", "The mesh whose texture will be filled according to source mesh data")); parlst.addParam(RichEnum("AttributeEnum", 0, QStringList("Vertex Color") << "Vertex Normal" << "Vertex Quality"<< "Texture Color", "Color Data Source", "Choose what attribute has to be transferred onto the target texture. You can choose bettween Per vertex attributes (color,normal,quality) or to transfer color information from source mesh texture")); parlst.addParam(RichAbsPerc("upperBound", md.mm()->cm.bbox.Diag()/50.0, 0.0f, md.mm()->cm.bbox.Diag(), tr("Max Dist Search"), tr("Sample points for which we do not find anything within this distance are rejected and not considered for recovering data"))); - parlst.addParam(RichString("textName", fileName, "Texture file", "The texture file to be created")); + parlst.addParam(RichString("textName", trgFileName, "Texture file", "The texture file to be created")); parlst.addParam(RichInt("textW", 1024, "Texture width (px)", "The texture width")); parlst.addParam(RichInt("textH", 1024, "Texture height (px)", "The texture height")); parlst.addParam(RichBool("overwrite", false, "Overwrite Target Mesh Texture", "if target mesh has a texture will be overwritten (with provided texture dimension)")); - parlst.addParam(RichBool("assign", false, "Assign Texture", "assign the newly created texture to target mesh")); parlst.addParam(RichBool("pullpush", true, "Fill texture", "if enabled the unmapped texture space is colored using a pull push filling algorithm, if false is set to black")); } break; case FP_TEX_TO_VCOLOR_TRANSFER : { - parlst.addParam(RichMesh ("sourceMesh",md.mm(),&md, "Source Mesh", + parlst.addParam(RichMesh ("sourceMesh",md.mm()->id(),&md, "Source Mesh", "The mesh with associated texture that we want to sample from")); - parlst.addParam(RichMesh ("targetMesh",md.mm(),&md, "Target Mesh", + parlst.addParam(RichMesh ("targetMesh",trg->id(),&md, "Target Mesh", "The mesh whose vertex color will be filled according to source mesh texture")); parlst.addParam(RichAbsPerc("upperBound", md.mm()->cm.bbox.Diag()/50.0, 0.0f, md.mm()->cm.bbox.Diag(), tr("Max Dist Search"), tr("Sample points for which we do not find anything within this distance are rejected and not considered for recovering color"))); @@ -253,6 +265,7 @@ void FilterTexturePlugin::initParameterList(const QAction *action, MeshDocument break; default: break; // do not add any parameter for the other filters } + return parlst; } @@ -330,10 +343,6 @@ inline void buildTrianglesCache(std::vector &arr, int maxLevels, float bor buildTrianglesCache (arr, maxLevels, border, quadSize, 2*idx+2); buildTrianglesCache (arr, maxLevels, border, quadSize, 2*idx+3); } - -// ERROR CHECKING UTILITY -#define CheckError(x,y); if ((x)) {throw MLException((y));} -/////////////////////////////////////////////////////// template T log_2(const T num) @@ -380,7 +389,7 @@ std::map FilterTexturePlugin::applyFilter( if(pp.overlap==false) tri::Clean::RemoveDuplicateVertex(paraModel->cm); - paraModel->UpdateBoxAndNormals(); + paraModel->updateBoxAndNormals(); baseModel->clearDataMask(bitToBeCleared); log("Voronoi Atlas: Completed Processing in %i iterations",pp.vas.iterNum); log("Asked %i generated %i regions",pp.sampleNum,pp.vas.regionNum); @@ -647,58 +656,16 @@ std::map FilterTexturePlugin::applyFilter( break; case FP_SET_TEXTURE : { - - const int CHECKERDIM=64; - // Get parameters QString textName = par.getOpenFileName("textName"); - int textDim = par.getInt("textDim"); - CheckError(textDim <= 0, "Texture Dimension has an incorrect value"); CheckError(textName.length() == 0, "Texture file not specified"); - QFile textFile(textName); - if (!textFile.exists()) - { - // Creates path to texture file - QString fileName(m.fullName()); - QFileInfo finfo(fileName); - if (!finfo.exists()) { - fileName = QStandardPaths::standardLocations(QStandardPaths::PicturesLocation).first() + "/" + textName; - } - else { - fileName = finfo.absolutePath(); - fileName.append("/"+ textName); - } - textName = fileName; - - // Create dummy checkers texture image - QImage img(textDim, textDim, QImage::Format_RGB32); - img.fill(qRgb(255,255,255)); // white - QPainter p(&img); - QBrush gray(Qt::gray); - QRect rect(0,0,CHECKERDIM,CHECKERDIM); - bool odd = true; - for (int y=0; y FilterTexturePlugin::applyFilter( int textW = par.getInt("textW"); int textH = par.getInt("textH"); bool overwrite = par.getBool("overwrite"); - bool assign = par.getBool("assign"); bool pp = par.getBool("pullpush"); - - CheckError(!QFile(m.fullName()).exists(), "Save the mesh before creating a texture"); + CheckError(textW <= 0, "Texture Width has an incorrect value"); CheckError(textH <= 0, "Texture Height has an incorrect value"); if (overwrite) @@ -723,32 +688,14 @@ std::map FilterTexturePlugin::applyFilter( CheckError(textName.length() == 0, "Texture file not specified"); //CheckError(std::max(textName.lastIndexOf("\\"), textName.lastIndexOf("/")) != -1, "Path in Texture file not allowed"); } - + if (m.cm.textures.empty()) { - // Creates path to texture file - QString fileName = textName; - if (std::max(textName.lastIndexOf("\\"), textName.lastIndexOf("/")) == -1){ - fileName = m.fullName(); - fileName = fileName.left(std::max(fileName.lastIndexOf('\\'), fileName.lastIndexOf('/')) + 1).append(textName); - } + QImage img(textW, textH, QImage::Format_RGB32); + img.fill(qRgb(255, 255, 255)); // white + m.addTexture(textName.toStdString(), img); - QFile textFile(fileName); - if (!textFile.exists()) - { - // Create dummy checkers texture image - QImage img(textW, textH, QImage::Format_RGB32); - img.fill(qRgb(255, 255, 255)); // white - - // Save texture - CheckError(!img.save(fileName, "PNG"), "Specified file cannot be saved"); - log("Dummy Texture \"%s\" Created ", fileName.toStdString().c_str()); - assert(textFile.exists()); - } - //Assign texture - m.cm.textures.clear(); - m.cm.textures.push_back(fileName.toStdString()); for(auto fi=m.cm.face.begin();fi!=m.cm.face.end();++fi){ if(!(*fi).IsD()) if((*fi).WT(0).N()==-1) { (*fi).WT(0).N() = 0; @@ -757,56 +704,52 @@ std::map FilterTexturePlugin::applyFilter( } } } - - QString filePath(m.fullName()); - filePath = filePath.left(std::max(filePath.lastIndexOf('\\'),filePath.lastIndexOf('/'))+1); + QString baseName(textName); if (baseName.lastIndexOf(".") != -1) if (baseName.endsWith("bmp", Qt::CaseInsensitive) || baseName.endsWith("jpg", Qt::CaseInsensitive) || baseName.endsWith("png", Qt::CaseInsensitive) || baseName.endsWith("jpeg", Qt::CaseInsensitive) || baseName.endsWith("tif", Qt::CaseInsensitive) || baseName.endsWith("tiff", Qt::CaseInsensitive)) baseName.truncate(baseName.lastIndexOf(".")); - - int texInd; - int texNum; - texNum = m.cm.textures.size(); + + unsigned int texNum = m.cm.textures.size(); vector texFileNames; texFileNames.resize(texNum); vector trgImgs; - trgImgs.reserve(m.cm.textures.size()); - + trgImgs.reserve(texNum); + // Image texture creation - for (texInd = 0; texInd < texNum; texInd++) + for (unsigned int texInd = 0; texInd < texNum; texInd++) { if (overwrite) { - texFileNames[texInd] = filePath + QString(m.cm.textures[texInd].c_str()); + texFileNames[texInd] = QString(m.cm.textures[texInd].c_str()); } else { if (texNum==1) - texFileNames[texInd] = filePath + baseName + ".png"; + texFileNames[texInd] = baseName + ".png"; else - texFileNames[texInd] = filePath + baseName + "_" + QString::number(texInd) + ".png"; + texFileNames[texInd] = baseName + "_" + QString::number(texInd) + ".png"; } - + trgImgs.push_back(QImage(QSize(textW, textH), QImage::Format_ARGB32)); trgImgs[texInd].fill(qRgba(0, 0, 0, 0)); // transparent black } - + // Compute (texture-space) border edges tri::UpdateTopology::FaceFaceFromTexCoord(m.cm); tri::UpdateFlags::FaceBorderFromFF(m.cm); - + // Rasterizing triangles RasterSampler rs(trgImgs); rs.InitCallback(cb, m.cm.fn, 0, 80); tri::SurfaceSampling::Texture(m.cm,rs,textW,textH,true); - + // Undo topology changes tri::UpdateTopology::FaceFace(m.cm); tri::UpdateFlags::FaceBorderFromFF(m.cm); - - for (texInd = 0; texInd < texNum; texInd++) + + for (unsigned int texInd = 0; texInd < texNum; texInd++) { // Revert alpha values for border edge pixels to 255 cb(81, "Cleaning up texture ..."); @@ -817,251 +760,37 @@ std::map FilterTexturePlugin::applyFilter( if (qAlpha(px) < 255 && (!pp || qAlpha(px) > 0)) trgImgs[texInd].setPixel(x, y, px | 0xff000000); } - + // PullPush if (pp) { cb(85, "Filling texture holes..."); PullPush(trgImgs[texInd], qRgba(0, 0, 0, 0)); } - - // Save texture - cb(90, "Saving texture ..."); - CheckError(!trgImgs[texInd].save(texFileNames[texInd]), "Texture file cannot be saved"); - log("Texture \"%s\" Created", texFileNames[texInd].toStdString().c_str()); - assert(QFile(texFileNames[texInd]).exists()); } - - if (assign && !overwrite) - { - m.cm.textures.clear(); - for (texInd = 0; texInd < texNum; texInd++) - m.cm.textures.push_back(textName.toStdString()); + + if (overwrite) { + for (unsigned int texInd = 0; texInd < texNum; texInd++) + m.setTexture(texFileNames[texInd].toStdString(), trgImgs[texInd]); } - + else { + m.clearTextures(); + for (unsigned int texInd = 0; texInd < texNum; texInd++) + m.addTexture(texFileNames[texInd].toStdString(), trgImgs[texInd]); + } + cb(100, "Done"); } break; - + case FP_TRANSFER_TO_TEXTURE : - { - MeshModel *srcMesh = par.getMesh("sourceMesh"); - MeshModel *trgMesh = par.getMesh("targetMesh"); - bool vertexSampling=false; - bool textureSampling=false; - int vertexMode= -1; - switch (par.getEnum("AttributeEnum")) - { - case 0: vertexSampling= true; vertexMode=0; break; // Color - case 1: vertexSampling= true; vertexMode=1; break; // Normal - case 2: vertexSampling= true; vertexMode=2; break; // Quality - case 3: textureSampling = true; break; - default: assert(0); - } - Scalarm upperbound = par.getAbsPerc("upperBound"); // maximum distance to stop search - QString textName = par.getString("textName"); - int textW = par.getInt("textW"); - int textH = par.getInt("textH"); - bool overwrite = par.getBool("overwrite"); - bool assign = par.getBool("assign"); - bool pp = par.getBool("pullpush"); - - assert (srcMesh != NULL); - assert (trgMesh != NULL); - CheckError(!QFile(trgMesh->fullName()).exists(), "Save the target mesh before creating a texture"); - CheckError(trgMesh->cm.fn == 0, "Target mesh needs to have faces"); - CheckError(!trgMesh->hasDataMask(MeshModel::MM_WEDGTEXCOORD), "Target mesh does not have Per-Wedge Texture Coordinates"); - CheckError(textW <= 0, "Texture Width has an incorrect value"); - CheckError(textH <= 0, "Texture Height has an incorrect value"); - - if (vertexSampling) { - if (vertexMode == 0) { CheckError(!srcMesh->hasDataMask(MeshModel::MM_VERTCOLOR), "Source mesh doesn't have Per-Vertex Color"); } - if (vertexMode == 1) { CheckError(!srcMesh->hasDataMask(MeshModel::MM_VERTNORMAL), "Source mesh doesn't have Per-Vertex Normal"); } - if (vertexMode == 2) { CheckError(!srcMesh->hasDataMask(MeshModel::MM_VERTQUALITY), "Source mesh doesn't have Per-Vertex Quality"); } - } - else - { - CheckError(srcMesh->cm.fn == 0, "Source mesh needs to have faces"); - CheckError(!srcMesh->hasDataMask(MeshModel::MM_WEDGTEXCOORD), "Source mesh does not have Per-Wedge Texture Coordinates"); - CheckError(srcMesh->cm.textures.empty(), "Source mesh does not have any associated texture"); - } - - if (overwrite) - { - CheckError(trgMesh->cm.textures.empty(), "Mesh has no associated texture to overwrite"); - } - else - { - CheckError(textName.length() == 0, "Texture file not specified"); - CheckError(std::max(textName.lastIndexOf("\\"), textName.lastIndexOf("/")) != -1, "Path in Texture file not allowed"); - } - - if (m.cm.textures.empty()) - { - // Creates path to texture file - QString fileName(m.fullName()); - fileName = fileName.left(std::max(fileName.lastIndexOf('\\'), fileName.lastIndexOf('/')) + 1).append(textName); - - QFile textFile(fileName); - if (!textFile.exists()) - { - // Create dummy checkers texture image - QImage img(textW, textH, QImage::Format_RGB32); - img.fill(qRgb(255, 255, 255)); // white - - // Save texture - CheckError(!img.save(fileName, "PNG"), "Specified file cannot be saved"); - log("Dummy Texture \"%s\" Created ", fileName.toStdString().c_str()); - assert(textFile.exists()); - } - - //Assign texture - m.cm.textures.clear(); - m.cm.textures.push_back(textName.toStdString()); - - - } - - // Source images (for texture to texture transfer) - int numSrcTex = srcMesh->cm.textures.size(); - QString srcPath(srcMesh->fullName()); - srcPath = srcPath.left(std::max(srcPath.lastIndexOf('\\'), srcPath.lastIndexOf('/')) + 1); - vector srcImgs; - vector srcTextureFileNames; - srcImgs.resize(numSrcTex); - srcTextureFileNames.resize(numSrcTex); - int srcTexInd = 0; - // Target images - int numTrgTex = trgMesh->cm.textures.size(); - QString trgPath(trgMesh->fullName()); - trgPath = trgPath.left(std::max(trgPath.lastIndexOf('\\'), trgPath.lastIndexOf('/')) + 1); - QString baseName(textName); - if (baseName.lastIndexOf(".") != -1) - if (baseName.endsWith("bmp", Qt::CaseInsensitive) || baseName.endsWith("jpg", Qt::CaseInsensitive) || baseName.endsWith("png", Qt::CaseInsensitive) - || baseName.endsWith("jpeg", Qt::CaseInsensitive) || baseName.endsWith("tif", Qt::CaseInsensitive) || baseName.endsWith("tiff", Qt::CaseInsensitive)) - baseName.truncate(baseName.lastIndexOf(".")); - vector trgImgs; - vector trgTextureFileNames; - trgImgs.reserve(numTrgTex); - trgTextureFileNames.resize(numTrgTex); - int trgTexInd = 0; - - // Check whether is possible to access source mesh textures, and load them - if (textureSampling) - { - for (srcTexInd = 0; srcTexInd < numSrcTex; srcTexInd++) - { - srcTextureFileNames[srcTexInd] = srcPath + srcMesh->cm.textures[srcTexInd].c_str(); - CheckError(!QFile(srcTextureFileNames[srcTexInd]).exists(), QString("Source texture \"").append(srcTextureFileNames[srcTexInd]).append("\" doesn't exists")); - CheckError(!srcImgs[srcTexInd].load(srcTextureFileNames[srcTexInd]), QString("Source texture \"").append(srcTextureFileNames[srcTexInd]).append("\" cannot be opened")); - } - } - - // target textures naming and creation - for (trgTexInd = 0; trgTexInd < numTrgTex; trgTexInd++) - { - if (overwrite) - { - trgTextureFileNames[trgTexInd] = trgPath + QString(m.cm.textures[trgTexInd].c_str()); - } - else - { - if (numTrgTex == 1) - trgTextureFileNames[trgTexInd] = trgPath + baseName + ".png"; - else - trgTextureFileNames[trgTexInd] = trgPath + baseName + "_" + QString::number(trgTexInd) + ".png"; - } - - trgImgs.push_back(QImage(QSize(textW, textH), QImage::Format_ARGB32)); - trgImgs[trgTexInd].fill(qRgba(0, 0, 0, 0)); // transparent black - } - - // Compute (texture-space) border edges - trgMesh->updateDataMask(MeshModel::MM_FACEFACETOPO); - tri::UpdateTopology::FaceFaceFromTexCoord(trgMesh->cm); - tri::UpdateFlags::FaceBorderFromFF(trgMesh->cm); - - // the meshes have to be transformed - // only if source different from target (if single mesh, it does not matter) - if (srcMesh != trgMesh) - { - if (srcMesh->cm.Tr != Matrix44m::Identity()) - tri::UpdatePosition::Matrix(srcMesh->cm, srcMesh->cm.Tr, true); - if (trgMesh->cm.Tr != Matrix44m::Identity()) - tri::UpdatePosition::Matrix(trgMesh->cm, trgMesh->cm.Tr, true); - } - - // Rasterizing faces - srcMesh->updateDataMask(MeshModel::MM_FACEMARK); - tri::UpdateNormal::PerFaceNormalized(srcMesh->cm); - if (vertexSampling) - { - TransferColorSampler sampler(srcMesh->cm, trgImgs, upperbound, vertexMode); // color sampling - sampler.InitCallback(cb, trgMesh->cm.fn, 0, 80); - tri::SurfaceSampling::Texture(trgMesh->cm, sampler, textW, textH, false); - } - else - { - TransferColorSampler sampler(srcMesh->cm, trgImgs, &srcImgs, upperbound); // texture sampling - sampler.InitCallback(cb, trgMesh->cm.fn, 0, 80); - tri::SurfaceSampling::Texture(trgMesh->cm, sampler, textW, textH, false); - } - - // the meshes have to return to their original position - // only if source different from target (if single mesh, it does not matter) - if (srcMesh != trgMesh) - { - if (srcMesh->cm.Tr != Matrix44m::Identity()) - tri::UpdatePosition::Matrix(srcMesh->cm, Inverse(srcMesh->cm.Tr), true); - if (trgMesh->cm.Tr != Matrix44m::Identity()) - tri::UpdatePosition::Matrix(trgMesh->cm, Inverse(trgMesh->cm.Tr), true); - } - - // Undo topology changes - tri::UpdateTopology::FaceFace(trgMesh->cm); - tri::UpdateFlags::FaceBorderFromFF(trgMesh->cm); - - for (trgTexInd = 0; trgTexInd < numTrgTex; trgTexInd++) - { - // Revert alpha values for border edge pixels to 255 - cb(81, "Cleaning up texture ..."); - for (int y = 0; y 0)) - trgImgs[trgTexInd].setPixel(x, y, px | 0xff000000); - } - - // PullPush - if (pp) - { - cb(85, "Filling texture holes..."); - PullPush(trgImgs[trgTexInd], qRgba(0, 0, 0, 0)); - } - - // Save texture - cb(90, "Saving texture ..."); - CheckError(!trgImgs[trgTexInd].save(trgTextureFileNames[trgTexInd]), "Texture file cannot be saved"); - log("Texture \"%s\" Created", trgTextureFileNames[trgTexInd].toStdString().c_str()); - assert(QFile(trgTextureFileNames[trgTexInd]).exists()); - } - - if (assign && !overwrite) - { - m.cm.textures.clear(); - for (trgTexInd = 0; trgTexInd < numTrgTex; trgTexInd++) - m.cm.textures.push_back(trgTextureFileNames[trgTexInd].toStdString()); - } - - cb(100, "Done"); - } + transferToTexture(md, par, cb); break; - + case FP_TEX_TO_VCOLOR_TRANSFER : { - MeshModel *srcMesh = par.getMesh("sourceMesh"); - MeshModel *trgMesh = par.getMesh("targetMesh"); + MeshModel *srcMesh = md.getMesh(par.getMeshId("sourceMesh")); + MeshModel *trgMesh = md.getMesh(par.getMeshId("targetMesh")); Scalarm upperbound = par.getAbsPerc("upperBound"); // maximum distance to stop search assert(srcMesh!=NULL); @@ -1075,14 +804,10 @@ std::map FilterTexturePlugin::applyFilter( vector srcImgs; srcImgs.resize(srcMesh->cm.textures.size()); - QString path; for (size_t textInd = 0; textInd < srcMesh->cm.textures.size(); textInd++) { - path = m.fullName(); - path = path.left(std::max(path.lastIndexOf('\\'), path.lastIndexOf('/')) + 1).append(srcMesh->cm.textures[textInd].c_str()); - CheckError(!QFile(path).exists(), QString("Source texture \"").append(path).append("\" doesn't exists")); - CheckError(!srcImgs[textInd].load(path), QString("Source texture \"").append(path).append("\" cannot be opened")); + srcImgs[textInd] = srcMesh->getTexture(srcMesh->cm.textures[textInd]); } trgMesh->updateDataMask(MeshModel::MM_VERTCOLOR); @@ -1144,5 +869,183 @@ FilterPlugin::FilterArity FilterTexturePlugin::filterArity(const QAction * filte return FilterPlugin::NONE; } +void FilterTexturePlugin::transferToTexture( + MeshDocument &md, + const RichParameterList & par, + vcg::CallBackPos * cb) +{ + MeshModel *srcMesh = md.getMesh(par.getMeshId("sourceMesh")); + MeshModel *trgMesh = md.getMesh(par.getMeshId("targetMesh")); + bool vertexSampling=false; + bool textureSampling=false; + int vertexMode= -1; + switch (par.getEnum("AttributeEnum")) + { + case 0: vertexSampling= true; vertexMode=0; break; // Color + case 1: vertexSampling= true; vertexMode=1; break; // Normal + case 2: vertexSampling= true; vertexMode=2; break; // Quality + case 3: textureSampling = true; break; + default: assert(0); + } + Scalarm upperbound = par.getAbsPerc("upperBound"); // maximum distance to stop search + QString textName = par.getString("textName"); + int textW = par.getInt("textW"); + int textH = par.getInt("textH"); + bool overwrite = par.getBool("overwrite"); + bool pp = par.getBool("pullpush"); + + assert (srcMesh != NULL); + assert (trgMesh != NULL); + CheckError(trgMesh->cm.fn == 0, "Target mesh needs to have faces"); + CheckError(!trgMesh->hasDataMask(MeshModel::MM_WEDGTEXCOORD), "Target mesh does not have Per-Wedge Texture Coordinates"); + CheckError(textW <= 0, "Texture Width has an incorrect value"); + CheckError(textH <= 0, "Texture Height has an incorrect value"); + + if (vertexSampling) { + if (vertexMode == 0) { CheckError(!srcMesh->hasDataMask(MeshModel::MM_VERTCOLOR), "Source mesh doesn't have Per-Vertex Color"); } + if (vertexMode == 1) { CheckError(!srcMesh->hasDataMask(MeshModel::MM_VERTNORMAL), "Source mesh doesn't have Per-Vertex Normal"); } + if (vertexMode == 2) { CheckError(!srcMesh->hasDataMask(MeshModel::MM_VERTQUALITY), "Source mesh doesn't have Per-Vertex Quality"); } + } + else { + CheckError(srcMesh->cm.fn == 0, "Source mesh needs to have faces"); + CheckError(!srcMesh->hasDataMask(MeshModel::MM_WEDGTEXCOORD), "Source mesh does not have Per-Wedge Texture Coordinates"); + CheckError(srcMesh->cm.textures.empty(), "Source mesh does not have any associated texture"); + } + + if (overwrite) { + CheckError(trgMesh->cm.textures.empty(), "Mesh has no associated texture to overwrite"); + } + else { + CheckError(textName.length() == 0, "Texture file not specified"); + } + + // Source images (for texture to texture transfer) + int numSrcTex = srcMesh->cm.textures.size(); + vector srcImgs; + vector srcTextureFileNames; + srcImgs.resize(numSrcTex); + srcTextureFileNames.resize(numSrcTex); + int srcTexInd = 0; + // Target images + int numTrgTex = 1; + if (trgMesh->cm.textures.size()> 0) + numTrgTex = trgMesh->cm.textures.size(); + QString baseName(textName); + if (baseName.lastIndexOf(".") != -1){ + if (baseName.endsWith("bmp", Qt::CaseInsensitive) || baseName.endsWith("jpg", Qt::CaseInsensitive) || baseName.endsWith("png", Qt::CaseInsensitive) + || baseName.endsWith("jpeg", Qt::CaseInsensitive) || baseName.endsWith("tif", Qt::CaseInsensitive) || baseName.endsWith("tiff", Qt::CaseInsensitive)) + baseName.truncate(baseName.lastIndexOf(".")); + } + vector trgImgs; + vector trgTextureFileNames; + trgImgs.reserve(numTrgTex); + trgTextureFileNames.resize(numTrgTex); + int trgTexInd = 0; + + if (textureSampling) + { + for (srcTexInd = 0; srcTexInd < numSrcTex; srcTexInd++) + { + srcTextureFileNames[srcTexInd] = srcMesh->cm.textures[srcTexInd].c_str(); + } + } + + // target textures naming and creation + for (trgTexInd = 0; trgTexInd < numTrgTex; trgTexInd++) + { + if (overwrite) + { + trgTextureFileNames[trgTexInd] = QString(trgMesh->cm.textures[trgTexInd].c_str()); + } + else + { + if (numTrgTex == 1) + trgTextureFileNames[trgTexInd] = baseName + ".png"; + else + trgTextureFileNames[trgTexInd] = baseName + "_" + QString::number(trgTexInd) + ".png"; + } + + trgImgs.push_back(QImage(QSize(textW, textH), QImage::Format_ARGB32)); + trgImgs[trgTexInd].fill(qRgba(0, 0, 0, 0)); // transparent black + } + + // Compute (texture-space) border edges + trgMesh->updateDataMask(MeshModel::MM_FACEFACETOPO); + tri::UpdateTopology::FaceFaceFromTexCoord(trgMesh->cm); + tri::UpdateFlags::FaceBorderFromFF(trgMesh->cm); + + // the meshes have to be transformed + // only if source different from target (if single mesh, it does not matter) + if (srcMesh != trgMesh) + { + if (srcMesh->cm.Tr != Matrix44m::Identity()) + tri::UpdatePosition::Matrix(srcMesh->cm, srcMesh->cm.Tr, true); + if (trgMesh->cm.Tr != Matrix44m::Identity()) + tri::UpdatePosition::Matrix(trgMesh->cm, trgMesh->cm.Tr, true); + } + + // Rasterizing faces + srcMesh->updateDataMask(MeshModel::MM_FACEMARK); + tri::UpdateNormal::PerFaceNormalized(srcMesh->cm); + if (vertexSampling) + { + TransferColorSampler sampler(srcMesh->cm, trgImgs, upperbound, vertexMode); // color sampling + sampler.InitCallback(cb, trgMesh->cm.fn, 0, 80); + tri::SurfaceSampling::Texture(trgMesh->cm, sampler, textW, textH, false); + } + else + { + TransferColorSampler sampler(srcMesh->cm, trgImgs, &srcImgs, upperbound); // texture sampling + sampler.InitCallback(cb, trgMesh->cm.fn, 0, 80); + tri::SurfaceSampling::Texture(trgMesh->cm, sampler, textW, textH, false); + } + + // the meshes have to return to their original position + // only if source different from target (if single mesh, it does not matter) + if (srcMesh != trgMesh) + { + if (srcMesh->cm.Tr != Matrix44m::Identity()) + tri::UpdatePosition::Matrix(srcMesh->cm, Inverse(srcMesh->cm.Tr), true); + if (trgMesh->cm.Tr != Matrix44m::Identity()) + tri::UpdatePosition::Matrix(trgMesh->cm, Inverse(trgMesh->cm.Tr), true); + } + + // Undo topology changes + tri::UpdateTopology::FaceFace(trgMesh->cm); + tri::UpdateFlags::FaceBorderFromFF(trgMesh->cm); + + for (trgTexInd = 0; trgTexInd < numTrgTex; trgTexInd++) + { + // Revert alpha values for border edge pixels to 255 + cb(81, "Cleaning up texture ..."); + for (int y = 0; y 0)) + trgImgs[trgTexInd].setPixel(x, y, px | 0xff000000); + } + + // PullPush + if (pp) + { + cb(85, "Filling texture holes..."); + PullPush(trgImgs[trgTexInd], qRgba(0, 0, 0, 0)); + } + } + + if (overwrite){ + for (trgTexInd = 0; trgTexInd < numTrgTex; trgTexInd++) + trgMesh->setTexture(trgTextureFileNames[trgTexInd].toStdString(), trgImgs[trgTexInd]); + } + else{ + trgMesh->clearTextures(); + for (trgTexInd = 0; trgTexInd < numTrgTex; trgTexInd++) + trgMesh->addTexture(trgTextureFileNames[trgTexInd].toStdString(), trgImgs[trgTexInd]); + } + + cb(100, "Done"); +} + MESHLAB_PLUGIN_NAME_EXPORTER(FilterTexturePlugin) diff --git a/src/meshlabplugins/filter_texture/filter_texture.h b/src/meshlabplugins/filter_texture/filter_texture.h index 7239d534a..7d0131f12 100644 --- a/src/meshlabplugins/filter_texture/filter_texture.h +++ b/src/meshlabplugins/filter_texture/filter_texture.h @@ -58,7 +58,7 @@ public: QString pluginName() const; virtual QString filterName(ActionIDType filter) const; virtual QString filterInfo(ActionIDType filter) const; - virtual void initParameterList(const QAction*, MeshDocument &/*m*/, RichParameterList & /*parent*/); + virtual RichParameterList initParameterList(const QAction*, const MeshDocument &/*m*/); std::map applyFilter( const QAction* action, const RichParameterList & parameters, @@ -70,6 +70,9 @@ public: virtual int postCondition(const QAction* ) const; FilterClass getClass(const QAction *a) const; FilterArity filterArity(const QAction* filter) const; + +private: + void transferToTexture(MeshDocument &md, const RichParameterList & parameters, vcg::CallBackPos * cb); }; #endif diff --git a/src/meshlabplugins/filter_texture/rastering.h b/src/meshlabplugins/filter_texture/rastering.h index b7f379a64..ba9e1489a 100644 --- a/src/meshlabplugins/filter_texture/rastering.h +++ b/src/meshlabplugins/filter_texture/rastering.h @@ -267,6 +267,8 @@ public: startPt[1] = bary[0]*f.cV(0)->cP().Y()+bary[1]*f.cV(1)->cP().Y()+bary[2]*f.cV(2)->cP().Y(); startPt[2] = bary[0]*f.cV(0)->cP().Z()+bary[1]*f.cV(1)->cP().Z()+bary[2]*f.cV(2)->cP().Z(); + if (!srcMesh->bbox.IsInEx(startPt)) return; + // Retrieve closest point on source mesh if(usePointCloudSampling) @@ -274,7 +276,7 @@ public: CMeshO::VertexType *nearestV=0; CMeshO::ScalarType dist=dist_upper_bound; nearestV = vcg::tri::GetClosestVertex(*srcMesh,unifGridVert,startPt,dist_upper_bound,dist); //(PDistFunct,markerFunctor,startPt,dist_upper_bound,dist,closestPt); - //if(cb) cb(sampleCnt++*100/sampleNum,"Resampling Vertex attributes"); + //if(cb) cb(sampleCnt++*100/sampleNum,"Resampling Vertex attributes"); //if(storeDistanceAsQualityFlag) p.Q() = dist; if(dist == dist_upper_bound) return ; @@ -298,7 +300,13 @@ public: rr = gg = bb = q; } break; } - trgImgs[f.cWT(0).N()].setPixel(tp.X(), trgImgs[f.cWT(0).N()].height() - 1 - tp.Y(), qRgba(rr, gg, bb, 255)); + int cx = tp.X(); + int cy = trgImgs[f.cWT(0).N()].height() - 1 - tp.Y(); + if (cx >= 0 && cx < trgImgs[f.cWT(0).N()].size().width()) { + if (cy >= 0 && cy < trgImgs[f.cWT(0).N()].size().height()){ + trgImgs[f.cWT(0).N()].setPixel(cx, cy, qRgba(rr, gg, bb, 255)); + } + } } else // sampling from a mesh { diff --git a/src/meshlabplugins/filter_texture_defragmentation/CMakeLists.txt b/src/meshlabplugins/filter_texture_defragmentation/CMakeLists.txt new file mode 100644 index 000000000..3db03ad0a --- /dev/null +++ b/src/meshlabplugins/filter_texture_defragmentation/CMakeLists.txt @@ -0,0 +1,56 @@ +set(SOURCES + filter_texture_defragmentation.cpp + + TextureDefragmentation/src/intersection.cpp + TextureDefragmentation/src/mesh_attribute.cpp + TextureDefragmentation/src/packing.cpp + TextureDefragmentation/src/seam_remover.cpp + TextureDefragmentation/src/seams.cpp + TextureDefragmentation/src/texture_optimization.cpp + TextureDefragmentation/src/mesh_graph.cpp + TextureDefragmentation/src/gl_utils.cpp + TextureDefragmentation/src/mesh.cpp + TextureDefragmentation/src/texture_rendering.cpp + TextureDefragmentation/src/logging.cpp + TextureDefragmentation/src/matching.cpp + TextureDefragmentation/src/arap.cpp + TextureDefragmentation/src/shell.cpp + TextureDefragmentation/src/texture_object.cpp + + ${VCGDIR}/wrap/ply/plylib.cpp + ${VCGDIR}/wrap/openfbx/src/ofbx.cpp + ${VCGDIR}/wrap/openfbx/src/miniz.c + ${VCGDIR}/wrap/qt/outline2_rasterizer.cpp +) + +set(HEADERS + filter_texture_defragmentation.h + TextureDefragmentation/src/intersection.h + TextureDefragmentation/src/mesh.h + TextureDefragmentation/src/packing.h + TextureDefragmentation/src/seam_remover.h + TextureDefragmentation/src/seams.h + TextureDefragmentation/src/timer.h + TextureDefragmentation/src/types.h + TextureDefragmentation/src/mesh_graph.h + TextureDefragmentation/src/texture_rendering.h + TextureDefragmentation/src/math_utils.h + TextureDefragmentation/src/texture_optimization.h + TextureDefragmentation/src/pushpull.h + TextureDefragmentation/src/gl_utils.h + TextureDefragmentation/src/mesh_attribute.h + TextureDefragmentation/src/logging.h + TextureDefragmentation/src/utils.h + TextureDefragmentation/src/matching.h + TextureDefragmentation/src/arap.h + TextureDefragmentation/src/shell.h + TextureDefragmentation/src/texture_object.h +) + +add_meshlab_plugin(filter_texture_defragmentation ${SOURCES} ${HEADERS}) + +target_link_libraries(filter_texture_defragmentation PRIVATE OpenGL::GLU) + +if(MSVC) + target_compile_definitions(filter_texture_defragmentation PRIVATE _USE_MATH_DEFINES) +endif() diff --git a/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/LICENSE b/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/LICENSE new file mode 100644 index 000000000..53d1f3d01 --- /dev/null +++ b/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/LICENSE @@ -0,0 +1,675 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. + diff --git a/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/arap.cpp b/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/arap.cpp new file mode 100644 index 000000000..fe9107324 --- /dev/null +++ b/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/arap.cpp @@ -0,0 +1,419 @@ +/******************************************************************************* + Copyright (c) 2021, Andrea Maggiordomo, Paolo Cignoni and Marco Tarini + + This file is part of TextureDefrag, a reference implementation for + the paper ``Texture Defragmentation for Photo-Reconstructed 3D Models'' + by Andrea Maggiordomo, Paolo Cignoni and Marco Tarini. + + TextureDefrag is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + TextureDefrag is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with TextureDefrag. If not, see . +*******************************************************************************/ + +#include "arap.h" + +#include "mesh_attribute.h" +#include "logging.h" +#include "math_utils.h" + +#include +#include + + +ARAP::ARAP(Mesh& mesh) + : m{mesh}, + max_iter{100} +{ +} + +void ARAP::FixVertex(Mesh::ConstVertexPointer vp, const vcg::Point2d& pos) +{ + fixed_i.push_back(tri::Index(m, vp)); + fixed_pos.push_back(pos); +} + +void ARAP::FixBoundaryVertices() +{ + for (auto& v : m.vert) { + if (v.IsB()) { + fixed_i.push_back(tri::Index(m, v)); + fixed_pos.push_back(v.T().P()); + } + } +} + +int ARAP::FixSelectedVertices() +{ + int nfixed = 0; + for (auto& v : m.vert) { + if (v.IsS()) { + fixed_i.push_back(tri::Index(m, v)); + fixed_pos.push_back(v.T().P()); + nfixed++; + } + } + return nfixed; +} + +/* This function fixes the vertices of an edge that is within 2pct of the target + * edge length */ +int ARAP::FixRandomEdgeWithinTolerance(double tol) +{ + std::unordered_set fixed; + for (int i : fixed_i) + fixed.insert(i); + + auto tsa = GetTargetShapeAttribute(m); + for (auto& f : m.face) { + for (int i = 0; i < 3; ++i) { + double dcurr = (f.WT(i).P() - f.WT(f.Next(i)).P()).Norm(); + double dtarget = (tsa[f].P[i] - tsa[f].P[f.Next(i)]).Norm(); + if (std::abs((dcurr - dtarget) / dtarget) < tol) { + if (fixed.count(tri::Index(m, f.V(i))) == 0 && fixed.count(tri::Index(m, f.V(f.Next(i)))) == 0) { + FixVertex(f.V(i), f.WT(i).P()); + FixVertex(f.V(f.Next(i)), f.WT(f.Next(i)).P()); + LOG_DEBUG << "Fixing vertices " << tri::Index(m, f.V(i)) << " " << tri::Index(m, f.V(f.Next(i))); + return 2; + } + } + } + } + return 0; +} + +void ARAP::SetMaxIterations(int n) +{ + max_iter = n; +} + +static std::vector ComputeCotangentVector(Mesh& m) +{ + std::vector cotan; + cotan.reserve(m.FN()); + auto tsa = GetTargetShapeAttribute(m); + double eps = std::numeric_limits::epsilon(); + for (auto& f : m.face) { + ARAP::Cot c; + for (int i = 0; i < 3; ++i) { + int j = (i+1)%3; + int k = (i+2)%3; + double alpha_i = std::max(VecAngle(tsa[f].P[j] - tsa[f].P[i], tsa[f].P[k] - tsa[f].P[i]), eps); + c.v[i] = 0.5 * std::tan(M_PI_2 - alpha_i); + } + cotan.push_back(c); + } + return cotan; +} + +void ARAP::ComputeSystemMatrix(Mesh& m, const std::vector& cotan, Eigen::SparseMatrix& L) +{ + using Td = Eigen::Triplet; + + L.resize(m.VN(), m.VN()); + L.setZero(); + std::vector tri; + auto Idx = [&m](const Mesh::VertexPointer vp) { return (int) tri::Index(m, vp); }; + for (auto &f : m.face) { + int fi = tri::Index(m, f); + for (int i = 0; i < 3; ++i) { + if (std::find(fixed_i.begin(), fixed_i.end(), (int) tri::Index(m, f.V(i))) == fixed_i.end()) { + Mesh::VertexPointer vi = f.V0(i); + int j = (i+1)%3; + Mesh::VertexPointer vj = f.V1(i); + int k = (i+2)%3; + Mesh::VertexPointer vk = f.V2(i); + + ensure(Idx(vi) >= 0); ensure(Idx(vi) < m.VN()); + ensure(Idx(vj) >= 0); ensure(Idx(vj) < m.VN()); + ensure(Idx(vk) >= 0); ensure(Idx(vk) < m.VN()); + + double weight_ij = cotan[fi].v[k]; + double weight_ik = cotan[fi].v[j]; + + if (!std::isfinite(weight_ij)) + weight_ij = 1e-8; + + if (!std::isfinite(weight_ik)) + weight_ik = 1e-8; + + tri.push_back(Td(Idx(vi), Idx(vj), -weight_ij)); + tri.push_back(Td(Idx(vi), Idx(vk), -weight_ik)); + tri.push_back(Td(Idx(vi), Idx(vi), (weight_ij + weight_ik))); + } + } + } + for (auto vi : fixed_i) { + tri.push_back(Td(vi, vi, 1)); + } + L.setFromTriplets(tri.begin(), tri.end()); + L.makeCompressed(); +} + +static std::vector ComputeRotations(Mesh& m) +{ + auto tsa = GetTargetShapeAttribute(m); + std::vector rotations; + rotations.reserve(m.FN()); + for (auto& f : m.face) { + vcg::Point2d x10, x20; + LocalIsometry(tsa[f].P[1] - tsa[f].P[0], tsa[f].P[2] - tsa[f].P[0], x10, x20); + Eigen::Matrix2d Jf = ComputeTransformationMatrix(x10, x20, f.WT(1).P() - f.WT(0).P(), f.WT(2).P() - f.WT(0).P()); + Eigen::Matrix2d U, V; + Eigen::Vector2d sigma; + Eigen::JacobiSVD svd; + svd.compute(Jf, Eigen::ComputeFullU | Eigen::ComputeFullV); + U = svd.matrixU(); V = svd.matrixV(); sigma = svd.singularValues(); + Eigen::MatrixXd R = U * V.transpose(); + if (R.determinant() < 0) { + U.col(U.cols() - 1) *= -1; + R = U * V.transpose(); + } + + rotations.push_back(R); + } + + return rotations; +} + +void ARAP::ComputeRHS(Mesh& m, const std::vector& rotations, const std::vector& cotan, Eigen::VectorXd& bu, Eigen::VectorXd& bv) +{ + auto Idx = [&m](const Mesh::VertexPointer vp) { return (int) tri::Index(m, vp); }; + bu = Eigen::VectorXd::Constant(m.VN(), 0); + bv = Eigen::VectorXd::Constant(m.VN(), 0); + auto tsa = GetTargetShapeAttribute(m); + for (auto &f : m.face) { + int fi = tri::Index(m, f); + const Eigen::Matrix2d& Rf = rotations[fi]; + + Eigen::Vector2d t[3]; + + // TODO this should be computed once and stored in the object state + Eigen::Vector2d x_10, x_20; + LocalIsometry(tsa[f].P[1] - tsa[f].P[0], tsa[f].P[2] - tsa[f].P[0], x_10, x_20); + t[0] = Eigen::Vector2d::Zero(); + t[1] = t[0] + x_10; + t[2] = t[0] + x_20; + + for (int i = 0; i < 3; ++i) { + Mesh::VertexPointer vi = f.V0(i); + int j = (i+1)%3; + int k = (i+2)%3; + + double weight_ij = cotan[fi].v[k]; + double weight_ik = cotan[fi].v[j]; + + if (!std::isfinite(weight_ij)) + weight_ij = 1e-8; + + if (!std::isfinite(weight_ik)) + weight_ik = 1e-8; + + Eigen::Vector2d x_ij = t[i] - t[j]; + Eigen::Vector2d x_ik = t[i] - t[k]; + + Eigen::Vector2d rhs = (weight_ij * Rf) * x_ij + (weight_ik * Rf) * x_ik; + bu(Idx(vi)) += rhs.x(); + bv(Idx(vi)) += rhs.y(); + } + } + for (unsigned i = 0; i < fixed_i.size(); ++i) { + bu(fixed_i[i]) = fixed_pos[i].X(); + bv(fixed_i[i]) = fixed_pos[i].Y(); + } +} + +double ARAP::ComputeEnergy(const vcg::Point2d& x10, const vcg::Point2d& x20, + const vcg::Point2d& u10, const vcg::Point2d& u20, + double *area) +{ + *area = std::abs(x10 ^ x20); + Eigen::Matrix2d Jf = ComputeTransformationMatrix(x10, x20, u10, u20); + Eigen::Matrix2d U, V; + Eigen::Vector2d sigma; + Eigen::JacobiSVD svd; + svd.compute(Jf, Eigen::ComputeFullU | Eigen::ComputeFullV); + U = svd.matrixU(); V = svd.matrixV(); sigma = svd.singularValues(); + return std::pow(sigma[0] - 1.0, 2.0) + std::pow(sigma[1] - 1.0, 2.0); +} + +double ARAP::ComputeEnergyFromStoredWedgeTC(const std::vector& fpVec, Mesh& m, double *num, double *denom) +{ + double n = 0; + double d = 0; + auto tsa = GetWedgeTexCoordStorageAttribute(m); + for (auto fptr : fpVec) { + vcg::Point2d x10 = tsa[fptr].tc[1].P() - tsa[fptr].tc[0].P(); + vcg::Point2d x20 = tsa[fptr].tc[2].P() - tsa[fptr].tc[0].P(); + vcg::Point2d u10 = fptr->WT(1).P() - fptr->WT(0).P(); + vcg::Point2d u20 = fptr->WT(2).P() - fptr->WT(0).P(); + double area; + double energy = ComputeEnergy(x10, x20, u10, u20, &area); + if (area > 0) { + n += (area * energy); + d += area; + } + } + if (num) + *num = n; + if (denom) + *denom = d; + return n / d; +} + +double ARAP::ComputeEnergyFromStoredWedgeTC(Mesh& m, double *num, double *denom) +{ + double e = 0; + double total_area = 0; + auto tsa = GetWedgeTexCoordStorageAttribute(m); + for (auto& f : m.face) { + vcg::Point2d x10 = tsa[f].tc[1].P() - tsa[f].tc[0].P(); + vcg::Point2d x20 = tsa[f].tc[2].P() - tsa[f].tc[0].P(); + double area_f = std::abs(x10 ^ x20); + if (area_f > 0) { + Eigen::Matrix2d Jf = ComputeTransformationMatrix(x10, x20, f.WT(1).P() - f.WT(0).P(), f.WT(2).P() - f.WT(0).P()); + Eigen::Matrix2d U, V; + Eigen::Vector2d sigma; + Eigen::JacobiSVD svd; + svd.compute(Jf, Eigen::ComputeFullU | Eigen::ComputeFullV); + U = svd.matrixU(); V = svd.matrixV(); sigma = svd.singularValues(); + total_area += area_f; + e += area_f * (std::pow(sigma[0] - 1.0, 2.0) + std::pow(sigma[1] - 1.0, 2.0)); + } + } + if (num) + *num = e; + if (denom) + *denom = total_area; + return e / total_area; +} + +double ARAP::CurrentEnergy() +{ + double e = 0; + double total_area = 0; + auto tsa = GetTargetShapeAttribute(m); + for (auto& f : m.face) { + vcg::Point2d x10, x20; + LocalIsometry(tsa[f].P[1] - tsa[f].P[0], tsa[f].P[2] - tsa[f].P[0], x10, x20); + Eigen::Matrix2d Jf = ComputeTransformationMatrix(x10, x20, f.WT(1).P() - f.WT(0).P(), f.WT(2).P() - f.WT(0).P()); + Eigen::Matrix2d U, V; + Eigen::Vector2d sigma; + Eigen::JacobiSVD svd; + svd.compute(Jf, Eigen::ComputeFullU | Eigen::ComputeFullV); + U = svd.matrixU(); V = svd.matrixV(); sigma = svd.singularValues(); + double area_f = 0.5 * ((tsa[f].P[1] - tsa[f].P[0]) ^ (tsa[f].P[2] - tsa[f].P[0])).Norm(); + total_area += area_f; + e += area_f * (std::pow(sigma[0] - 1.0, 2.0) + std::pow(sigma[1] - 1.0, 2.0)); + } + return e / total_area; +} + +ARAPSolveInfo ARAP::Solve() +{ + ARAPSolveInfo si = {0, 0, 0, false}; + std::vector cotan = ComputeCotangentVector(m); + + Eigen::SparseMatrix A; + ComputeSystemMatrix(m, cotan, A); + + Eigen::VectorXd xu = Eigen::VectorXd::Constant(m.VN(), 0); + Eigen::VectorXd xv = Eigen::VectorXd::Constant(m.VN(), 0); + + double e = CurrentEnergy(); + + // The system matrix is not symmetric + Eigen::SparseLU> solver; + + solver.analyzePattern(A); + solver.factorize(A); + + if (solver.info() != Eigen::Success) { + LOG_WARN << "Cotan matrix factorization failed: " << solver.info(); + si.numericalError = true; + return si; + } + + si.initialEnergy = CurrentEnergy(); + LOG_DEBUG << "ARAP: Starting energy is " << si.initialEnergy; + + bool converged = false; + int iter = 0; + while (!converged && iter < max_iter) { + + std::vector rotations = ComputeRotations(m); + Eigen::VectorXd bu(m.VN()); + Eigen::VectorXd bv(m.VN()); + ComputeRHS(m, rotations, cotan, bu, bv); + + Eigen::VectorXd xu_iter = solver.solve(bu); + + if (!(solver.info() == Eigen::Success)) { + LOG_WARN << "ARAP solve failed"; + si.numericalError = true; + return si; + } + + Eigen::VectorXd xv_iter = solver.solve(bv); + + if (!(solver.info() == Eigen::Success)) { + LOG_WARN << "ARAP solve failed"; + si.numericalError = true; + return si; + } + + for (auto& f : m.face) { + for (int i = 0; i < 3; ++i) { + int vi = tri::Index(m, f.V(i)); + f.WT(i).U() = xu_iter(vi); + f.WT(i).V() = xv_iter(vi); + f.V(i)->T().P() = f.WT(i).P(); + } + } + + double e_curr = CurrentEnergy(); + si.finalEnergy = e_curr; + + double delta_e = e - e_curr; + if (delta_e < 1e-8) { + LOG_DEBUG << "ARAP: convergence reached (change in the energy value is too small)"; + converged = true; + } + + xu = xu_iter; + xv = xv_iter; + e = e_curr; + + iter++; + } + + si.iterations = iter; + + if (iter == max_iter) { + LOG_DEBUG << "ARAP: iteration limit reached"; + } + + LOG_DEBUG << "ARAP: Energy after optimization is " << CurrentEnergy() << " (" << iter << " iterations)"; + + // Extra step to ensure the fixed vertices do not move at all + for (unsigned i = 0; i < fixed_i.size(); ++i) { + m.vert[fixed_i[i]].T().P() = fixed_pos[i]; + } + for (auto& f : m.face) { + for (int i = 0; i < 3; ++i) { + f.WT(i).P() = f.cV(i)->T().P(); + } + } + + return si; +} + + diff --git a/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/arap.h b/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/arap.h new file mode 100644 index 000000000..33e66e331 --- /dev/null +++ b/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/arap.h @@ -0,0 +1,79 @@ +/******************************************************************************* + Copyright (c) 2021, Andrea Maggiordomo, Paolo Cignoni and Marco Tarini + + This file is part of TextureDefrag, a reference implementation for + the paper ``Texture Defragmentation for Photo-Reconstructed 3D Models'' + by Andrea Maggiordomo, Paolo Cignoni and Marco Tarini. + + TextureDefrag is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + TextureDefrag is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with TextureDefrag. If not, see . +*******************************************************************************/ + +#ifndef ARAP_H +#define ARAP_H + +#include "mesh.h" + +#include +#include + + +struct ARAPSolveInfo { + double initialEnergy; + double finalEnergy; + int iterations; + bool numericalError; +}; + +class ARAP { + +public: + + struct Cot { + double v[3]; + }; + +private: + + Mesh& m; + + std::vector fixed_i; + std::vector fixed_pos; + + int max_iter; + + void ComputeSystemMatrix(Mesh& m, const std::vector& cotan, Eigen::SparseMatrix& L); + void ComputeRHS(Mesh& m, const std::vector& rotations, const std::vector& cotan, Eigen::VectorXd& bu, Eigen::VectorXd& bv); + +public: + + ARAP(Mesh& mesh); + + double CurrentEnergy(); + void FixVertex(Mesh::ConstVertexPointer vp, const vcg::Point2d& pos); + void FixBoundaryVertices(); + int FixSelectedVertices(); + int FixRandomEdgeWithinTolerance(double tol); + void SetMaxIterations(int n); + + ARAPSolveInfo Solve(); + + static double ComputeEnergyFromStoredWedgeTC(Mesh& m, double *num, double *denom); + static double ComputeEnergyFromStoredWedgeTC(const std::vector& fpVec, Mesh& m, double *num, double *denom); + static double ComputeEnergy(const vcg::Point2d& x10, const vcg::Point2d& x20, + const vcg::Point2d& u10, const vcg::Point2d& u20, + double *area); +}; + + +#endif // ARAP_H diff --git a/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/gl_utils.cpp b/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/gl_utils.cpp new file mode 100644 index 000000000..d4202253f --- /dev/null +++ b/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/gl_utils.cpp @@ -0,0 +1,115 @@ +/******************************************************************************* + Copyright (c) 2021, Andrea Maggiordomo, Paolo Cignoni and Marco Tarini + + This file is part of TextureDefrag, a reference implementation for + the paper ``Texture Defragmentation for Photo-Reconstructed 3D Models'' + by Andrea Maggiordomo, Paolo Cignoni and Marco Tarini. + + TextureDefrag is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + TextureDefrag is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with TextureDefrag. If not, see . +*******************************************************************************/ + +#include "gl_utils.h" +#include "logging.h" + +#include +#include +#include + +#include +#include + +void CheckGLError() +{ + GLenum error = glGetError(); + if (error != GL_NO_ERROR) + { + std::stringstream ss; + ss << "OpenGL error " << error << " "; + if (error == GL_INVALID_VALUE) ss << "GL_INVALID_VALUE"; + if (error == GL_INVALID_OPERATION) ss << "GL_INVALID_OPERATION"; + LOG_ERR << ss.str(); + } +} + +std::string ReadShader(const char *path) +{ + std::ifstream sf(path); + if (sf.is_open()) { + std::stringstream ss; + while (sf.good()) { + std::string s; + std::getline(sf, s); + ss << s << std::endl; + } + return ss.str(); + } else { + LOG_ERR << "Unable to read shader file " << path; + return ""; + } +} + +uint32_t CompileShaders(const char **vs_text, const char **fs_text) +{ + GLint status; + char infoLog[1024] = {0}; + + GLuint vs = glCreateShader(GL_VERTEX_SHADER); + glShaderSource(vs, 1, vs_text, NULL); + glCompileShader(vs); + glGetShaderInfoLog(vs, 1024, NULL, infoLog); + if (*infoLog) { + LOG_DEBUG << infoLog; + memset(infoLog, 0, 1024); + } + glGetShaderiv(vs, GL_COMPILE_STATUS, &status); + if (status == GL_FALSE) { + LOG_ERR << "Vertex shader compilation failed"; + } + + GLuint fs = glCreateShader(GL_FRAGMENT_SHADER); + glShaderSource(fs, 1, fs_text, NULL); + glCompileShader(fs); + glGetShaderInfoLog(fs, 1024, NULL, infoLog); + if (*infoLog) { + LOG_DEBUG << infoLog; + memset(infoLog, 0, 1024); + } + glGetShaderiv(fs, GL_COMPILE_STATUS, &status); + if (status == GL_FALSE) { + LOG_ERR << "Fragment shader compilation failed"; + } + + GLuint program = glCreateProgram(); + glAttachShader(program, vs); + glAttachShader(program, fs); + glLinkProgram(program); + glValidateProgram(program); + glGetProgramInfoLog(program, 1024, NULL, infoLog); + if (*infoLog) { + LOG_DEBUG << infoLog; + } + glGetProgramiv(program, GL_LINK_STATUS, &status); + if (status == GL_FALSE) { + LOG_ERR << "Shader program link failed"; + } + + glDeleteShader(vs); + glDeleteShader(fs); + + CheckGLError(); + + return program; +} + + diff --git a/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/gl_utils.h b/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/gl_utils.h new file mode 100644 index 000000000..b93c4680d --- /dev/null +++ b/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/gl_utils.h @@ -0,0 +1,44 @@ +/******************************************************************************* + Copyright (c) 2021, Andrea Maggiordomo, Paolo Cignoni and Marco Tarini + + This file is part of TextureDefrag, a reference implementation for + the paper ``Texture Defragmentation for Photo-Reconstructed 3D Models'' + by Andrea Maggiordomo, Paolo Cignoni and Marco Tarini. + + TextureDefrag is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + TextureDefrag is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with TextureDefrag. If not, see . +*******************************************************************************/ + +#ifndef GL_UTILS_H +#define GL_UTILS_H + +#include +#include +#include +#include + +#include + + +/* Prints the last OpenGL error code */ +void CheckGLError(); + +/* Reads a shader from path into a string and returns it */ +std::string ReadShader(const char *path); + +/* Compiles a vertex shader source and a fragment shader source into a program */ +uint32_t CompileShaders(const char **vs_text, const char **fs_text); + + +#endif // GL_UTIL_H + diff --git a/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/intersection.cpp b/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/intersection.cpp new file mode 100644 index 000000000..a25163aa6 --- /dev/null +++ b/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/intersection.cpp @@ -0,0 +1,198 @@ +/******************************************************************************* + Copyright (c) 2021, Andrea Maggiordomo, Paolo Cignoni and Marco Tarini + + This file is part of TextureDefrag, a reference implementation for + the paper ``Texture Defragmentation for Photo-Reconstructed 3D Models'' + by Andrea Maggiordomo, Paolo Cignoni and Marco Tarini. + + TextureDefrag is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + TextureDefrag is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with TextureDefrag. If not, see . +*******************************************************************************/ + +#include "intersection.h" +#include "utils.h" + +#include +#include +#include + +#include + + +struct Point2iHasher { + std::size_t operator()(const vcg::Point2i& p) const noexcept + { + std::size_t seed = 0; + seed ^= std::hash()(p[0]) + 0x9e3779b9 + (seed << 6) + (seed >> 2); + seed ^= std::hash()(p[1]) + 0x9e3779b9 + (seed << 6) + (seed >> 2); + return seed; + } +}; + + +static vcg::Box2d ComputeBox(const std::vector& hev); + + +bool SegmentBoxIntersection(const Segment& seg, const vcg::Box2d& box) +{ + vcg::Point2d isec; + vcg::Point2d c1{box.min}; + vcg::Point2d c2{box.max[0], box.min[1]}; + vcg::Point2d c3{box.max}; + vcg::Point2d c4{box.min[0], box.max[1]}; + + if (vcg::SegmentSegmentIntersection(seg, vcg::Segment2{c1, c2}, isec)) return true; + if (vcg::SegmentSegmentIntersection(seg, vcg::Segment2{c2, c3}, isec)) return true; + if (vcg::SegmentSegmentIntersection(seg, vcg::Segment2{c3, c4}, isec)) return true; + if (vcg::SegmentSegmentIntersection(seg, vcg::Segment2{c4, c1}, isec)) return true; + + // if the segment does not intersect the sides, check if it is fully contained in the box + return (box.min[0] <= std::min(seg.P0()[0], seg.P1()[0]) && + box.min[1] <= std::min(seg.P0()[1], seg.P1()[1]) && + box.max[0] >= std::max(seg.P0()[0], seg.P1()[0]) && + box.max[1] >= std::max(seg.P0()[1], seg.P1()[1])); +} + +std::vector CrossIntersection(const std::vector& heVec1, const std::vector& heVec2) +{ + using HalfEdgeID = std::pair; + + std::vector isects; + + std::unordered_map, Point2iHasher> grid; + unsigned elems = heVec1.size() + heVec2.size(); + + // init grid helper + vcg::BasicGrid2D gh; + vcg::Box2d bbox1 = ComputeBox(heVec1); + vcg::Box2d bbox2 = ComputeBox(heVec2); + gh.bbox = bbox1; + gh.bbox.Add(bbox2.min); + gh.bbox.Add(bbox2.max); + vcg::BestDim2D(elems, gh.bbox.Dim(), gh.siz); + gh.ComputeDimAndVoxel(); + + const std::vector *vp[] = {&heVec1, &heVec2}; + + for (int i = 0; i < 2; ++i) { + for (unsigned j = 0; j < vp[i]->size(); ++j) { + const HalfEdge& he = vp[i]->at(j); + + vcg::Box2d segmentBox; + segmentBox.Add(he.P0()); + segmentBox.Add(he.P1()); + vcg::Box2i gridCover; + gh.BoxToIBox(segmentBox, gridCover); + for (int h = gridCover.min[0]; h <= gridCover.max[0]; h++) { + for (int k = gridCover.min[1]; k <= gridCover.max[1]; k++) { + vcg::Box2d cell; + vcg::Point2i voxel(h, k); + gh.IPiToBox(voxel, cell); + if (SegmentBoxIntersection(Segment(he.P0(), he.P1()), cell)) { + grid[voxel].push_back(std::make_pair(i, j)); + } + } + } + } + } + + for (auto& entry : grid) { + for (unsigned j = 0; j < entry.second.size(); ++j) { + for (unsigned k = j+1; k < entry.second.size(); ++k) { + HalfEdgeID i1 = entry.second[j]; + HalfEdgeID i2 = entry.second[k]; + + if (i1.first > i2.first) + std::swap(i1, i2); + + if (i1.first != i2.first) { + ensure(i1.first == 0); + // test for intersection only if the segments have no common endpoints (this improves robustness) + HalfEdge he1 = vp[i1.first]->at(i1.second); + HalfEdge he2 = vp[i2.first]->at(i2.second); + vcg::Point2d intersectionPoint; + if (he1.P0() != he2.P0() && he1.P1() != he2.P1() && he1.P0() != he2.P1() && he1.P1() != he2.P0() + && SegmentSegmentIntersection(Segment(he1.P0(), he1.P1()), Segment(he2.P0(), he2.P1()), intersectionPoint)) { + isects.push_back(std::make_pair(he1, he2)); + } + } + } + } + } + + return isects; +} + +std::vector Intersection(const std::vector& heVec) +{ + std::vector isects; + + std::unordered_map, Point2iHasher> grid; + unsigned elems = heVec.size(); + + // init grid helper + vcg::BasicGrid2D gh; + gh.bbox = ComputeBox(heVec); + vcg::BestDim2D(elems, gh.bbox.Dim(), gh.siz); + gh.ComputeDimAndVoxel(); + + for (unsigned j = 0; j < heVec.size(); ++j) { + const HalfEdge& he = heVec[j]; + + vcg::Box2d segmentBox; + segmentBox.Add(he.P0()); + segmentBox.Add(he.P1()); + vcg::Box2i gridCover; + gh.BoxToIBox(segmentBox, gridCover); + for (int h = gridCover.min[0]; h <= gridCover.max[0]; h++) { + for (int k = gridCover.min[1]; k <= gridCover.max[1]; k++) { + vcg::Box2d cell; + vcg::Point2i voxel(h, k); + gh.IPiToBox(voxel, cell); + if (SegmentBoxIntersection(Segment(he.P0(), he.P1()), cell)) { + grid[voxel].push_back(j); + } + } + } + } + + for (auto& entry : grid) { + for (unsigned j = 0; j < entry.second.size(); ++j) { + for (unsigned k = j+1; k < entry.second.size(); ++k) { + int i1 = entry.second[j]; + int i2 = entry.second[k]; + Segment s1 = Segment(heVec[i1].P0(), heVec[i1].P1()); + Segment s2 = Segment(heVec[i2].P0(), heVec[i2].P1()); + vcg::Point2d intersectionPoint; + + if (s1.P0() != s2.P0() && s1.P1() != s2.P1() && s1.P0() != s2.P1() && s1.P1() != s2.P0() + && SegmentSegmentIntersection(s1, s2, intersectionPoint)) { + isects.push_back(std::make_pair(heVec[i1], heVec[i2])); + } + } + } + } + + + return isects; +} + +static vcg::Box2d ComputeBox(const std::vector& hev) +{ + vcg::Box2d box; + for (auto& he : hev) { + box.Add(he.P0()); + box.Add(he.P1()); + } + return box; +} diff --git a/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/intersection.h b/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/intersection.h new file mode 100644 index 000000000..f47ec2bdf --- /dev/null +++ b/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/intersection.h @@ -0,0 +1,55 @@ +/******************************************************************************* + Copyright (c) 2021, Andrea Maggiordomo, Paolo Cignoni and Marco Tarini + + This file is part of TextureDefrag, a reference implementation for + the paper ``Texture Defragmentation for Photo-Reconstructed 3D Models'' + by Andrea Maggiordomo, Paolo Cignoni and Marco Tarini. + + TextureDefrag is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + TextureDefrag is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with TextureDefrag. If not, see . +*******************************************************************************/ + +#ifndef INTERSECTION_H +#define INTERSECTION_H + +#include +#include +#include + +#include + +#include "mesh.h" + +struct HalfEdge { + Mesh::FacePointer fp; + int e; + + vcg::Point2d P0() const { return fp->V0(e)->T().P(); } + vcg::Point2d P1() const { return fp->V1(e)->T().P(); } + + Mesh::VertexPointer V0() const { return fp->V0(e); } + Mesh::VertexPointer V1() const { return fp->V1(e); } + + bool operator<(const HalfEdge& other) const { return (fp < other.fp) || (fp == other.fp && e < other.e); } + bool operator==(const HalfEdge& other) const { return fp == other.fp && e == other.e; } +}; + +typedef vcg::Segment2d Segment; +typedef std::pair HalfEdgePair; + +bool SegmentBoxIntersection(const Segment& seg, const vcg::Box2d& box); + +std::vector Intersection(const std::vector& heVec); +std::vector CrossIntersection(const std::vector& heVec1, const std::vector& heVec2); + +#endif // INTERSECTION_H diff --git a/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/logging.cpp b/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/logging.cpp new file mode 100644 index 000000000..e740b40f6 --- /dev/null +++ b/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/logging.cpp @@ -0,0 +1,112 @@ +/******************************************************************************* + Copyright (c) 2021, Andrea Maggiordomo, Paolo Cignoni and Marco Tarini + + This file is part of TextureDefrag, a reference implementation for + the paper ``Texture Defragmentation for Photo-Reconstructed 3D Models'' + by Andrea Maggiordomo, Paolo Cignoni and Marco Tarini. + + TextureDefrag is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + TextureDefrag is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with TextureDefrag. If not, see . +*******************************************************************************/ + +#include "logging.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace logging { + +Buffer::Buffer(int level) + : os{} +{ + switch(level) { + case -2: + os << std::setw(8); + os << " ERR| "; + break; + case -1: + os << std::setw(8); + os << "WARN| "; + break; + default: + os << std::setw(6); + os << level << "| "; + } +} + +Buffer::~Buffer() +{ + Logger::Log(os.str()); +} + +int Logger::logLevel = 0; +std::vector Logger::streamVec{}; +std::map Logger::threadNames{}; +std::mutex Logger::singletonMtx{}; + +void Logger::Init(int level) +{ + Logger::logLevel = level; + threadNames[std::this_thread::get_id()] = "MainThread"; +} + +int Logger::GetLogLevel() +{ + return Logger::logLevel; +} + +void Logger::RegisterStream(std::ostream *os) +{ + std::lock_guard lock{Logger::singletonMtx}; + Logger::streamVec.push_back(os); +} + +void Logger::RegisterName(const std::string& threadName) +{ + std::lock_guard lock{Logger::singletonMtx}; + threadNames[std::this_thread::get_id()] = threadName; +} + +std::string Logger::GetName() +{ + std::lock_guard lock{Logger::singletonMtx}; + auto tid = std::this_thread::get_id(); + if (threadNames.count(tid) > 0) + return threadNames[tid]; + else { + std::stringstream ss; + ss << tid; + return ss.str(); + } +} + +void Logger::Log(const std::string& s) +{ + std::stringstream ss; + ss << std::setw(16) << Logger::GetName() << " | " << s << std::endl; + + std::lock_guard lock{Logger::singletonMtx}; + + std::cout << ss.str() << std::flush; + + for (auto os : streamVec) + (*os) << ss.str() << std::flush; +} + +} // namespace logging diff --git a/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/logging.h b/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/logging.h new file mode 100644 index 000000000..fc23f5916 --- /dev/null +++ b/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/logging.h @@ -0,0 +1,108 @@ +/******************************************************************************* + Copyright (c) 2021, Andrea Maggiordomo, Paolo Cignoni and Marco Tarini + + This file is part of TextureDefrag, a reference implementation for + the paper ``Texture Defragmentation for Photo-Reconstructed 3D Models'' + by Andrea Maggiordomo, Paolo Cignoni and Marco Tarini. + + TextureDefrag is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + TextureDefrag is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with TextureDefrag. If not, see . +*******************************************************************************/ + +#ifndef LOGGING_H +#define LOGGING_H + +#include +#include +#include +#include +#include +#include + +// logging macros + +#define LOG_INIT(level) (logging::Logger::Init(level)) +#define LOG_SET_THREAD_NAME(name) (logging::Logger::RegisterName(name)) +#define LOG_GET_THREAD_NAME (logging::Logger::GetName()) +#define LOG(level) (level > logging::Logger::GetLogLevel()) ? ((void) 0) : logging::V_() & logging::Buffer(level) + +#define LOG_ERR LOG(logging::Level::Error) +#define LOG_WARN LOG(logging::Level::Warning) +#define LOG_INFO LOG(logging::Level::Info) +#define LOG_VERBOSE LOG(logging::Level::Verbose) +#define LOG_DEBUG LOG(logging::Level::Debug) + +namespace logging { + +enum Level { + Error = -2, + Warning = -1, + Info = 0, + Verbose = 1, + Debug = 2 +}; + +class Buffer { + + std::ostringstream os; + +public: + + Buffer(int level); + ~Buffer(); + + template + Buffer& operator<<(const T& t) + { + os << t; + return *this; + } + + /* + Buffer& operator<<(std::ostream& (*f)(std::ostream&)) + { + f(os); + return *this; + } + */ + +}; + +struct V_ { + void operator &(const Buffer&) { } +}; + +class Logger { + + static int logLevel; + static std::vector streamVec; + static std::map threadNames; + + static std::mutex singletonMtx; + +public: + + static void Init(int level); + + static int GetLogLevel(); + static std::string GetName(); + static void RegisterStream(std::ostream *os); + static void RegisterName(const std::string& threadName); + static void Log(const std::string& s); + +}; + +} + +#endif // LOGGING_H + diff --git a/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/matching.cpp b/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/matching.cpp new file mode 100644 index 000000000..310ac2f25 --- /dev/null +++ b/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/matching.cpp @@ -0,0 +1,208 @@ +/******************************************************************************* + Copyright (c) 2021, Andrea Maggiordomo, Paolo Cignoni and Marco Tarini + + This file is part of TextureDefrag, a reference implementation for + the paper ``Texture Defragmentation for Photo-Reconstructed 3D Models'' + by Andrea Maggiordomo, Paolo Cignoni and Marco Tarini. + + TextureDefrag is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + TextureDefrag is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with TextureDefrag. If not, see . +*******************************************************************************/ + +#include "matching.h" +#include "utils.h" + +#include +#include + +#include +#include + +MatchingTransform ComputeMatchingMatrix(const std::vector& targetVector, const std::vector& matchingVector) +{ + ensure(targetVector.size() == matchingVector.size()); + ensure(targetVector.size() >= 2); + + vcg::Point2d ct = std::accumulate(targetVector.begin(), targetVector.end(), vcg::Point2d::Zero()) / (double) targetVector.size(); + vcg::Point2d cm = std::accumulate(matchingVector.begin(), matchingVector.end(), vcg::Point2d::Zero()) / (double) matchingVector.size(); + + Eigen::MatrixXd A(2 * targetVector.size() + 1, 4); + Eigen::VectorXd b(2 * targetVector.size() + 1); + + A.setZero(); + b.setZero(); + + int n = targetVector.size(); + for (int i = 0; i < n; ++i) { + vcg::Point2d p = targetVector[i] - ct; + vcg::Point2d q = matchingVector[i] - cm; + A(i, 0) = q.X(); A(i, 1) = q.Y(); b(i) = p.X(); + A(i+n, 2) = q.X(); A(i+n, 3) = q.Y(); b(i+n) = p.Y(); + } + + Eigen::VectorXd x = A.fullPivHouseholderQr().solve(b); + Eigen::Matrix2d SR; + SR << x[0], x[1], + x[2], x[3]; + + Eigen::Vector2d ect(ct.X(), ct.Y()); + Eigen::Vector2d ecm(cm.X(), cm.Y()); + + Eigen::Vector2d t = ect - SR * ecm; + + + return { vcg::Point2d(t[0], t[1]), { SR(0, 0), SR(0, 1), SR(1, 0), SR(1, 1) } }; +} + +MatchingTransform ComputeMatchingSimilarityMatrix(const std::vector& targetVector, const std::vector& matchingVector) +{ + ensure(targetVector.size() == matchingVector.size()); + ensure(targetVector.size() >= 2); + + int n = targetVector.size(); + + vcg::Point2d ct = std::accumulate(targetVector.begin(), targetVector.end(), vcg::Point2d::Zero()) / (double) targetVector.size(); + vcg::Point2d cm = std::accumulate(matchingVector.begin(), matchingVector.end(), vcg::Point2d::Zero()) / (double) matchingVector.size(); + + std::vector pv; + std::vector qv; + + for (int i = 0; i < n; ++i) { + vcg::Point2d p = targetVector[i] - ct; + vcg::Point2d q = matchingVector[i] - cm; + pv.push_back({p.X(), p.Y()}); + qv.push_back({q.X(), q.Y()}); + } + + double pSquaredNormSum = 0; + double qSquaredNormSum = 0; + Eigen::Matrix2d M = Eigen::Matrix2d::Zero(); + for (int i = 0; i < n; ++i) { + pSquaredNormSum += pv[i].squaredNorm(); + qSquaredNormSum += qv[i].squaredNorm(); + M += pv[i] * qv[i].transpose(); + } + + double scale = std::sqrt(pSquaredNormSum / qSquaredNormSum); + + Eigen::Matrix2d Q = M.transpose() * M; + + Eigen::EigenSolver es; + es.compute(Q); + + ensure(es.eigenvalues().imag().squaredNorm() < 1e-8); + ensure(es.eigenvectors().imag().squaredNorm() < 1e-8); + + Eigen::Vector2d lambda = es.eigenvalues().real(); + Eigen::Matrix2d V = es.eigenvectors().real(); + + Eigen::Matrix2d invsqrtQ = (1/std::sqrt(lambda[0])) * (V.col(0) * V.col(0).transpose()) + (1/std::sqrt(lambda[1])) * (V.col(1) * V.col(1).transpose()); + Eigen::Matrix2d R = M * invsqrtQ; + Eigen::Matrix2d sR = scale * R; + + // does this work? + if(sR.determinant() < 0) { + Eigen::Matrix2d U, V; + Eigen::Vector2d sigma; + Eigen::JacobiSVD svd; + svd.compute(R, Eigen::ComputeFullU | Eigen::ComputeFullV); + U = svd.matrixU(); V = svd.matrixV(); sigma = svd.singularValues(); + ensure(std::abs(sigma[0] - 1) < 1e-8); + ensure(std::abs(sigma[1] - 1) < 1e-8); + U.col(U.cols() - 1) *= -1; + R = U * V.transpose(); + } + + Eigen::Vector2d ect(ct[0], ct[1]); + Eigen::Vector2d ecm(cm[0], cm[1]); + + Eigen::Vector2d t = ect - scale * R * ecm; + + return { vcg::Point2d(t[0], t[1]), { sR(0,0), sR(0,1), sR(1,0), sR(1,1) } }; +} + +MatchingTransform ComputeMatchingRigidMatrix(const std::vector& targetVector, const std::vector& matchingVector) +{ + ensure(targetVector.size() == matchingVector.size()); + ensure(targetVector.size() >= 2); + + int n = targetVector.size(); + + vcg::Point2d ct = std::accumulate(targetVector.begin(), targetVector.end(), vcg::Point2d::Zero()) / (double) n; + vcg::Point2d cm = std::accumulate(matchingVector.begin(), matchingVector.end(), vcg::Point2d::Zero()) / (double) n; + + std::vector pv; + std::vector qv; + + for (int i = 0; i < n; ++i) { + vcg::Point2d p = targetVector[i] - ct; + vcg::Point2d q = matchingVector[i] - cm; + pv.push_back({p.X(), p.Y()}); + qv.push_back({q.X(), q.Y()}); + } + + // compute the covariance matrix + Eigen::Matrix2d S = Eigen::Matrix2d::Zero(); + for (int i = 0; i < n; ++i) { + S += qv[i] * pv[i].transpose(); + } + + Eigen::Matrix2d U, V; + Eigen::JacobiSVD svd; + svd.compute(S, Eigen::ComputeFullU | Eigen::ComputeFullV); + U = svd.matrixU(); + V = svd.matrixV(); + + Eigen::Vector2d d(1, 1); + if (U.determinant() * V.determinant() < 0) { + d[1] = -1; + } + + Eigen::Matrix2d R = V * d.asDiagonal() * U.transpose(); + + ensure(R.determinant() > 0); + + Eigen::Vector2d ect(ct[0], ct[1]); + Eigen::Vector2d ecm(cm[0], cm[1]); + + Eigen::Vector2d t = ect - R * ecm; + + return { vcg::Point2d(t[0], t[1]), { R(0,0), R(0,1), R(1,0), R(1,1) } }; +} + +double MatchingError(const MatchingTransform& matching, const std::vector& points1, const std::vector& points2) +{ + return MatchingErrorAverage(matching, points1, points2); +} + +double MatchingErrorAverage(const MatchingTransform& matching, const std::vector& points1, const std::vector& points2) +{ + ensure(points1.size() == points2.size()); + double error = 0; + for (unsigned i = 0; i < points1.size(); ++i) { + error += (points1[i] - matching.Apply(points2[i])).Norm(); + } + + return error / (double) points1.size(); +} + +double MatchingErrorTotal(const MatchingTransform& matching, const std::vector& points1, const std::vector& points2) +{ + ensure(points1.size() == points2.size()); + double error = 0; + for (unsigned i = 0; i < points1.size(); ++i) { + error += (points1[i] - matching.Apply(points2[i])).Norm(); + } + + return error; +} diff --git a/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/matching.h b/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/matching.h new file mode 100644 index 000000000..62ce7237f --- /dev/null +++ b/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/matching.h @@ -0,0 +1,67 @@ +/******************************************************************************* + Copyright (c) 2021, Andrea Maggiordomo, Paolo Cignoni and Marco Tarini + + This file is part of TextureDefrag, a reference implementation for + the paper ``Texture Defragmentation for Photo-Reconstructed 3D Models'' + by Andrea Maggiordomo, Paolo Cignoni and Marco Tarini. + + TextureDefrag is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + TextureDefrag is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with TextureDefrag. If not, see . +*******************************************************************************/ + +#ifndef MATCHING_H +#define MATCHING_H + +#include + +#include + +/* Class that encodes a matching transform. The method Apply transforms the + * given point according to the matching encoded in the object */ +struct MatchingTransform { + vcg::Point2d t; // the translation of the matching transform + double matCoeff[4]; // the linear portion of the matching transform, row-maj 2x2 + + inline vcg::Point2d Apply(const vcg::Point2d &q) const + { + return vcg::Point2d(matCoeff[0] * q.X() + matCoeff[1] * q.Y() + t.X(), + matCoeff[2] * q.X() + matCoeff[3] * q.Y() + t.Y()); + } + + static inline MatchingTransform Identity() + { + return {vcg::Point2d::Zero(), { 1.0, 0.0, 0.0, 1.0 }}; + } + +}; + +/* Computes the least squares affine transform of the matchingVector points to + * the targetVector points */ +MatchingTransform ComputeMatchingMatrix(const std::vector& targetVector, const std::vector& matchingVector); + +/* Computes the least squares similarity transform of the matchingVector points + * to the targetVector points */ +MatchingTransform ComputeMatchingSimilarityMatrix(const std::vector& targetVector, const std::vector& matchingVector); + +/* Computes the least squares rigid (non-scaled) transform of the matchingVector + * points to the targetVector points */ +MatchingTransform ComputeMatchingRigidMatrix(const std::vector& targetVector, const std::vector& matchingVector); + +/* Computes the average matching error applied to the given point sequences */ +double MatchingError(const MatchingTransform& matching, const std::vector& points1, const std::vector& points2); +double MatchingErrorAverage(const MatchingTransform& matching, const std::vector& points1, const std::vector& points2); + +/* Computes the absolute matching error applied to the given point sequences */ +double MatchingErrorTotal(const MatchingTransform& matching, const std::vector& points1, const std::vector& points2); + +#endif // MATCHING_H diff --git a/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/math_utils.h b/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/math_utils.h new file mode 100644 index 000000000..7e9ca47d0 --- /dev/null +++ b/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/math_utils.h @@ -0,0 +1,117 @@ +/******************************************************************************* + Copyright (c) 2021, Andrea Maggiordomo, Paolo Cignoni and Marco Tarini + + This file is part of TextureDefrag, a reference implementation for + the paper ``Texture Defragmentation for Photo-Reconstructed 3D Models'' + by Andrea Maggiordomo, Paolo Cignoni and Marco Tarini. + + TextureDefrag is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + TextureDefrag is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with TextureDefrag. If not, see . +*******************************************************************************/ + +#ifndef MATH_UTILS_H +#define MATH_UTILS_H + +#include +#include + +#ifndef M_PI + #define M_PI 3.1415926535897932384626433832795 +#endif +#ifndef M_PI_2 + #define M_PI_2 1.5707963267948966192313216916398 +#endif + +constexpr double Infinity() +{ + return std::numeric_limits::infinity(); +} + +template +inline double EdgeLength(const FaceType& f, int i) +{ + return (f.cV0(i)->P() - f.cV1(i)->P()).Norm(); +} + +template +inline double EdgeLengthUV(const FaceType& f, int i) +{ + return (f.cWT(i).P() - f.cWT((i+1)%3).P()).Norm(); +} + + +/* Computes the angle between u and v */ +template +double VecAngle(const PointType& u, const PointType& v) +{ + typename PointType::ScalarType nu = u.Norm(); + typename PointType::ScalarType nv = v.Norm(); + + double n = (u*nv - v*nu).Norm(); + double d = (u*nv + v*nu).Norm(); + + return 2.0 * std::atan(n/d); +} + +/* Computes the cotangent of the angle between u and v */ +template +double VecCotg(const PointType& u, const PointType& v) +{ + const PointType w = v - u; + double dblArea = (u ^ v).Norm(); + return (u.SquaredNorm() + v.SquaredNorm() - w.SquaredNorm()) / (2.0 * dblArea); +} + +/* Given two vectors, it transforms them to the local 2d-frame of the plane they span */ +template +void LocalIsometry(const PointType& v1, const PointType& v2, PointTypeOut& w1, PointTypeOut& w2) +{ + //ensure(v1.Norm() > 0 && v2.Norm() > 0); + double v1n = v1.Norm(); + double v2n = v2.Norm(); + if (v1n == 0 || v2n == 0) { + if (v1n == 0) v1n = 1e-6; + if (v2n == 0) v2n = 1e-6; + } + double theta = VecAngle(v1, v2); + if (!(theta > 0 && theta < M_PI)) { + if (theta == 0) theta = 1e-3; // push theta to be very small + else if (theta == M_PI) theta = M_PI - 1e-3; // almost flat + else theta = M_PI / 2.0; // completely arbitrary value, should never happen + } + w1[0] = v1n; + w1[1] = 0; + w2[0] = v2n * std::cos(theta); + w2[1] = v2n * std::sin(theta); +} + +template +Eigen::Matrix2d ComputeTransformationMatrix(const PointType& x10, const PointType& x20, const PointType& u10, const PointType& u20) +{ + Eigen::Matrix2d f; + Eigen::Matrix2d g; + + f(0, 0) = x10[0]; + f(1, 0) = x10[1]; + f(0, 1) = x20[0]; + f(1, 1) = x20[1]; + g(0, 0) = u10[0]; + g(1, 0) = u10[1]; + g(0, 1) = u20[0]; + g(1, 1) = u20[1]; + + return g * f.inverse(); +} + +#endif // MATH_UTILS_H + diff --git a/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/mesh.cpp b/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/mesh.cpp new file mode 100644 index 000000000..5461f1271 --- /dev/null +++ b/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/mesh.cpp @@ -0,0 +1,233 @@ +/******************************************************************************* + Copyright (c) 2021, Andrea Maggiordomo, Paolo Cignoni and Marco Tarini + + This file is part of TextureDefrag, a reference implementation for + the paper ``Texture Defragmentation for Photo-Reconstructed 3D Models'' + by Andrea Maggiordomo, Paolo Cignoni and Marco Tarini. + + TextureDefrag is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + TextureDefrag is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with TextureDefrag. If not, see . +*******************************************************************************/ + +#include +#include + +#include "gl_utils.h" // required for obj importer to use glu::tessellator + +#include +#include + +#include + +#include +#include +#include +#include + +#include "mesh.h" +#include "texture_object.h" +#include "timer.h" +#include "utils.h" +#include "logging.h" + +bool LoadMesh(const char *fileName, Mesh& m, TextureObjectHandle& textureObject, int &loadMask) +{ + m.Clear(); + textureObject = std::make_shared(); + loadMask = 0; + + QFileInfo fi(fileName); + fi.makeAbsolute(); + + if (!fi.exists() || !fi.isReadable()) { + LOG_ERR << "Unable to read " << fileName; + return false; + } + + std::string dirname = fi.dir().dirName().toStdString(); + m.name = dirname + "_" + fi.fileName().toStdString(); + + QString wd = QDir::currentPath(); + QDir::setCurrent(fi.absoluteDir().absolutePath()); + + int r = tri::io::Importer::Open(m, fi.fileName().toStdString().c_str(), loadMask); + if (tri::io::Importer::ErrorCritical(r)) { + LOG_ERR << tri::io::Importer::ErrorMsg(r); + return false; + } else if (r) { + LOG_WARN << tri::io::Importer::ErrorMsg(r); + } + + for (auto& f : m.face) + f.SetMesh(); + + LOG_INFO << "Loaded mesh " << fileName << " (VN " << m.VN() << ", FN " << m.FN() << ")"; + + for (const string& textureName : m.textures) { + QFileInfo textureFile(textureName.c_str()); + textureFile.makeAbsolute(); + if (!textureFile.exists() || !textureFile.isReadable()) { + LOG_ERR << "Error: Texture file " << textureName.c_str() << " does not exist or is not readable."; + return false; + } + + if (!textureObject->AddImage(textureFile.absoluteFilePath().toStdString())) { + LOG_ERR << "Error: Unable to load texture file " << textureName.c_str(); + return false; + } + } + + QDir::setCurrent(wd); + return true; +} + +bool SaveMesh(const char *fileName, Mesh& m, const std::vector>& textureImages, bool color) +{ + int mask = tri::io::Mask::IOM_WEDGTEXCOORD; + + m.textures.clear(); + for (std::size_t i = 0; i < textureImages.size(); ++i) { + std::stringstream suffix; + suffix << "_texture_" << i << ".png"; + std::string s(fileName); + m.textures.push_back(s.substr(0, s.find_last_of('.')).append(suffix.str())); + } + + Timer t; + LOG_INFO << "Saving mesh file " << fileName; + if (color) mask = mask | tri::io::Mask::IOM_FACEQUALITY | tri::io::Mask::IOM_FACECOLOR; + int err; + if ((err = tri::io::Exporter::Save(m, fileName, mask))) { + LOG_ERR << "Error: " << tri::io::Exporter::ErrorMsg(err); + return false; + } + LOG_INFO << "Saving mesh took " << t.TimeElapsed() << " seconds"; + + QFileInfo fi(fileName); + ensure (fi.exists()); + + QString wd = QDir::currentPath(); + QDir::setCurrent(fi.absoluteDir().absolutePath()); + + t.Reset(); + LOG_INFO << "Saving texture files... "; + for (std::size_t i = 0; i < textureImages.size(); ++i) { + if (textureImages[i]->save(m.textures[i].c_str(), "png", 66) == false) { + LOG_ERR << "Error saving texture file " << m.textures[i]; + return false; + } + } + LOG_INFO << "Writing textures took " << t.TimeElapsed() << " seconds"; + + QDir::setCurrent(wd); + return true; +} + +void ScaleTextureCoordinatesToImage(Mesh& m, TextureObjectHandle textureObject) +{ + for (auto& f : m.face) { + int ti = f.WT(0).N(); + for (int i = 0; i < f.VN(); ++i) { + f.WT(i).P().X() *= (ti < (int) textureObject->ArraySize()) ? textureObject->TextureWidth(ti) : 1.0; + f.WT(i).P().Y() *= (ti < (int) textureObject->ArraySize()) ? textureObject->TextureHeight(ti) : 1.0; + } + } +} + +void ScaleTextureCoordinatesToParameterArea(Mesh& m, TextureObjectHandle textureObject) +{ + for (auto& f : m.face) { + int ti = f.WT(0).N(); + for (int i = 0; i < f.VN(); ++i) { + f.WT(i).P().X() /= (ti < (int) textureObject->ArraySize()) ? textureObject->TextureWidth(ti) : 1.0; + f.WT(i).P().Y() /= (ti < (int) textureObject->ArraySize()) ? textureObject->TextureHeight(ti) : 1.0; + } + } +} + +Box2d UVBox(const Mesh& m) +{ + Box2d uvbox; + for(auto const& f : m.face) { + for (int i = 0; i < 3; ++i) { + uvbox.Add(f.cWT(i).P()); + } + } + return uvbox; +} + +Box2d UVBoxVertex(const Mesh& m) +{ + Box2d uvbox; + for(auto const& f : m.face) { + for (int i = 0; i < 3; ++i) { + uvbox.Add(f.cV(i)->T().P()); + } + } + return uvbox; +} + +/* Utility functions for AttributeSeam */ +static inline void vExt(const Mesh& msrc, const MeshFace& f, int k, const Mesh& mdst, MeshVertex& v) +{ + (void) msrc; + (void) mdst; + v.ImportData(*(f.cV(k))); + v.T() = f.cWT(k); +} + +static inline bool vCmp(const Mesh& mdst, const MeshVertex& v1, const MeshVertex& v2) +{ + (void) mdst; + return v1.T() == v2.T(); +} + +void CutAlongSeams(Mesh& m) +{ + tri::AttributeSeam::SplitVertex(m, vExt, vCmp); + tri::Allocator::CompactVertexVector(m); + tri::UpdateTopology::FaceFace(m); + tri::UpdateTopology::VertexFace(m); +} + +void MeshFromFacePointers(const std::vector& vfp, Mesh& out) +{ + out.Clear(); + std::unordered_map vpmap; + vpmap.reserve(vfp.size() * 2); + std::size_t vn = 0; + for (auto fptr : vfp) { + for (int i = 0; i < 3; ++i) { + if (vpmap.count(fptr->V(i)) == 0) { + vn++; + vpmap[fptr->V(i)] = nullptr; + } + } + } + auto mvi = tri::Allocator::AddVertices(out, vn); + auto mfi = tri::Allocator::AddFaces(out, vfp.size()); + for (auto fptr : vfp) { + Mesh::FacePointer mfp = &*mfi++; + for (int i = 0; i < 3; ++i) { + Mesh::VertexPointer vp = fptr->V(i); + typename Mesh::VertexPointer& mvp = vpmap[vp]; + if (mvp == nullptr) { + mvp = &*mvi++; + mvp->P() = vp->P(); + } + mfp->V(i) = mvp; + mfp->WT(i) = fptr->WT(i); + } + mfp->SetMesh(); + } +} diff --git a/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/mesh.h b/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/mesh.h new file mode 100644 index 000000000..137751613 --- /dev/null +++ b/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/mesh.h @@ -0,0 +1,144 @@ +/******************************************************************************* + Copyright (c) 2021, Andrea Maggiordomo, Paolo Cignoni and Marco Tarini + + This file is part of TextureDefrag, a reference implementation for + the paper ``Texture Defragmentation for Photo-Reconstructed 3D Models'' + by Andrea Maggiordomo, Paolo Cignoni and Marco Tarini. + + TextureDefrag is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + TextureDefrag is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with TextureDefrag. If not, see . +*******************************************************************************/ + +#ifndef MESH_H +#define MESH_H + +#include + +#include +#include + +#include + +#include "types.h" + + +typedef vcg::face::Pos PosF; + + +using namespace vcg; + + +/* per face extra flags, defined according to the vcg style */ +template +class FaceQualifier : public T { + +public: + + FaceQualifier() : _qualifier(0) {} + + void SetMesh() { _qualifier = MESH; } + void SetHoleFilling() { _qualifier = HOLE_FILLING; } + void SetScaffold() { _qualifier = SCAFFOLD; } + + bool IsMesh() const { return _qualifier == MESH; } + bool IsHoleFilling() const { return _qualifier == HOLE_FILLING; } + bool IsScaffold() const { return _qualifier == SCAFFOLD; } + + template + void ImportData(const RType& rhs) { + assert(rhs.HasQualifier() && "RHS NOT COMPATIBLE"); + _qualifier = rhs._qualifier; + T::ImportData(rhs); + } + void Alloc(const int & ns) { T::Alloc(ns); } + void Dealloc() { T::Dealloc(); } + static bool HasQualifier() { return true; } + static void Name(std::vector & name) { + name.push_back(std::string("FaceQualifier")); + T::Name(name); + } + +private: + static constexpr unsigned char MESH = 1; + static constexpr unsigned char HOLE_FILLING = 2; + static constexpr unsigned char SCAFFOLD = 3; + + unsigned char _qualifier; +}; + +struct MeshUsedTypes : public UsedTypes::AsVertexType, Use::AsFaceType, Use::AsEdgeType> {}; + +class MeshVertex : public Vertex {}; +class MeshFace : public Face +{ +public: + RegionID id = INVALID_ID; + RegionID initialId = INVALID_ID; +}; + +class MeshEdge : public Edge {}; +class Mesh : public tri::TriMesh, std::vector>{ +public: + std::string name{"mesh"}; + + ~Mesh() + { + ClearAttributes(); + } +}; + +struct SeamUsedTypes : public UsedTypes::AsVertexType, Use::AsEdgeType/*, Use::AsFaceType*/>{}; + +class SeamVertex : public Vertex< SeamUsedTypes, vertex::Coord3d, vertex::Normal3d, vertex::Color4b, vertex::VEAdj, vertex::VFAdj,vertex::BitFlags >{}; +class SeamEdge : public Edge< SeamUsedTypes, edge::VertexRef, edge::VEAdj, edge::EEAdj, edge::Color4b, edge::BitFlags> { +public: + Mesh::FacePointer fa; + Mesh::FacePointer fb; + int ea; + int eb; +}; +//class SeamFace : public Face < SeamUsedTypes, face::VertexRef, face::VFAdj, face::FFAdj, face::Mark, face::Color4b, face::BitFlags > {}; +class SeamMesh : public tri::TriMesh< std::vector, std::vector/*, std::vector */>{}; + +bool LoadMesh(const char *fileName, Mesh& m, TextureObjectHandle& textureObject, int &loadMask); +bool SaveMesh(const char *fileName, Mesh& m, const std::vector>& textureImages, bool color); + +void ScaleTextureCoordinatesToImage(Mesh& m, TextureObjectHandle textureObject); +void ScaleTextureCoordinatesToParameterArea(Mesh& m, TextureObjectHandle textureObject); + +vcg::Box2d UVBox(const Mesh& m); +vcg::Box2d UVBoxVertex(const Mesh& m); + +/* Duplicates vertices at seams */ +void CutAlongSeams(Mesh& m); + +/* Builds a mesh from a given vector of face pointers. The order of the faces + * is guaranteed to be preserved in the face container of the mesh. */ +void MeshFromFacePointers(const std::vector& vfp, Mesh& out); + +inline double AreaUV(const Mesh::FaceType& f) +{ + vcg::Point2d u0 = f.cWT(0).P(); + vcg::Point2d u1 = f.cWT(1).P(); + vcg::Point2d u2 = f.cWT(2).P(); + return ((u1 - u0) ^ (u2 - u0)) / 2.0; +} + + +inline double Area3D(const Mesh::FaceType& f) +{ + return ((f.cP(1) - f.cP(0)) ^ (f.cP(2) - f.cP(0))).Norm() / 2.0; +} + + +#endif // MESH_H diff --git a/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/mesh_attribute.cpp b/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/mesh_attribute.cpp new file mode 100644 index 000000000..49ef006ba --- /dev/null +++ b/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/mesh_attribute.cpp @@ -0,0 +1,83 @@ +/******************************************************************************* + Copyright (c) 2021, Andrea Maggiordomo, Paolo Cignoni and Marco Tarini + + This file is part of TextureDefrag, a reference implementation for + the paper ``Texture Defragmentation for Photo-Reconstructed 3D Models'' + by Andrea Maggiordomo, Paolo Cignoni and Marco Tarini. + + TextureDefrag is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + TextureDefrag is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with TextureDefrag. If not, see . +*******************************************************************************/ + +#include "mesh_attribute.h" +#include "math_utils.h" +#include "logging.h" + +void Compute3DFaceAdjacencyAttribute(Mesh& m) +{ + auto ffadj = Get3DFaceAdjacencyAttribute(m); + tri::UpdateTopology::FaceFace(m); + for (auto& f : m.face) { + for (int i = 0; i < 3; ++i) { + ffadj[f].f[i] = tri::Index(m, f.FFp(i)); + ffadj[f].e[i] = f.FFi(i); + } + } +} + +void ComputeWedgeTexCoordStorageAttribute(Mesh& m) +{ + auto WTCSh = GetWedgeTexCoordStorageAttribute(m); + for (auto &f : m.face) { + for (int i = 0; i < 3; ++i) { + WTCSh[&f].tc[i].P() = f.WT(i).P(); + WTCSh[&f].tc[i].N() = f.WT(i).N(); + } + } +} + +// assumes topology is updated (FaceFace) +void ComputeBoundaryInfoAttribute(Mesh& m) +{ + BoundaryInfo& info = (tri::Allocator::GetPerMeshAttribute(m, "MeshAttribute_BoundaryInfo"))(); + info.Clear(); + tri::UpdateFlags::FaceClearV(m); + for (auto& f : m.face) { + for (int i = 0; i < 3; ++i) { + if (!f.IsV() && face::IsBorder(f, i)) { + double totalBorderLength = 0; + std::vector borderFaces; + std::vector vi; + + face::Pos p(&f, i); + face::Pos startPos = p; + ensure(p.IsBorder()); + do { + ensure(p.IsManifold()); + p.F()->SetV(); + borderFaces.push_back(tri::Index(m, p.F())); + vi.push_back(p.VInd()); + totalBorderLength += EdgeLength(*p.F(), p.VInd()); + p.NextB(); + } while (p != startPos); + info.vBoundaryLength.push_back(totalBorderLength); + info.vBoundarySize.push_back(borderFaces.size()); + info.vBoundaryFaces.push_back(borderFaces); + info.vVi.push_back(vi); + } + } + } + + LOG_DEBUG << "Mesh has " << info.N() << " boundaries"; +} + diff --git a/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/mesh_attribute.h b/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/mesh_attribute.h new file mode 100644 index 000000000..b96c93fd5 --- /dev/null +++ b/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/mesh_attribute.h @@ -0,0 +1,168 @@ +/******************************************************************************* + Copyright (c) 2021, Andrea Maggiordomo, Paolo Cignoni and Marco Tarini + + This file is part of TextureDefrag, a reference implementation for + the paper ``Texture Defragmentation for Photo-Reconstructed 3D Models'' + by Andrea Maggiordomo, Paolo Cignoni and Marco Tarini. + + TextureDefrag is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + TextureDefrag is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with TextureDefrag. If not, see . +*******************************************************************************/ + +#ifndef MESH_ATTRIBUTE_H +#define MESH_ATTRIBUTE_H + +#include "mesh.h" +#include "utils.h" + + +struct TexCoordStorage { + vcg::TexCoord2d tc[3]; +}; + +struct CoordStorage { + vcg::Point3d P[3]; +}; + +struct BoundaryInfo { + std::vector vBoundaryLength; + std::vector vBoundarySize; + std::vector> vBoundaryFaces; + std::vector> vVi; // The face boundary vertex indices + + std::size_t N(); + std::size_t LongestBoundary(); + void Clear(); +}; + +inline std::size_t BoundaryInfo::N() +{ + ensure(vBoundaryLength.size() == vBoundarySize.size() && vBoundaryLength.size() == vBoundaryFaces.size()); + return vBoundaryLength.size(); +} + +inline std::size_t BoundaryInfo::LongestBoundary() +{ + ensure(N() > 0); + return std::distance(vBoundaryLength.begin(), + std::max_element(vBoundaryLength.begin(), vBoundaryLength.end())); +} + +inline void BoundaryInfo::Clear() + { + vBoundaryLength.clear(); + vBoundarySize.clear(); + vBoundaryFaces.clear(); + vVi.clear(); +} + +struct FF { + int f[3]; // opposite face index + int e[3]; // opposite edge index +}; + +inline bool IsEdgeManifold3D(Mesh& m, const MeshFace& f, int i, Mesh::PerFaceAttributeHandle& ffadj) +{ + const MeshFace& ff = m.face[ffadj[f].f[i]]; // opposite face + int ffi = ffadj[f].e[i]; // opposite index + return tri::Index(m, f) == ffadj[ff].f[ffi]; +} + +inline Mesh::PerFaceAttributeHandle Get3DFaceAdjacencyAttribute(Mesh& m); +inline Mesh::PerFaceAttributeHandle GetWedgeTexCoordStorageAttribute(Mesh& m); +inline Mesh::PerMeshAttributeHandle GetBoundaryInfoAttribute(Mesh& m); +inline Mesh::PerFaceAttributeHandle GetTargetShapeAttribute(Mesh& shell); +inline Mesh::PerFaceAttributeHandle GetFaceIndexAttribute(Mesh& shell); +inline Mesh::PerFaceAttributeHandle GetShell3DShapeAttribute(Mesh& shell); + +inline bool Has3DFaceAdjacencyAttribute(Mesh& m); +inline bool HasWedgeTexCoordStorageAttribute(Mesh& m); +inline bool HasBoundaryInfoAttribute(Mesh& m); +inline bool HasTargetShapeAttribute(Mesh& shell); +inline bool HasFaceIndexAttribute(Mesh& shell); +inline bool HasShell3DShapeAttribute(Mesh& shell); + +void Compute3DFaceAdjacencyAttribute(Mesh& m); +void ComputeWedgeTexCoordStorageAttribute(Mesh& m); +void ComputeBoundaryInfoAttribute(Mesh& m); + + +inline Mesh::PerFaceAttributeHandle Get3DFaceAdjacencyAttribute(Mesh& m) +{ + return tri::Allocator::GetPerFaceAttribute(m, "FaceAttribute_3DFaceAdjacency"); +} + +inline bool Has3DFaceAdjacencyAttribute(Mesh& m) +{ + return tri::Allocator::IsValidHandle( + m, tri::Allocator::FindPerFaceAttribute(m, "FaceAttribute_3DFaceAdjacency")); +} + +inline Mesh::PerFaceAttributeHandle GetWedgeTexCoordStorageAttribute(Mesh& m) +{ + return tri::Allocator::GetPerFaceAttribute(m, "WedgeTexCoordStorage"); +} + +inline bool HasWedgeTexCoordStorageAttribute(Mesh& m) +{ + return tri::Allocator::IsValidHandle( + m, tri::Allocator::FindPerFaceAttribute(m, "WedgeTexCoordStorage")); +} + +inline Mesh::PerMeshAttributeHandle GetBoundaryInfoAttribute(Mesh& m) +{ + ensure(HasBoundaryInfoAttribute(m)); + return tri::Allocator::GetPerMeshAttribute(m, "MeshAttribute_BoundaryInfo"); +} + +inline bool HasBoundaryInfoAttribute(Mesh& m) +{ + return tri::Allocator::IsValidHandle( + m, tri::Allocator::FindPerMeshAttribute(m, "MeshAttribute_BoundaryInfo")); +} + +inline Mesh::PerFaceAttributeHandle GetTargetShapeAttribute(Mesh& shell) +{ + return tri::Allocator::GetPerFaceAttribute(shell, "FaceAttribute_TargetShape"); +} + +inline bool HasTargetShapeAttribute(Mesh& shell) +{ + return tri::Allocator::IsValidHandle( + shell, tri::Allocator::FindPerFaceAttribute(shell, "FaceAttribute_TargetShape")); +} + +inline Mesh::PerFaceAttributeHandle GetFaceIndexAttribute(Mesh& shell) +{ + return tri::Allocator::GetPerFaceAttribute(shell, "FaceAttribute_FaceIndex"); +} + +inline bool HasFaceIndexAttribute(Mesh& shell) +{ + return tri::Allocator::IsValidHandle( + shell, tri::Allocator::FindPerFaceAttribute(shell, "FaceAttribute_FaceIndex")); +} + +inline Mesh::PerFaceAttributeHandle GetShell3DShapeAttribute(Mesh& shell) +{ + return tri::Allocator::GetPerFaceAttribute(shell, "FaceAttribute_Shell3DShape"); +} + +inline bool HasShell3DShapeAttribute(Mesh& shell) +{ + return tri::Allocator::IsValidHandle( + shell, tri::Allocator::FindPerFaceAttribute(shell, "FaceAttribute_Shell3DShape")); +} + +#endif // MESH_ATTRIBUTE_H + diff --git a/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/mesh_graph.cpp b/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/mesh_graph.cpp new file mode 100644 index 000000000..87854e81d --- /dev/null +++ b/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/mesh_graph.cpp @@ -0,0 +1,470 @@ +/******************************************************************************* + Copyright (c) 2021, Andrea Maggiordomo, Paolo Cignoni and Marco Tarini + + This file is part of TextureDefrag, a reference implementation for + the paper ``Texture Defragmentation for Photo-Reconstructed 3D Models'' + by Andrea Maggiordomo, Paolo Cignoni and Marco Tarini. + + TextureDefrag is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + TextureDefrag is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with TextureDefrag. If not, see . +*******************************************************************************/ + +#include "mesh_graph.h" + +#include "mesh.h" +#include "gl_utils.h" +#include "math_utils.h" +#include "mesh_attribute.h" +#include "timer.h" +#include "utils.h" +#include "logging.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + + + +void CopyToMesh(FaceGroup& fg, Mesh& m) +{ + m.Clear(); + auto ia = GetFaceIndexAttribute(m); + std::unordered_map vpmap; + vpmap.reserve(fg.FN() * 3); + std::size_t vn = 0; + for (auto fptr : fg.fpVec) { + for (int i = 0; i < 3; ++i) { + if (vpmap.count(fptr->V(i)) == 0) { + vn++; + vpmap[fptr->V(i)] = nullptr; + } + } + } + auto mvi = tri::Allocator::AddVertices(m, vn); + auto mfi = tri::Allocator::AddFaces(m, fg.FN()); + for (auto fptr : fg.fpVec) { + Mesh::FacePointer mfp = &*mfi++; + ia[mfp] = tri::Index(fg.mesh, fptr); + for (int i = 0; i < 3; ++i) { + Mesh::VertexPointer vp = fptr->V(i); + typename Mesh::VertexPointer& mvp = vpmap[vp]; + if (mvp == nullptr) { + mvp = &*mvi++; + mvp->P() = vp->P(); + mvp->T() = vp->T(); + mvp->C() = vp->C(); + } + mfp->V(i) = mvp; + mfp->WT(i) = fptr->WT(i); + } + mfp->SetMesh(); + } + + LOG_DEBUG << "Built mesh has " << m.FN() << " faces"; +} + +// FaceGroup class implementation +// ============================== + +FaceGroup::FaceGroup(Mesh& m, const RegionID id_) + : mesh{m}, + id{id_}, + fpVec{}, + adj{}, + numMerges{0}, + minMappedFaceValue{-1}, + maxMappedFaceValue{-1}, + error{0}, + dirty{false}, + cache{} +{ +} + +void FaceGroup::Clear() +{ + id = INVALID_ID; + fpVec.clear(); + adj.clear(); + numMerges = 0; + minMappedFaceValue = -1; + maxMappedFaceValue = -1; + error = 0; + dirty = false; + cache = {}; +} + +void FaceGroup::UpdateCache() const +{ + using ::AreaUV; + using ::Area3D; + + double areaUV = 0; + double area3D = 0; + vcg::Point3d weightedSumNormal = vcg::Point3d::Zero(); + for (auto fptr : fpVec) { + areaUV += AreaUV(*fptr); + area3D += Area3D(*fptr); + weightedSumNormal += (fptr->P(1) - fptr->P(0)) ^ (fptr->P(2) ^ fptr->P(0)); + } + + double border3D = 0.0; + double borderUV = 0.0; + for (auto fptr : fpVec) { + for (int i = 0; i < 3; ++i) { + if (face::IsBorder(*fptr, i)) { + border3D += EdgeLength(*fptr, i); + borderUV += EdgeLengthUV(*fptr, i); + } + } + } + + cache.area3D = area3D; + cache.areaUV = std::abs(areaUV); + cache.borderUV = borderUV; + cache.border3D = border3D; + cache.weightedSumNormal = weightedSumNormal; + cache.uvFlipped = (areaUV < 0); + + dirty = false; +} + +vcg::Point3d FaceGroup::AverageNormal() const +{ + if (dirty) + UpdateCache(); + vcg::Point3d avgN = ((cache.weightedSumNormal) / (2.0 * cache.area3D)); + return avgN.Normalize(); +} + +void FaceGroup::AddFace(const Mesh::FacePointer fptr) +{ + fpVec.push_back(fptr); + dirty = true; +} + +double FaceGroup::OriginalAreaUV() const +{ + ensure(HasWedgeTexCoordStorageAttribute(mesh)); + auto wtcsattr = GetWedgeTexCoordStorageAttribute(mesh); + + double doubleAreaUV = 0; + for (auto fptr : fpVec) { + const TexCoordStorage& tcs = wtcsattr[fptr]; + doubleAreaUV += std::abs((tcs.tc[1].P() - tcs.tc[0].P()) ^ (tcs.tc[2].P() - tcs.tc[0].P())); + } + return 0.5 * doubleAreaUV; +} + +double FaceGroup::AreaUV() const +{ + if (dirty) + UpdateCache(); + return cache.areaUV; +} + +double FaceGroup::Area3D() const +{ + if (dirty) + UpdateCache(); + return cache.area3D; +} + +double FaceGroup::BorderUV() const +{ + if (dirty) + UpdateCache(); + return cache.borderUV; +} + +double FaceGroup::Border3D() const +{ + if (dirty) + UpdateCache(); + return cache.border3D; +} + +bool FaceGroup::UVFlipped() const +{ + if (dirty) + UpdateCache(); + return cache.uvFlipped; +} + +vcg::Box2d FaceGroup::UVBox() const +{ + vcg::Box2d box; + for (auto fptr : fpVec) { + box.Add(fptr->WT(0).P()); + box.Add(fptr->WT(1).P()); + box.Add(fptr->WT(2).P()); + } + return box; +} + +bool FaceGroup::UVFlipped() +{ + if (dirty) + UpdateCache(); + return cache.uvFlipped; +} + +void FaceGroup::ParameterizationChanged() +{ + dirty = true; +} + +Mesh::FacePointer FaceGroup::Fp() +{ + ensure(!fpVec.empty()); return fpVec[0]; +} + +std::size_t FaceGroup::FN() const +{ + return fpVec.size(); +} + +std::size_t FaceGroup::NumAdj() const +{ + return adj.size(); +} + +void FaceGroup::UpdateBorder() const +{ + if (dirty) + UpdateCache(); +} + +// MeshGraph class implementation +// ============================== + +MeshGraph::MeshGraph(Mesh& m) + : mesh{m} +{ +} + +MeshGraph::~MeshGraph() +{ + textureObject = nullptr; + // Explicitly remove adjacency handles to remove dangling references + for (auto& entry: charts) { + entry.second->adj.clear(); + } + charts.clear(); +} + +std::pair MeshGraph::DistortionRange() const +{ + std::pair range = std::make_pair(std::numeric_limits::max(), std::numeric_limits::lowest()); + for (const auto& c : charts) { + range.first = std::min(c.second->minMappedFaceValue, range.first); + range.second = std::max(c.second->maxMappedFaceValue, range.second); + } + return range; +} + +std::shared_ptr MeshGraph::GetChart(RegionID i) +{ + //ensure(charts.find(i) != charts.end() && "Chart does not exist"); + auto e = charts.find(i); + if (e != charts.end()) return e->second; + else return nullptr; +} + +std::shared_ptr MeshGraph::GetChart_Insert(RegionID i) +{ + if (charts.find(i) == charts.end()) charts.insert(std::make_pair(i, std::make_shared(mesh, i))); + return charts[i]; +} + +std::size_t MeshGraph::Count() const +{ + return charts.size(); +} + +int MeshGraph::MergeCount() const +{ + int n = 0; + for (const auto& c : charts) n += c.second->numMerges; + return n; + +} + +double MeshGraph::Area3D() const +{ + double area3D = 0; + for (const auto& c : charts) area3D += c.second->Area3D(); + return area3D; +} + +double MeshGraph::MappedFraction() const +{ + double area3D = 0; + double mappedArea3D = 0; + for (const auto& c : charts) { + area3D += c.second->Area3D(); + if (c.second->AreaUV() > 0) + mappedArea3D += c.second->Area3D(); + } + return mappedArea3D / area3D; +} + +double MeshGraph::AreaUV() const +{ + double areaUV = 0; + for (const auto& c : charts) areaUV += c.second->AreaUV(); + return areaUV; +} + +double MeshGraph::SignedAreaUV() const +{ + double areaUV = 0; + for (const auto& c : charts) + areaUV += (c.second->UVFlipped() ? -1 : 1) * c.second->AreaUV(); + return areaUV; +} + +double MeshGraph::BorderUV() const +{ + double borderUV = 0; + for (const auto& c : charts) borderUV += c.second->BorderUV(); + return borderUV; +} + +GraphHandle ComputeGraph(Mesh &m, TextureObjectHandle textureObject) +{ + // visit the connected components and assign chart ids + tri::UpdateFlags::FaceClearV(m); + RegionID id = 0; + for (auto& f : m.face) { + if (!f.IsV()) { + // visit the connected component + std::stack s; + s.push(&f); + while (!s.empty()) { + Mesh::FacePointer fp = s.top(); + s.pop(); + fp->SetV(); + fp->id = id; + fp->initialId = id; + for (int i = 0; i < 3; ++i) { + Mesh::FacePointer ffp = fp->FFp(i); + if (!ffp->IsV()) + s.push(ffp); + } + } + id++; + } + } + + GraphHandle graph = std::make_shared(m); + graph->textureObject = textureObject; + + auto ffadj = Get3DFaceAdjacencyAttribute(m); + + tri::UpdateTopology::FaceFace(m); + for (auto &f : m.face) { + RegionID regionId = f.id; + graph->GetChart_Insert(regionId)->AddFace(&f); + for (int i = 0; i < f.VN(); ++i) { + if (IsEdgeManifold3D(m, f, i, ffadj)) { + RegionID adjId = m.face[ffadj[f].f[i]].id; + if (regionId != adjId) { + (graph->GetChart_Insert(regionId)->adj).insert(graph->GetChart_Insert(adjId)); + } + } + } + } + + return graph; +} + +void DisconnectCharts(GraphHandle graph) +{ + typedef std::pair VertexRID; + + Mesh& m = graph->mesh; + + int numExtraVertices = 0; + std::map remap; + + tri::UpdateFlags::VertexClearV(m); + for (auto& c : graph->charts) { + std::set vset; + for (auto fptr : c.second->fpVec) { + for (int i = 0; i < 3; ++i) { + vset.insert(fptr->V(i)); + } + } + for (auto vp : vset) { + if (vp->IsV()) { + numExtraVertices++; + remap[std::make_pair(tri::Index(m, vp), c.first)] = -1; + } + vp->SetV(); + } + } + + auto vi = tri::Allocator::AddVertices(m, numExtraVertices); + + tri::UpdateFlags::VertexClearV(m); + + for (auto& entry : remap) { + VertexRID vrid = entry.first; + vi->ImportData(m.vert[vrid.first]); + m.vert[vrid.first].SetV(); + + ensure(entry.second == -1); + entry.second = tri::Index(m, *vi); + vi++; + } + int updated = 0; + int iters = 0; + for (auto& c : graph->charts) { + for (auto fptr : c.second->fpVec) { + for (int i = 0; i < 3; ++i) { + VertexRID vrid = std::make_pair(tri::Index(m, fptr->V(i)), c.first); + iters++; + if (fptr->V(i)->IsV() && remap.count(vrid) > 0) { + int vind = remap[vrid]; + fptr->V(i) = &m.vert[vind]; + updated++; + } + } + } + } + + // safety check + tri::UpdateFlags::VertexClearV(m); + for (auto& c : graph->charts) { + std::set vset; + for (auto fptr : c.second->fpVec) { + for (int i = 0; i < 3; ++i) { + vset.insert(fptr->V(i)); + } + } + for (auto vp : vset) { + ensure(!vp->IsV()); + vp->SetV(); + } + } +} diff --git a/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/mesh_graph.h b/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/mesh_graph.h new file mode 100644 index 000000000..0855186a1 --- /dev/null +++ b/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/mesh_graph.h @@ -0,0 +1,156 @@ +/******************************************************************************* + Copyright (c) 2021, Andrea Maggiordomo, Paolo Cignoni and Marco Tarini + + This file is part of TextureDefrag, a reference implementation for + the paper ``Texture Defragmentation for Photo-Reconstructed 3D Models'' + by Andrea Maggiordomo, Paolo Cignoni and Marco Tarini. + + TextureDefrag is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + TextureDefrag is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with TextureDefrag. If not, see . +*******************************************************************************/ + +#ifndef MESH_GRAPH_H +#define MESH_GRAPH_H + +#include +#include +#include +#include +#include + +#include + +#include "types.h" +#include "mesh.h" +#include "math_utils.h" + +class Mesh; + +typedef std::pair ChartPair; + +/* FaceGroup class + * Used to store a mesh chart as an array of Face pointers */ +struct FaceGroup { + + struct Hasher { + std::size_t operator()(const ChartHandle& ch) const + { + return std::hash()(ch->id); + } + }; + + struct Cache { + double areaUV; + double area3D; + double borderUV; + double border3D; + vcg::Point3d weightedSumNormal; + bool uvFlipped; + }; + + void UpdateCache() const; + + Mesh& mesh; + RegionID id; + std::vector fpVec; + std::unordered_set adj; + + int numMerges; + + float minMappedFaceValue; + float maxMappedFaceValue; + + double error; + + mutable bool dirty; + mutable Cache cache; + + FaceGroup(Mesh& m, const RegionID id_); + + void Clear(); + void AddFace(const Mesh::FacePointer fptr); + void ParameterizationChanged(); + Mesh::FacePointer Fp(); + + vcg::Point3d AverageNormal() const; + + std::size_t FN() const; + std::size_t NumAdj() const; + double OriginalAreaUV() const; + double AreaUV() const; + double Area3D() const; + double BorderUV() const; + double Border3D() const; + bool UVFlipped() const; + vcg::Box2d UVBox() const; + + bool UVFlipped(); + + void UpdateBorder() const; +}; + +/* Constructs a mesh from a FaceGroup, the created mesh has the FaceIndex + * attribute defined (see mesh_attribute.h) */ +void CopyToMesh(FaceGroup& fg, Mesh& m); + +/* Computes the mesh graph relying on the pre-computed FF adjacency attribute + * to determine chart adjacency relations */ +GraphHandle ComputeGraph(Mesh &m, TextureObjectHandle textureObject); + +/* This function ensures that the vertices referenced by each chart are unique + * to the chart. Necessary because non-manifold vertices adjacent to + * non-manifold edges cannot be split by the VCG's SplitNonManifoldVertices() */ +void DisconnectCharts(GraphHandle graph); + +/* + * MeshGraph class + * + * The graph is actually stored as an associative array mapping each Region id to the relative FaceGroup, the adjacencies + * are recorded inside each FaceGroup + */ +struct MeshGraph { + + Mesh& mesh; + + std::unordered_map charts; + TextureObjectHandle textureObject; + + MeshGraph(Mesh& m); + ~MeshGraph(); + + /* compute the minmax distortion of the graph */ + std::pair DistortionRange() const; + + /* Retrieve region i (ensure if not found) */ + std::shared_ptr GetChart(RegionID i); + + /* Retrieve region i, creating if it is not found */ + std::shared_ptr GetChart_Insert(RegionID i); + + /* Number of regions */ + std::size_t Count() const; + + /* Number of merges performed on the graph (is it used?) */ + int MergeCount() const; + + double Area3D() const; + double AreaUV() const; + double SignedAreaUV() const; + + double MappedFraction() const; + + double BorderUV() const; + +}; + +#endif // MESH_GRAPH_H diff --git a/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/packing.cpp b/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/packing.cpp new file mode 100644 index 000000000..effb1ec96 --- /dev/null +++ b/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/packing.cpp @@ -0,0 +1,328 @@ +/******************************************************************************* + Copyright (c) 2021, Andrea Maggiordomo, Paolo Cignoni and Marco Tarini + + This file is part of TextureDefrag, a reference implementation for + the paper ``Texture Defragmentation for Photo-Reconstructed 3D Models'' + by Andrea Maggiordomo, Paolo Cignoni and Marco Tarini. + + TextureDefrag is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + TextureDefrag is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with TextureDefrag. If not, see . +*******************************************************************************/ + +#include "packing.h" +#include "texture_object.h" +#include "mesh_graph.h" +#include "logging.h" +#include "utils.h" +#include "mesh_attribute.h" + +#include +#include +#include +//#include + +typedef vcg::RasterizedOutline2Packer RasterizationBasedPacker; + + +int Pack(const std::vector& charts, TextureObjectHandle textureObject, std::vector& texszVec) +{ + // Pack the atlas + + texszVec.clear(); + + std::vector outlines; + + for (auto c : charts) { + // Save the outline of the parameterization for this portion of the mesh + Outline2f outline = ExtractOutline2f(*c); + outlines.push_back(outline); + } + + int packingSize = 4096; + std::vector> trs = textureObject->ComputeRelativeSizes(); + + std::vector containerVec; + for (auto rs : trs) { + vcg::Point2i container(packingSize * rs.first, packingSize * rs.second); + containerVec.push_back(container); + } + + // compute the scale factor for the packing + int packingArea = 0; + int textureArea = 0; + for (unsigned i = 0; i < containerVec.size(); ++i) { + packingArea += containerVec[i].X() * containerVec[i].Y(); + textureArea += textureObject->TextureWidth(i) * textureObject->TextureHeight(i); + } + double packingScale = std::sqrt(packingArea / (double) textureArea); + + RasterizationBasedPacker::Parameters packingParams; + packingParams.costFunction = RasterizationBasedPacker::Parameters::LowestHorizon; + packingParams.doubleHorizon = false; + packingParams.innerHorizon = true; + //packingParams.permutations = false; + packingParams.permutations = (charts.size() < 50); + packingParams.rotationNum = 4; + packingParams.gutterWidth = 4; + packingParams.minmax = false; // not used + + int totPacked = 0; + + std::vector containerIndices(outlines.size(), -1); // -1 means not packed to any container + + std::vector packingTransforms(outlines.size(), vcg::Similarity2f{}); + + unsigned nc = 0; // current container index + while (totPacked < (int) charts.size()) { + if (nc >= containerVec.size()) + containerVec.push_back(vcg::Point2i(packingSize, packingSize)); + + std::vector outlineIndex_iter; + std::vector outlines_iter; + for (unsigned i = 0; i < containerIndices.size(); ++i) { + if (containerIndices[i] == -1) { + outlineIndex_iter.push_back(i); + outlines_iter.push_back(outlines[i]); + } + } + + const int MAX_SIZE = 20000; + std::vector transforms; + std::vector polyToContainer; + int n = 0; + do { + transforms.clear(); + polyToContainer.clear(); + LOG_INFO << "Packing into grid of size " << containerVec[nc].X() << " " << containerVec[nc].Y(); + n = RasterizationBasedPacker::PackBestEffortAtScale(outlines_iter, {containerVec[nc]}, transforms, polyToContainer, packingParams, packingScale); + if (n == 0) { + containerVec[nc].X() *= 1.1; + containerVec[nc].Y() *= 1.1; + } + } while (n == 0 && containerVec[nc].X() <= MAX_SIZE && containerVec[nc].Y() <= MAX_SIZE); + + totPacked += n; + + if (n == 0) // no charts were packed, stop + break; + else { + double textureScale = 1.0 / packingScale; + texszVec.push_back({(int) (containerVec[nc].X() * textureScale), (int) (containerVec[nc].Y() * textureScale)}); + for (unsigned i = 0; i < outlines_iter.size(); ++i) { + if (polyToContainer[i] != -1) { + ensure(polyToContainer[i] == 0); // We only use a single container + int outlineInd = outlineIndex_iter[i]; + ensure(containerIndices[outlineInd] == -1); + containerIndices[outlineInd] = nc; + packingTransforms[outlineInd] = transforms[i]; + } + } + } + nc++; + } + + for (unsigned i = 0; i < charts.size(); ++i) { + for (auto fptr : charts[i]->fpVec) { + int ic = containerIndices[i]; + if (ic < 0) { + for (int j = 0; j < fptr->VN(); ++j) { + fptr->V(j)->T().P() = Point2d::Zero(); + fptr->V(j)->T().N() = 0; + fptr->WT(j).P() = Point2d::Zero(); + fptr->WT(j).N() = 0; + } + } + else { + Point2i gridSize = containerVec[ic]; + for (int j = 0; j < fptr->VN(); ++j) { + Point2d uv = fptr->WT(j).P(); + Point2f p = packingTransforms[i] * (Point2f(uv[0], uv[1])); + p.X() /= (double) gridSize.X(); + p.Y() /= (double) gridSize.Y(); + fptr->V(j)->T().P() = Point2d(p.X(), p.Y()); + fptr->V(j)->T().N() = ic; + fptr->WT(j).P() = fptr->V(j)->T().P(); + fptr->WT(j).N() = fptr->V(j)->T().N(); + } + } + } + } + + for (auto c : charts) + c->ParameterizationChanged(); + + return totPacked; +} + +Outline2f ExtractOutline2f(FaceGroup& chart) +{ + Outline2d outline2d = ExtractOutline2d(chart); + Outline2f outline2f; + for (auto& p : outline2d) { + outline2f.push_back(vcg::Point2f(p.X(), p.Y())); + } + return outline2f; +} + +Outline2d ExtractOutline2d(FaceGroup& chart) +{ + //ensure(chart.numMerges == 0); + + std::vector outline2Vec; + Outline2d outline; + + for (auto fptr : chart.fpVec) + fptr->ClearV(); + + for (auto fptr : chart.fpVec) { + for (int i = 0; i < 3; ++i) { + if (!fptr->IsV() && face::IsBorder(*fptr, i)) { + face::Pos p(fptr, i); + face::Pos startPos = p; + ensure(p.IsBorder()); + do { + ensure(p.IsManifold()); + p.F()->SetV(); + vcg::Point2d uv = p.F()->WT(p.VInd()).P(); + outline.push_back(uv); + p.NextB(); + } + while (p != startPos); + outline2Vec.push_back(outline); + outline.clear(); + } + } + } + + vcg::Box2d box = chart.UVBox(); + + int outlineIndex = -1; + double largestArea = 0; + + for (int i = 0; i < outline2Vec.size(); ++i) { + double outlineArea = tri::OutlineUtil::Outline2Area(outline2Vec[i]); + if (outlineArea < 0) + tri::OutlineUtil::ReverseOutline2(outline2Vec[i]); + if (std::abs(outlineArea) >= largestArea) { + vcg::Box2d outlineBox; + for (const auto& p : outline2Vec[i]) + outlineBox.Add(p); + if (outlineBox.DimX() >= box.DimX() && outlineBox.DimY() >= box.DimY()) { + outlineIndex = i; + largestArea = std::abs(outlineArea); + } + } + } + + if (outlineIndex == -1) { + LOG_WARN << "Outline not bounding, falling back to UV bounding box for chart " << chart.id; + outline.clear(); + outline.push_back(Point2d(box.min.X(), box.min.Y())); + outline.push_back(Point2d(box.max.X(), box.min.Y())); + outline.push_back(Point2d(box.max.X(), box.max.Y())); + outline.push_back(Point2d(box.min.X(), box.max.Y())); + return outline; + } else { + return outline2Vec[outlineIndex]; + } + +} + +void IntegerShift(Mesh& m, const std::vector& chartsToPack, const std::vector& texszVec, const std::map& anchorMap, const std::map& flippedInput) +{ + // compute grid-preserving translation + // for each chart + // - find an anchor vertex (i.e. find a vertex that belonged to the + // source chart that determined the integer translation of the final chart. + // - compute the displacement of this anchor vertex wrt the integer pixel coordinates + // both in its original configuration (t0) and in the final, packed chart (t1) + // - compute the translation vector t = t0 - t1 + // - apply the translation t to the entire chart + + ensure(HasWedgeTexCoordStorageAttribute(m)); + auto wtcsh = GetWedgeTexCoordStorageAttribute(m); + + std::vector angle = { 0, M_PI_2, M_PI, (M_PI_2 + M_PI) }; + + auto Rotate = [] (vcg::Point2d p, double theta) -> vcg::Point2d { return p.Rotate(theta); }; + + for (auto c : chartsToPack) { + auto it = anchorMap.find(c); + if (it != anchorMap.end()) { + Mesh::FacePointer fptr = &(m.face[it->second]); + bool flipped = flippedInput.at(fptr->initialId); + + vcg::Point2d d0 = wtcsh[fptr].tc[1].P() - wtcsh[fptr].tc[0].P(); + vcg::Point2d d1 = fptr->cWT(1).P() - fptr->cWT(0).P(); + + if (flipped) + d0.X() *= -1; + + double minResidual = 2 * M_PI; + int minResidualIndex = -1; + for (int i = 0; i < 4; ++i) { + double residual = VecAngle(Rotate(d0, angle[i]), d1); + if (residual < minResidual) { + minResidual = residual; + minResidualIndex = i; + } + } + + int ti = fptr->cWT(0).N(); + ensure(ti < (int) texszVec.size()); + vcg::Point2d textureSize(texszVec[ti].w, texszVec[ti].h); + + vcg::Point2d u0 = wtcsh[fptr].tc[0].P(); + vcg::Point2d u1 = fptr->cWT(0).P(); + + double unused; + double dx = std::modf(u0.X(), &unused); + double dy = std::modf(u0.Y(), &unused); + + if (flipped) + dx = 1 - dx; + + switch(minResidualIndex) { + case 0: + break; + case 1: + std::swap(dx, dy); + dx = 1 - dx; + break; + case 2: + dx = 1 - dx; + dy = 1 - dy; + break; + case 3: + std::swap(dx, dy); + dy = 1 - dy; + break; + default: + ensure(0 && "VERY BAD"); + } + + double dx1 = std::modf(u1.X() * textureSize.X(), &unused); + double dy1 = std::modf(u1.Y() * textureSize.Y(), &unused); + vcg::Point2d t(0, 0); + t.X() = (dx - dx1) / textureSize.X(); + t.Y() = (dy - dy1) / textureSize.Y(); + + for (auto fptr : c->fpVec) { + for (int i = 0; i < 3; ++i) { + fptr->WT(i).P() += t; + fptr->V(i)->T().P() = fptr->WT(i).P(); + } + } + } + } +} diff --git a/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/packing.h b/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/packing.h new file mode 100644 index 000000000..d58fbf0dc --- /dev/null +++ b/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/packing.h @@ -0,0 +1,53 @@ +/******************************************************************************* + Copyright (c) 2021, Andrea Maggiordomo, Paolo Cignoni and Marco Tarini + + This file is part of TextureDefrag, a reference implementation for + the paper ``Texture Defragmentation for Photo-Reconstructed 3D Models'' + by Andrea Maggiordomo, Paolo Cignoni and Marco Tarini. + + TextureDefrag is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + TextureDefrag is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with TextureDefrag. If not, see . +*******************************************************************************/ + +#ifndef PACKING_H +#define PACKING_H + +#include "types.h" + +#include +#include + + +/* Pack the texture atlas encoded in the graph. Assumes the segmentation + * correctly reflects the texture coordinates. + * Returns the actual number of charts packed */ +int Pack(const std::vector& charts, TextureObjectHandle textureObject, std::vector& texszVec); + +/* Computes the UV outline(s) of the given chart. If the chart has no outlines, + * which can happen for some inputs on small closed components that are ignored + * by the reparameterization procedure, it returns as outline the bounding box + * of the chart texture coordinates. + * NOTE: It assumes the face-face topology is computed according to the wedge + * texture coordinates of the chart/mesh */ +Outline2f ExtractOutline2f(FaceGroup& chart); +Outline2d ExtractOutline2d(FaceGroup& chart); + + +void IntegerShift(Mesh& m, + const std::vector& chartsToPack, + const std::vector& texszVec, + const std::map& anchorMap, + const std::map& flippedInput); + + +#endif // PACKING_H diff --git a/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/pushpull.h b/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/pushpull.h new file mode 100644 index 000000000..777657e8d --- /dev/null +++ b/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/pushpull.h @@ -0,0 +1,173 @@ +/**************************************************************************** +* MeshLab o o * +* A versatile mesh processing toolbox o o * +* _ O _ * +* Copyright(C) 2005 \/)\/ * +* Visual Computing Lab /\/| * +* ISTI - Italian National Research Council | * +* \ * +* All rights reserved. * +* * +* This program is free software; you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation; either version 2 of the License, or * +* (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) * +* for more details. * +* * +****************************************************************************/ + +#ifndef _PUSHPULL_H +#define _PUSHPULL_H + +typedef unsigned char byte; + +#include +#include + +namespace vcg +{ + /* pull push filling algorithm */ + + static int mean4w(int p1,byte w1,int p2,byte w2,int p3,byte w3,int p4,byte w4) + { + int result =(p1*int(w1) + p2*int(w2) +p3*int(w3) + p4*int(w4) ) + / ( int(w1)+int(w2)+int(w3)+int(w4) ) ; + return result; + } + + static QRgb mean4Pixelw(QRgb p1,byte w1,QRgb p2,byte w2,QRgb p3,byte w3,QRgb p4,byte w4) + { + int r= mean4w(qRed(p1),w1,qRed(p2),w2,qRed(p3),w3,qRed(p4),w4); + int g= mean4w(qGreen(p1),w1,qGreen(p2),w2,qGreen(p3),w3,qGreen(p4),w4); + int b= mean4w(qBlue(p1),w1,qBlue(p2),w2,qBlue(p3),w3,qBlue(p4),w4); + int a= mean4w(qAlpha(p1),w1,qAlpha(p2),w2,qAlpha(p3),w3,qAlpha(p4),w4); + + return qRgba(r,g,b,a); + + } + + // Genera una mipmap pesata + static void PullPushMip( QImage & p, QImage & mip, QRgb bkcolor ) + { + assert(p.width()/2==mip.width()); + assert(p.height()/2==mip.height()); + byte w1,w2,w3,w4; + int x,y; + for(y=0;y0 ) + mip.setPixel(x, y, mean4Pixelw( + p.pixel(x*2 ,y*2 ),w1, + p.pixel(x*2+1,y*2 ),w2, + p.pixel(x*2 ,y*2+1),w3, + p.pixel(x*2+1,y*2+1),w4 )); + } + } + + // interpola a partire da una mipmap + static void PullPushFill( QImage & p, QImage & mip, QRgb bkg ) + { + assert(p.width()/2==mip.width()); + assert(p.height()/2==mip.height()); + // byte w1,w2,w3,w4; + int x,y; + for(y=0;y0 ? mip.pixel(x-1,y ) : bkg), (x>0 ? byte( 48) : 0), + (y>0 ? mip.pixel(x ,y-1) : bkg), (y>0 ? byte( 48) : 0), + ((x>0 && y>0 )? mip.pixel(x-1,y-1) : bkg), ((x>0 && y>0 )? byte( 16) : 0))); + if(p.pixel(x*2+1,y*2 )==bkg) + p.setPixel(x*2+1,y*2 ,mean4Pixelw(mip.pixel(x ,y ) ,byte(144), + (x0 ? mip.pixel(x ,y-1) : bkg), (y>0 ? byte( 48) : 0), + ((x0) ? mip.pixel(x+1,y-1) : bkg), ((x0) ? byte( 16) : 0))); + if(p.pixel(x*2 ,y*2+1)==bkg) + p.setPixel(x*2 ,y*2+1, mean4Pixelw( mip.pixel(x ,y ), byte(144), + (x>0 ? mip.pixel(x-1,y ) : bkg), (x>0 ? byte( 48) : 0), + (y0 && y0 && y 0 && p.pixel(x, y) == bkg) + p.setPixel(x, y, p.pixel(x-1, y)); + } + } + } + + if ((p.height() % 2) != 0) { + for (y = 2 * mip.height(); y < p.height(); ++y) { + for (x = 0; x < p.width(); ++x) { + if (y > 0 && p.pixel(x, y) == bkg) + p.setPixel(x, y, p.pixel(x, y-1)); + } + } + } + + + } + + + static void PullPush( QImage & p, QRgb bkcolor ) + { + int i=0; + std::vector mip(16); + int div=2; + int miplev=0; + + // pull phase create the mipmap + while(1){ + mip[miplev]= QImage(p.width()/div,p.height()/div,p.format()); + mip[miplev].fill(bkcolor); + div*=2; + if(miplev>0) PullPushMip(mip[miplev-1],mip[miplev],bkcolor); + else PullPushMip(p,mip[miplev],bkcolor); + //if(mip[miplev].width()<=4 || mip[miplev].height()<=4) break; + if(mip[miplev].width()<=1 || mip[miplev].height()<=1) break; + ++miplev; + } + miplev++; +#ifdef _PUSHPULL_DEBUG + for(int k=0;k=0;--i){ + if(i>0) PullPushFill(mip[i-1],mip[i],bkcolor); + else PullPushFill(p,mip[i],bkcolor); + } + +#ifdef _PUSHPULL_DEBUG + for(k=0;k. +*******************************************************************************/ + +#include "seam_remover.h" +#include "mesh.h" +#include "mesh_attribute.h" +#include "mesh_graph.h" +#include "matching.h" +#include "intersection.h" +#include "shell.h" +#include "arap.h" +#include "timer.h" +#include "logging.h" + + +#include +#include +#include + +#include + + +constexpr double PENALTY_MULTIPLIER = 2.0; + + +struct Perf { + double t_init; + double t_seamdata; + double t_alignmerge; + double t_optimization_area; + double t_optimize; + double t_optimize_build; + double t_optimize_arap; + double t_check_before; + double t_check_after; + double t_accept; + double t_reject; + Timer timer; +}; + + +static void InsertNewClusterInQueue(ClusteredSeamHandle csh, AlgoStateHandle state, GraphHandle graph, const AlgoParameters& params); +static CostInfo ComputeCost(ClusteredSeamHandle csh, GraphHandle graph, const AlgoParameters& params, double penalty); +static inline double GetPenalty(ClusteredSeamHandle csh, AlgoStateHandle state); +static inline bool Valid(const WeightedSeam& ws, ConstAlgoStateHandle state); +static inline void PurgeQueue(AlgoStateHandle state); +static void ComputeSeamData(SeamData& sd, ClusteredSeamHandle csh, GraphHandle graph, AlgoStateHandle state); +static OffsetMap AlignAndMerge(ClusteredSeamHandle csh, SeamData& sd, const MatchingTransform& mi, const AlgoParameters& params); +static void ComputeOptimizationArea(SeamData& sd, Mesh& mesh, OffsetMap& om); +static std::unordered_set ComputeVerticesWithinOffsetThreshold(Mesh& m, const OffsetMap& om, const SeamData& sd); +static CheckStatus CheckBoundaryAfterAlignment(SeamData& sd); +static CheckStatus CheckAfterLocalOptimization(SeamData& sd, AlgoStateHandle state, const AlgoParameters& params); +static CheckStatus OptimizeChart(SeamData& sd, GraphHandle graph, bool fixIntersectingEdges); +static void AcceptMove(const SeamData& sd, AlgoStateHandle state, GraphHandle graph, const AlgoParameters& params); +static void RejectMove(const SeamData& sd, AlgoStateHandle state, GraphHandle graph, CheckStatus status); +static void EraseSeam(ClusteredSeamHandle csh, AlgoStateHandle state, GraphHandle graph); +static void InvalidateCluster(ClusteredSeamHandle csh, AlgoStateHandle state, GraphHandle graph, CheckStatus status, double penaltyMultiplier); +static void RestoreChartAttributes(ChartHandle c, Mesh& m, std::vector::const_iterator itvi, std::vector::const_iterator ittc); +static CostInfo ReduceSeam(ClusteredSeamHandle csh, AlgoStateHandle state, GraphHandle graph, const AlgoParameters& params); + + +Perf perf = {}; + +#define PERF_TIMER_RESET (perf = {}, perf.timer.Reset()) +#define PERF_TIMER_START double perf_timer_t0 = perf.timer.TimeElapsed() +#define PERF_TIMER_ACCUMULATE(field) perf.field += perf.timer.TimeElapsed() - perf_timer_t0 +#define PERF_TIMER_ACCUMULATE_FROM_PREVIOUS(field) perf.field += perf.timer.TimeSinceLastCheck() + +//static int statsCheck[10] = {}; +//static int feasibility[6] = {}; + +static std::vector statsCheck(CheckStatus::_END, 0); +static std::vector feasibility(CostInfo::MatchingValue::_END, 0); + +static vcg::Color4b statusColor[] = { + vcg::Color4b::White, // PASS=0, + vcg::Color4b::Gray , // FAIL_LOCAL_OVERLAP, + vcg::Color4b::Red, // FAIL_GLOBAL_OVERLAP_BEFORE, + vcg::Color4b::Green, // FAIL_GLOBAL_OVERLAP_AFTER_OPT, // border of the optimization area self-intersects + vcg::Color4b::LightGreen, // FAIL_GLOBAL_OVERLAP_AFTER_BND, // border of the optimzation area hit the fixed border + vcg::Color4b::LightBlue, // FAIL_DISTORTION_LOCAL, + vcg::Color4b::Blue, // FAIL_DISTORTION_LOCAL, + vcg::Color4b::LightRed, // FAIL_TOPOLOGY + vcg::Color4b::Yellow, // FAIL_NUMERICAL_ERROR + vcg::Color4b::White, // UNKNOWN + vcg::Color4b(176, 0, 255, 255) // FAIL_GLOBAL_OVERLAP_UNFIXABLE +}; + +static vcg::Color4b mvColor[] = { + vcg::Color4b::White, // FEASIBLE=0, + vcg::Color4b::Black, // ZERO_AREA, + vcg::Color4b::Cyan, // UNFEASIBLE_BOUNDARY, + vcg::Color4b::Magenta // UNFEASIBLE_MATCHING, +}; + +static int accept = 0; +static int reject = 0; + +static int num_retry = 0; +static int retry_success = 0; + +double mincost = 100000; +double maxcost = -1; + +double min_energy = 10000000000; +double max_energy = 0; + +static void ClearGlobals() +{ + for (unsigned i = 0; i < statsCheck.size(); ++i) + statsCheck[i] = 0; + for (unsigned i = 0; i < feasibility.size(); ++i) + feasibility[i] = 0; + accept = 0; + reject = 0; + + num_retry = 0; + retry_success = 0; +} + +void LogExecutionStats() +{ + LOG_INFO << "======== EXECUTION STATS ========"; + LOG_INFO << "INIT " << std::fixed << std::setprecision(3) << perf.t_init / perf.timer.TimeElapsed() << " , " << std::defaultfloat << std::setprecision(6)<< perf.t_init << " secs"; + LOG_INFO << "SEAM " << std::fixed << std::setprecision(3) << perf.t_seamdata / perf.timer.TimeElapsed() << " , " << std::defaultfloat << std::setprecision(6)<< perf.t_seamdata << " secs"; + LOG_INFO << "MERGE " << std::fixed << std::setprecision(3) << perf.t_alignmerge / perf.timer.TimeElapsed() << " , " << std::defaultfloat << std::setprecision(6)<< perf.t_alignmerge << " secs"; + LOG_INFO << "AREA OPT " << std::fixed << std::setprecision(3) << perf.t_optimization_area / perf.timer.TimeElapsed() << " , " << std::defaultfloat << std::setprecision(6)<< perf.t_optimization_area << " secs"; + LOG_INFO << "OPTIMIZE " << std::fixed << std::setprecision(3) << perf.t_optimize / perf.timer.TimeElapsed() << " , " << std::defaultfloat << std::setprecision(6)<< perf.t_optimize << " secs"; + LOG_VERBOSE << " BUILD " << std::fixed << std::setprecision(3) << perf.t_optimize_build / perf.timer.TimeElapsed() << " , " << std::defaultfloat << std::setprecision(6)<< perf.t_optimize_build << " secs"; + LOG_VERBOSE << " ARAP " << std::fixed << std::setprecision(3) << perf.t_optimize_arap / perf.timer.TimeElapsed() << " , " << std::defaultfloat << std::setprecision(6)<< perf.t_optimize_arap << " secs"; + LOG_INFO << "CHECK " << std::fixed << std::setprecision(3) << (perf.t_check_before + perf.t_check_after) / perf.timer.TimeElapsed() << " , " << std::defaultfloat << std::setprecision(6)<< (perf.t_check_before + perf.t_check_after) << " secs"; + LOG_VERBOSE << " BEFORE " << std::fixed << std::setprecision(3) << perf.t_check_before / perf.timer.TimeElapsed() << " , " << std::defaultfloat << std::setprecision(6)<< perf.t_check_before << " secs"; + LOG_VERBOSE << " AFTER " << std::fixed << std::setprecision(3) << perf.t_check_after / perf.timer.TimeElapsed() << " , " << std::defaultfloat << std::setprecision(6)<< perf.t_check_after << " secs"; + LOG_INFO << "ACCEPT " << std::fixed << std::setprecision(3) << perf.t_accept / perf.timer.TimeElapsed() << " , " << std::defaultfloat << std::setprecision(6)<< perf.t_accept << " secs"; + LOG_INFO << " count: " << accept; + LOG_INFO << " with retry: " << retry_success; + LOG_VERBOSE << " min energy: " << min_energy; + LOG_VERBOSE << " max energy: " << max_energy; + LOG_INFO << "REJECT " << std::fixed << std::setprecision(3) << perf.t_reject / perf.timer.TimeElapsed() << " , " << std::defaultfloat << std::setprecision(6)<< perf.t_reject << " secs"; + LOG_INFO << " count: " << reject; + LOG_INFO << " with retry: " << num_retry - retry_success; + LOG_VERBOSE << " local overlaps " << statsCheck[FAIL_LOCAL_OVERLAP]; + LOG_VERBOSE << " global overlaps before " << statsCheck[FAIL_GLOBAL_OVERLAP_BEFORE]; + LOG_VERBOSE << " global overlaps after opt " << statsCheck[FAIL_GLOBAL_OVERLAP_AFTER_OPT]; + LOG_VERBOSE << " global overlaps after bnd " << statsCheck[FAIL_GLOBAL_OVERLAP_AFTER_BND]; + LOG_VERBOSE << " global overlaps unfixable " << statsCheck[FAIL_GLOBAL_OVERLAP_UNFIXABLE]; + LOG_VERBOSE << " distortion (local) " << statsCheck[FAIL_DISTORTION_LOCAL]; + LOG_VERBOSE << " distortion (global) " << statsCheck[FAIL_DISTORTION_GLOBAL]; + LOG_VERBOSE << " topology " << statsCheck[FAIL_TOPOLOGY]; + LOG_VERBOSE << " numerical error " << statsCheck[FAIL_NUMERICAL_ERROR]; + LOG_VERBOSE << " FEASIBILITY"; + LOG_VERBOSE << " feasible " << feasibility[CostInfo::FEASIBLE]; + LOG_VERBOSE << " unfeasible boundary " << feasibility[CostInfo::UNFEASIBLE_BOUNDARY]; + LOG_VERBOSE << " unfeasible matching " << feasibility[CostInfo::UNFEASIBLE_MATCHING]; + LOG_INFO << "TOTAL " << std::fixed << std::setprecision(3) << perf.timer.TimeElapsed() / perf.timer.TimeElapsed() << " , " << std::defaultfloat << std::setprecision(6)<< perf.timer.TimeElapsed() << " secs"; + LOG_VERBOSE << "Minimum computed cost is " << mincost; + LOG_VERBOSE << "Maximum computed cost is " << maxcost; + LOG_INFO << "==================================="; +} + +static void PrintStateInfo(AlgoStateHandle state, GraphHandle graph, const AlgoParameters& params) +{ + std::set moveSet; + + for (auto& entry : state->chartSeamMap) { + for (auto csh : entry.second) { + moveSet.insert(csh); + } + } + + LOG_VERBOSE << "Status of the residual " << moveSet.size() << " operations:"; + + int nstat[100] = {}; + int mstat[100] = {}; + for (auto csh : moveSet) { + auto it = state->status.find(csh); + ensure(it != state->status.end()); + ensure(it->second != PASS); + CostInfo ci = ComputeCost(csh, graph, params, GetPenalty(csh, state)); + nstat[state->status[csh]]++; + mstat[ci.mvalue]++; + } + + LOG_VERBOSE << "PASS " << nstat[CheckStatus::PASS]; + LOG_VERBOSE << "FAIL_LOCAL_OVERLAP " << nstat[CheckStatus::FAIL_LOCAL_OVERLAP]; + LOG_VERBOSE << "FAIL_GLOBAL_OVERLAP_BEFORE " << nstat[CheckStatus::FAIL_GLOBAL_OVERLAP_BEFORE]; + LOG_VERBOSE << "FAIL_GLOBAL_OVERLAP_AFTER_OPT " << nstat[CheckStatus::FAIL_GLOBAL_OVERLAP_AFTER_OPT]; + LOG_VERBOSE << "FAIL_GLOBAL_OVERLAP_AFTER_BND " << nstat[CheckStatus::FAIL_GLOBAL_OVERLAP_AFTER_BND]; + LOG_VERBOSE << "FAIL_GLOBAL_OVERLAP_UNFIXABLE " << nstat[CheckStatus::FAIL_GLOBAL_OVERLAP_UNFIXABLE]; + LOG_VERBOSE << "FAIL_DISTORTION_LOCAL " << nstat[CheckStatus::FAIL_DISTORTION_LOCAL]; + LOG_VERBOSE << "FAIL_DISTORTION_GLOBAL " << nstat[CheckStatus::FAIL_DISTORTION_GLOBAL]; + LOG_VERBOSE << "FAIL_TOPOLOGY " << nstat[CheckStatus::FAIL_TOPOLOGY]; + LOG_VERBOSE << "FAIL_NUMERICAL_ERROR " << nstat[CheckStatus::FAIL_NUMERICAL_ERROR]; + LOG_VERBOSE << "UNKNOWN " << nstat[CheckStatus::UNKNOWN]; + LOG_VERBOSE << " - FEASIBLE " << mstat[CostInfo::MatchingValue::FEASIBLE]; + LOG_VERBOSE << " - ZERO_AREA " << mstat[CostInfo::MatchingValue::ZERO_AREA]; + LOG_VERBOSE << " - UNFEASIBLE_BOUNDARY " << mstat[CostInfo::MatchingValue::UNFEASIBLE_BOUNDARY]; + LOG_VERBOSE << " - UNFEASIBLE_MATCHING " << mstat[CostInfo::MatchingValue::UNFEASIBLE_MATCHING]; + LOG_VERBOSE << " - REJECTED " << mstat[CostInfo::MatchingValue::REJECTED]; + +} + +void PrepareMesh(Mesh& m, int *vndup) +{ + int dupVert = tri::Clean::RemoveDuplicateVertex(m); + if (dupVert > 0) + LOG_INFO << "Removed " << dupVert << " duplicate vertices"; + + int zeroArea = tri::Clean::RemoveZeroAreaFace(m); + if (zeroArea > 0) + LOG_INFO << "Removed " << zeroArea << " zero area faces"; + + tri::UpdateTopology::FaceFace(m); + + // orient faces coherently + bool wasOriented, isOrientable; + tri::Clean::OrientCoherentlyMesh(m, wasOriented, isOrientable); + + tri::UpdateTopology::FaceFace(m); + + int numRemovedFaces = tri::Clean::RemoveNonManifoldFace(m); + if (numRemovedFaces > 0) + LOG_INFO << "Removed " << numRemovedFaces << " non-manifold faces"; + + tri::Allocator::CompactEveryVector(m); + tri::UpdateTopology::FaceFace(m); + + Compute3DFaceAdjacencyAttribute(m); + + CutAlongSeams(m); + tri::Allocator::CompactEveryVector(m); + + *vndup = m.VN(); + + tri::UpdateTopology::FaceFace(m); + while (tri::Clean::SplitNonManifoldVertex(m, 0)) + ; + tri::UpdateTopology::VertexFace(m); + + tri::Allocator::CompactEveryVector(m); +} + +AlgoStateHandle InitializeState(GraphHandle graph, const AlgoParameters& algoParameters) +{ + PERF_TIMER_RESET; + PERF_TIMER_START; + + AlgoStateHandle state = std::make_shared(); + ARAP::ComputeEnergyFromStoredWedgeTC(graph->mesh, &state->arapNum, &state->arapDenom); + state->inputUVBorderLength = 0; + state->currentUVBorderLength = 0; + + BuildSeamMesh(graph->mesh, state->sm, graph); + std::vector seams = GenerateSeams(state->sm); + + // disconnecting seams are (initially) clustered by chart adjacency + // non-disconnecting seams are not clustered (segment granularity) + + std::vector cshvec = ClusterSeamsByChartId(seams); + int ndisconnecting = 0; + int nself = 0; + + for (auto csh : cshvec) { + ChartPair charts = GetCharts(csh, graph); + if (charts.first == charts.second) + nself++; + else + ndisconnecting++; + InsertNewClusterInQueue(csh, state, graph, algoParameters); + } + LOG_INFO << "Found " << ndisconnecting << " disconnecting seams"; + LOG_INFO << "Found " << nself << " non-disconnecting seams"; + + // sanity check + //for (auto& entry : state->chartSeamMap) { + // LOG_INFO << entry.first; + // ensure(entry.second.size() >= (graph->GetChart(entry.first)->adj.size())); + //} + + for (const auto& ch : graph->charts) { + state->inputUVBorderLength += ch.second->BorderUV(); + state->currentUVBorderLength += ch.second->BorderUV(); + } + + PERF_TIMER_ACCUMULATE(t_init); + return state; +} + +void GreedyOptimization(GraphHandle graph, AlgoStateHandle state, const AlgoParameters& params) +{ + ClearGlobals(); + + Timer timer; + + PrintStateInfo(state, graph, params); + + LOG_INFO << "Atlas energy before optimization is " << ARAP::ComputeEnergyFromStoredWedgeTC(graph->mesh, nullptr, nullptr); + + int k = 0; + while (state->queue.size() > 0) { + + if (state->queue.size() > 5 * state->cost.size()) + PurgeQueue(state); + + if (state->queue.size() == 0) { + LOG_INFO << "Queue is empty, interrupting."; + break; + } + + if (params.timelimit > 0 && timer.TimeElapsed() > params.timelimit) { + LOG_INFO << "Timelimit hit, interrupting."; + break; + } + + if (params.UVBorderLengthReduction > (state->currentUVBorderLength / state->inputUVBorderLength)) { + LOG_INFO << "Target UV border reduction reached, interrupting."; + break; + } + + WeightedSeam ws = state->queue.top(); + state->queue.pop(); + if (Valid(ws, state)) { + if (ws.second == Infinity()) { + // sanity check + for (auto& entry : state->cost) + ensure(entry.second == Infinity()); + LOG_INFO << "Queue is empty, interrupting."; + break; + } else { + ++k; + if ((k % 200) == 0) { + LOG_INFO << "Logging execution stats after " << k << " iterations"; + LogExecutionStats(); + } + SeamData sd; + ComputeSeamData(sd, ws.first, graph, state); + LOG_DEBUG << " Chart ids are " << sd.a->id << " " << sd.b->id << " (areas = " << sd.a->AreaUV() << ", " << sd.b->AreaUV() << ")"; + + OffsetMap om = AlignAndMerge(ws.first, sd, state->transform[ws.first], params); + + ComputeOptimizationArea(sd, graph->mesh, om); + + // when merging two charts, check if they collide outside the optimization area + + CheckStatus status = (sd.a != sd.b) ? CheckBoundaryAfterAlignment(sd) : PASS; + + if (status == PASS) + status = OptimizeChart(sd, graph, false); + + if (status == PASS) + status = CheckAfterLocalOptimization(sd, state, params); + + while (status == FAIL_GLOBAL_OVERLAP_AFTER_OPT || status == FAIL_GLOBAL_OVERLAP_AFTER_BND) { + LOG_DEBUG << "Global overlaps detected after ARAP optimization, fixing edges"; + CheckStatus iterStatus = OptimizeChart(sd, graph, true); + if (iterStatus == _END) + break; + else + status = CheckAfterLocalOptimization(sd, state, params); + } + + statsCheck[status]++; + + if (status == PASS) { + AcceptMove(sd, state, graph, params); + ColorizeSeam(sd.csh, vcg::Color4b(255, 69, 0, 255)); + accept++; + LOG_DEBUG << "Accepted operation"; + } else { + RejectMove(sd, state, graph, status); + reject++; + LOG_DEBUG << "Rejected operation"; + } + } + } + } + PrintStateInfo(state, graph, params); + LogExecutionStats(); + LOG_INFO << "Atlas energy after optimization is " << ARAP::ComputeEnergyFromStoredWedgeTC(graph->mesh, nullptr, nullptr); +} + +void Finalize(GraphHandle graph, int *vndup) +{ + std::unordered_set vset; + for (const MeshFace& f : graph->mesh.face) + for (int i = 0; i < 3; ++i) + vset.insert(f.cV(i)); + + *vndup = (int) vset.size(); + + tri::Clean::RemoveDuplicateVertex(graph->mesh); + tri::Clean::RemoveUnreferencedVertex(graph->mesh); + tri::UpdateTopology::VertexFace(graph->mesh); +} + +// -- static functions --------------------------------------------------------- + +static void InsertNewClusterInQueue(ClusteredSeamHandle csh, AlgoStateHandle state, GraphHandle graph, const AlgoParameters& params) +{ + ColorizeSeam(csh, vcg::Color4b::White); + + CostInfo ci = ComputeCost(csh, graph, params, GetPenalty(csh, state)); + + if (params.reduce) { + while (ci.mvalue == CostInfo::UNFEASIBLE_MATCHING) { + ci = ReduceSeam(csh, state, graph, params); + } + } + + ColorizeSeam(csh, mvColor[ci.mvalue]); + + feasibility[ci.mvalue]++; + + if (ci.cost != Infinity()) { + mincost = std::min(mincost, ci.cost); + maxcost = std::max(maxcost, ci.cost); + } + + state->queue.push(std::make_pair(csh, ci.cost)); + state->cost[csh] = ci.cost; + state->transform[csh] = ci.matching; + state->status[csh] = UNKNOWN; + state->mvalue[csh] = ci.mvalue; + + // initialize chart-to-seam map + ChartPair p = GetCharts(csh, graph); + state->chartSeamMap[p.first->id].insert(csh); + state->chartSeamMap[p.second->id].insert(csh); + + // add cluster to endpoint map + std::set endpoints = GetEndpoints(csh); + for (auto vi : endpoints) + state->emap[vi].insert(csh); +} + +// this function returns true if there exists a sequence of at most maxSteps operations +// that results in a UV-island being formed in the graph AND involves a and b +static bool IslandLookahead(ChartHandle a, ChartHandle b, int maxSteps) +{ + // if there are too many candidates, exit early + if (a->adj.size() > (unsigned) maxSteps || b->adj.size() > (unsigned) maxSteps) + return false; + + std::unordered_set nab; + nab.insert(a->adj.begin(), a->adj.end()); + nab.insert(b->adj.begin(), b->adj.end()); + + for (auto c : nab) { + std::stack s; + s.push(a); + + std::set visited = {c, a}; // prevent the visit from reaching c + int steps = 0; + + // start the visit + while (!s.empty()) { + ChartHandle sc = s.top(); + s.pop(); + visited.insert(sc); + for (auto ac : sc->adj) { + if (visited.find(ac) == visited.end()) { + s.push(ac); + steps++; + } + if (steps > maxSteps) + break; + } + if (steps > maxSteps) + break; + } + + // if the stack is empty we could not advance the visit + // this means that the visited component would only be adjacent to c + // => the visited component is an island whose only adjacency is c + if (s.empty()) + return true; + } + + return false; +} + +static CostInfo ComputeCost(ClusteredSeamHandle csh, GraphHandle graph, const AlgoParameters& params, double penalty) +{ + bool swapped; + ChartPair charts = GetCharts(csh, graph, &swapped); + + ChartHandle a = charts.first; + ChartHandle b = charts.second; + if (a->AreaUV() == 0 || b->AreaUV() == 0 || a->Area3D() == 0 || b->Area3D() == 0) { + return { Infinity(), {}, CostInfo::ZERO_AREA }; + } + + std::vector bpa; + std::vector bpb; + + ExtractUVCoordinates(csh, bpa, bpb, {a->id}); + + MatchingTransform mi = MatchingTransform::Identity(); + // if seam is disconnecting compute the actual matching + if (a != b) + mi = ComputeMatchingRigidMatrix(bpa, bpb); + + std::map bmap; + double seamLength3D = 0; + + int ne = 0; + SeamMesh& seamMesh = csh->sm; + for (SeamHandle sh : csh->seams) { + for (int iedge : sh->edges) { + SeamEdge& edge = seamMesh.edge[iedge]; + bmap[edge.fa->id] += (edge.fa->V0(edge.ea)->T().P() - edge.fa->V1(edge.ea)->T().P()).Norm(); + bmap[edge.fb->id] += (edge.fb->V0(edge.eb)->T().P() - edge.fb->V1(edge.eb)->T().P()).Norm(); + seamLength3D += (edge.fa->P0(edge.ea) - edge.fa->P1(edge.ea)).Norm(); + ne++; + } + } + + CostInfo ci; + ci.matching = mi; + ci.mvalue = CostInfo::FEASIBLE; + + if (a != b) { + double maxSeamToBoundaryRatio = std::max(bmap[a->id] / a->BorderUV(), bmap[b->id] / b->BorderUV()); + if (maxSeamToBoundaryRatio < params.boundaryTolerance && (!params.visitComponents || !IslandLookahead(a, b, 5))) { + ci.cost = Infinity(); + ci.mvalue = CostInfo::UNFEASIBLE_BOUNDARY; + return ci; + } + } + + double totErr = MatchingErrorTotal(mi, bpa, bpb); + double avgErr = totErr / (double) bpa.size(); + + if (avgErr > params.matchingThreshold * ((bmap[a->id] + bmap[b->id]) / 2.0)) { + ci.cost = Infinity(); + ci.mvalue = CostInfo::UNFEASIBLE_MATCHING; + return ci; + } + + double lossgain = avgErr * std::pow(std::min(a->BorderUV() / bmap[a->id], b->BorderUV() / bmap[b->id]), params.expb); + double sizebonus = std::min(a->AreaUV(), b->AreaUV()); + + ci.cost = lossgain * sizebonus; + + if (ci.cost == 0 && penalty > 1.0) + ci.cost = 1; + + ci.cost *= penalty; + + return ci; +} + +static inline double GetPenalty(ClusteredSeamHandle csh, AlgoStateHandle state) +{ + if (state->penalty.find(csh) == state->penalty.end()) + state->penalty[csh] = 1.0; + return state->penalty[csh]; +} + +static inline bool Valid(const WeightedSeam& ws, ConstAlgoStateHandle state) +{ + auto it = state->cost.find(ws.first); + return (it != state->cost.end() && it->second == ws.second); +} + +static inline void PurgeQueue(AlgoStateHandle state) +{ + std::unordered_set valid; + while (!state->queue.empty()) { + WeightedSeam ws = state->queue.top(); + if (Valid(ws, state) && ws.second != Infinity()) + valid.insert(ws.first); + state->queue.pop(); + } + ensure(state->queue.empty()); + for (ClusteredSeamHandle csh : valid) + state->queue.push(std::make_pair(csh, state->cost[csh])); +} + +static void ComputeSeamData(SeamData& sd, ClusteredSeamHandle csh, GraphHandle graph, AlgoStateHandle state) +{ + PERF_TIMER_START; + + sd.csh = csh; + + ChartPair charts = GetCharts(csh, graph); + sd.a = charts.first; + sd.b = charts.second; + + if (state->failed[sd.a->id].count(sd.b->id) > 0) + num_retry++; + + Mesh& m = graph->mesh; + + sd.texcoorda.reserve(3 * sd.a->FN()); + sd.vertexinda.reserve(3 * sd.a->FN()); + for (auto fptr : sd.a->fpVec) { + sd.texcoorda.push_back(fptr->V(0)->T().P()); + sd.texcoorda.push_back(fptr->V(1)->T().P()); + sd.texcoorda.push_back(fptr->V(2)->T().P()); + sd.vertexinda.push_back(tri::Index(m, fptr->V(0))); + sd.vertexinda.push_back(tri::Index(m, fptr->V(1))); + sd.vertexinda.push_back(tri::Index(m, fptr->V(2))); + } + + if (sd.a != sd.b) { + sd.texcoordb.reserve(3 * sd.b->FN()); + sd.vertexindb.reserve(3 * sd.b->FN()); + for (auto fptr : sd.b->fpVec) { + sd.texcoordb.push_back(fptr->V(0)->T().P()); + sd.texcoordb.push_back(fptr->V(1)->T().P()); + sd.texcoordb.push_back(fptr->V(2)->T().P()); + sd.vertexindb.push_back(tri::Index(m, fptr->V(0))); + sd.vertexindb.push_back(tri::Index(m, fptr->V(1))); + sd.vertexindb.push_back(tri::Index(m, fptr->V(2))); + } + } + + sd.inputUVBorderLength = sd.a->BorderUV(); + if (sd.a != sd.b) + sd.inputUVBorderLength += sd.b->BorderUV(); + + PERF_TIMER_ACCUMULATE(t_seamdata); +} + +static void WedgeTexFromVertexTex(ChartHandle c) +{ + for (auto fptr : c->fpVec) + for (int i = 0; i < 3; ++i) + fptr->WT(i).P() = fptr->V(i)->T().P(); +} + +static OffsetMap AlignAndMerge(ClusteredSeamHandle csh, SeamData& sd, const MatchingTransform& mi, const AlgoParameters& params) +{ + PERF_TIMER_START; + + OffsetMap om; + + // align + if (sd.a != sd.b) { + std::unordered_set visited; + for (auto fptr : sd.b->fpVec) { + for (int i = 0; i < 3; ++i) { + if (visited.count(fptr->V(i)) == 0) { + visited.insert(fptr->V(i)); + fptr->V(i)->T().P() = mi.Apply(fptr->V(i)->T().P()); + } + } + } + } + + // elect representative vertices for the merge (only 1 vert must be referenced after the merge) + SeamMesh& seamMesh = csh->sm; + for (SeamHandle sh : csh->seams) { + for (int iedge : sh->edges) { + SeamEdge& edge = seamMesh.edge[iedge]; + + Mesh::VertexPointer v0a = edge.fa->V0(edge.ea); + Mesh::VertexPointer v1a = edge.fa->V1(edge.ea); + Mesh::VertexPointer v0b = edge.fb->V0(edge.eb); + Mesh::VertexPointer v1b = edge.fb->V1(edge.eb); + + sd.seamVertices.insert(v0a); + sd.seamVertices.insert(v1a); + sd.seamVertices.insert(v0b); + sd.seamVertices.insert(v1b); + + if (v0a->P() != edge.V(0)->P()) + std::swap(v0a, v1a); + if (v0b->P() != edge.V(0)->P()) + std::swap(v0b, v1b); + + if (sd.mrep.count(v0a) == 0) + sd.evec[edge.V(0)].push_back(v0a); + sd.mrep[v0a] = sd.evec[edge.V(0)].front(); + + if (sd.mrep.count(v1a) == 0) + sd.evec[edge.V(1)].push_back(v1a); + sd.mrep[v1a] = sd.evec[edge.V(1)].front(); + + if (sd.mrep.count(v0b) == 0) + sd.evec[edge.V(0)].push_back(v0b); + sd.mrep[v0b] = sd.evec[edge.V(0)].front(); + + if (sd.mrep.count(v1b) == 0) + sd.evec[edge.V(1)].push_back(v1b); + sd.mrep[v1b] = sd.evec[edge.V(1)].front(); + } + } + + for (auto vp : sd.seamVertices) { + std::vector faces; + std::vector indices; + face::VFStarVF(vp, faces, indices); + sd.vfTopologyFaceSet.insert(faces.begin(), faces.end()); + } + + // update vertex references + for (auto fptr : sd.a->fpVec) { + for (int i = 0; i < 3; ++i) + if (sd.mrep.count(fptr->V(i))) + fptr->V(i) = sd.mrep[fptr->V(i)]; + } + if (sd.a != sd.b) { + for (auto fptr : sd.b->fpVec) { + for (int i = 0; i < 3; ++i) + if (sd.mrep.count(fptr->V(i))) + fptr->V(i) = sd.mrep[fptr->V(i)]; + } + } + + // update topologies. face-face is trivial + + // face-face + for (SeamHandle sh : csh->seams) { + for (int iedge : sh->edges) { + SeamEdge& edge = seamMesh.edge[iedge]; + edge.fa->FFp(edge.ea) = edge.fb; + edge.fa->FFi(edge.ea) = edge.eb; + edge.fb->FFp(edge.eb) = edge.fa; + edge.fb->FFi(edge.eb) = edge.ea; + } + } + + { + for (Mesh::VertexPointer vp : sd.seamVertices) { + vp->VFp() = 0; + vp->VFi() = 0; + } + + for (Mesh::FacePointer fptr : sd.vfTopologyFaceSet) { + for (int i = 0; i < 3; ++i) { + if (sd.seamVertices.find(fptr->V(i)) != sd.seamVertices.end()) { + (*fptr).VFp(i) = (*fptr).V(i)->VFp(); + (*fptr).VFi(i) = (*fptr).V(i)->VFi(); + (*fptr).V(i)->VFp() = &(*fptr); + (*fptr).V(i)->VFi() = i; + } + } + } + } + + // compute average positions and displacements + for (auto& entry : sd.evec) { + vcg::Point2d sumpos = vcg::Point2d::Zero(); + for (auto vp : entry.second) { + sumpos += vp->T().P(); + } + vcg::Point2d avg = sumpos / (double) entry.second.size(); + + double maxOffset = 0; + for (auto& vp : entry.second) + maxOffset = std::max(maxOffset, params.offsetFactor * (vp->T().P() - avg).Norm()); + + om[entry.second.front()] = maxOffset; + entry.second.front()->T().P() = avg; + } + + PERF_TIMER_ACCUMULATE(t_alignmerge); + return om; +} + +static void ComputeOptimizationArea(SeamData& sd, Mesh& mesh, OffsetMap& om) +{ + PERF_TIMER_START; + + std::vector fpvec; + fpvec.insert(fpvec.end(), sd.a->fpVec.begin(), sd.a->fpVec.end()); + if (sd.a != sd.b) + fpvec.insert(fpvec.end(), sd.b->fpVec.begin(), sd.b->fpVec.end()); + + sd.verticesWithinThreshold = ComputeVerticesWithinOffsetThreshold(mesh, om, sd); + sd.optimizationArea.clear(); + + auto ffadj = Get3DFaceAdjacencyAttribute(mesh); + for (auto fptr : fpvec) { + bool addFace = false; + bool edgeManifold = true; + for (int i = 0; i < 3; ++i) { + edgeManifold &= IsEdgeManifold3D(mesh, *fptr, i, ffadj); + if (sd.verticesWithinThreshold.find(fptr->V(i)) != sd.verticesWithinThreshold.end()) + addFace = true; + } + if (addFace && edgeManifold) + sd.optimizationArea.insert(fptr); + if (addFace && !edgeManifold) { + sd.verticesWithinThreshold.erase(fptr->V(0)); + sd.verticesWithinThreshold.erase(fptr->V(1)); + sd.verticesWithinThreshold.erase(fptr->V(2)); + } + } + + for (auto fptr : sd.optimizationArea) { + sd.texcoordoptVert.push_back(fptr->V(0)->T().P()); + sd.texcoordoptVert.push_back(fptr->V(1)->T().P()); + sd.texcoordoptVert.push_back(fptr->V(2)->T().P()); + + sd.texcoordoptWedge.push_back(fptr->WT(0).P()); + sd.texcoordoptWedge.push_back(fptr->WT(1).P()); + sd.texcoordoptWedge.push_back(fptr->WT(2).P()); + + } + + { + sd.inputNegativeArea = 0; + sd.inputAbsoluteArea = 0; + for (auto fptr : sd.optimizationArea) { + vcg::Point2d uv0in = fptr->WT(0).P(); + vcg::Point2d uv1in = fptr->WT(1).P(); + vcg::Point2d uv2in = fptr->WT(2).P(); + + double inputAreaUV = ((uv1in - uv0in) ^ (uv2in - uv0in)) / 2.0; + if (inputAreaUV < 0) + sd.inputNegativeArea += inputAreaUV; + sd.inputAbsoluteArea += std::abs(inputAreaUV); + } + } + + PERF_TIMER_ACCUMULATE(t_optimization_area); +} + +/* Visit vertices starting from the merged ones, subject to the distance budget + * stored in the OffsetMap object. */ +static std::unordered_set ComputeVerticesWithinOffsetThreshold(Mesh& m, const OffsetMap& om, const SeamData& sd) +{ + // typedef for heap nodes + typedef std::pair VertexNode; + + // comparison operator for the max-heap + auto cmp = [] (const VertexNode& v1, const VertexNode& v2) { return v1.second < v2.second; }; + + std::unordered_set vset; + + // distance budget map + OffsetMap dist; + // heap + std::vector h; + + for (const auto& entry : om) { + h.push_back(std::make_pair(entry.first, entry.second)); + dist[entry.first] = entry.second; + } + + std::make_heap(h.begin(), h.end()); + + while (!h.empty()) { + std::pop_heap(h.begin(), h.end(), cmp); + VertexNode node = h.back(); + h.pop_back(); + if (node.second == dist[node.first]) { + std::vector faces; + std::vector indices; + face::VFStarVF(node.first, faces, indices); + + for (unsigned i = 0; i < faces.size(); ++i) { + if(faces[i]->id != sd.a->id && faces[i]->id != sd.b->id){ + LOG_ERR << "issue at face " << tri::Index(m, faces[i]); + } + ensure(faces[i]->id == sd.a->id || faces[i]->id == sd.b->id); + + // if either neighboring vertex is seen with more spare distance, + // update the distance map + + int e1 = indices[i]; + Mesh::VertexPointer v1 = faces[i]->V1(indices[i]); + double d1 = dist[node.first] - EdgeLengthUV(*faces[i], e1); + + if (d1 >= 0 && (dist.find(v1) == dist.end() || dist[v1] < d1)) { + dist[v1] = d1; + h.push_back(std::make_pair(v1, d1)); + std::push_heap(h.begin(), h.end(), cmp); + } + + int e2 = (indices[i]+2)%3; + Mesh::VertexPointer v2 = faces[i]->V2(indices[i]); + double d2 = dist[node.first] - EdgeLengthUV(*faces[i], e2); + + if (d2 >= 0 && (dist.find(v2) == dist.end() || dist[v2] < d2)) { + dist[v2] = d2; + h.push_back(std::make_pair(v2, d2)); + std::push_heap(h.begin(), h.end(), cmp); + } + } + } + } + + for (const auto& entry : dist) + vset.insert(entry.first); + + LOG_DEBUG << "vset.size() == " << vset.size(); + + return vset; +} + +static std::vector ExtractHalfEdges(const std::vector& charts, const vcg::Box2d& box, bool internalOnly) +{ + std::vector hvec; + for (auto ch : charts) + for (auto fptr : ch->fpVec) + for (int i = 0; i < 3; ++i) + if ((!internalOnly || !face::IsBorder(*fptr, i)) && SegmentBoxIntersection(Segment(fptr->V0(i)->T().P(), fptr->V1(i)->T().P()), box)) + hvec.push_back(HalfEdge{fptr, i}); + return hvec; +} + +static CheckStatus CheckBoundaryAfterAlignmentInner(SeamData& sd) +{ + ensure(sd.a != sd.b); + + // check if the borders of the fixed areas of a and b intersect each other + std::vector aVec; + for (auto fptr : sd.a->fpVec) + if (sd.optimizationArea.find(fptr) == sd.optimizationArea.end()) + for (int i = 0; i < 3; ++i) + if (face::IsBorder(*fptr, i) || (sd.optimizationArea.find(fptr->FFp(i)) != sd.optimizationArea.end())) + aVec.push_back(HalfEdge{fptr, i}); + + std::vector bVec; + for (auto fptr : sd.b->fpVec) + if (sd.optimizationArea.find(fptr) == sd.optimizationArea.end()) + for (int i = 0; i < 3; ++i) + if (face::IsBorder(*fptr, i) || (sd.optimizationArea.find(fptr->FFp(i)) != sd.optimizationArea.end())) + bVec.push_back(HalfEdge{fptr, i}); + + if ((aVec.size() > 0) && (bVec.size() > 0)) { + std::vector heVec = CrossIntersection(aVec, bVec); + if (heVec.size() > 0) + return FAIL_GLOBAL_OVERLAP_BEFORE; + } +#if 0 + vcg::Box2d box; + for (auto fptr : sd.b->fpVec) + for (int i = 0; i < 3; ++i) + box.Add(fptr->V(i)->T().P()); + + // also check if the edges of b overlap the edges of a (only check the edges inside the bbox of b) + aVec = ExtractHalfEdges({sd.a}, box, false); + bVec = ExtractHalfEdges({sd.b}, box, false); + if ((aVec.size() > 0) && (bVec.size() > 0)) { + std::vector heVec = CrossIntersection(aVec, bVec); + if (heVec.size() > 0) + return FAIL_GLOBAL_OVERLAP_BEFORE; + } +#endif + + return PASS; +} + +static CheckStatus CheckBoundaryAfterAlignment(SeamData& sd) +{ + PERF_TIMER_START; + LOG_DEBUG << "Running CheckBoundaryAfterAlignment()"; + CheckStatus status = CheckBoundaryAfterAlignmentInner(sd); + PERF_TIMER_ACCUMULATE(t_check_before); + return status; +} + +static CheckStatus CheckAfterLocalOptimizationInner(SeamData& sd, AlgoStateHandle state, const AlgoParameters& params) +{ + double newArapVal = (state->arapNum + (sd.outputArapNum - sd.inputArapNum)) / state->arapDenom; + if (newArapVal > params.globalDistortionThreshold) + return FAIL_DISTORTION_GLOBAL; + + double localDistortion = sd.outputArapNum / sd.outputArapDenom; + if (localDistortion > params.distortionTolerance) { + return FAIL_DISTORTION_LOCAL; + } + + /* Check if the folded area is too large */ + double outputNegativeArea = 0; + double outputAbsoluteArea = 0; + for (auto fptr : sd.optimizationArea) { + double areaUV = AreaUV(*fptr); + if (areaUV < 0) + outputNegativeArea += areaUV; + outputAbsoluteArea += std::abs(areaUV); + } + + double inputRatio = std::abs(sd.inputNegativeArea / sd.inputAbsoluteArea); + double outputRatio = std::abs(outputNegativeArea / outputAbsoluteArea); + + if (outputRatio > inputRatio) { + return FAIL_LOCAL_OVERLAP; + } + + // Functions to detect if the half-edges have already been fixed (in which case detecting the intersection is meaningless, + // the half-edges were intersecting to begin with) + + auto FixedPair = [&] (const HalfEdgePair& hep) -> bool { + return /*hep.first.fp->id == hep.second.fp->id + &&*/ sd.fixedVerticesFromIntersectingEdges.find(hep.first.V0()) != sd.fixedVerticesFromIntersectingEdges.end() + && sd.fixedVerticesFromIntersectingEdges.find(hep.first.V1()) != sd.fixedVerticesFromIntersectingEdges.end() + && sd.fixedVerticesFromIntersectingEdges.find(hep.second.V0()) != sd.fixedVerticesFromIntersectingEdges.end() + && sd.fixedVerticesFromIntersectingEdges.find(hep.second.V1()) != sd.fixedVerticesFromIntersectingEdges.end(); + }; + + auto FixedFirst = [&] (const HalfEdgePair& hep) -> bool { + return /*hep.first.fp->id == hep.second.fp->id + &&*/ sd.fixedVerticesFromIntersectingEdges.find(hep.first.V0()) != sd.fixedVerticesFromIntersectingEdges.end() + && sd.fixedVerticesFromIntersectingEdges.find(hep.first.V1()) != sd.fixedVerticesFromIntersectingEdges.end(); + }; + + // ensure the optimization border does not self-intersect + std::vector sVec; + for (auto fptr : sd.optimizationArea) + for (int i = 0; i < 3; ++i) + if (face::IsBorder(*fptr, i) || (sd.optimizationArea.find(fptr->FFp(i)) == sd.optimizationArea.end())) + sVec.push_back(HalfEdge{fptr, i}); + + if (sVec.size() > 0) { + sd.intersectionOpt = Intersection(sVec); + sd.intersectionOpt.erase(std::remove_if(sd.intersectionOpt.begin(), sd.intersectionOpt.end(), FixedPair), sd.intersectionOpt.end()); + if (sd.intersectionOpt.size() > 0) { + return FAIL_GLOBAL_OVERLAP_AFTER_OPT; + } + } + + // also ensure the optimization border does not intersect the border of the fixed area + // note that this check is not suficient, we should make sure that the optimization AREA + // does not intersect with the non-optimized area. This check should be done either with + // rasterization or triangle intersections + std::vector nopVecBorder; + for (auto fptr : sd.a->fpVec) + if (sd.optimizationArea.find(fptr) == sd.optimizationArea.end()) + for (int i = 0; i < 3; ++i) + if (face::IsBorder(*fptr, i) /* || (sd.optimizationArea.find(fptr->FFp(i)) != sd.optimizationArea.end()) */) + nopVecBorder.push_back(HalfEdge{fptr, i}); + + if (sd.a != sd.b) { + for (auto fptr : sd.b->fpVec) + if (sd.optimizationArea.find(fptr) == sd.optimizationArea.end()) + for (int i = 0; i < 3; ++i) + if (face::IsBorder(*fptr, i) /* || (sd.optimizationArea.find(fptr->FFp(i)) != sd.optimizationArea.end()) */) + nopVecBorder.push_back(HalfEdge{fptr, i}); + } + + if (sVec.size() > 0 && nopVecBorder.size() > 0) { + sd.intersectionBoundary = CrossIntersection(sVec, nopVecBorder); + sd.intersectionBoundary.erase(std::remove_if(sd.intersectionBoundary.begin(), sd.intersectionBoundary.end(), FixedFirst), sd.intersectionBoundary.end()); + if (sd.intersectionBoundary.size() > 0) { + return FAIL_GLOBAL_OVERLAP_AFTER_BND; + } + } + + // also ensure that the optimization border does not overlap any internal edge (inside or outside the optimization area) + // to speed things up, only check edges that are inside the bbox of the opt area + vcg::Box2d optBox; + for (auto fptr : sd.optimizationArea) + for (int i = 0; i < 3; ++i) + optBox.Add(fptr->V(i)->T().P()); + + std::vector internal = ExtractHalfEdges({sd.a, sd.b}, optBox, true); // internal only + + if (sVec.size() > 0 && internal.size() > 0) { + sd.intersectionInternal = CrossIntersection(sVec, internal); + sd.intersectionInternal.erase(std::remove_if(sd.intersectionInternal.begin(), sd.intersectionInternal.end(), FixedFirst), sd.intersectionInternal.end()); + if (sd.intersectionInternal.size() > 0) { + return FAIL_GLOBAL_OVERLAP_AFTER_BND; + } + } + + vcg::Box2d box; + for (auto fptr : sd.b->fpVec) + for (int i = 0; i < 3; ++i) + box.Add(fptr->V(i)->T().P()); + + // also check if the edges of b overlap the edges of a (only check the edges inside the bbox of b) + std::vector aVec = ExtractHalfEdges({sd.a}, box, false); + std::vector bVec = ExtractHalfEdges({sd.b}, box, false); + if ((aVec.size() > 0) && (bVec.size() > 0)) { + std::vector heVec = CrossIntersection(aVec, bVec); + if (heVec.size() > 0) + return FAIL_GLOBAL_OVERLAP_UNFIXABLE; + } + + return PASS; +} + +static CheckStatus CheckAfterLocalOptimization(SeamData& sd, AlgoStateHandle state, const AlgoParameters& params) +{ + PERF_TIMER_START; + LOG_DEBUG << "Running CheckAfterLocalOptimization()"; + CheckStatus status = CheckAfterLocalOptimizationInner(sd, state, params); + PERF_TIMER_ACCUMULATE(t_check_after); + return status; +} + +static CheckStatus OptimizeChart(SeamData& sd, GraphHandle graph, bool fixIntersectingEdges) +{ + PERF_TIMER_START; + + // Create a support face group that contains only the faces that must be + // optimized with arap, i.e. the faces that have at least one vertex in vset + // also initialize the tex coords to the stored tex coords + // (needed if this is called more than once) + auto itV = sd.texcoordoptVert.begin(); + auto itW = sd.texcoordoptWedge.begin(); + FaceGroup support(graph->mesh, INVALID_ID); + for (auto fptr : sd.optimizationArea) { + support.AddFace(fptr); + fptr->V(0)->T().P() = *itV++; fptr->WT(0).P() = *itW++; + fptr->V(1)->T().P() = *itV++; fptr->WT(1).P() = *itW++; + fptr->V(2)->T().P() = *itV++; fptr->WT(2).P() = *itW++; + } + + // before updating the wedge tex coords, compute the arap contribution of the optimization area + // WARNING: it is critial that at this point the wedge tex coords HAVE NOT YET BEEN UPDATED + ARAP::ComputeEnergyFromStoredWedgeTC(support.fpVec, graph->mesh, &sd.inputArapNum, &sd.inputArapDenom); + + WedgeTexFromVertexTex(sd.a); + if (sd.a != sd.b) + WedgeTexFromVertexTex(sd.b); + + LOG_DEBUG << "Building shell..."; + + sd.shell.Clear(); + sd.shell.ClearAttributes(); + bool singleComponent = BuildShellWithTargetsFromUV(sd.shell, support, 1.0); + + if (!singleComponent) + LOG_DEBUG << "Shell is not single component"; + + // Use the existing texture coordinates as starting point for ARAP + + // Copy the wedge texcoords + for (unsigned i = 0; i < support.FN(); ++i) { + auto& sf = sd.shell.face[i]; + auto& f = *(support.fpVec[i]); + for (int j = 0; j < 3; ++j) { + sf.WT(j) = f.V(j)->T(); + sf.V(j)->T() = sf.WT(j); + } + } + + // split non manifold vertices + while (tri::Clean::SplitNonManifoldVertex(sd.shell, 0.3)) + ; + ensure(tri::Clean::CountNonManifoldEdgeFF(sd.shell) == 0); + + CutAlongSeams(sd.shell); + + int nholes = tri::Clean::CountHoles(sd.shell); + int genus = tri::Clean::MeshGenus(sd.shell); + if (nholes == 0 || genus != 0) { + return FAIL_TOPOLOGY; + } + + if (singleComponent && nholes > 1) + CloseHoles3D(sd.shell); + + SyncShellWithUV(sd.shell); + + PERF_TIMER_ACCUMULATE(t_optimize_build); + + LOG_DEBUG << "Optimizing..."; + ARAP arap(sd.shell); + arap.SetMaxIterations(100); + + // select the vertices, using the fact that the faces are mirrored in + // the support object + + for (unsigned i = 0; i < support.FN(); ++i) { + for (int j = 0; j < 3; ++j) { + if (sd.verticesWithinThreshold.find(support.fpVec[i]->V(j)) == sd.verticesWithinThreshold.end()) { + ensure(sd.shell.face[i].IsHoleFilling() == false); + sd.shell.face[i].V(j)->SetS(); + } + } + } + + if (fixIntersectingEdges) { + unsigned fixedBefore = sd.fixedVerticesFromIntersectingEdges.size(); + for (auto hep : sd.intersectionOpt) { + sd.fixedVerticesFromIntersectingEdges.insert(hep.first.fp->V0(hep.first.e)); + sd.fixedVerticesFromIntersectingEdges.insert(hep.first.fp->V1(hep.first.e)); + sd.fixedVerticesFromIntersectingEdges.insert(hep.second.fp->V0(hep.second.e)); + sd.fixedVerticesFromIntersectingEdges.insert(hep.second.fp->V1(hep.second.e)); + } + for (auto hep : sd.intersectionBoundary) { + HalfEdge he = hep.first; + sd.fixedVerticesFromIntersectingEdges.insert(he.fp->V0(he.e)); + sd.fixedVerticesFromIntersectingEdges.insert(he.fp->V1(he.e)); + } + for (auto hep : sd.intersectionInternal) { + HalfEdge he = hep.first; + sd.fixedVerticesFromIntersectingEdges.insert(he.fp->V0(he.e)); + sd.fixedVerticesFromIntersectingEdges.insert(he.fp->V1(he.e)); + } + if (fixedBefore == sd.fixedVerticesFromIntersectingEdges.size()) + return _END; + + for (unsigned i = 0; i < support.FN(); ++i) { + for (int j = 0; j < 3; ++j) { + if (sd.fixedVerticesFromIntersectingEdges.find(support.fpVec[i]->V(j)) != sd.fixedVerticesFromIntersectingEdges.end()) + sd.shell.face[i].V(j)->SetS(); + } + } + } + + // Fix the selected vertices of the shell; + int nfixed = arap.FixSelectedVertices(); + LOG_DEBUG << "Fixed " << nfixed << " vertices"; + double tol = 0.02; + while (nfixed < 2) { + LOG_DEBUG << "Not enough selected vertices found, fixing random edge with tolerance " << tol; + nfixed += arap.FixRandomEdgeWithinTolerance(tol); + tol += 0.02; + } + ensure(nfixed > 0); + + LOG_DEBUG << "Solving..."; + sd.si = arap.Solve(); + + PERF_TIMER_ACCUMULATE_FROM_PREVIOUS(t_optimize_arap); + + SyncShellWithUV(sd.shell); + + LOG_DEBUG << "Syncing chart..."; + + ensure(HasFaceIndexAttribute(sd.shell)); + auto ia = GetFaceIndexAttribute(sd.shell); + for (auto& sf : sd.shell.face) { + if (!sf.IsHoleFilling()) { + auto& f = (graph->mesh).face[ia[sf]]; + for (int k = 0; k < 3; ++k) { + f.WT(k).P() = sf.V(k)->T().P(); + f.V(k)->T().P() = sf.V(k)->T().P(); + } + } + } + + if (!sd.si.numericalError) + ARAP::ComputeEnergyFromStoredWedgeTC(support.fpVec, graph->mesh, &sd.outputArapNum, &sd.outputArapDenom); + + PERF_TIMER_ACCUMULATE(t_optimize); + + return sd.si.numericalError ? FAIL_NUMERICAL_ERROR : PASS; +} + +static bool SeamInterceptsOptimizationArea(ClusteredSeamHandle csh, const SeamData& sd) +{ + const SeamMesh& sm = csh->sm; + for (auto sh : csh->seams) { + for (int i : sh->edges) { + const SeamEdge& edge = sm.edge[i]; + if ((sd.optimizationArea.find(edge.fa) != sd.optimizationArea.end()) || (sd.optimizationArea.find(edge.fb) != sd.optimizationArea.end())) + return true; + } + } + return false; +} + +static void AcceptMove(const SeamData& sd, AlgoStateHandle state, GraphHandle graph, const AlgoParameters& params) +{ + PERF_TIMER_START; + + if (min_energy > sd.si.finalEnergy) + min_energy = sd.si.finalEnergy; + if (max_energy < sd.si.finalEnergy) + max_energy = sd.si.finalEnergy; + + state->changeSet.insert(sd.optimizationArea.begin(), sd.optimizationArea.end()); + + std::vector shared; + std::set sharedClusters; // clusters that can be aggregated after the merge + std::set independentClusters; // clusters not directly impacted by the merge + + std::set selfClusters; + + if (sd.a != sd.b) { + // ``disjoint'' seams, i.e. seams between B and C with C not in N(a) + // are inherited by A + for (auto csh : state->chartSeamMap[sd.b->id]) { + ChartPair p = GetCharts(csh, graph); + ChartHandle c = (p.first == sd.b) ? p.second : p.first; + if (c == sd.a || c == sd.b) { + selfClusters.insert(csh); + } else if (sd.a->adj.find(c) == sd.a->adj.end()) { + independentClusters.insert(csh); + } else { + ensure(c->adj.find(sd.a) != c->adj.end()); + ensure(c->adj.find(sd.b) != c->adj.end()); + ensure(sharedClusters.count(csh) == 0); + sharedClusters.insert(csh); + for (auto sh : csh->seams) + shared.push_back(sh); + } + } + + // we also need to recompute the cost of seams between A and C with C not in N(b) + for (auto csh : state->chartSeamMap[sd.a->id]) { + ChartPair p = GetCharts(csh, graph); + ChartHandle c = (p.first == sd.a) ? p.second : p.first; + if (c == sd.a || c == sd.b) { + selfClusters.insert(csh); + } else if (sd.b->adj.find(c) == sd.b->adj.end()) { + independentClusters.insert(csh); + } else { + ensure(c->adj.find(sd.a) != c->adj.end()); + ensure(c->adj.find(sd.b) != c->adj.end()); + ensure(sharedClusters.count(csh) == 0); + sharedClusters.insert(csh); + for (auto sh : csh->seams) + shared.push_back(sh); + } + } + + /* + for (auto x : std::set{sd.a, sd.b}) { + for (auto csh : state->chartSeamMap[x->id]) { + ChartPair p = GetCharts(csh, graph); + ChartHandle c = (p.first == x) ? p.second : p.first; + if ((sd.a->adj.find(c) != sd.a->adj.end()) && (sd.b->adj.find(c) != sd.b->adj.end())) { + ensure(c != sd.a); + ensure(c != sd.b); + ensure(sharedClusters.count(csh) == 0); + sharedClusters.insert(csh); + for (auto sh : csh->seams) + shared.push_back(sh); + } + } + } + */ + + // update the MeshGraph object + for (auto fptr : sd.b->fpVec) + fptr->id = sd.a->Fp()->id; + sd.a->fpVec.insert(sd.a->fpVec.end(), sd.b->fpVec.begin(), sd.b->fpVec.end()); + + sd.a->adj.erase(sd.b); + for (auto c : sd.b->adj) { + if (c != sd.a) { // chart a is now (if it wasn't already) adjacent to c + c->adj.erase(sd.b); + c->adj.insert(sd.a); + sd.a->adj.insert(c); + } + } + graph->charts.erase(sd.b->id); + + // update state + state->chartSeamMap.erase(sd.b->id); + std::set& failed_b = state->failed[sd.b->id]; + state->failed[sd.a->id].insert(failed_b.begin(), failed_b.end()); + state->failed.erase(sd.b->id); + } else { + // if removing a non-disconnecting seam then all the clusters are independent + independentClusters.insert(state->chartSeamMap[sd.b->id].begin(), state->chartSeamMap[sd.b->id].end()); + independentClusters.erase(sd.csh); + } + + // invalidate cache + sd.a->ParameterizationChanged(); + + // update current UV border length + double deltaUVBorderLength = sd.a->BorderUV() - sd.inputUVBorderLength; + state->currentUVBorderLength += deltaUVBorderLength; + + // update atlas energy + state->arapNum += (sd.outputArapNum - sd.inputArapNum); + state->arapDenom += (sd.outputArapDenom - sd.inputArapDenom); + + if (state->failed[sd.a->id].count(sd.b->id) > 0) + retry_success++; + + // Erase seam + EraseSeam(sd.csh, state, graph); + state->penalty.erase(sd.csh); + + for (auto csh : independentClusters) { + auto it = state->status.find(csh); + ensure(it != state->status.end()); + + CheckStatus clusterStatus = it->second; + ensure(clusterStatus != PASS); + + CostInfo::MatchingValue mv = state->mvalue[csh]; + + EraseSeam(csh, state, graph); + + bool invalidate = (clusterStatus == CheckStatus::FAIL_GLOBAL_OVERLAP_BEFORE) + || (clusterStatus == CheckStatus::FAIL_GLOBAL_OVERLAP_AFTER_OPT) + || (clusterStatus == CheckStatus::FAIL_GLOBAL_OVERLAP_AFTER_BND) + || (clusterStatus == CheckStatus::FAIL_GLOBAL_OVERLAP_UNFIXABLE && !SeamInterceptsOptimizationArea(csh, sd)) + || (clusterStatus == CheckStatus::FAIL_TOPOLOGY); + + if (invalidate || (params.ignoreOnReject && mv == CostInfo::REJECTED)) + InvalidateCluster(csh, state, graph, clusterStatus, 1.0); + else + InsertNewClusterInQueue(csh, state, graph, params); + } + + for (auto csh : sharedClusters) + EraseSeam(csh, state, graph); + + std::vector cshvec = ClusterSeamsByChartId(shared); + for (auto csh : cshvec) { + InsertNewClusterInQueue(csh, state, graph, params); + } + + if (params.visitComponents) { + // if potential islands are allowed to ignore the boundary length limit, + // then check if any chart adjacent to a or b becomes a potential island + // after the merge and activate the corresponding seams below threshold + + std::set unfeasibleBoundaryAdj; + for (ChartHandle c : sd.a->adj) + for (auto csh : state->chartSeamMap[c->id]) + if (state->mvalue[csh] == CostInfo::MatchingValue::UNFEASIBLE_BOUNDARY) + unfeasibleBoundaryAdj.insert(csh); + + for (ClusteredSeamHandle csh : unfeasibleBoundaryAdj) { + EraseSeam(csh, state, graph); + InsertNewClusterInQueue(csh, state, graph, params); + } + } + + PERF_TIMER_ACCUMULATE(t_accept); +} + +static void RejectMove(const SeamData& sd, AlgoStateHandle state, GraphHandle graph, CheckStatus status) +{ + PERF_TIMER_START; + + Mesh& m = graph->mesh; + + // restore texture coordinates and indices + RestoreChartAttributes(sd.a, m, sd.vertexinda.begin(), sd.texcoorda.begin()); + if (sd.a != sd.b) + RestoreChartAttributes(sd.b, m, sd.vertexindb.begin(), sd.texcoordb.begin()); + + // restore face-face topology + SeamMesh& seamMesh = sd.csh->sm; + for (SeamHandle sh : sd.csh->seams) { + for (int iedge : sh->edges) { + const SeamEdge& edge = seamMesh.edge[iedge]; + edge.fa->FFp(edge.ea) = edge.fa; + edge.fa->FFi(edge.ea) = edge.ea; + edge.fb->FFp(edge.eb) = edge.fb; + edge.fb->FFi(edge.eb) = edge.eb; + } + } + + // restore vertex-face topology + // iterate over emap, and split the lists according to the original topology + // recall that we never touched any vertex topology attribute + { + for (Mesh::VertexPointer vp : sd.seamVertices) { + vp->VFp() = 0; + vp->VFi() = 0; + } + + for (Mesh::FacePointer fptr : sd.vfTopologyFaceSet) { + for (int i = 0; i < 3; ++i) { + if (sd.seamVertices.find(fptr->V(i)) != sd.seamVertices.end()) { + (*fptr).VFp(i) = (*fptr).V(i)->VFp(); + (*fptr).VFi(i) = (*fptr).V(i)->VFi(); + (*fptr).V(i)->VFp() = &(*fptr); + (*fptr).V(i)->VFi() = i; + } + } + } + } + + EraseSeam(sd.csh, state, graph); + + InvalidateCluster(sd.csh, state, graph, status, PENALTY_MULTIPLIER); + if (sd.a != sd.b) + state->failed[sd.a->id].insert(sd.b->id); + + PERF_TIMER_ACCUMULATE(t_reject); +} + +static void EraseSeam(ClusteredSeamHandle csh, AlgoStateHandle state, GraphHandle graph) +{ + ensure(csh->size() > 0); + + std::size_t n = state->cost.erase(csh); + ensure(n > 0); + + n = state->transform.erase(csh); + ensure(n > 0); + + n = state->status.erase(csh); + ensure(n > 0); + + n = state->mvalue.erase(csh); + ensure(n > 0); + + ChartPair charts = GetCharts(csh, graph); + + // the following check are needed because AcceptMove() may erase seams after + // fiddling with the chartSeamMap... + if (state->chartSeamMap.find(charts.first->id) != state->chartSeamMap.end()) + state->chartSeamMap[charts.first->id].erase(csh); + + if (state->chartSeamMap.find(charts.second->id) != state->chartSeamMap.end()) + state->chartSeamMap[charts.second->id].erase(csh); + + // erase seam from endpoint map + std::set endpoints = GetEndpoints(csh); + for (auto vi : endpoints) { + unsigned n = state->emap[vi].erase(csh); + ensure(n > 0); + } +} + +static void InvalidateCluster(ClusteredSeamHandle csh, AlgoStateHandle state, GraphHandle graph, CheckStatus status, double penaltyMultiplier) +{ + ColorizeSeam(csh, statusColor[status]); + + CostInfo ci; + ci.cost = Infinity(); + ci.mvalue = CostInfo::REJECTED; + ci.matching = MatchingTransform::Identity(); + + state->queue.push(std::make_pair(csh, ci.cost)); + state->cost[csh] = Infinity(); + state->transform[csh] = ci.matching; + state->status[csh] = status; + state->mvalue[csh] = ci.mvalue; + + ChartPair p = GetCharts(csh, graph); + state->chartSeamMap[p.first->id].insert(csh); + state->chartSeamMap[p.second->id].insert(csh); + + // add penalty if the cluster is later re-evaluated + double penalty = GetPenalty(csh, state); + state->penalty[csh] = penalty * penaltyMultiplier; + + // add cluster to endpoint map + std::set endpoints = GetEndpoints(csh); + for (auto vi : endpoints) + state->emap[vi].insert(csh); +} + +static void RestoreChartAttributes(ChartHandle c, Mesh& m, std::vector::const_iterator itvi, std::vector::const_iterator ittc) +{ + for (auto fptr : c->fpVec) { + for (int i = 0; i < 3; ++i) { + fptr->V(i) = &m.vert[*itvi++]; + fptr->V(i)->T().P() = *ittc; + fptr->WT(i).P() = *ittc++; + } + } +} + +static CostInfo ReduceSeam(ClusteredSeamHandle csh, AlgoStateHandle state, GraphHandle graph, const AlgoParameters& params) +{ + ClusteredSeamHandle reduced = nullptr; + + double totlen = ComputeSeamLength3D(csh); + + SeamMesh& sm = csh->sm; + + // reduce ``forward'' + ClusteredSeamHandle fwd, bwd; + { + fwd = std::make_shared(sm); + double lenfwd = 0; + auto seamHandleIt = csh->seams.begin(); + while (lenfwd < params.reductionFactor * totlen && seamHandleIt != csh->seams.end()) { + SeamHandle sh = *seamHandleIt; + SeamHandle shnew = std::make_shared(sm); + + std::map visited; + for (int e : sh->edges) { + if (lenfwd >= params.reductionFactor * totlen) + break; + shnew->edges.push_back(e); + visited[sm.edge[e].V(0)]++; + visited[sm.edge[e].V(1)]++; + lenfwd += (sm.edge[e].P(0) - sm.edge[e].P(1)).Norm(); + } + + if (shnew->edges.size() == sh->edges.size()) { + shnew->endpoints = sh->endpoints; + } else { + for (auto& entry : visited) { + if (entry.second == 1) { + shnew->endpoints.push_back(tri::Index(sm, entry.first)); + } + } + if (tri::Index(sm, sm.edge[shnew->edges.front()].V(0)) != (unsigned) shnew->endpoints.front() + && tri::Index(sm, sm.edge[shnew->edges.front()].V(1)) != (unsigned) shnew->endpoints.front()) { + std::reverse(shnew->endpoints.begin(), shnew->endpoints.end()); + } + } + + fwd->seams.push_back(shnew); + } + } + + // reduce ``backward'' + { + bwd = std::make_shared(sm); + double lenbwd = 0; + auto seamHandleIt = csh->seams.rbegin(); + while (lenbwd < params.reductionFactor * totlen && seamHandleIt != csh->seams.rend()) { + SeamHandle sh = *seamHandleIt; + SeamHandle shnew = std::make_shared(sm); + + std::map visited; + for (auto ei = sh->edges.rbegin(); ei != sh->edges.rend(); ++ei) { + if (lenbwd >= params.reductionFactor * totlen) + break; + shnew->edges.push_back(*ei); + visited[sm.edge[*ei].V(0)]++; + visited[sm.edge[*ei].V(1)]++; + lenbwd += (sm.edge[*ei].P(0) - sm.edge[*ei].P(1)).Norm(); + } + std::reverse(shnew->edges.begin(), shnew->edges.end()); + + if (shnew->edges.size() == sh->edges.size()) { + shnew->endpoints = sh->endpoints; + } else { + for (auto& entry : visited) { + if (entry.second == 1) { + shnew->endpoints.push_back(tri::Index(sm, entry.first)); + } + } + if (tri::Index(sm, sm.edge[shnew->edges.front()].V(0)) != (unsigned) shnew->endpoints.front() + && tri::Index(sm, sm.edge[shnew->edges.front()].V(1)) != (unsigned) shnew->endpoints.front()) { + std::reverse(shnew->endpoints.begin(), shnew->endpoints.end()); + } + } + + bwd->seams.push_back(shnew); + } + std::reverse(bwd->seams.begin(), bwd->seams.end()); + } + + CostInfo cfwd = ComputeCost(fwd, graph, params, GetPenalty(csh, state)); + CostInfo cbwd = ComputeCost(bwd, graph, params, GetPenalty(csh, state)); + + if (cfwd.cost < cbwd.cost) { + csh->seams = fwd->seams; + return cfwd; + } else { + csh->seams = bwd->seams; + return cbwd; + } +} diff --git a/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/seam_remover.h b/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/seam_remover.h new file mode 100644 index 000000000..944dd4da9 --- /dev/null +++ b/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/seam_remover.h @@ -0,0 +1,173 @@ +/******************************************************************************* + Copyright (c) 2021, Andrea Maggiordomo, Paolo Cignoni and Marco Tarini + + This file is part of TextureDefrag, a reference implementation for + the paper ``Texture Defragmentation for Photo-Reconstructed 3D Models'' + by Andrea Maggiordomo, Paolo Cignoni and Marco Tarini. + + TextureDefrag is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + TextureDefrag is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with TextureDefrag. If not, see . +*******************************************************************************/ + +#ifndef SEAM_REMOVER_H +#define SEAM_REMOVER_H + +#include +#include + +#include +#include + +#include "types.h" +#include "mesh.h" +#include "mesh_graph.h" +#include "matching.h" +#include "arap.h" + +#include "seams.h" +#include "intersection.h" + +typedef std::unordered_map OffsetMap; + +struct AlgoParameters { + double matchingThreshold = 2.0; + double offsetFactor = 5.0; + double boundaryTolerance = 0.2; + double distortionTolerance = 0.5; + double globalDistortionThreshold = 0.025; + double reductionFactor = 0.8; + bool reduce = false; + double timelimit = 0; + bool visitComponents = true; + double expb = 1.0; + double UVBorderLengthReduction = 0.0; + bool ignoreOnReject = false; +}; + +struct SeamData { + ClusteredSeamHandle csh; + + ChartHandle a; + ChartHandle b; + + std::vector texcoorda; + std::vector texcoordb; + std::vector vertexinda; + std::vector vertexindb; + + std::unordered_set seamVertices; + std::unordered_set vfTopologyFaceSet; + + std::map mrep; + std::map> evec; + + std::unordered_set verticesWithinThreshold; + std::unordered_set optimizationArea; + std::vector texcoordoptVert; + std::vector texcoordoptWedge; + + double inputNegativeArea; + double inputAbsoluteArea; + + double inputUVBorderLength; + + double inputArapNum; + double inputArapDenom; + + double outputArapNum; + double outputArapDenom; + + ARAPSolveInfo si; + + Mesh shell; + + std::vector intersectionOpt; + std::vector intersectionBoundary; + std::vector intersectionInternal; + + std::unordered_set fixedVerticesFromIntersectingEdges; + + SeamData() : a{nullptr}, b{nullptr}, inputNegativeArea{0}, inputAbsoluteArea{0} {} +}; + +// enum of the possible outcomes for safety checks when performing merge operations +enum CheckStatus { + PASS=0, + FAIL_LOCAL_OVERLAP, + FAIL_GLOBAL_OVERLAP_BEFORE, + FAIL_GLOBAL_OVERLAP_AFTER_OPT, // border of the optimization area self-intersects + FAIL_GLOBAL_OVERLAP_AFTER_BND, // border of the optimzation area hit the fixed border + FAIL_DISTORTION_LOCAL, + FAIL_DISTORTION_GLOBAL, + FAIL_TOPOLOGY, // shell genus is > 0 or shell is closed + FAIL_NUMERICAL_ERROR, + UNKNOWN, + FAIL_GLOBAL_OVERLAP_UNFIXABLE, + _END +}; + +struct CostInfo { + enum MatchingValue { + FEASIBLE=0, + ZERO_AREA, + UNFEASIBLE_BOUNDARY, + UNFEASIBLE_MATCHING, + REJECTED, + _END + }; + + double cost; + MatchingTransform matching; + MatchingValue mvalue; +}; + +struct AlgoState { + + struct WeightedSeamCmp { + bool operator()(const WeightedSeam& a, const WeightedSeam& b) + { + return a.second > b.second; + } + }; + + std::priority_queue, WeightedSeamCmp> queue; + std::unordered_map cost; + std::unordered_map penalty; + std::unordered_map> chartSeamMap; + + std::map status; + + std::map> emap; // endpoint -> seams map + + std::unordered_map transform; // the rigid matching computed for each currently active move + std::unordered_map mvalue; + + std::unordered_map> failed; + + SeamMesh sm; + std::set changeSet; + + double arapNum; + double arapDenom; + + double inputUVBorderLength; + double currentUVBorderLength; +}; + +void PrepareMesh(Mesh& m, int *vndup); +AlgoStateHandle InitializeState(GraphHandle graph, const AlgoParameters& algoParameters); +void GreedyOptimization(GraphHandle graph, AlgoStateHandle state, const AlgoParameters& params); +void Finalize(GraphHandle graph, int *vndup); + + +#endif // SEAM_REMOVER_H diff --git a/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/seams.cpp b/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/seams.cpp new file mode 100644 index 000000000..ad60bc509 --- /dev/null +++ b/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/seams.cpp @@ -0,0 +1,329 @@ +/******************************************************************************* + Copyright (c) 2021, Andrea Maggiordomo, Paolo Cignoni and Marco Tarini + + This file is part of TextureDefrag, a reference implementation for + the paper ``Texture Defragmentation for Photo-Reconstructed 3D Models'' + by Andrea Maggiordomo, Paolo Cignoni and Marco Tarini. + + TextureDefrag is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + TextureDefrag is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with TextureDefrag. If not, see . +*******************************************************************************/ + +#include "seams.h" +#include "mesh_attribute.h" +#include "logging.h" + +#include + + +static void SortSeam(SeamHandle seam); +static int NextNotVisitedEdge(const SeamMesh& sm, const std::vector& edges); + +static inline PosF GetDualPos(Mesh& m, const PosF& pos, Mesh::PerFaceAttributeHandle& ffadj); + + +ChartPair GetCharts(ClusteredSeamHandle csh, GraphHandle graph, bool *swapped) +{ + ensure(csh->size() > 0); + + if (swapped) + *swapped = false; + + SeamMesh& sm = csh->sm; + SeamEdge se = sm.edge[csh->seams[0]->edges[0]]; + ChartPair p(graph->GetChart(se.fa->id), graph->GetChart(se.fb->id)); + + if (p.first->FN() < p.second->FN()) { + std::swap(p.first, p.second); + if (swapped) + *swapped = true; + } + + return p; +} + +std::set GetEndpoints(ClusteredSeamHandle csh) +{ + // count occurrences and extract real endpoints + std::map endpoints; + for (SeamHandle sh : csh->seams) { + for (int e : sh->endpoints) + endpoints[e]++; + } + + // only return endpoints found once + std::set es; + for (auto entry : endpoints) + if (entry.second == 1) + es.insert(entry.first); + + return es; +} + +void ColorizeSeam(ClusteredSeamHandle csh, const vcg::Color4b& color) +{ + for (auto sh : csh->seams) + ColorizeSeam(sh, color); +} + +void ColorizeSeam(SeamHandle sh, const vcg::Color4b& color) +{ + SeamMesh& sm = sh->sm; + for (int e : sh->edges) { + sm.edge[e].fa->C() = color; + sm.edge[e].fb->C() = color; + } +} + +double ComputeSeamLength3D(ClusteredSeamHandle csh) +{ + ensure(csh->size() > 0); + double l = 0; + for (auto sh : csh->seams) + l += ComputeSeamLength3D(sh); + return l; +} + +double ComputeSeamLength3D(SeamHandle sh) +{ + double l = 0; + SeamMesh& sm = sh->sm; + for (int e : sh->edges) + l += (sm.edge[e].V(0)->P() - sm.edge[e].V(1)->P()).Norm(); + return l; +} + +// ASSUMPTION: the mesh is coherently oriented in 3D and UV space +void ExtractUVCoordinates(ClusteredSeamHandle csh, std::vector& uva, std::vector& uvb, const std::unordered_set &a) +{ + std::unordered_set visited; + for (SeamHandle sh : csh->seams) { + SeamMesh& seamMesh = sh->sm; + for (int iedge : sh->edges) { + SeamEdge& edge = seamMesh.edge[iedge]; + Mesh::FacePointer fa = edge.fa; + Mesh::FacePointer fb = edge.fb; + int ea = edge.ea; + int eb = edge.eb; + if (a.find(edge.fa->id) == a.end()) { + std::swap(fa, fb); + std::swap(ea, eb); + } + if ((visited.count(fa->V0(ea)) == 0) || (visited.count(fb->V1(eb)) == 0)) { + visited.insert(fa->V0(ea)); + visited.insert(fb->V1(eb)); + uva.push_back(fa->V0(ea)->T().P()); + uvb.push_back(fb->V1(eb)->T().P()); + } + if ((visited.count(fa->V1(ea)) == 0) || (visited.count(fb->V0(eb)) == 0)) { + visited.insert(fa->V1(ea)); + visited.insert(fb->V0(eb)); + uva.push_back(fa->V1(ea)->T().P()); + uvb.push_back(fb->V0(eb)->T().P()); + } + } + } +} + +void BuildSeamMesh(Mesh& m, SeamMesh& seamMesh, GraphHandle graph) +{ + seamMesh.Clear(); + + auto ffadj = Get3DFaceAdjacencyAttribute(m); + + seamMesh.Clear(); + tri::UpdateFlags::FaceClearFaceEdgeS(m); + for (auto& f : m.face) { + for (int i = 0; i < 3; ++i) { + if (IsEdgeManifold3D(m, f, i, ffadj) && face::IsBorder(f, i) && f.IsFaceEdgeS(i) == false) { + PosF pa(&f, i); + PosF pb = GetDualPos(m, pa, ffadj); + ChartHandle ca = graph->GetChart(pa.F()->id); + ChartHandle cb = graph->GetChart(pb.F()->id); + if (ca == cb || ca->adj.count(cb) > 0) { + if (pa.F()->id > pb.F()->id) + std::swap(pa, pb); + auto ei = tri::Allocator::AddEdge(seamMesh, pa.V()->P(), pa.VFlip()->P()); + ei->fa = pa.F(); + ei->ea = pa.E(); + ei->fb = pb.F(); + ei->eb = pb.E(); + pa.F()->SetFaceEdgeS(pa.E()); + pb.F()->SetFaceEdgeS(pb.E()); + } + } + } + } + + tri::Clean::RemoveDuplicateVertex(seamMesh); + tri::UpdateTopology::VertexEdge(seamMesh); + tri::UpdateTopology::EdgeEdge(seamMesh); +} + +// seams are sorted according to the edge mesh topology, and kept sorted when +// merging them into clusters. This simplifies things if the seam later needs +// to be shortened +std::vector GenerateSeams(SeamMesh& seamMesh) +{ + std::vector svec; + tri::UpdateFlags::VertexClearV(seamMesh); + tri::UpdateFlags::EdgeClearV(seamMesh); + + for (auto& v : seamMesh.vert) { + std::vector starVec; + edge::VEStarVE(&v, starVec); + for (auto startEdge : starVec) { + // if the edge was already visited or was on the border of the mesh, skip + if (startEdge->IsV() || (startEdge->fa == startEdge->fb)) { + continue; + } + + std::pair chartPair = std::make_pair(startEdge->fa->id, startEdge->fb->id); + + SeamHandle seam = std::make_shared(seamMesh); + startEdge->SetV(); + std::stack s; + s.push(startEdge); + while (!s.empty()) { + SeamMesh::EdgePointer eptr = s.top(); + s.pop(); + seam->edges.push_back(tri::Index(seamMesh, eptr)); + for (int i = 0; i < 2; ++i) { + std::vector eptrStarVec; + edge::VEStarVE(eptr->V(i), eptrStarVec); + + // test edge case where the seam traverses a non-manif vert adjacent to multiple charts + bool nonManifoldVertexOnSeam = false; + for (auto ep : eptrStarVec) { + bool sameCharts = std::make_pair(ep->fa->id, ep->fb->id) == chartPair; + bool sameChartsRev = std::make_pair(ep->fb->id, ep->fa->id) == chartPair; + nonManifoldVertexOnSeam |= !(sameCharts || sameChartsRev); + } + + if (eptrStarVec.size() != 2 || nonManifoldVertexOnSeam) { + seam->endpoints.push_back(tri::Index(seamMesh, eptr->V(i))); + } else if(eptr->EEp(i)->IsV() == false) { + eptr->EEp(i)->SetV(); + s.push(eptr->EEp(i)); + } + } + } + ensure(seam->endpoints.size() != 1); + if (seam->endpoints.size() == 0) { + seam->endpoints.push_back(tri::Index(seamMesh, startEdge->V(0))); + seam->endpoints.push_back(tri::Index(seamMesh, startEdge->V(0))); + } + SortSeam(seam); + svec.push_back(seam); + } + } + int nmissed = 0; + for (auto& e : seamMesh.edge) { + if (!(e.IsV() || (e.fa == e.fb))) { + nmissed++; + } + } + if (nmissed > 0) + LOG_ERR << "Missed " << nmissed << " edges"; + ensure(nmissed == 0); + return svec; +} + +std::vector ClusterSeamsByChartId(const std::vector& seams) +{ + std::vector cshvec; + std::map, ClusteredSeamHandle> cshmap; + for (auto& sh : seams) { + SeamMesh& sm = sh->sm; + SeamEdge e = sm.edge[sh->edges.front()]; + std::pair idpair(e.fa->id, e.fb->id); + if (idpair.first == idpair.second) { + ClusteredSeamHandle csh = std::make_shared(sm); + csh->seams.push_back(sh); + cshvec.push_back(csh); + } else { + if (idpair.first > idpair.second) + std::swap(idpair.first, idpair.second); + if (cshmap.find(idpair) == cshmap.end()) { + cshmap[idpair] = std::make_shared(sm); + cshvec.push_back(cshmap[idpair]); + } + cshmap[idpair]->seams.push_back(sh); + } + } + + return cshvec; +} + +ClusteredSeamHandle Flatten(const std::vector& cshVec) +{ + if (cshVec.size() == 0) + return nullptr; + + ClusteredSeamHandle out = std::make_shared(cshVec.front()->sm); + for (ClusteredSeamHandle csh : cshVec) + for (SeamHandle sh : csh->seams) + out->seams.push_back(sh); + + return out; +} + +// -- static functions --------------------------------------------------------- + + +static void SortSeam(SeamHandle sh) +{ + if (sh->endpoints.size() == 0) + return; + + SeamMesh& sm = sh->sm; + + std::map> vtoe; // vertex to edge map + for (auto e : sh->edges) { + vtoe[tri::Index(sm, sm.edge[e].V(0))].push_back(e); + vtoe[tri::Index(sm, sm.edge[e].V(1))].push_back(e); + sm.edge[e].ClearV(); + } + + std::vector sortedEdges; + int v = sh->endpoints.front(); + while (sortedEdges.size() < sh->edges.size()) { + int e = NextNotVisitedEdge(sm, vtoe[v]); + ensure(e != -1); + sm.edge[e].SetV(); + sortedEdges.push_back(e); + int nextv = tri::Index(sm, sm.edge[e].V(0)); + if (nextv == v) + nextv = tri::Index(sm, sm.edge[e].V(1)); + v = nextv; + } + + sh->edges = sortedEdges; +} + +static int NextNotVisitedEdge(const SeamMesh& sm, const std::vector& edges) +{ + for (auto e : edges) + if (sm.edge[e].IsV() == false) + return e; + return -1; +} + +static inline PosF GetDualPos(Mesh& m, const PosF& pos, Mesh::PerFaceAttributeHandle& ffadj) +{ + Mesh::FacePointer dualf = &m.face[ffadj[pos.F()].f[pos.E()]]; + int e = ffadj[pos.F()].e[pos.E()]; + PosF dual(dualf, e); + dual.FlipV(); + return dual; +} diff --git a/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/seams.h b/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/seams.h new file mode 100644 index 000000000..8183040b8 --- /dev/null +++ b/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/seams.h @@ -0,0 +1,65 @@ +/******************************************************************************* + Copyright (c) 2021, Andrea Maggiordomo, Paolo Cignoni and Marco Tarini + + This file is part of TextureDefrag, a reference implementation for + the paper ``Texture Defragmentation for Photo-Reconstructed 3D Models'' + by Andrea Maggiordomo, Paolo Cignoni and Marco Tarini. + + TextureDefrag is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + TextureDefrag is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with TextureDefrag. If not, see . +*******************************************************************************/ + +#ifndef SEAMS_H +#define SEAMS_H + +#include +#include + +#include "types.h" +#include "mesh_graph.h" + +struct Seam { + SeamMesh& sm; + std::vector edges; // the list of seam segment edges + std::vector endpoints; // the two endpoint vertices + + Seam(SeamMesh& m) : sm{m} {} +}; + +struct ClusteredSeam { + SeamMesh& sm; + std::vector seams; + + ClusteredSeam(SeamMesh& m) : sm{m} {} + std::size_t size() { return seams.size(); } + SeamHandle at(int i) { return seams.at(i); } +}; + +ChartPair GetCharts(ClusteredSeamHandle csh, GraphHandle graph, bool *swapped = nullptr); +std::set GetEndpoints(ClusteredSeamHandle csh); + +void ColorizeSeam(ClusteredSeamHandle csh, const vcg::Color4b& color); +void ColorizeSeam(SeamHandle sh, const vcg::Color4b& color); + +double ComputeSeamLength3D(ClusteredSeamHandle csh); +double ComputeSeamLength3D(SeamHandle sh); + +// a is a set of ids that logically describe one side of the seam (whose coordinates are inserted in uva) +void ExtractUVCoordinates(ClusteredSeamHandle csh, std::vector& uva, std::vector& uvb, const std::unordered_set& a); + +void BuildSeamMesh(Mesh& m, SeamMesh& seamMesh, GraphHandle graph); +std::vector GenerateSeams(SeamMesh& seamMesh); +std::vector ClusterSeamsByChartId(const std::vector& seams); +ClusteredSeamHandle Flatten(const std::vector& cshVec); + +#endif // SEAMS_H diff --git a/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/shell.cpp b/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/shell.cpp new file mode 100644 index 000000000..57000a19b --- /dev/null +++ b/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/shell.cpp @@ -0,0 +1,251 @@ +/******************************************************************************* + Copyright (c) 2021, Andrea Maggiordomo, Paolo Cignoni and Marco Tarini + + This file is part of TextureDefrag, a reference implementation for + the paper ``Texture Defragmentation for Photo-Reconstructed 3D Models'' + by Andrea Maggiordomo, Paolo Cignoni and Marco Tarini. + + TextureDefrag is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + TextureDefrag is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with TextureDefrag. If not, see . +*******************************************************************************/ + +#include "shell.h" +#include "mesh.h" +#include "utils.h" +#include "logging.h" +#include "mesh_graph.h" +#include "mesh_attribute.h" + +#include "timer.h" + +#include + +#include + + +static bool Build(Mesh& shell, FaceGroup& fg); + +/* + * Convention: s0 > s1 + * downscaleFactor determines the uv area shrinking. We discussed two different + * possibilities: + * 1. ds defines a `linear' downscaling on the largest singular value, the + * generator F = USV of the new target shape uses S={s0', s1'} such that + * s0' = k * s0 + * s1' = min(s1, s0') + * + * 2. ds defines the scaling factor of the parameterization, and we compute + * the singular values accordingly. (there are some notes of mine on + * overleaf). Essentially, we can find a scaling threshold such that, + * above this threshold we shrink only the largest sing.val. s1, below + * this threshold we set s1' = s0' = k * s0 for a suitable k + * INTUITION: a square mapped to a rectangle, we can reduce the area of the + * rectangle by making it more and more like a square, shrinking only + * one dimension. At some point the rectangle becomes a square, and we + * start making it smaller until we reach the target area + * + * */ +bool BuildShellWithTargetsFromUV(Mesh& shell, FaceGroup& fg, double downsamplingFactor) +{ + bool singleComponent = Build(shell, fg); + + auto ia_ = GetFaceIndexAttribute(shell); + for (unsigned i = 0; i < fg.FN(); ++i) { + ensure(tri::Index(fg.mesh, fg.fpVec[i]) == (unsigned) ia_[shell.face[i]]); + } + + Mesh& m = fg.mesh; + + double targetArea = 0; + + auto sa = GetShell3DShapeAttribute(shell); + auto ia = GetFaceIndexAttribute(shell); + auto tsa = GetTargetShapeAttribute(shell); + auto wtcsa = GetWedgeTexCoordStorageAttribute(m); + + for (auto& sf : shell.face) { + CoordStorage target; + auto& f = m.face[ia[sf]]; + + // Interpolate between texture and mesh face shapes to mitigate distortion + const Point2d& u0 = wtcsa[f].tc[0].P(); + const Point2d& u1 = wtcsa[f].tc[1].P(); + const Point2d& u2 = wtcsa[f].tc[2].P(); + Point2d u10 = u1 - u0; + Point2d u20 = u2 - u0; + double area = std::abs(u10 ^ u20) / 2.0; + + if (area == 0) { + // just scale everything by the linear scaling factor + target.P[0] = vcg::Point3d(u0.X(), u0.Y(), 0) * downsamplingFactor; + target.P[1] = vcg::Point3d(u1.X(), u1.Y(), 0) * downsamplingFactor; + target.P[2] = vcg::Point3d(u2.X(), u2.Y(), 0) * downsamplingFactor; + } else { + // Compute the matrix of the input mapping and its SVD + Point2d x10; + Point2d x20; + LocalIsometry(f.P(1) - f.P(0), f.P(2) - f.P(0), x10, x20); + Eigen::Matrix2d A = ComputeTransformationMatrix(x10, x20, u10, u20); + + Eigen::Matrix2d U; + Eigen::Matrix2d V; + Eigen::Vector2d s; + Eigen::JacobiSVD svd; + svd.compute(A, Eigen::ComputeFullU | Eigen::ComputeFullV); + U = svd.matrixU(); + V = svd.matrixV(); + s = svd.singularValues(); + ensure(s[0] >= s[1]); + + // Compute the 'generator' matrix and the target shape + Eigen::Vector2d sNew; + + // First strategy - capping the texel-per-dim allocation + sNew[0] = s[0] * downsamplingFactor; + sNew[1] = std::min(sNew[0], s[1]); + + Eigen::Matrix2d gen = U * sNew.asDiagonal() * V.transpose(); + + Eigen::Vector2d t10 = gen * Eigen::Vector2d(x10[0], x10[1]); + Eigen::Vector2d t20 = gen * Eigen::Vector2d(x20[0], x20[1]); + + target.P[0] = Point3d(0, 0, 0); + target.P[1] = Point3d(t10[0], t10[1], 0); + target.P[2] = Point3d(t20[0], t20[1], 0); + } + + tsa[sf] = target; + targetArea += ((target.P[1] - target.P[0]) ^ (target.P[2] - target.P[0])).Norm() / 2.0; + + ensure(std::isfinite(targetArea)); + + sa[sf].P[0] = sf.P(0); + sa[sf].P[1] = sf.P(1); + sa[sf].P[2] = sf.P(2); + } + + return singleComponent; +} + +void CloseHoles3D(Mesh& shell) +{ + Timer t; + + int startFN = shell.FN(); + + auto ia = GetFaceIndexAttribute(shell); + auto tsa = GetTargetShapeAttribute(shell); + + // Use the target area of the original faces (which should have been already computed) to + // compute the scaling factors for the target triangles of the hole-filling faces + double surfaceArea = 0; + double targetArea = 0; + for (auto& sf : shell.face) { + targetArea += ((tsa[sf].P[1] - tsa[sf].P[0]) ^ (tsa[sf].P[2] - tsa[sf].P[0])).Norm() / 2.0; + surfaceArea += vcg::DoubleArea(sf) / 2.0; + } + + double scale = std::sqrt(targetArea / surfaceArea); + + // Get border info + ComputeBoundaryInfoAttribute(shell); + BoundaryInfo& info = GetBoundaryInfoAttribute(shell)(); + + // Leave only the longest boundary + tri::UpdateFlags::FaceClearS(shell); + ensure(info.vBoundaryFaces.size() > 0 && "Mesh has no boundaries"); + if (info.vBoundaryFaces.size() > 1) { + std::size_t k = info.LongestBoundary(); + // select all the boundary faces + for (std::size_t i = 0; i < info.vBoundaryFaces.size(); ++i) { + if (i == k) continue; + for (auto j : info.vBoundaryFaces[i]) { + ensure(face::IsBorder(shell.face[j], 0) || face::IsBorder(shell.face[j], 1) || face::IsBorder(shell.face[j], 2)); + shell.face[j].SetS(); + } + } + tri::Hole::EarCuttingFill>(shell, shell.FN(), true); + } + + tri::Allocator::CompactFaceVector(shell); + ensure(shell.FN() == (int) shell.face.size()); + + for (auto& sf : shell.face) { + if (int(tri::Index(shell, sf)) >= startFN) { + sf.SetHoleFilling(); + ia[sf] = -1; + double area = Area3D(sf); + for (int i = 0; i < 3; ++i) { + vcg::Point2d wti = sf.V(i)->T().P(); + sf.WT(i).P() = wti; + + // if the hole-filling face is zero-area (which can happen if the shell has been cut along seams) + // use the texture coordinates at the vertices to determine the target shape, otherwise + // use the scaled 3D shape. This is just to avoid numerical issues when using the shell to solve arap instances + if (area == 0) + tsa[sf].P[i] = vcg::Point3d(wti.X(), wti.Y(), 0); + else + tsa[sf].P[i] = sf.P(i) * scale; + } + } + } + + tri::UpdateTopology::FaceFace(shell); + tri::UpdateTopology::VertexFace(shell); +} + +void SyncShellWithUV(Mesh& shell) +{ + for (auto& v : shell.vert) { + v.P().X() = v.T().U(); + v.P().Y() = v.T().V(); + v.P().Z() = 0.0; + } + tri::UpdateBounding::Box(shell); +} + +void SyncShellWith3D(Mesh& shell) +{ + auto sa = GetShell3DShapeAttribute(shell); + for (auto& sf : shell.face) { + ensure(sf.IsMesh()); + for (int i = 0; i < 3; ++i) + sf.P(i) = sa[sf].P[i]; + } + tri::UpdateBounding::Box(shell); +} + +void ClearHoleFillingFaces(Mesh& shell, bool holefill, bool scaffold) +{ + for (auto& f : shell.face) + if ((holefill && f.IsHoleFilling()) || (scaffold && f.IsScaffold())) + tri::Allocator::DeleteFace(shell, f); + + tri::Clean::RemoveUnreferencedVertex(shell); + tri::UpdateTopology::FaceFace(shell); + tri::UpdateTopology::VertexFace(shell); + tri::Allocator::CompactEveryVector(shell); +} + +static bool Build(Mesh& shell, FaceGroup& fg) +{ + CopyToMesh(fg, shell); + + tri::Clean::RemoveDuplicateVertex(shell); + tri::Allocator::CompactEveryVector(shell); + + tri::UpdateBounding::Box(shell); + tri::UpdateTopology::FaceFace(shell); + + return tri::Clean::CountConnectedComponents(shell) == 1; +} diff --git a/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/shell.h b/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/shell.h new file mode 100644 index 000000000..a7b9bae4a --- /dev/null +++ b/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/shell.h @@ -0,0 +1,53 @@ +/******************************************************************************* + Copyright (c) 2021, Andrea Maggiordomo, Paolo Cignoni and Marco Tarini + + This file is part of TextureDefrag, a reference implementation for + the paper ``Texture Defragmentation for Photo-Reconstructed 3D Models'' + by Andrea Maggiordomo, Paolo Cignoni and Marco Tarini. + + TextureDefrag is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + TextureDefrag is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with TextureDefrag. If not, see . +*******************************************************************************/ + +#ifndef SHELL_H +#define SHELL_H + +class Mesh; +class FaceGroup; + +/* Builds a shell for the given chart. A shell is a mesh object specifically + * constructed to compute the parameterization of a chart. In order to support + * the various operations that we need to perform on it, it is more convenient + * to keep its shape as the current 2D parameter-space configuration (possibly + * not updated). The shell has suitable attributes to retrieve information about + * the shell-face to input mesh-face mappings, as well as the target shape + * features of each face to guide the parameterization process. (See also the + * comments in mesh_attribute.h). */ +bool BuildShellWithTargetsFromUV(Mesh& shell, FaceGroup& fg, double downscaleFactor); + +void CloseHoles3D(Mesh& shell); + +/* This function synchronizes a shell with its UV coordinates, that is it + * updates its vertex coordinates to match the parameter space configurations + * (with z = 0). The operation is performed per-vertex. */ +void SyncShellWithUV(Mesh& shell); + +/* This function synchronizes a shell with the model space coordinates of its + * chart. */ +void SyncShellWith3D(Mesh& shell); + +/* Removes any hole-filling face from the shell and compacts its containers */ +void ClearHoleFillingFaces(Mesh& shell, bool holefill, bool scaffold); + + +#endif // SHELL_H diff --git a/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/texture_object.cpp b/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/texture_object.cpp new file mode 100644 index 000000000..ef917ea2e --- /dev/null +++ b/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/texture_object.cpp @@ -0,0 +1,185 @@ +/******************************************************************************* + Copyright (c) 2021, Andrea Maggiordomo, Paolo Cignoni and Marco Tarini + + This file is part of TextureDefrag, a reference implementation for + the paper ``Texture Defragmentation for Photo-Reconstructed 3D Models'' + by Andrea Maggiordomo, Paolo Cignoni and Marco Tarini. + + TextureDefrag is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + TextureDefrag is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with TextureDefrag. If not, see . +*******************************************************************************/ + +#include "texture_object.h" +#include "logging.h" +#include "utils.h" +#include "gl_utils.h" + +#include + +#include +#include + + +TextureObject::TextureObject() +{ +} + +TextureObject::~TextureObject() +{ + for (std::size_t i = 0; i < texNameVec.size(); ++i) + Release(i); +} + +bool TextureObject::AddImage(std::string path) +{ + QImageReader qir(QString(path.c_str())); + if (qir.canRead()) { + TextureImageInfo tii = {QImage(path.c_str())}; + texInfoVec.push_back(tii); + texNameVec.push_back(0); + return true; + } else return false; +} + +bool TextureObject::AddImage(const QImage& image) +{ + TextureImageInfo tii = {QImage(image)}; + texInfoVec.push_back(tii); + texNameVec.push_back(0); + return true; +} + +void TextureObject::Bind(int i) +{ + ensure(i >= 0 && i < (int) texInfoVec.size()); + // load texture from qimage on first use + if (texNameVec[i] == 0) { + QImage& img = texInfoVec[i].texture; + ensure(!img.isNull()); + if ((img.format() != QImage::Format_RGB32) || (img.format() != QImage::Format_ARGB32)) { + QImage glimg = img.convertToFormat(QImage::Format_ARGB32); + img = glimg; + } + glGenTextures(1, &texNameVec[i]); + + Mirror(img); + glBindTexture(GL_TEXTURE_2D, texNameVec[i]); + int miplevels = std::log2((float) img.width()); + int width = img.width(); + int height = img.height(); + for (int m = 0; m < miplevels; m++) { + glTexImage2D(GL_TEXTURE_2D, m, GL_RGBA8, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL); + width = std::max(1, (width / 2)); + height = std::max(1, (height / 2)); + } + //glTexStorage2D(GL_TEXTURE_2D, miplevels, GL_RGBA8, img.width(), img.height()); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, img.width(), img.height(), GL_BGRA, GL_UNSIGNED_BYTE, img.constBits()); + glGenerateMipmap(GL_TEXTURE_2D); + CheckGLError(); + Mirror(img); + } + else { + glBindTexture(GL_TEXTURE_2D, texNameVec[i]); + CheckGLError(); + } +} + +void TextureObject::Release(int i) +{ + ensure(i >= 0 && i < (int) texInfoVec.size()); + if (texNameVec[i]) { + glDeleteTextures(1, &texNameVec[i]); + texNameVec[i] = 0; + } +} + +int TextureObject::TextureWidth(std::size_t i) +{ + ensure(i < texInfoVec.size()); + return texInfoVec[i].texture.width(); +} + +int TextureObject::TextureHeight(std::size_t i) +{ + ensure(i < texInfoVec.size()); + return texInfoVec[i].texture.height(); +} + +int TextureObject::MaxSize() +{ + int maxsz = 0; + for (unsigned i = 0; i < ArraySize(); ++i) { + maxsz = std::max(maxsz, TextureWidth(i)); + maxsz = std::max(maxsz, TextureHeight(i)); + } + return maxsz; +} + +std::vector TextureObject::GetTextureSizes() +{ + std::vector texszVec; + for (unsigned i = 0; i < ArraySize(); ++i) + texszVec.push_back({TextureWidth(i), TextureHeight(i)}); + return texszVec; + +} + +std::size_t TextureObject::ArraySize() +{ + return texInfoVec.size(); +} + +int64_t TextureObject::TextureArea(std::size_t i) +{ + ensure(i < ArraySize()); + return ((int64_t) TextureWidth(i)) * TextureHeight(i); +} + +double TextureObject::GetResolutionInMegaPixels() +{ + int64_t totArea = 0; + for (unsigned i = 0; i < ArraySize(); ++i) { + totArea += TextureArea(i); + } + return totArea / 1000000.0; +} + +std::vector> TextureObject::ComputeRelativeSizes() +{ + std::vector texSizeVec = GetTextureSizes(); + int maxsz = 0; + for (auto tsz : texSizeVec) { + maxsz = std::max(maxsz, tsz.h); + maxsz = std::max(maxsz, tsz.w); + } + std::vector> trs; + for (auto tsz : texSizeVec) { + double rw = tsz.w / (double) maxsz; + double rh = tsz.h / (double) maxsz; + trs.push_back(std::make_pair(rw, rh)); + } + return trs; +} + +void Mirror(QImage& img) +{ + int i = 0; + while (i < (img.height() / 2)) { + QRgb *line0 = (QRgb *) img.scanLine(i); + QRgb *line1 = (QRgb *) img.scanLine(img.height() - 1 - i); + i++; + for (int j = 0; j < img.width(); ++j) + std::swap(line0[j], line1[j]); + } +} + diff --git a/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/texture_object.h b/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/texture_object.h new file mode 100644 index 000000000..fb0e2db62 --- /dev/null +++ b/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/texture_object.h @@ -0,0 +1,86 @@ +/******************************************************************************* + Copyright (c) 2021, Andrea Maggiordomo, Paolo Cignoni and Marco Tarini + + This file is part of TextureDefrag, a reference implementation for + the paper ``Texture Defragmentation for Photo-Reconstructed 3D Models'' + by Andrea Maggiordomo, Paolo Cignoni and Marco Tarini. + + TextureDefrag is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + TextureDefrag is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with TextureDefrag. If not, see . +*******************************************************************************/ + +#ifndef TEXTURE_OBJECT_H +#define TEXTURE_OBJECT_H + +#include +#include +#include +#include + +#include + +struct TextureObject; + +typedef std::shared_ptr TextureObjectHandle; + +struct TextureSize { + int w; + int h; +}; + +struct TextureImageInfo { + QImage texture; +}; + +/* wrapper to an array of textures */ +struct TextureObject { + + std::vector texInfoVec; + std::vector texNameVec; + + TextureObject(); + ~TextureObject(); + + TextureObject(const TextureObject &) = delete; + TextureObject &operator=(const TextureObject &) = delete; + + /* Add QImage ref to the texture object */ + bool AddImage(std::string path); + bool AddImage(const QImage& image); + + /* Binds the texture at index i */ + void Bind(int i); + + /* Releases the texture i, without unbinding it if it is bound */ + void Release(int i); + + int TextureWidth(std::size_t i); + int TextureHeight(std::size_t i); + + int MaxSize(); + std::vector GetTextureSizes(); + + std::size_t ArraySize(); + + int64_t TextureArea(std::size_t i); + double GetResolutionInMegaPixels(); + + std::vector> ComputeRelativeSizes(); +}; + +/* Vertically mirrors a QImage in-place, useful to match the OpenGL convention + * for texture data storage */ +void Mirror(QImage& img); + + +#endif // TEXTURE_OBJECT_H diff --git a/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/texture_optimization.cpp b/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/texture_optimization.cpp new file mode 100644 index 000000000..34492608c --- /dev/null +++ b/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/texture_optimization.cpp @@ -0,0 +1,212 @@ +/******************************************************************************* + Copyright (c) 2021, Andrea Maggiordomo, Paolo Cignoni and Marco Tarini + + This file is part of TextureDefrag, a reference implementation for + the paper ``Texture Defragmentation for Photo-Reconstructed 3D Models'' + by Andrea Maggiordomo, Paolo Cignoni and Marco Tarini. + + TextureDefrag is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + TextureDefrag is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with TextureDefrag. If not, see . +*******************************************************************************/ + +#include "texture_optimization.h" + +#include "mesh.h" +#include "mesh_graph.h" +#include "timer.h" +#include "texture_rendering.h" +#include "arap.h" +#include "mesh_attribute.h" +#include "logging.h" + +#include "shell.h" + +#include + +#include +#include + + +static void MirrorU(ChartHandle chart); + +void ReorientCharts(GraphHandle graph) +{ + for (auto entry : graph->charts) { + ChartHandle chart = entry.second; + if (chart->UVFlipped()) + MirrorU(chart); + } +} + +int RotateChartForResampling(ChartHandle chart, const std::set& changeSet, const std::map &flippedInput, bool colorize, double *zeroResamplingArea) +{ + Mesh& m = chart->mesh; + auto wtcsh = GetWedgeTexCoordStorageAttribute(m); + *zeroResamplingArea = 0; + + // compute the area contribution of each initial region restricted to + // faces that have _NOT_ been changed by the optimization + + std::unordered_map areaMap; + std::unordered_map idfp; + + for (auto fptr : chart->fpVec) { + double areaUV = AreaUV(*fptr); + double area3D = Area3D(*fptr); + if ((changeSet.find(fptr) == changeSet.end()) && (areaUV != 0)) { + areaMap[fptr->initialId] += area3D; + idfp[fptr->initialId] = fptr; + } + } + + // if all the faces changed coordinates there is nothing to do + if (areaMap.size() == 0) { + return -1; + } + + // compute the unchanged region with the largest area contribution + + Mesh::FacePointer zeroResamplingAreaFp = nullptr; + for (auto& entry : areaMap) { + if (entry.second > *zeroResamplingArea) { + *zeroResamplingArea = entry.second; + zeroResamplingAreaFp = idfp[entry.first]; + } + } + + // compute the rotation angle + TexCoordStorage tcs = wtcsh[zeroResamplingAreaFp]; + vcg::Point2d d0 = tcs.tc[1].P() - tcs.tc[0].P(); + vcg::Point2d d1 = zeroResamplingAreaFp->WT(1).P() - zeroResamplingAreaFp->WT(0).P(); + + if (flippedInput.at(zeroResamplingAreaFp->initialId)) { + d0.X() *= -1; + } + + //double rotAngle = ((signedArea > 0) ? -1 : 1) * VecAngle(d0, d1); + double rotAngle = VecAngle(d0, d1); + + // rotate the uvs + for (auto fptr : chart->fpVec) { + for (int i = 0; i < 3; ++i) { + fptr->WT(i).P().Rotate(rotAngle); + fptr->V(i)->T().P() = fptr->WT(i).P(); + } + if (colorize) { + if ((fptr->initialId == zeroResamplingAreaFp->initialId) && (changeSet.find(fptr) == changeSet.end())) + fptr->C() = vcg::Color4b(85, 246, 85, 255); + } + } + + return tri::Index(chart->mesh, zeroResamplingAreaFp); + +} + +void TrimTexture(Mesh& m, std::vector& texszVec, bool unsafeMip) +{ + std::vector> facesByTexture; + unsigned ntex = FacesByTextureIndex(m, facesByTexture); + + for (unsigned ti = 0; ti < ntex; ++ti) { + vcg::Box2d uvBox; + for (auto fptr : facesByTexture[ti]) { + if (AreaUV(*fptr) != 0) { + for (int i = 0; i < 3; ++i) { + uvBox.Add(fptr->WT(i).P()); + } + } + } + + if (std::min(uvBox.DimX(), uvBox.DimY()) > 0.95) + continue; + + uvBox.min.Scale(texszVec[ti].w, texszVec[ti].h); + uvBox.max.Scale(texszVec[ti].w, texszVec[ti].h); + uvBox.min.X() = std::max(0, int(uvBox.min.X()) - 2); + uvBox.min.Y() = std::max(0, int(uvBox.min.Y()) - 2); + uvBox.max.X() = std::min(texszVec[ti].w, int(uvBox.max.X()) + 2); + uvBox.max.Y() = std::min(texszVec[ti].h, int(uvBox.max.Y()) + 2); + + if (!unsafeMip) { + // pad the bbox so that MIP artifacts only occur at level above + const int MAX_SAFE_MIP_LEVEL = 5; + const int MOD_VAL = (1 << MAX_SAFE_MIP_LEVEL); + + int bboxw = uvBox.max.X() - uvBox.min.X(); + int bboxh = uvBox.max.Y() - uvBox.min.Y(); + + int incw = MOD_VAL - (bboxw % MOD_VAL); + int inch = MOD_VAL - (bboxh % MOD_VAL); + + uvBox.max.X() += incw; + uvBox.max.Y() += inch; + } + + double uscale = texszVec[ti].w / uvBox.DimX(); + double vscale = texszVec[ti].h / uvBox.DimY(); + + vcg::Point2d t(uvBox.min.X() / texszVec[ti].w, uvBox.min.Y() / texszVec[ti].h); + + for (auto fptr : facesByTexture[ti]) { + if (AreaUV(*fptr) != 0) { + for (int i = 0; i < 3; ++i) { + fptr->WT(i).P() -= t; + fptr->WT(i).P().Scale(uscale, vscale); + fptr->V(i)->T().P() = fptr->WT(i).P(); + } + } + } + + // sanity check + { + vcg::Box2d uvBoxCheck; + for (auto fptr : facesByTexture[ti]) { + if (AreaUV(*fptr) != 0) { + for (int i = 0; i < 3; ++i) { + uvBoxCheck.Add(fptr->WT(i).P()); + } + } + } + + ensure(uvBoxCheck.min.X() > 0); + ensure(uvBoxCheck.min.Y() > 0); + ensure(uvBoxCheck.max.X() < 1); + ensure(uvBoxCheck.max.X() < 1); + } + + // resize + texszVec[ti].w = (int) uvBox.DimX(); + texszVec[ti].h = (int) uvBox.DimY(); + } +} + +// -- static functions --------------------------------------------------------- + +static void MirrorU(ChartHandle chart) +{ + double u_old = chart->UVBox().min.X(); + for (auto fptr : chart->fpVec) { + for (int i = 0; i < 3; ++i) + fptr->WT(i).U() *= -1; + } + chart->ParameterizationChanged(); + double u_new = chart->UVBox().min.X(); + for (auto fptr : chart->fpVec) { + for (int i = 0; i < 3; ++i) { + fptr->WT(i).U() += (u_old - u_new); + fptr->V(i)->T().U() = fptr->WT(i).U(); + } + } + chart->ParameterizationChanged(); +} + diff --git a/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/texture_optimization.h b/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/texture_optimization.h new file mode 100644 index 000000000..55d3dcbfd --- /dev/null +++ b/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/texture_optimization.h @@ -0,0 +1,55 @@ +/******************************************************************************* + Copyright (c) 2021, Andrea Maggiordomo, Paolo Cignoni and Marco Tarini + + This file is part of TextureDefrag, a reference implementation for + the paper ``Texture Defragmentation for Photo-Reconstructed 3D Models'' + by Andrea Maggiordomo, Paolo Cignoni and Marco Tarini. + + TextureDefrag is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + TextureDefrag is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with TextureDefrag. If not, see . +*******************************************************************************/ + +#ifndef TEXTURE_OPTIMIZATION_H +#define TEXTURE_OPTIMIZATION_H + +#include "mesh.h" + +#include +#include + + +struct Point2iHasher { + std::size_t operator()(const vcg::Point2i& p) const noexcept + { + std::size_t seed = 0; + seed ^= std::hash()(p[0]) + 0x9e3779b9 + (seed << 6) + (seed >> 2); + seed ^= std::hash()(p[1]) + 0x9e3779b9 + (seed << 6) + (seed >> 2); + return seed; + } +}; + +void ReorientCharts(GraphHandle graph); + + +/* Given a chart, compute both the set of 2D orientation of each initial component + * and its 3D area. Then rotate the chart according to the largest surface area contribution + * of the initial components that have been clustered in the chart. + * Returns the index of an anchor face, i.e. a face that does not belong to the + * change set and is inside the largest initial component that induced the rotation + */ +int RotateChartForResampling(ChartHandle chart, const std::set &changeSet, const std::map& flippedInput, bool colorize, double *zeroResamplingArea); + +/* Texture trimming to remove unused space */ +void TrimTexture(Mesh& m, std::vector& texszVec, bool unsafeMip); + +#endif // TEXTURE_OPTIMIZATION_H diff --git a/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/texture_rendering.cpp b/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/texture_rendering.cpp new file mode 100644 index 000000000..85a7ff36e --- /dev/null +++ b/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/texture_rendering.cpp @@ -0,0 +1,339 @@ +/******************************************************************************* + Copyright (c) 2021, Andrea Maggiordomo, Paolo Cignoni and Marco Tarini + + This file is part of TextureDefrag, a reference implementation for + the paper ``Texture Defragmentation for Photo-Reconstructed 3D Models'' + by Andrea Maggiordomo, Paolo Cignoni and Marco Tarini. + + TextureDefrag is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + TextureDefrag is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with TextureDefrag. If not, see . +*******************************************************************************/ + +/* + * References for the bicubic interpolated texture lookup: + * - GPU gems 2 ch 20 (Sigg and Hadwiger, 2005) + * - Efficient GPU-Based Texture Interpolation using Uniform B-Splines (Ruijters et al., 2009) + * */ + +#include "mesh.h" +#include "texture_rendering.h" +#include "gl_utils.h" +#include "pushpull.h" +#include "mesh_attribute.h" +#include "logging.h" + +#include +#include + +#include + + + +static const char *vs_text[] = { + "attribute vec2 position; \n" + "attribute vec2 texcoord; \n" + "attribute vec4 color; \n" + "varying vec2 uv; \n" + "varying vec4 fcolor; \n" + " \n" + "void main(void) \n" + "{ \n" + " uv = texcoord; \n" + " fcolor = color; \n" + " //if (uv.s < 0) uv = vec2(0.0, 0.0); \n" + " vec2 p = 2.0 * position - vec2(1.0, 1.0); \n" + " gl_Position = vec4(p, 0.5, 1.0); \n" + "} \n" +}; + +static const char *fs_text[] = { + "uniform sampler2D img0; \n" + " \n" + "uniform vec2 texture_size; \n" + "uniform int render_mode; \n" + " \n" + "varying vec2 uv; \n" + "varying vec4 fcolor; \n" + " \n" + "void main(void) \n" + "{ \n" + " if (render_mode == 0) { \n" + " if (uv.s < float(0)) \n" + " gl_FragColor = vec4(0, 1, 0, 1); \n" + " else \n" + " gl_FragColor = vec4(texture2D(img0, uv).rgb, 1); \n" + " } else if (render_mode == 1) { \n" + " vec2 coord = uv * texture_size - vec2(0.5, 0.5); \n" + " vec2 idx = floor(coord); \n" + " vec2 fraction = coord - idx; \n" + " vec2 one_frac = vec2(1.0, 1.0) - fraction; \n" + " vec2 one_frac2 = one_frac * one_frac; \n" + " vec2 fraction2 = fraction * fraction; \n" + " vec2 w0 = (1.0/6.0) * one_frac2 * one_frac; \n" + " vec2 w1 = (2.0/3.0) - 0.5 * fraction2 * (2.0 - fraction); \n" + " vec2 w2 = (2.0/3.0) - 0.5 * one_frac2 * (2.0 - one_frac); \n" + " vec2 w3 = (1.0/6.0) * fraction2 * fraction; \n" + " vec2 g0 = w0 + w1; \n" + " vec2 g1 = w2 + w3; \n" + " vec2 h0 = (w1 / g0) - 0.5 + idx; \n" + " vec2 h1 = (w3 / g1) + 1.5 + idx; \n" + " vec4 tex00 = texture2D(img0, vec2(h0.x, h0.y) / texture_size);\n" + " vec4 tex10 = texture2D(img0, vec2(h1.x, h0.y) / texture_size);\n" + " vec4 tex01 = texture2D(img0, vec2(h0.x, h1.y) / texture_size);\n" + " vec4 tex11 = texture2D(img0, vec2(h1.x, h1.y) / texture_size);\n" + " tex00 = mix(tex00, tex01, g1.y); \n" + " tex10 = mix(tex10, tex11, g1.y); \n" + " gl_FragColor = mix(tex00, tex10, g1.x); \n" + " } else { \n" + " gl_FragColor = fcolor; \n" + " } \n" + "} \n" +}; + + + +static std::shared_ptr RenderTexture(std::vector& fvec, + Mesh &m, TextureObjectHandle textureObject, + bool filter, RenderMode imode, + int textureWidth, int textureHeight); + + +int FacesByTextureIndex(Mesh& m, std::vector>& fv) +{ + fv.clear(); + + // Detect the number of required textures + int nTex = 1; + for (auto&f : m.face) { + nTex = std::max(nTex, f.cWT(0).N() + 1); + } + + fv.resize(nTex); + + for (auto& f : m.face) { + int ti = f.cWT(0).N(); + ensure(ti < nTex); + fv[ti].push_back(&f); + } + + return fv.size(); +} + +std::vector> RenderTexture(Mesh& m, TextureObjectHandle textureObject, const std::vector &texSizes, + bool filter, RenderMode imode) +{ + std::vector> facesByTexture; + int nTex = FacesByTextureIndex(m, facesByTexture); + + ensure(nTex <= (int) texSizes.size()); + + std::vector> newTextures; + for (int i = 0; i < nTex; ++i) { + std::shared_ptr teximg = RenderTexture(facesByTexture[i], m, textureObject, filter, imode, texSizes[i].w, texSizes[i].h); + newTextures.push_back(teximg); + } + + return newTextures; +} + +static std::shared_ptr RenderTexture(std::vector& fvec, + Mesh &m, TextureObjectHandle textureObject, + bool filter, RenderMode imode, + int textureWidth, int textureHeight) +{ + auto WTCSh = GetWedgeTexCoordStorageAttribute(m); + + // sort the faces in increasing order of input texture unit + auto FaceComparatorByInputTexIndex = [&WTCSh](const Mesh::FacePointer& f1, const Mesh::FacePointer& f2) { + return WTCSh[f1].tc[0].N() < WTCSh[f2].tc[0].N(); + }; + + std::sort(fvec.begin(), fvec.end(), FaceComparatorByInputTexIndex); + + // OpenGL setup + + GLuint vao; + glGenVertexArrays(1, &vao); + glBindVertexArray(vao); + + GLint program = CompileShaders(vs_text, fs_text); + glUseProgram(program); + + CheckGLError(); + + // Allocate vertex data + + GLuint vertexbuf; + glGenBuffers(1, &vertexbuf); + + std::vector inTexSizes; + for (std::size_t i = 0; i < textureObject->ArraySize(); ++i) { + int iw = textureObject->TextureWidth(i); + int ih = textureObject->TextureHeight(i); + inTexSizes.push_back({iw, ih}); + } + + glBindBuffer(GL_ARRAY_BUFFER, vertexbuf); + glBufferData(GL_ARRAY_BUFFER, m.FN()*15*sizeof(float), NULL, GL_STATIC_DRAW); + float *p = (float *) glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY); + for (auto fptr : fvec) { + int ti = WTCSh[fptr].tc[0].N(); + for (int i = 0; i < 3; ++i) { + *p++ = fptr->cWT(i).U(); + *p++ = fptr->cWT(i).V(); + vcg::Point2d uv = WTCSh[fptr].tc[i].P(); + *p++ = uv.X() / inTexSizes[ti].w; + *p++ = uv.Y() / inTexSizes[ti].h; + unsigned char *colorptr = (unsigned char *) p; + *colorptr++ = fptr->C()[0]; + *colorptr++ = fptr->C()[1]; + *colorptr++ = fptr->C()[2]; + *colorptr++ = fptr->C()[3]; + p++; + + } + } + glUnmapBuffer(GL_ARRAY_BUFFER); + + GLint pos_location = glGetAttribLocation(program, "position"); + glVertexAttribPointer(pos_location, 2, GL_FLOAT, GL_FALSE, 5*sizeof(float), 0); + glEnableVertexAttribArray(pos_location); + + GLint tc_location = glGetAttribLocation(program, "texcoord"); + glVertexAttribPointer(tc_location, 2, GL_FLOAT, GL_FALSE, 5*sizeof(float), (void *) (2*sizeof(float))); + glEnableVertexAttribArray(tc_location); + + GLint color_location = glGetAttribLocation(program, "color"); + glVertexAttribPointer(color_location, 4, GL_UNSIGNED_BYTE, GL_TRUE, 5*sizeof(float), (void *) (4*sizeof(float))); + glEnableVertexAttribArray(color_location); + + p = nullptr; + glBindBuffer(GL_ARRAY_BUFFER, 0); // done, unbind + + int renderedTexWidth = textureWidth; + int renderedTexHeight = textureHeight; + + GLint drawBuffer; + glGetIntegerv(GL_DRAW_BUFFER, &drawBuffer); + + GLuint fbo; + glGenFramebuffers(1, &fbo); + glBindFramebuffer(GL_FRAMEBUFFER, fbo); + + glViewport(0, 0, renderedTexWidth, renderedTexHeight); + + GLuint renderTarget; + glGenTextures(1, &renderTarget); + glBindTexture(GL_TEXTURE_2D, renderTarget); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, renderedTexWidth, renderedTexHeight, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, renderTarget, 0); + glBindTexture(GL_TEXTURE_2D, 0); + + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { + LOG_ERR << "Framebuffer is not complete " << glCheckFramebufferStatus(GL_FRAMEBUFFER); + std::exit(-1); + } + + std::shared_ptr textureImage = std::make_shared(renderedTexWidth, renderedTexHeight, QImage::Format_ARGB32); + + // disable depth and stencil test (if they were enabled) as the render target does not have the buffers attached + glDisable(GL_DEPTH_TEST); + glDisable(GL_STENCIL_TEST); + + glDrawBuffer(GL_COLOR_ATTACHMENT0); + + glClearColor(0.0f, 1.0f, 0.0f, 128 / float(255)); + + glClear(GL_COLOR_BUFFER_BIT); + + auto f0 = fvec.begin(); + auto fbase = f0; + while (fbase != fvec.end()) { + auto fcurr = fbase; + int currTexIndex = WTCSh[*fcurr].tc[0].N(); + while (fcurr != fvec.end() && WTCSh[*fcurr].tc[0].N() == currTexIndex) + fcurr++; + int baseIndex = std::distance(f0, fbase) * 3; + int count = std::distance(fbase, fcurr) * 3; + + // Load texture image + glActiveTexture(GL_TEXTURE0); + LOG_DEBUG << "Binding texture unit " << currTexIndex; + textureObject->Bind(currTexIndex); + + GLint loc_img0 = glGetUniformLocation(program, "img0"); + glUniform1i(loc_img0, 0); + GLint loc_texture_size = glGetUniformLocation(program, "texture_size"); + glUniform2f(loc_texture_size, float(textureObject->TextureWidth(currTexIndex)), float(textureObject->TextureHeight(currTexIndex))); + + + GLint loc_render_mode = glGetUniformLocation(program, "render_mode"); + glUniform1i(loc_render_mode, 0); + switch (imode) { + case Cubic: + glUniform1i(loc_render_mode, 1); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 16.0f); + break; + case Linear: + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 16.0f); + //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + //glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.0f); + break; + case Nearest: + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + break; + case FaceColor: + glUniform1i(loc_render_mode, 2); + break; + default: + ensure(0 && "Should never happen"); + } + + glDrawArrays(GL_TRIANGLES, baseIndex, count); + CheckGLError(); + + textureObject->Release(currTexIndex); + + fbase = fcurr; + } + + glReadBuffer(GL_COLOR_ATTACHMENT0); + glReadPixels(0, 0, renderedTexWidth, renderedTexHeight, GL_BGRA, GL_UNSIGNED_BYTE, textureImage->bits()); + + // clean up + glUseProgram(0); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glBindVertexArray(0); + + glDeleteTextures(1, &renderTarget); + glDeleteFramebuffers(1, &fbo); + glDeleteBuffers(1, &vertexbuf); + glDeleteProgram(program); + glDeleteVertexArrays(1, &vao); + + glDrawBuffer(drawBuffer); + + if (filter) + vcg::PullPush(*textureImage, qRgba(0, 255, 0, 128)); + + Mirror(*textureImage); + + return textureImage; +} diff --git a/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/texture_rendering.h b/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/texture_rendering.h new file mode 100644 index 000000000..d8e67f88a --- /dev/null +++ b/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/texture_rendering.h @@ -0,0 +1,44 @@ +/******************************************************************************* + Copyright (c) 2021, Andrea Maggiordomo, Paolo Cignoni and Marco Tarini + + This file is part of TextureDefrag, a reference implementation for + the paper ``Texture Defragmentation for Photo-Reconstructed 3D Models'' + by Andrea Maggiordomo, Paolo Cignoni and Marco Tarini. + + TextureDefrag is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + TextureDefrag is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with TextureDefrag. If not, see . +*******************************************************************************/ + +#ifndef TEXTURE_RENDERING_H +#define TEXTURE_RENDERING_H + +#include "texture_object.h" +#include "mesh_graph.h" + +#include + +class Mesh; +class MeshFace; + +enum RenderMode { + Nearest, Linear, Cubic, FaceColor +}; + +int FacesByTextureIndex(Mesh& m, std::vector>& fv); + +std::vector> +RenderTexture(Mesh& m, TextureObjectHandle textureObject, const std::vector &texSizes, + bool filter, RenderMode imode); + +#endif // TEXTURE_RENDERING_H + diff --git a/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/timer.h b/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/timer.h new file mode 100644 index 000000000..2663a8313 --- /dev/null +++ b/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/timer.h @@ -0,0 +1,44 @@ +/******************************************************************************* + Copyright (c) 2021, Andrea Maggiordomo, Paolo Cignoni and Marco Tarini + + This file is part of TextureDefrag, a reference implementation for + the paper ``Texture Defragmentation for Photo-Reconstructed 3D Models'' + by Andrea Maggiordomo, Paolo Cignoni and Marco Tarini. + + TextureDefrag is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + TextureDefrag is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with TextureDefrag. If not, see . +*******************************************************************************/ + +#ifndef TIMER_H +#define TIMER_H + +#include + +struct Timer { + using hrc = std::chrono::high_resolution_clock; + + hrc::time_point start; + hrc::time_point last; + + Timer() : start(hrc::now()) { last = start; } + + double TimeElapsed() { last = hrc::now(); return std::chrono::duration(last - start).count(); } + + double TimeSinceLastCheck() { auto t = last; last = hrc::now(); return std::chrono::duration(last - t).count(); } + + void Reset() { start = last = hrc::now(); } + +}; + +#endif // TIMER_H + diff --git a/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/types.h b/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/types.h new file mode 100644 index 000000000..1bae88b34 --- /dev/null +++ b/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/types.h @@ -0,0 +1,64 @@ +/******************************************************************************* + Copyright (c) 2021, Andrea Maggiordomo, Paolo Cignoni and Marco Tarini + + This file is part of TextureDefrag, a reference implementation for + the paper ``Texture Defragmentation for Photo-Reconstructed 3D Models'' + by Andrea Maggiordomo, Paolo Cignoni and Marco Tarini. + + TextureDefrag is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + TextureDefrag is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with TextureDefrag. If not, see . +*******************************************************************************/ + +#ifndef TYPES_H +#define TYPES_H + +#include +#include +#include + +class Mesh; +class MeshVertex; +class MeshFace; +class MeshEdge; + +class SeamMesh; +class SeamEdge; +class SeamVertex; + +typedef int RegionID; +constexpr RegionID INVALID_ID = 0xffffffff; + +class MeshGraph; +class FaceGroup; +class TextureObject; + +class AlgoState; +class Seam; +class ClusteredSeam; + +typedef std::shared_ptr GraphHandle; +typedef std::shared_ptr ChartHandle; +typedef std::shared_ptr TextureObjectHandle; +typedef std::shared_ptr SeamHandle; +typedef std::shared_ptr ClusteredSeamHandle; +typedef std::shared_ptr AlgoStateHandle; +typedef std::shared_ptr ConstAlgoStateHandle; + +typedef std::vector Outline2f; +typedef std::vector Outline2d; + +typedef std::pair WeightedSeam; + +struct TextureSize; + +#endif // TYPES_H diff --git a/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/utils.h b/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/utils.h new file mode 100644 index 000000000..6dbee6ac4 --- /dev/null +++ b/src/meshlabplugins/filter_texture_defragmentation/TextureDefragmentation/src/utils.h @@ -0,0 +1,41 @@ +/******************************************************************************* + Copyright (c) 2021, Andrea Maggiordomo, Paolo Cignoni and Marco Tarini + + This file is part of TextureDefrag, a reference implementation for + the paper ``Texture Defragmentation for Photo-Reconstructed 3D Models'' + by Andrea Maggiordomo, Paolo Cignoni and Marco Tarini. + + TextureDefrag is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + TextureDefrag is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with TextureDefrag. If not, see . +*******************************************************************************/ + +#ifndef UTILS_H +#define UTILS_H + +#include +#include + +#define ensure(expr) \ + ((expr) \ + ? (void) (0) \ + : ensure_fail(#expr, __FILE__, __LINE__)) + +[[ noreturn ]] +inline void ensure_fail(const char *expr, const char *filename, unsigned int line) +{ + std::cerr << filename << " (line " << line << "): Failed check `" << expr << "'" << std::endl; + std::abort(); +} + +#endif // UTILS_H + diff --git a/src/meshlabplugins/filter_texture_defragmentation/filter_texture_defragmentation.cpp b/src/meshlabplugins/filter_texture_defragmentation/filter_texture_defragmentation.cpp new file mode 100644 index 000000000..fd3aacdc9 --- /dev/null +++ b/src/meshlabplugins/filter_texture_defragmentation/filter_texture_defragmentation.cpp @@ -0,0 +1,419 @@ +/**************************************************************************** +* MeshLab o o * +* A versatile mesh processing toolbox o o * +* _ O _ * +* Copyright(C) 2005 \/)\/ * +* Visual Computing Lab /\/| * +* ISTI - Italian National Research Council | * +* \ * +* All rights reserved. * +* * +* This program is free software; you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation; either version 2 of the License, or * +* (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) * +* for more details. * +* * +****************************************************************************/ + +#include "filter_texture_defragmentation.h" + +#include + +#include +#include + +#include +#include +#include + +#include + +#include "TextureDefragmentation/src/mesh.h" +#include "TextureDefragmentation/src/texture_object.h" +#include "TextureDefragmentation/src/mesh_attribute.h" +#include "TextureDefragmentation/src/mesh_graph.h" +#include "TextureDefragmentation/src/texture_optimization.h" +#include "TextureDefragmentation/src/seam_remover.h" +#include "TextureDefragmentation/src/packing.h" +#include "TextureDefragmentation/src/texture_rendering.h" + +#include "TextureDefragmentation/src/logging.h" + +using namespace vcg; + +FilterTextureDefragPlugin::FilterTextureDefragPlugin() +{ + typeList = { + FP_TEXTURE_DEFRAG, + }; + + for(ActionIDType tt: types()) + actionList.push_back(new QAction(filterName(tt), this)); + + LOG_INIT(logging::Level::Error); + LOG_SET_THREAD_NAME("TextureDefrag"); +} + +QString FilterTextureDefragPlugin::pluginName() const +{ + return "FilterTextureDefrag"; +} + +QString FilterTextureDefragPlugin::filterName(ActionIDType filterId) const +{ + switch(filterId) { + case FP_TEXTURE_DEFRAG: + return QString("Texture Map Defragmentation"); + default: + assert(0); + } + return {}; +} + +QString FilterTextureDefragPlugin::filterInfo(ActionIDType filterId) const +{ + switch(filterId) { + case FP_TEXTURE_DEFRAG: + return QString("Reduces the texture fragmentation by merging atlas charts. \ + The used algorithm is:
Texture Defragmentation for Photo-Reconstructed 3D Models
\ + Andrea Maggiordomo, Paolo Cignoni and Marco Tarini
\ + Eurographics 2021"); + default: + assert(0); + } + return QString("Unknown Filter"); +} + +int FilterTextureDefragPlugin::getPreConditions(const QAction *a) const +{ + switch (ID(a)) { + case FP_TEXTURE_DEFRAG: + return MeshModel::MM_WEDGTEXCOORD; + default: + assert(0); + } + return MeshModel::MM_NONE; +} + +int FilterTextureDefragPlugin::getRequirements(const QAction *a) +{ + switch (ID(a)) { + case FP_TEXTURE_DEFRAG: + return MeshModel::MM_FACEFACETOPO; + default: + assert(0); + } + return MeshModel::MM_NONE; +} + +bool FilterTextureDefragPlugin::requiresGLContext(const QAction* a) const +{ + switch (ID(a)) { + case FP_TEXTURE_DEFRAG: + return true; + default: + assert(0); + return false; + } +} + +int FilterTextureDefragPlugin::postCondition(const QAction *a) const +{ + switch (ID(a)) { + case FP_TEXTURE_DEFRAG: + return MeshModel::MM_WEDGTEXCOORD | MeshModel::MM_GEOMETRY_AND_TOPOLOGY_CHANGE; // just to disable preview... + default: + assert(0); + } + return MeshModel::MM_NONE; +} + +FilterTextureDefragPlugin::FilterClass FilterTextureDefragPlugin::getClass(const QAction *a) const +{ + switch (ID(a)) { + case FP_TEXTURE_DEFRAG: + return FilterPlugin::Texture; + default: + assert(0); + } + return FilterPlugin::Generic; +} + +RichParameterList FilterTextureDefragPlugin::initParameterList(const QAction *action, const MeshDocument &) +{ + RichParameterList parlst; + switch (ID(action)) { + case FP_TEXTURE_DEFRAG: + parlst.addParam(RichFloat( + "matchingThreshold", + 2.0, + "Matching Error Threshold", + "Threshold on the seam alignment error. Using a higher threshold can reduce the fragmentation but increase runtime and distortion.")); + parlst.addParam(RichFloat( + "boundaryTolerance", + 0.2, + "Seam to chart-boundary-length tolerance", + "Cutoff on the minimum fractional seam length. Seams with lower fractional length (relative to the chart perimeter) are not merged to keep the " + "chart borders compact.")); + parlst.addParam(RichFloat( + "distortionTolerance", + 0.5, + "Local ARAP distortion tolerance", + "Local UV-optimization distortion tolerance when merging a seam. If the local energy is higher than this value, the operation is reverted.")); + parlst.addParam(RichFloat( + "globalDistortionTolerance", + 0.025, + "Global ARAP distortion tolerance", + "Global ARAP distortion tolerance when merging a seam. If the global atlas energy is higher than this value, the operation is reverted.")); + parlst.addParam(RichDynamicFloat( + "uvReductionLimit", + 0.0, + 0.0, + 100.0, + "UV Length Target (percentage)", + "Target UV length as percentage of the input length. The algorithm halts if the target UV length has be en reached, or if no futher " + "seams can be merged.")); + parlst.addParam(RichFloat( + "offsetFactor", + 5.0, + "Local expansion coefficient", + "Coefficient used to control the extension of the UV-optimization area. Larger values can increase the efficacy of the defragmentation, " + "but increase the cost of the geometric optimization and the algorithm runtime.")); + parlst.addParam(RichFloat( + "timelimit", + 0.0, + "Time limit (seconds)", + "Time limit for the defragmentation process (zero means unlimited).")); + break; + default: + break; + } + return parlst; +} + +// The Real Core Function doing the actual mesh processing. +std::map FilterTextureDefragPlugin::applyFilter( + const QAction *filter, + const RichParameterList &par, + MeshDocument &md, + unsigned int& /*postConditionMask*/, + CallBackPos *cb) +{ + const MeshModel ¤tModel = *(md.mm()); + switch(ID(filter)) { + case FP_TEXTURE_DEFRAG: + { + cb(0, "Initializing layer..."); + + MeshModel& mm = *(md.addNewMesh(md.mm()->cm, "texdefrag_" + currentModel.label())); + mm.updateDataMask(¤tModel); + + QString path = currentModel.pathName(); + + tri::Clean::RemoveZeroAreaFace(mm.cm); + tri::Clean::RemoveDuplicateVertex(mm.cm); + tri::Allocator::CompactEveryVector(mm.cm); + + tri::UpdateTopology::FaceFace(mm.cm); + if (tri::Clean::CountNonManifoldEdgeFF(mm.cm) > 0) + log(GLLogStream::Levels::WARNING, "Texture Defragmentation: mesh has non-manifold edges, seam topology may be unreliable"); + + // switch working directory + QDir wd = QDir::current(); + QDir::setCurrent(path); + + // build mesh object + Mesh defragMesh; + auto fi = tri::Allocator::AddFaces(defragMesh, mm.cm.FN()); + auto vi = tri::Allocator::AddVertices(defragMesh, mm.cm.VN()); + + for (int i = 0; i < mm.cm.VN(); ++i) { + vi->P().X() = mm.cm.vert[i].P().X(); + vi->P().Y() = mm.cm.vert[i].P().Y(); + vi->P().Z() = mm.cm.vert[i].P().Z(); + ++vi; + } + + for (int i = 0; i < mm.cm.FN(); ++i) { + for (int k = 0; k < 3; ++k) { + fi->V(k) = &defragMesh.vert[mm.cm.face[i].cV(k)->Index()]; + fi->WT(k).U() = mm.cm.face[i].cWT(k).U(); + fi->WT(k).V() = mm.cm.face[i].cWT(k).V(); + fi->WT(k).N() = mm.cm.face[i].cWT(k).N(); + } + ++fi; + } + + for (auto& f : defragMesh.face) + f.SetMesh(); + + // build textureobjecthandle object + TextureObjectHandle textureObject = std::make_shared(); + + for (const string& textureName : currentModel.cm.textures) { + textureObject->AddImage(currentModel.getTexture(textureName)); + } + + AlgoParameters ap; + + ap.matchingThreshold = par.getFloat("matchingThreshold"); + ap.boundaryTolerance = par.getFloat("boundaryTolerance"); + ap.distortionTolerance = par.getFloat("distortionTolerance"); + ap.globalDistortionThreshold = par.getFloat("globalDistortionTolerance"); + ap.UVBorderLengthReduction = par.getFloat("uvReductionLimit") / 100.0f; + ap.offsetFactor = par.getFloat("offsetFactor"); + ap.timelimit = par.getFloat("timelimit"); + + tri::UpdateTopology::FaceFace(defragMesh); + tri::UpdateNormal::PerFaceNormalized(defragMesh); + tri::UpdateNormal::PerVertexNormalized(defragMesh); + + ScaleTextureCoordinatesToImage(defragMesh, textureObject); + + // setup proxy mesh + Compute3DFaceAdjacencyAttribute(defragMesh); + CutAlongSeams(defragMesh); + + GraphHandle graph = ComputeGraph(defragMesh, textureObject); + + while (tri::Clean::SplitNonManifoldVertex(defragMesh, 0)) + ; + tri::Allocator::CompactEveryVector(defragMesh); + + DisconnectCharts(graph); + tri::UpdateTopology::FaceFace(defragMesh); + tri::UpdateTopology::VertexFace(defragMesh); + + + ComputeWedgeTexCoordStorageAttribute(defragMesh); + + std::map flipped; + for (auto& c : graph->charts) + flipped[c.first] = c.second->UVFlipped(); + + ReorientCharts(graph); + + // run defragmentation algorithm + + std::map anchorMap; + AlgoStateHandle state = InitializeState(graph, ap); + + cb(20, "Defragmenting atlas..."); + + GreedyOptimization(graph, state, ap); + + int vndupOut; + Finalize(graph, &vndupOut); + + bool colorize = true; + + if (colorize) + tri::UpdateColor::PerFaceConstant(defragMesh, vcg::Color4b(91, 130, 200, 255)); + + for (auto& entry : graph->charts) { + ChartHandle chart = entry.second; + double zeroResamplingChartArea; + int anchor = RotateChartForResampling(chart, state->changeSet, flipped, colorize, &zeroResamplingChartArea); + if (anchor != -1) { + anchorMap[chart] = anchor; + } + } + + cb(70, "Packing atlas..."); + // clear texture coordinates of empty-area charts + std::vector chartsToPack; + for (auto& entry : graph->charts) { + if (entry.second->AreaUV() != 0) { + chartsToPack.push_back(entry.second); + } else { + for (auto fptr : entry.second->fpVec) { + for (int j = 0; j < fptr->VN(); ++j) { + fptr->V(j)->T().P() = Point2d::Zero(); + fptr->V(j)->T().N() = 0; + fptr->WT(j).P() = Point2d::Zero(); + fptr->WT(j).N() = 0; + } + } + } + } + + // Set non-manifold edges as border, otherwise outline extraction fails + for (auto& f : graph->mesh.face) { + for (int i = 0; i < 3; ++i) { + if (!face::IsManifold(f, i)) { + f.FFp(i) = &f; + f.FFi(i) = i; + } + } + } + + std::vector texszVec; + int npacked = Pack(chartsToPack, textureObject, texszVec); + + // this should never happen + if (npacked < (int) chartsToPack.size()) + throw MLException("Error: Packing failed (not all charts were packed)"); + + TrimTexture(defragMesh, texszVec, false); + + IntegerShift(defragMesh, chartsToPack, texszVec, anchorMap, flipped); + + glContext->makeCurrent(); + GLExtensionsManager::initializeGLextensions(); + std::vector> newTextures = RenderTexture(defragMesh, textureObject, texszVec, true, RenderMode::Linear); + glContext->doneCurrent(); + + // Copy wedge tex coords from defragMesh to cm + if (mm.cm.FN() != defragMesh.FN()) + throw MLException("TextureDefragmentation: Unexpected face count mismatch with proxy mesh"); + + for (int i = 0; i < defragMesh.FN(); ++i) { + for (int k = 0; k < 3; ++k) { + mm.cm.face[i].WT(k).U() = defragMesh.face[i].WT(k).U(); + mm.cm.face[i].WT(k).V() = defragMesh.face[i].WT(k).V(); + mm.cm.face[i].WT(k).N() = defragMesh.face[i].WT(k).N(); + } + } + + // save and assign textures + cb(90, "Saving textures..."); + mm.clearTextures(); + + const char *imageFormat = "png"; + QString textureBase = mm.label() + "_optimized_texture_"; + for (unsigned i = 0; i < newTextures.size(); ++i) { + QString tname = textureBase + QString(std::to_string(i).c_str()) + "." + imageFormat; + mm.addTexture(tname.toStdString(), *newTextures[i]); + } + + cb(100, "Done!"); + + // restore working dir + QDir::setCurrent(wd.absolutePath()); + } + break; + + default: + wrongActionCalled(filter); + } + + return std::map(); +} + +FilterPlugin::FilterArity FilterTextureDefragPlugin::filterArity(const QAction * filter ) const +{ + switch(ID(filter)) { + case FP_TEXTURE_DEFRAG: + return FilterPlugin::SINGLE_MESH; + } + + return FilterPlugin::NONE; +} + +MESHLAB_PLUGIN_NAME_EXPORTER(FilterTextureDefragPlugin) diff --git a/src/common/mainwindow_interface.h b/src/meshlabplugins/filter_texture_defragmentation/filter_texture_defragmentation.h similarity index 55% rename from src/common/mainwindow_interface.h rename to src/meshlabplugins/filter_texture_defragmentation/filter_texture_defragmentation.h index ec0520d2f..9391b5747 100644 --- a/src/common/mainwindow_interface.h +++ b/src/meshlabplugins/filter_texture_defragmentation/filter_texture_defragmentation.h @@ -2,13 +2,13 @@ * MeshLab o o * * A versatile mesh processing toolbox o o * * _ O _ * -* Copyright(C) 2005-2020 \/)\/ * +* Copyright(C) 2005 \/)\/ * * Visual Computing Lab /\/| * * ISTI - Italian National Research Council | * * \ * * All rights reserved. * * * -* This program is free software; you can redistribute it and/or modify * +* This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * @@ -21,22 +21,49 @@ * * ****************************************************************************/ -#ifndef MESHLAB_MAINWINDOW_INTERFACE_H -#define MESHLAB_MAINWINDOW_INTERFACE_H +#ifndef _FILTER_TEXTURE_H +#define _FILTER_TEXTURE_H -#include -#include "parameters/rich_parameter_list.h" -/** The MainWindowInterface class defines just the executeFilter() callback function -that is invoked by the standard parameter input dialog. -It is used as base class of the MainWindow. -*/ -class MainWindowInterface +#include +#include + +#include +#include +#include +#include +#include + +class FilterTextureDefragPlugin : public QObject, public FilterPlugin { -public: - virtual void executeFilter(const QAction *, RichParameterList &, bool = false) {} - //parexpval is a string map containing the parameter expression values set in the filter's dialog. - //These parameter expression values will be evaluated when the filter will start. + Q_OBJECT + MESHLAB_PLUGIN_IID_EXPORTER(FILTER_PLUGIN_IID) + Q_INTERFACES(FilterPlugin) + + public: + + enum { + FP_TEXTURE_DEFRAG, + }; + + FilterTextureDefragPlugin(); + + QString pluginName() const; + QString filterName(ActionIDType filter) const; + QString filterInfo(ActionIDType filter) const; + RichParameterList initParameterList(const QAction*, const MeshDocument &/*m*/); + std::map applyFilter( + const QAction* action, + const RichParameterList & parameters, + MeshDocument &md, + unsigned int& postConditionMask, + vcg::CallBackPos * cb); + virtual int getRequirements(const QAction*); + bool requiresGLContext(const QAction*) const; + virtual int getPreConditions(const QAction*) const; + virtual int postCondition(const QAction* ) const; + FilterClass getClass(const QAction *a) const; + FilterArity filterArity(const QAction* filter) const; }; -#endif // MESHLAB_MAINWINDOW_INTERFACE_H +#endif diff --git a/src/meshlabplugins/filter_trioptimize/filter_trioptimize.cpp b/src/meshlabplugins/filter_trioptimize/filter_trioptimize.cpp index 0f27e4597..4ff5767dc 100644 --- a/src/meshlabplugins/filter_trioptimize/filter_trioptimize.cpp +++ b/src/meshlabplugins/filter_trioptimize/filter_trioptimize.cpp @@ -202,8 +202,9 @@ int TriOptimizePlugin::postCondition(const QAction *a) const // - the string shown in the dialog // - the default value // - a possibly long string describing the meaning of that parameter (shown as a popup help in the dialog) -void TriOptimizePlugin::initParameterList(const QAction *action, MeshModel &m, RichParameterList & parlst) +RichParameterList TriOptimizePlugin::initParameterList(const QAction *action, const MeshModel &m) { + RichParameterList parlst; if (ID(action) == FP_CURVATURE_EDGE_FLIP) { parlst.addParam(RichBool("selection", m.cm.sfn > 0, tr("Update selection"), tr("Apply edge flip optimization on selected faces only"))); parlst.addParam(RichFloat("pthreshold", 1.0f, @@ -259,6 +260,7 @@ void TriOptimizePlugin::initParameterList(const QAction *action, MeshModel &m, R parlst.addParam(RichFloat("AngleDeg", 0.5f, tr("Max Normal Dev (deg)"), tr("maximum mean normal angle displacement (degrees) from old to new faces"))); parlst.addParam(RichInt("iterations", 1, "Iterations", tr("number of laplacian smooth iterations in every run"))); } + return parlst; } // The Real Core Function doing the actual mesh processing. diff --git a/src/meshlabplugins/filter_trioptimize/filter_trioptimize.h b/src/meshlabplugins/filter_trioptimize/filter_trioptimize.h index d9bbc0900..ebca7bd83 100644 --- a/src/meshlabplugins/filter_trioptimize/filter_trioptimize.h +++ b/src/meshlabplugins/filter_trioptimize/filter_trioptimize.h @@ -47,7 +47,7 @@ public: QString pluginName() const; QString filterName(ActionIDType filter) const; QString filterInfo(ActionIDType filter) const; - void initParameterList(const QAction*, MeshModel &/*m*/, RichParameterList & /*parent*/); + RichParameterList initParameterList(const QAction*, const MeshModel &/*m*/); std::map applyFilter( const QAction* action, const RichParameterList & parameters, diff --git a/src/meshlabplugins/filter_unsharp/filter_unsharp.cpp b/src/meshlabplugins/filter_unsharp/filter_unsharp.cpp index 440213950..988002e4f 100644 --- a/src/meshlabplugins/filter_unsharp/filter_unsharp.cpp +++ b/src/meshlabplugins/filter_unsharp/filter_unsharp.cpp @@ -312,8 +312,9 @@ int FilterUnsharp::postCondition(const QAction *a) const return MeshModel::MM_NONE; } -void FilterUnsharp::initParameterList(const QAction *action, MeshDocument &md, RichParameterList & parlst) +RichParameterList FilterUnsharp::initParameterList(const QAction *action, const MeshDocument &md) { + RichParameterList parlst; switch(ID(action)) { case FP_RECOMPUTE_VERTEX_NORMAL : @@ -387,7 +388,7 @@ void FilterUnsharp::initParameterList(const QAction *action, MeshDocument &md, R break; case FP_LINEAR_MORPH : { - parlst.addParam(RichMesh ("TargetMesh", md.mm(), &md,"Target Mesh", "The mesh that is the morph target.")); + parlst.addParam(RichMesh ("TargetMesh", md.mm()->id(), &md,"Target Mesh", "The mesh that is the morph target.")); parlst.addParam(RichDynamicFloat("PercentMorph", 0.0, -150, 250, "% Morph", tr("The percent you want to morph towards (or away from) the target.
" "0 means current mesh
" @@ -403,6 +404,7 @@ void FilterUnsharp::initParameterList(const QAction *action, MeshDocument &md, R parlst.addParam(RichBool("colorize", true, "Colorize", "Colorize the mesh to provide an indication of the obtained harmonic field.")); break; } + return parlst; } std::map FilterUnsharp::applyFilter( @@ -450,7 +452,7 @@ std::map FilterUnsharp::applyFilter( tri::Smooth::VertexCoordLaplacian(m.cm,stepSmoothNum,Selected,cotangentWeight,cb); log( "Smoothed %d vertices", Selected ? m.cm.svn : m.cm.vn); - m.UpdateBoxAndNormals(); + m.updateBoxAndNormals(); } break; case FP_DEPTH_SMOOTH : @@ -463,7 +465,7 @@ std::map FilterUnsharp::applyFilter( Point3m viewpoint = par.getPoint3m("viewPoint"); tri::Smooth::VertexCoordViewDepth(m.cm, viewpoint, delta, stepSmoothNum, Selected,true); log("depth Smoothed %d vertices", Selected ? m.cm.svn : m.cm.vn); - m.UpdateBoxAndNormals(); + m.updateBoxAndNormals(); } break; case FP_DIRECTIONAL_PRESERVATION: @@ -502,7 +504,7 @@ std::map FilterUnsharp::applyFilter( float s = d * ( (*vi).cP() - h[vi] ); (*vi).P() = h[vi] + d * (s*alpha); } - m.UpdateBoxAndNormals(); + m.updateBoxAndNormals(); log( "Projected smoothed Position %d vertices", m.cm.vn); } break; @@ -519,7 +521,7 @@ std::map FilterUnsharp::applyFilter( Scalarm delta = par.getAbsPerc("delta"); tri::Smooth::VertexCoordScaleDependentLaplacian_Fujiwara(m.cm,stepSmoothNum,delta); log( "Smoothed %d vertices", cnt>0 ? cnt : m.cm.vn); - m.UpdateBoxAndNormals(); + m.updateBoxAndNormals(); } break; case FP_HC_LAPLACIAN_SMOOTH: @@ -527,7 +529,7 @@ std::map FilterUnsharp::applyFilter( tri::UpdateFlags::FaceBorderFromNone(m.cm); size_t cnt=tri::UpdateSelection::VertexFromFaceStrict(m.cm); tri::Smooth::VertexCoordLaplacianHC(m.cm,1,cnt>0); - m.UpdateBoxAndNormals(); + m.updateBoxAndNormals(); } break; case FP_TWO_STEP_SMOOTH: @@ -548,7 +550,7 @@ std::map FilterUnsharp::applyFilter( tri::UpdateNormal::PerFaceNormalized(m.cm); tri::Smooth::VertexCoordPasoDoble(m.cm, stepNormalNum, sigma, stepFitNum,selectedFlag); } - m.UpdateBoxAndNormals(); + m.updateBoxAndNormals(); } break; case FP_TAUBIN_SMOOTH : @@ -561,7 +563,7 @@ std::map FilterUnsharp::applyFilter( size_t cnt=tri::UpdateSelection::VertexFromFaceStrict(m.cm); tri::Smooth::VertexCoordTaubin(m.cm,stepSmoothNum,lambda,mu,cnt>0,cb); log( "Smoothed %d vertices", cnt>0 ? cnt : m.cm.vn); - m.UpdateBoxAndNormals(); + m.updateBoxAndNormals(); } break; case FP_RECOMPUTE_FACE_NORMAL : @@ -648,7 +650,7 @@ std::map FilterUnsharp::applyFilter( for(int i=0;i FilterUnsharp::applyFilter( case FP_LINEAR_MORPH: { - CMeshO &targetMesh = par.getMesh("TargetMesh")->cm; + CMeshO &targetMesh = md.getMesh(par.getMeshId("TargetMesh"))->cm; CMeshO &sourceMesh = m.cm; //if the numbers of vertices don't match up @@ -716,7 +718,7 @@ std::map FilterUnsharp::applyFilter( srcP = srcP + (trgP-srcP)*percentage; } - m.UpdateBoxAndNormals(); + m.updateBoxAndNormals(); } break; case FP_SCALAR_HARMONIC_FIELD: { diff --git a/src/meshlabplugins/filter_unsharp/filter_unsharp.h b/src/meshlabplugins/filter_unsharp/filter_unsharp.h index 67d56bfa7..cad9cfc66 100644 --- a/src/meshlabplugins/filter_unsharp/filter_unsharp.h +++ b/src/meshlabplugins/filter_unsharp/filter_unsharp.h @@ -78,7 +78,7 @@ public: MeshDocument &md, unsigned int& postConditionMask, vcg::CallBackPos * cb); - void initParameterList(const QAction* action, MeshDocument &/*m*/, RichParameterList & parlst); + RichParameterList initParameterList(const QAction* action, const MeshDocument &/*m*/); int postCondition(const QAction* ) const; int getPreConditions(const QAction*) const; FilterArity filterArity(const QAction* filter) const; diff --git a/src/meshlabplugins/filter_voronoi/filter_voronoi.cpp b/src/meshlabplugins/filter_voronoi/filter_voronoi.cpp index bc33fc64f..0fc8dff1f 100644 --- a/src/meshlabplugins/filter_voronoi/filter_voronoi.cpp +++ b/src/meshlabplugins/filter_voronoi/filter_voronoi.cpp @@ -132,21 +132,22 @@ FilterPlugin::FilterArity FilterVoronoiPlugin::filterArity(const QAction* a) con } } -void FilterVoronoiPlugin::initParameterList(const QAction* action, MeshModel& m, RichParameterList& par) +RichParameterList FilterVoronoiPlugin::initParameterList(const QAction* action, const MeshModel& m) { - switch(ID(action)) { - case VORONOI_SAMPLING : - par.addParam(RichInt("iterNum", 10, "Iteration", "number of iterations")); - par.addParam(RichInt("sampleNum", 10, "Sample Num.", "Number of samples")); - par.addParam(RichFloat("radiusVariance", 1, "Radius Variance", "The distance metric will vary along the surface between 1/x and x, linearly according to the scalar field specified by the quality.")); - par.addParam(RichEnum("colorStrategy", 1, {"None", "Seed Distance", "Border Distance", "Region Area"}, "Color Strategy")); - par.addParam(RichEnum("distanceType", 0, {"Euclidean", "Quality Weighted", "Anisotropic"}, "Distance Type")); - par.addParam(RichBool("preprocessFlag", false, "Preprocessing")); - par.addParam(RichInt("refineFactor", 10, "Refinement Factor", "To ensure good convergence the mesh should be more complex than the voronoi partitioning. This number affect how much the mesh is refined according to the required number of samples.")); - par.addParam(RichFloat("perturbProbability", 0, "Perturbation Probability", "To ensure good convergence the mesh should be more complex than the voronoi partitioning. This number affect how much the mesh is refined according to the required number of samples.")); - par.addParam(RichFloat("perturbAmount", 0.001, "Perturbation Amount", "To ensure good convergence the mesh should be more complex than the voronoi partitioning. This number affect how much the mesh is refined according to the required number of samples.")); - par.addParam(RichInt("randomSeed", 0, "Random seed", "To ensure repeatability you can specify the random seed used. If 0 the random seed is tied to the current clock.")); - par.addParam(RichEnum("relaxType", 1, {"Geodesic", "Squared Distance", "Restricted"}, "Relax Type", + RichParameterList par; + switch(ID(action)) { + case VORONOI_SAMPLING : + par.addParam(RichInt("iterNum", 10, "Iteration", "number of iterations")); + par.addParam(RichInt("sampleNum", 10, "Sample Num.", "Number of samples")); + par.addParam(RichFloat("radiusVariance", 1, "Radius Variance", "The distance metric will vary along the surface between 1/x and x, linearly according to the scalar field specified by the quality.")); + par.addParam(RichEnum("colorStrategy", 1, {"None", "Seed Distance", "Border Distance", "Region Area"}, "Color Strategy")); + par.addParam(RichEnum("distanceType", 0, {"Euclidean", "Quality Weighted", "Anisotropic"}, "Distance Type")); + par.addParam(RichBool("preprocessFlag", false, "Preprocessing")); + par.addParam(RichInt("refineFactor", 10, "Refinement Factor", "To ensure good convergence the mesh should be more complex than the voronoi partitioning. This number affect how much the mesh is refined according to the required number of samples.")); + par.addParam(RichFloat("perturbProbability", 0, "Perturbation Probability", "To ensure good convergence the mesh should be more complex than the voronoi partitioning. This number affect how much the mesh is refined according to the required number of samples.")); + par.addParam(RichFloat("perturbAmount", 0.001, "Perturbation Amount", "To ensure good convergence the mesh should be more complex than the voronoi partitioning. This number affect how much the mesh is refined according to the required number of samples.")); + par.addParam(RichInt("randomSeed", 0, "Random seed", "To ensure repeatability you can specify the random seed used. If 0 the random seed is tied to the current clock.")); + par.addParam(RichEnum("relaxType", 1, {"Geodesic", "Squared Distance", "Restricted"}, "Relax Type", "At each relaxation step we search for each voronoi region the new position of the seed. " "According to the classical LLoyd relaxation strategy it should have been placed onto the " "barycenter of the region. Over a surface we have two different strategies:
    " @@ -154,45 +155,46 @@ void FilterVoronoiPlugin::initParameterList(const QAction* action, MeshModel& m, "
  • Squared Distance: the seed is placed in the vertex that minimize the squared sum of the distances from all the pints of the region.
  • " "
  • Restricted: the seed is placed in the barycenter of current voronoi region. Even if it is outside the surface. During the relaxation process the seed is free to move off the surface in a continuous way. Re-association to vertex is done at the end..
  • " "
")); - break; - case VOLUME_SAMPLING: - par.addParam(RichAbsPerc("sampleSurfRadius", m.cm.bbox.Diag() / 500.0, 0, m.cm.bbox.Diag(),"Surface Sampling Radius", "Surface Sampling is used only as an optimization.")); - par.addParam(RichInt("sampleVolNum", 200000, "Volume Sample Num.", "Number of volumetric samples scattered inside the mesh and used for choosing the voronoi seeds and performing the Lloyd relaxation for having a centroidal voronoi diagram.")); - par.addParam(RichBool("poissonFiltering", true, "Poisson Filtering", "If true the base montecarlo sampling of the volume is filtered to get a poisson disk volumetric distribution.")); - par.addParam(RichAbsPerc("poissonRadius", m.cm.bbox.Diag() / 100.0, 0, m.cm.bbox.Diag(), "Poisson Radius", "Number of voxel per side in the volumetric representation.")); - break; - case VORONOI_SCAFFOLDING: - par.addParam(RichAbsPerc("sampleSurfRadius", m.cm.bbox.Diag() / 100.0, 0, m.cm.bbox.Diag(), "Surface Sampling Radius", "Surface Sampling is used only as an optimization.")); - par.addParam(RichInt("sampleVolNum", 100000, "Volume Sample Num.", "Number of volumetric samples scattered inside the mesh and used for choosing the voronoi seeds and performing the Lloyd relaxation for having a centroidal voronoi diagram.")); - par.addParam(RichInt("voxelRes", 50, "Volume Side Resolution", "Number of voxel per side in the volumetric representation.")); - par.addParam(RichFloat("isoThr", 1, "Width of the entity (in voxel)", "Number of voxel per side in the volumetric representation.")); - par.addParam(RichInt("smoothStep", 3, "Smooth Step", "Number of voxel per side in the volumetric representation.")); - par.addParam(RichInt("relaxStep", 5, "Lloyd Relax Step", "Number of Lloyd relaxation step to get a better distribution of the voronoi seeds.")); - par.addParam(RichBool("surfFlag", true, "Add original surface", "Number of voxel per side in the volumetric representation.")); - par.addParam(RichEnum("elemType", 1, {"Seed", "Edge", "Face"}, "Voronoi Element")); - break; - case BUILD_SHELL: - par.addParam(RichBool("edgeCylFlag", true, "Edge -> Cyl.", "If True all the edges are converted into cylinders.")); - par.addParam(RichAbsPerc("edgeCylRadius", m.cm.bbox.Diag() / 100.0, 0, m.cm.bbox.Diag(), "Edge Cylinder Rad.", "The radius of the cylinder replacing each edge.")); - par.addParam(RichBool("vertCylFlag", false, "Vertex -> Cyl.", "If True all the vertices are converted into cylinders.")); - par.addParam(RichAbsPerc("vertCylRadius", m.cm.bbox.Diag() / 100.0, 0, m.cm.bbox.Diag(), "Vertex Cylinder Rad.", "The radius of the cylinder replacing each vertex.")); - par.addParam(RichBool("vertSphFlag", true, "Vertex -> Sph.", "If True all the vertices are converted into sphere.")); - par.addParam(RichAbsPerc("vertSphRadius", m.cm.bbox.Diag() / 100.0, 0, m.cm.bbox.Diag(), "Vertex Sphere Rad.", "The radius of the sphere replacing each vertex.")); - par.addParam(RichBool("faceExtFlag", true, "Face -> Prism", "If True all the faces are converted into prism.")); - par.addParam(RichAbsPerc("faceExtHeight", m.cm.bbox.Diag() / 200.0, 0, m.cm.bbox.Diag(), "Face Prism Height", "The Height of the prism that is substitued with each face.")); - par.addParam(RichAbsPerc("faceExtInset", m.cm.bbox.Diag() / 200.0, 0, m.cm.bbox.Diag(), "Face Prism Inset", "The inset radius of each prism, e.g. how much it is moved toward the inside each vertex on the border of the prism.")); - par.addParam(RichBool("edgeFauxFlag", true, "Ignore faux edges", "If true only the Non-Faux edges will be considered for conversion.")); - par.addParam(RichInt("cylinderSideNum", 16, "Cylinder Side", "Number of sides of the cylinder (both edge and vertex).")); - break; - case CROSS_FIELD_CREATION: - par.addParam(RichEnum("crossType", 0, {"Linear Y", "Radial", "Curvature"}, "Cross Type", "")); - break; -// case CROSS_FIELD_SMOOTHING: -// par.addParam(RichBool("preprocessFlag", true, "Preprocessing")); -// break; - default : - assert(0); - } + break; + case VOLUME_SAMPLING: + par.addParam(RichAbsPerc("sampleSurfRadius", m.cm.bbox.Diag() / 500.0, 0, m.cm.bbox.Diag(),"Surface Sampling Radius", "Surface Sampling is used only as an optimization.")); + par.addParam(RichInt("sampleVolNum", 200000, "Volume Sample Num.", "Number of volumetric samples scattered inside the mesh and used for choosing the voronoi seeds and performing the Lloyd relaxation for having a centroidal voronoi diagram.")); + par.addParam(RichBool("poissonFiltering", true, "Poisson Filtering", "If true the base montecarlo sampling of the volume is filtered to get a poisson disk volumetric distribution.")); + par.addParam(RichAbsPerc("poissonRadius", m.cm.bbox.Diag() / 100.0, 0, m.cm.bbox.Diag(), "Poisson Radius", "Number of voxel per side in the volumetric representation.")); + break; + case VORONOI_SCAFFOLDING: + par.addParam(RichAbsPerc("sampleSurfRadius", m.cm.bbox.Diag() / 100.0, 0, m.cm.bbox.Diag(), "Surface Sampling Radius", "Surface Sampling is used only as an optimization.")); + par.addParam(RichInt("sampleVolNum", 100000, "Volume Sample Num.", "Number of volumetric samples scattered inside the mesh and used for choosing the voronoi seeds and performing the Lloyd relaxation for having a centroidal voronoi diagram.")); + par.addParam(RichInt("voxelRes", 50, "Volume Side Resolution", "Number of voxel per side in the volumetric representation.")); + par.addParam(RichFloat("isoThr", 1, "Width of the entity (in voxel)", "Number of voxel per side in the volumetric representation.")); + par.addParam(RichInt("smoothStep", 3, "Smooth Step", "Number of voxel per side in the volumetric representation.")); + par.addParam(RichInt("relaxStep", 5, "Lloyd Relax Step", "Number of Lloyd relaxation step to get a better distribution of the voronoi seeds.")); + par.addParam(RichBool("surfFlag", true, "Add original surface", "Number of voxel per side in the volumetric representation.")); + par.addParam(RichEnum("elemType", 1, {"Seed", "Edge", "Face"}, "Voronoi Element")); + break; + case BUILD_SHELL: + par.addParam(RichBool("edgeCylFlag", true, "Edge -> Cyl.", "If True all the edges are converted into cylinders.")); + par.addParam(RichAbsPerc("edgeCylRadius", m.cm.bbox.Diag() / 100.0, 0, m.cm.bbox.Diag(), "Edge Cylinder Rad.", "The radius of the cylinder replacing each edge.")); + par.addParam(RichBool("vertCylFlag", false, "Vertex -> Cyl.", "If True all the vertices are converted into cylinders.")); + par.addParam(RichAbsPerc("vertCylRadius", m.cm.bbox.Diag() / 100.0, 0, m.cm.bbox.Diag(), "Vertex Cylinder Rad.", "The radius of the cylinder replacing each vertex.")); + par.addParam(RichBool("vertSphFlag", true, "Vertex -> Sph.", "If True all the vertices are converted into sphere.")); + par.addParam(RichAbsPerc("vertSphRadius", m.cm.bbox.Diag() / 100.0, 0, m.cm.bbox.Diag(), "Vertex Sphere Rad.", "The radius of the sphere replacing each vertex.")); + par.addParam(RichBool("faceExtFlag", true, "Face -> Prism", "If True all the faces are converted into prism.")); + par.addParam(RichAbsPerc("faceExtHeight", m.cm.bbox.Diag() / 200.0, 0, m.cm.bbox.Diag(), "Face Prism Height", "The Height of the prism that is substitued with each face.")); + par.addParam(RichAbsPerc("faceExtInset", m.cm.bbox.Diag() / 200.0, 0, m.cm.bbox.Diag(), "Face Prism Inset", "The inset radius of each prism, e.g. how much it is moved toward the inside each vertex on the border of the prism.")); + par.addParam(RichBool("edgeFauxFlag", true, "Ignore faux edges", "If true only the Non-Faux edges will be considered for conversion.")); + par.addParam(RichInt("cylinderSideNum", 16, "Cylinder Side", "Number of sides of the cylinder (both edge and vertex).")); + break; + case CROSS_FIELD_CREATION: + par.addParam(RichEnum("crossType", 0, {"Linear Y", "Radial", "Curvature"}, "Cross Type", "")); + break; +// case CROSS_FIELD_SMOOTHING: +// par.addParam(RichBool("preprocessFlag", true, "Preprocessing")); +// break; + default : + assert(0); + } + return par; } int FilterVoronoiPlugin::getPreConditions(const QAction* action) const @@ -391,7 +393,7 @@ void FilterVoronoiPlugin::voronoiSampling( for(auto vi =seedVec.begin();vi!=seedVec.end();++vi) (*vi)->SetS(); - om->UpdateBoxAndNormals(); + om->updateBoxAndNormals(); } void FilterVoronoiPlugin::volumeSampling( @@ -470,7 +472,7 @@ void FilterVoronoiPlugin::voronoiScaffolding( vvs.BuildScaffoldingMesh(sm->cm,par); cb(90, "Final Smoothing..."); tri::Smooth::VertexCoordLaplacian(sm->cm, smoothStep); - sm->UpdateBoxAndNormals(); + sm->updateBoxAndNormals(); tri::Append::MeshCopy(mcVm->cm,vvs.montecarloVolumeMesh); tri::Append::MeshCopy(pm->cm,vvs.psd.poissonSurfaceMesh); } @@ -506,7 +508,7 @@ void FilterVoronoiPlugin::createSolidWireframe( if(vertSphFlag) tri::BuildSphereVertexShell(m->cm,sm->cm,vertSphRadius); if(faceExtFlag) tri::BuildPrismFaceShell(m->cm,sm->cm,faceExtHeight,faceExtInset); - sm->UpdateBoxAndNormals(); + sm->updateBoxAndNormals(); } void FilterVoronoiPlugin::crossFieldCreation( diff --git a/src/meshlabplugins/filter_voronoi/filter_voronoi.h b/src/meshlabplugins/filter_voronoi/filter_voronoi.h index 472455ca4..6c1414dac 100644 --- a/src/meshlabplugins/filter_voronoi/filter_voronoi.h +++ b/src/meshlabplugins/filter_voronoi/filter_voronoi.h @@ -49,7 +49,7 @@ public: QString filterInfo(ActionIDType filter) const; FilterClass getClass(const QAction* a) const; FilterArity filterArity(const QAction* a) const; - void initParameterList(const QAction* action, MeshModel& m, RichParameterList& par); + RichParameterList initParameterList(const QAction* action, const MeshModel& m); int getPreConditions(const QAction* action) const; std::map applyFilter( const QAction* action, diff --git a/src/meshlabplugins/io_3ds/import_3ds.h b/src/meshlabplugins/io_3ds/import_3ds.h index 2ef1db8db..5fa1cf6e2 100644 --- a/src/meshlabplugins/io_3ds/import_3ds.h +++ b/src/meshlabplugins/io_3ds/import_3ds.h @@ -143,215 +143,232 @@ static int Load( OpenMeshType &m, Lib3dsFile *file, Lib3dsNode *node, _3dsInfo & int numVertices = 0; int numFaces = 0; - if (!node) - { - for (p=file->nodes; p!=0; p=p->next) - if (ReadNode(m, file, p, vi, fi, info, numVertices, numFaces) == E_ABORTED) - return E_ABORTED; - } - else - { - if (ReadNode(m, file, node, vi, fi, info, numVertices, numFaces) == E_ABORTED) + if (node == nullptr) { //load all nodes in a single file + for (p=file->nodes; p!=0; p=p->next) + if (readNode(m, file, p, vi, fi, info, numVertices, numFaces) == E_ABORTED) return E_ABORTED; - } - + } + else { + if (readNode(m, file, node, vi, fi, info, numVertices, numFaces, false) == E_ABORTED) + return E_ABORTED; + } + return result; } // end of Open - static int ReadNode(OpenMeshType &m, Lib3dsFile* file, Lib3dsNode *node, VertexIterator &vi, FaceIterator &fi, _3dsInfo &info, int &numVertices, int &numFaces) +static int readNode( + OpenMeshType &m, + Lib3dsFile* file, + Lib3dsNode *node, + VertexIterator &vi, + FaceIterator &fi, _3dsInfo &info, + int &numVertices, + int &numFaces, + bool applyTransformMatrix = true) +{ + int result = E_NOERROR; + ASSERT(file); + { - int result = E_NOERROR; - ASSERT(file); + Lib3dsNode *p; + for (p=node->childs; p!=0; p=p->next) + if (readNode(m, file, p, vi, fi, info, numVertices, numFaces) == E_ABORTED) + return E_ABORTED; + } + if (node->type==LIB3DS_OBJECT_NODE) + { + if (strcmp(node->name,"$$$DUMMY") == 0) + return E_NOERROR; + + Lib3dsMesh * mesh = lib3ds_file_mesh_by_name(file, node->data.object.morph); + if( mesh == NULL ) + mesh = lib3ds_file_mesh_by_name(file, node->name); + + ASSERT(mesh); + if (!mesh) + return E_NOERROR; + + if (!mesh->user.d) { - Lib3dsNode *p; - for (p=node->childs; p!=0; p=p->next) - if (ReadNode(m, file, p, vi, fi, info, numVertices, numFaces) == E_ABORTED) - return E_ABORTED; - } + int numVerticesPlusFaces = info.numVertices + info.numTriangles; - if (node->type==LIB3DS_OBJECT_NODE) - { - if (strcmp(node->name,"$$$DUMMY") == 0) - return E_NOERROR; - - Lib3dsMesh * mesh = lib3ds_file_mesh_by_name(file, node->data.object.morph); - if( mesh == NULL ) - mesh = lib3ds_file_mesh_by_name(file, node->name); + Lib3dsVector *normalL= (Lib3dsVector*) malloc(3*sizeof(Lib3dsVector)*mesh->faces); - ASSERT(mesh); - if (!mesh) - return E_NOERROR; - - if (!mesh->user.d) - { - int numVerticesPlusFaces = info.numVertices + info.numTriangles; - - Lib3dsVector *normalL= (Lib3dsVector*) malloc(3*sizeof(Lib3dsVector)*mesh->faces); + // Obtain current transformation matrix + // ------------------------------------ + Lib3dsMatrix matrix; + //Lib3dsMatrix translatedMatrix; + Lib3dsMatrix inverseMatrix; - // Obtain current transformation matrix - // ------------------------------------ - Lib3dsMatrix matrix; - //Lib3dsMatrix translatedMatrix; - Lib3dsMatrix inverseMatrix; - - Lib3dsObjectData *d; - d=&node->data.object; + Lib3dsObjectData *d; + d=&node->data.object; - // Version for lib3ds-1.2.0 - //lib3ds_matrix_copy(translatedMatrix, mesh->matrix); - //lib3ds_matrix_copy(inverseMatrix, mesh->matrix); - //lib3ds_matrix_inv(inverseMatrix); - //lib3ds_matrix_translate_xyz(translatedMatrix, -d->pivot[0], -d->pivot[1], -d->pivot[2]); - //lib3ds_matrix_mult(matrix, translatedMatrix, inverseMatrix); - - // Version for lib3ds-1.3.0 - lib3ds_matrix_copy(matrix, mesh->matrix); - lib3ds_matrix_copy(inverseMatrix, mesh->matrix); - lib3ds_matrix_inv(inverseMatrix); - lib3ds_matrix_translate_xyz(matrix, -d->pivot[0], -d->pivot[1], -d->pivot[2]); - lib3ds_matrix_mult(matrix, inverseMatrix); - + // Version for lib3ds-1.2.0 + //lib3ds_matrix_copy(translatedMatrix, mesh->matrix); + //lib3ds_matrix_copy(inverseMatrix, mesh->matrix); + //lib3ds_matrix_inv(inverseMatrix); + //lib3ds_matrix_translate_xyz(translatedMatrix, -d->pivot[0], -d->pivot[1], -d->pivot[2]); + //lib3ds_matrix_mult(matrix, translatedMatrix, inverseMatrix); - lib3ds_mesh_calculate_normals(mesh, normalL); + // Version for lib3ds-1.3.0 + lib3ds_matrix_copy(matrix, mesh->matrix); + lib3ds_matrix_copy(inverseMatrix, mesh->matrix); + lib3ds_matrix_inv(inverseMatrix); + lib3ds_matrix_translate_xyz(matrix, -d->pivot[0], -d->pivot[1], -d->pivot[2]); + lib3ds_matrix_mult(matrix, inverseMatrix); + // + + lib3ds_mesh_calculate_normals(mesh, normalL); - // allocazione spazio per i vertici e le facce della mesh corrente - vi = Allocator::AddVertices(m ,mesh->points); - fi = Allocator::AddFaces(m ,mesh->faces); - - for (unsigned v=0; vpoints; ++v) { - Lib3dsVector *p = &mesh->pointL[v].pos; - - Lib3dsVector transformedP; - lib3ds_vector_transform( transformedP, matrix, *p); - - (*vi).P()[0] = transformedP[0]; - (*vi).P()[1] = transformedP[1]; - (*vi).P()[2] = transformedP[2]; + // allocazione spazio per i vertici e le facce della mesh corrente + vi = Allocator::AddVertices(m ,mesh->points); + fi = Allocator::AddFaces(m ,mesh->faces); - ++vi; + if (!applyTransformMatrix){ + for (int i = 0; i < 4; i++) + for (int j = 0; j < 4; j++) + m.Tr.ElementAt(i,j) = matrix[i][j]; + } - // callback invocation, abort loading process if the call returns false - if ( (info.cb !=NULL) && - (((numFaces + numVertices + v)%100)==0) && - !(*info.cb)(100.0f * (float)(numFaces + numVertices + v)/(float)numVerticesPlusFaces, "Vertex Loading") ) - return E_ABORTED; - } + for (unsigned v=0; vpoints; ++v) { + Lib3dsVector *p = &mesh->pointL[v].pos; - for (unsigned p=0; pfaces; ++p) { - Lib3dsFace *f = &mesh->faceL[p]; - Lib3dsMaterial *mat = 0; - if (f->material[0]) - mat = lib3ds_file_material_by_name(file, f->material); - - if (mat) - { - // considering only diffuse color component - if( info.mask & vcg::tri::io::Mask::IOM_FACECOLOR) - { - // assigning face color - // -------------------- - (*fi).C()[0] = (unsigned char) (mat->diffuse[0] * 255.0f); - (*fi).C()[1] = (unsigned char) (mat->diffuse[1] * 255.0f); - (*fi).C()[2] = (unsigned char) (mat->diffuse[2] * 255.0f); - (*fi).C()[3] = (unsigned char) (mat->diffuse[3] * 255.0f); - } - - // texture map 1 - if (mat->texture1_map.name[0]) - { - std::string textureName = mat->texture1_map.name; - int textureIdx = 0; - - // adding texture name into textures vector (if not already present) - // avoid adding the same name twice - bool found = false; - unsigned size = unsigned(m.textures.size()); - unsigned j = 0; - while (!found && (j < size)) - { - if (textureName.compare(m.textures[j])==0) - { - textureIdx = (int)j; - found = true; - } - ++j; - } - if (!found) - { - m.textures.push_back(textureName); - textureIdx = (int)size; - } - - if (tri::HasPerWedgeTexCoord(m) && (info.mask & vcg::tri::io::Mask::IOM_WEDGTEXCOORD) ) - { - // texture coordinates - for (int i=0; i<3; ++i) - { - (*fi).WT(i).u() = mesh->texelL[f->points[i]][0]; - (*fi).WT(i).v() = mesh->texelL[f->points[i]][1]; - - (*fi).WT(i).n() = textureIdx; - } - } - } - } - else { - // we consider only diffuse color component, using default value - if(tri::HasPerFaceColor(m) && (info.mask & vcg::tri::io::Mask::IOM_FACECOLOR) ) - { - // assigning default face color - // ---------------------------- - (*fi).C()[0] = 204; - (*fi).C()[1] = 204; - (*fi).C()[2] = 204; - (*fi).C()[3] = 255; - } - } - - if ( info.mask & vcg::tri::io::Mask::IOM_FACENORMAL ) - { - // assigning face normal - // --------------------- - // we do not have to multiply normal for current matrix (as we did for vertices) - // since translation operations do not affect normals - (*fi).N() = Point3f(f->normal); - } - - for (int i=0; i<3; ++i) - { - if (tri::HasPerWedgeNormal(m) && ( info.mask & vcg::tri::io::Mask::IOM_WEDGNORMAL ) ) - { - // assigning per wedge normal - // -------------------------- - (*fi).WN(i) = Point3f(normalL[3*p+i]); - } - - // assigning face vertices - // ----------------------- - (*fi).V(i) = &(m.vert[ (numVertices + f->points[i]) ]); - } - - ++fi; - ++numFaces; - // callback invocation, abort loading process if the call returns false - if ( (info.cb !=NULL) && - (((numFaces + numVertices + mesh->points)%100)==0) && - !(*info.cb)(100.0f * (float)(numFaces + numVertices + mesh->points)/(float)numVerticesPlusFaces, "Face Loading") ) - return E_ABORTED; + Lib3dsVector transformedP; + if (applyTransformMatrix){ + lib3ds_vector_transform(transformedP, matrix, *p); + } + else { + lib3ds_vector_copy(transformedP, *p); } - free(normalL); + (*vi).P()[0] = transformedP[0]; + (*vi).P()[1] = transformedP[1]; + (*vi).P()[2] = transformedP[2]; - numVertices += mesh->points; - } + ++vi; + // callback invocation, abort loading process if the call returns false + if ((info.cb !=NULL) && + (((numFaces + numVertices + v)%100)==0) && + !(*info.cb)(100.0f * (float)(numFaces + numVertices + v)/(float)numVerticesPlusFaces, "Vertex Loading") ) + return E_ABORTED; + } + + for (unsigned p=0; pfaces; ++p) { + Lib3dsFace *f = &mesh->faceL[p]; + Lib3dsMaterial *mat = 0; + if (f->material[0]) + mat = lib3ds_file_material_by_name(file, f->material); + + if (mat) + { + // considering only diffuse color component + if( info.mask & vcg::tri::io::Mask::IOM_FACECOLOR) + { + // assigning face color + // -------------------- + (*fi).C()[0] = (unsigned char) (mat->diffuse[0] * 255.0f); + (*fi).C()[1] = (unsigned char) (mat->diffuse[1] * 255.0f); + (*fi).C()[2] = (unsigned char) (mat->diffuse[2] * 255.0f); + (*fi).C()[3] = (unsigned char) (mat->diffuse[3] * 255.0f); + } + + // texture map 1 + if (mat->texture1_map.name[0]) + { + std::string textureName = mat->texture1_map.name; + int textureIdx = 0; + + // adding texture name into textures vector (if not already present) + // avoid adding the same name twice + bool found = false; + unsigned size = unsigned(m.textures.size()); + unsigned j = 0; + while (!found && (j < size)) + { + if (textureName.compare(m.textures[j])==0) + { + textureIdx = (int)j; + found = true; + } + ++j; + } + if (!found) + { + m.textures.push_back(textureName); + textureIdx = (int)size; + } + + if (tri::HasPerWedgeTexCoord(m) && (info.mask & vcg::tri::io::Mask::IOM_WEDGTEXCOORD) ) + { + // texture coordinates + for (int i=0; i<3; ++i) + { + (*fi).WT(i).u() = mesh->texelL[f->points[i]][0]; + (*fi).WT(i).v() = mesh->texelL[f->points[i]][1]; + + (*fi).WT(i).n() = textureIdx; + } + } + } + } + else { + // we consider only diffuse color component, using default value + if(tri::HasPerFaceColor(m) && (info.mask & vcg::tri::io::Mask::IOM_FACECOLOR) ) + { + // assigning default face color + // ---------------------------- + (*fi).C()[0] = 204; + (*fi).C()[1] = 204; + (*fi).C()[2] = 204; + (*fi).C()[3] = 255; + } + } + + if ( info.mask & vcg::tri::io::Mask::IOM_FACENORMAL ) + { + // assigning face normal + // --------------------- + // we do not have to multiply normal for current matrix (as we did for vertices) + // since translation operations do not affect normals + (*fi).N() = Point3f(f->normal); + } + + for (int i=0; i<3; ++i) + { + if (tri::HasPerWedgeNormal(m) && ( info.mask & vcg::tri::io::Mask::IOM_WEDGNORMAL ) ) + { + // assigning per wedge normal + // -------------------------- + (*fi).WN(i) = Point3f(normalL[3*p+i]); + } + + // assigning face vertices + // ----------------------- + (*fi).V(i) = &(m.vert[ (numVertices + f->points[i]) ]); + } + + ++fi; + ++numFaces; + // callback invocation, abort loading process if the call returns false + if ( (info.cb !=NULL) && + (((numFaces + numVertices + mesh->points)%100)==0) && + !(*info.cb)(100.0f * (float)(numFaces + numVertices + mesh->points)/(float)numVerticesPlusFaces, "Face Loading") ) + return E_ABORTED; + } + + free(normalL); + + numVertices += mesh->points; } - return result; } + + return result; +} /*! * Retrieves kind of data stored into the file and fills a mask appropriately diff --git a/src/meshlabplugins/io_3ds/meshio.cpp b/src/meshlabplugins/io_3ds/meshio.cpp index 9154eb210..f78dae0b2 100644 --- a/src/meshlabplugins/io_3ds/meshio.cpp +++ b/src/meshlabplugins/io_3ds/meshio.cpp @@ -75,41 +75,61 @@ void ExtraMeshIOPlugin::exportMaskCapability(const QString &format, int &capabil return; } +RichParameterList ExtraMeshIOPlugin::initPreOpenParameter(const QString& format) const +{ + RichParameterList parameters; + if(format.toUpper() == tr("3DS")) + parameters.addParam(RichBool( + "load_in_a_single_layer", false, "Load in a single layer", + "3DS files may contain more than one mesh. If this parameter is " + "set to false, all the meshes contained in the file will be " + "merged in a single mesh.")); + return parameters; +} + unsigned int ExtraMeshIOPlugin::numberMeshesContainedInFile( const QString& format, - const QString& fileName) const + const QString& fileName, + const RichParameterList& preParams) const { if (format.toUpper() == tr("3DS")) { - Lib3dsFile *file = NULL; - file = lib3ds_file_load(fileName.toStdString().c_str()); - if (!file) - throw MLException("Malformed file."); - // No nodes? Fabricate nodes to display all the meshes. - if( !file->nodes && file->meshes) { - Lib3dsMesh *mesh; - Lib3dsNode *node; + if (preParams.getBool("load_in_a_single_layer")){ + //all the meshes loaded from the file must be placed in a single layer + return 1; + } + else { + //multiple layers from the same file, check how many layers... + Lib3dsFile *file = NULL; + file = lib3ds_file_load(fileName.toStdString().c_str()); + if (!file) + throw MLException("Malformed file."); + // No nodes? Fabricate nodes to display all the meshes. + if( !file->nodes && file->meshes) { + Lib3dsMesh *mesh; + Lib3dsNode *node; - for (mesh = file->meshes; mesh != NULL; mesh = mesh->next) { - node = lib3ds_node_new_object(); - strcpy(node->name, mesh->name); - node->parent_id = LIB3DS_NO_PARENT; - lib3ds_file_insert_node(file, node); + for (mesh = file->meshes; mesh != NULL; mesh = mesh->next) { + node = lib3ds_node_new_object(); + strcpy(node->name, mesh->name); + node->parent_id = LIB3DS_NO_PARENT; + lib3ds_file_insert_node(file, node); + } } - } - if( !file->nodes) { + if( !file->nodes) { + lib3ds_file_free(file); + throw MLException("Malformed file."); + } + lib3ds_file_eval(file, 0); + unsigned int i = 0; + Lib3dsNode *p = file->nodes; + while (p) { + i++; + p = p->next; + } + log("Expected meshes in file: " + std::to_string(i) ); lib3ds_file_free(file); - throw MLException("Malformed file."); + return i; } - lib3ds_file_eval(file, 0); - unsigned int i = 0; - Lib3dsNode *p = file->nodes; - while (p) { - i++; - p = p->next; - } - log("Expected meshes in file: " + std::to_string(i) ); - lib3ds_file_free(file); - return i; } else { wrongOpenFormat(format); @@ -128,47 +148,96 @@ void ExtraMeshIOPlugin::open( wrongOpenFormat(formatName); } +void ExtraMeshIOPlugin::loadFromNode(MeshModel& mm, int& mask, vcg::tri::io::_3dsInfo& info, Lib3dsFile *file, Lib3dsNode *p) +{ + bool normalsUpdated = false; + + if (p) + mm.setLabel(QString(p->name)); + + vcg::tri::io::Importer3DS::LoadMask(file, p, info); + mm.enable(info.mask); + + int result = vcg::tri::io::Importer3DS::Load(mm.cm, file, p, info); + + if (result != vcg::tri::io::Importer3DS::E_NOERROR) { + reportWarning("3DS Opening Error: " + QString(vcg::tri::io::Importer3DS::ErrorMsg(result))); + } + else { + + if(info.mask & vcg::tri::io::Mask::IOM_WEDGNORMAL) + normalsUpdated = true; + + mask |= info.mask; + + // verify if texture files are present + QString missingTextureFilesMsg = "The following texture files were not found:\n"; + bool someTextureNotFound = false; + for ( unsigned textureIdx = 0; textureIdx < mm.cm.textures.size(); ++textureIdx) + { + FILE* pFile = fopen (mm.cm.textures[textureIdx].c_str(), "r"); + if (pFile == nullptr) { + missingTextureFilesMsg.append("\n"); + missingTextureFilesMsg.append(mm.cm.textures[textureIdx].c_str()); + someTextureNotFound = true; + } + else { + fclose (pFile); + } + } + if (someTextureNotFound){ + reportWarning("Missing texture files: " + missingTextureFilesMsg); + } + + vcg::tri::UpdateBounding::Box(mm.cm); // updates bounding box + if (!normalsUpdated) + vcg::tri::UpdateNormal::PerVertex(mm.cm); // updates normals + } +} + void ExtraMeshIOPlugin::open( const QString &formatName, const QString &fileName, const std::list& meshList, std::list& maskList, - const RichParameterList&, + const RichParameterList& preParams, CallBackPos *cb) { + bool singleLayer = preParams.getBool("load_in_a_single_layer"); + // initializing mask maskList.clear(); for (unsigned int i = 0; i < meshList.size(); i++) maskList.push_back(0); - + // initializing progress bar status if (cb != nullptr) (*cb)(0, "Loading..."); - + QString errorMsgFormat = "Error encountered while loading file:\n\"%1\"\n\nError details: %2"; //QString error_2MsgFormat = "Error encountered while loading file:\n\"%1\"\n\n File with more than a mesh.\n Load only the first!"; - + string filename = QFile::encodeName(fileName).constData (); //string filename = fileName.toUtf8().data(); - + if (formatName.toUpper() == tr("3DS")) { - vcg::tri::io::_3dsInfo info; + vcg::tri::io::_3dsInfo info; info.cb = cb; Lib3dsFile *file = NULL; - - + + file = lib3ds_file_load(filename.c_str()); if (!file) { int result = vcg::tri::io::Importer3DS::E_CANTOPEN; throw MLException(errorMsgFormat.arg(fileName, vcg::tri::io::Importer3DS::ErrorMsg(result))); } - + // No nodes? Fabricate nodes to display all the meshes. if( !file->nodes && file->meshes) { Lib3dsMesh *mesh; Lib3dsNode *node; - + for (mesh = file->meshes; mesh != NULL; mesh = mesh->next) { node = lib3ds_node_new_object(); @@ -177,66 +246,33 @@ void ExtraMeshIOPlugin::open( lib3ds_file_insert_node(file, node); } } - + if( !file->nodes) { throw MLException("Malformed file."); } - + lib3ds_file_eval(file, 0); - Lib3dsNode *p; - int i=1; - auto iter = meshList.begin(); - auto miter = maskList.begin(); - for (p=file->nodes; p!=nullptr; p=p->next, ++iter, ++miter) - { - bool normalsUpdated = false; - - MeshModel &mm = *(*iter); - mm.setLabel(QString(p->name)); + if (singleLayer){ + MeshModel* m = *meshList.begin(); if (cb != nullptr) - (*cb)(i/meshList.size() * 100, (QString("Loading Mesh ")+QString(p->name)).toStdString().c_str()); - - vcg::tri::io::Importer3DS::LoadMask(file, p, info); - mm.Enable(info.mask); - - int result = vcg::tri::io::Importer3DS::Load(mm.cm, file, p, info); - if (result != vcg::tri::io::Importer3DS::E_NOERROR) { - reportWarning("3DS Opening Error: " + errorMsgFormat.arg(fileName, vcg::tri::io::Importer3DS::ErrorMsg(result))); - continue; + (*cb)(20, (QString("Loading Mesh ")+QString(file->name)).toStdString().c_str()); + loadFromNode(*m, *maskList.begin(), info, file, 0); + } + else { + Lib3dsNode *p; + int i=1; + auto iter = meshList.begin(); + auto miter = maskList.begin(); + for (p=file->nodes; p!=nullptr; p=p->next, ++iter, ++miter) { + if (cb != nullptr) + (*cb)(i/meshList.size() * 100, (QString("Loading Mesh ")+QString(p->name)).toStdString().c_str()); + loadFromNode(**iter, *miter, info, file, p); } - - if(info.mask & vcg::tri::io::Mask::IOM_WEDGNORMAL) - normalsUpdated = true; - - (*miter) |= info.mask; - - // verify if texture files are present - QString missingTextureFilesMsg = "The following texture files were not found:\n"; - bool someTextureNotFound = false; - for ( unsigned textureIdx = 0; textureIdx < mm.cm.textures.size(); ++textureIdx) - { - FILE* pFile = fopen (mm.cm.textures[textureIdx].c_str(), "r"); - if (pFile == nullptr) { - missingTextureFilesMsg.append("\n"); - missingTextureFilesMsg.append(mm.cm.textures[textureIdx].c_str()); - someTextureNotFound = true; - } - else { - fclose (pFile); - } - } - if (someTextureNotFound){ - reportWarning("Missing texture files: " + missingTextureFilesMsg); - } - - vcg::tri::UpdateBounding::Box(mm.cm); // updates bounding box - if (!normalsUpdated) - vcg::tri::UpdateNormal::PerVertex(mm.cm); // updates normals } if (cb != NULL) (*cb)(99, "Done"); - + // freeing memory lib3ds_file_free(file); } @@ -257,7 +293,7 @@ void ExtraMeshIOPlugin::save( string filename = QFile::encodeName(fileName).constData (); //string filename = fileName.toUtf8().data(); string ex = formatName.toUtf8().data(); - + if(formatName.toUpper() == tr("3DS")) { int result = vcg::tri::io::Exporter3DS::Save(m.cm,filename.c_str(),mask,cb); if(result!=0) { diff --git a/src/meshlabplugins/io_3ds/meshio.h b/src/meshlabplugins/io_3ds/meshio.h index 23ea813d1..c1c8df0c3 100644 --- a/src/meshlabplugins/io_3ds/meshio.h +++ b/src/meshlabplugins/io_3ds/meshio.h @@ -29,6 +29,16 @@ #include +namespace vcg{ +namespace tri { +namespace io { +class _3dsInfo; +} +} +} +class Lib3dsFile; +class Lib3dsNode; + class ExtraMeshIOPlugin : public QObject, public IOPlugin { Q_OBJECT @@ -44,9 +54,13 @@ public: void exportMaskCapability(const QString& format, int &capability, int &defaultBits) const; + RichParameterList initPreOpenParameter( + const QString& format) const; + unsigned int numberMeshesContainedInFile( const QString& format, - const QString& fileName) const; + const QString& fileName, + const RichParameterList& preParams) const; void open( const QString &formatName, @@ -71,6 +85,9 @@ public: const int mask, const RichParameterList &, vcg::CallBackPos *cb=0); + +private: + void loadFromNode(MeshModel& mm, int& mask, vcg::tri::io::_3dsInfo& info, Lib3dsFile *file, Lib3dsNode *p); }; #endif diff --git a/src/meshlabplugins/io_base/CMakeLists.txt b/src/meshlabplugins/io_base/CMakeLists.txt index da10ac369..04082df5c 100644 --- a/src/meshlabplugins/io_base/CMakeLists.txt +++ b/src/meshlabplugins/io_base/CMakeLists.txt @@ -1,16 +1,10 @@ # Copyright 2019-2020, Collabora, Ltd. # SPDX-License-Identifier: BSL-1.0 - -set(SOURCES - baseio.cpp - ${VCGDIR}/wrap/openfbx/src/miniz.c - ${VCGDIR}/wrap/openfbx/src/ofbx.cpp - ${VCGDIR}/wrap/ply/plylib.cpp - ${EXTERNAL_DIR}/easyexif/exif.cpp) - set(HEADERS baseio.h + load_project.h + save_project.h ${VCGDIR}/wrap/io_trimesh/export_obj.h ${VCGDIR}/wrap/io_trimesh/export_off.h ${VCGDIR}/wrap/io_trimesh/export_ply.h @@ -23,8 +17,16 @@ set(HEADERS ${VCGDIR}/wrap/io_trimesh/io_material.h ${VCGDIR}/wrap/ply/plylib.h) +set(SOURCES + baseio.cpp + load_project.cpp + save_project.cpp + ${VCGDIR}/wrap/openfbx/src/miniz.c + ${VCGDIR}/wrap/openfbx/src/ofbx.cpp + ${VCGDIR}/wrap/ply/plylib.cpp) + add_meshlab_plugin(io_base ${SOURCES} ${HEADERS}) -target_include_directories(io_base PRIVATE ${EXTERNAL_DIR}/easyexif/) +#target_include_directories(io_base PRIVATE ${EXTERNAL_DIR}/easyexif/) target_link_libraries(io_base PRIVATE OpenGL::GLU) diff --git a/src/meshlabplugins/io_base/baseio.cpp b/src/meshlabplugins/io_base/baseio.cpp index 83092a5f5..c781410cb 100644 --- a/src/meshlabplugins/io_base/baseio.cpp +++ b/src/meshlabplugins/io_base/baseio.cpp @@ -22,6 +22,9 @@ ****************************************************************************/ #include "baseio.h" +#include "load_project.h" +#include "save_project.h" + #include #include @@ -42,8 +45,6 @@ #include #include -#include "exif.h" - using namespace std; using namespace vcg; @@ -68,14 +69,26 @@ class PFace :public vcg::Face< class PMesh : public tri::TriMesh< vector, vector, vector > {}; +const static std::list importImageFormatList = { + FileFormat("Windows Bitmap", "BMP"), + FileFormat("Joint Photographic Experts Group", "JPG"), + FileFormat("Joint Photographic Experts Group", "JPEG"), + FileFormat("Portable Network Graphics", "PNG"), + FileFormat("X11 Bitmap", "XBM"), + FileFormat("X11 Bitmap", "XPM") +}; + +const static std::list exportImageFormatList = { + FileFormat("Windows Bitmap", "BMP"), + FileFormat("Joint Photographic Experts Group", "JPG"), + FileFormat("Joint Photographic Experts Group", "JPEG"), + FileFormat("Portable Network Graphics", "PNG"), + FileFormat("X11 Bitmap", "XBM"), + FileFormat("X11 Bitmap", "XPM") +}; + BaseMeshIOPlugin::BaseMeshIOPlugin() : IOPlugin() { - rasterFormatList = { - FileFormat("JPEG", tr("JPEG")), - FileFormat("JPG", tr("JPG")), - FileFormat("PNG", tr("PNG")), - FileFormat("XPM", tr("XPM")) - }; } QString BaseMeshIOPlugin::pluginName() const @@ -117,14 +130,42 @@ std::list BaseMeshIOPlugin::exportFormats() const return formatList; } -std::list BaseMeshIOPlugin::importRasterFormats() const +std::list BaseMeshIOPlugin::importImageFormats() const { - return rasterFormatList; + return importImageFormatList; +} + +std::list BaseMeshIOPlugin::exportImageFormats() const +{ + return exportImageFormatList; +} + +std::list BaseMeshIOPlugin::importProjectFormats() const +{ + std::list formatList = { + FileFormat("MeshLab Project", tr("MLP")), + FileFormat("MeshLab Binary Project", tr("MLB")), + FileFormat("Align Project", tr("ALN")), + FileFormat("Bundler Output", tr("OUT")), + FileFormat("VisualSFM Output", tr("NVM")) + }; + return formatList; +} + +std::list BaseMeshIOPlugin::exportProjectFormats() const +{ + std::list formatList = { + FileFormat("MeshLab Project", tr("MLP")), + FileFormat("MeshLab Binary Project", tr("MLB")), + FileFormat("Align Project", tr("ALN")) + }; + return formatList; } // initialize importing parameters -void BaseMeshIOPlugin::initPreOpenParameter(const QString &formatName, RichParameterList &parlst) +RichParameterList BaseMeshIOPlugin::initPreOpenParameter(const QString &formatName) const { + RichParameterList parlst; if (formatName.toUpper() == tr("PTX")) { parlst.addParam(RichInt("meshindex", 0, "Index of Range Map to be Imported", "PTX files may contain more than one range map. 0 is the first range map. If the number if higher than the actual mesh number, the import will fail")); @@ -136,8 +177,13 @@ void BaseMeshIOPlugin::initPreOpenParameter(const QString &formatName, RichParam parlst.addParam(RichFloat("angle", 85.0, "Angle limit for face culling", "short")); } if (formatName.toUpper() == tr("STL")) { - parlst.addParam(RichBool(stlUnifyParName(), true, "Unify Duplicated Vertices in STL files", "The STL format is not an vertex-indexed format. Each triangle is composed by independent vertices, so, usually, duplicated vertices should be unified")); + parlst.addParam(RichBool( + "unify_vertices", true, "Unify Duplicated Vertices in STL files", + "The STL format is not an vertex-indexed format. Each triangle is " + "composed by independent vertices, so, usually, duplicated vertices " + "should be unified")); } + return parlst; } void BaseMeshIOPlugin::open(const QString &formatName, const QString &fileName, MeshModel &m, int& mask, const RichParameterList &parlst, CallBackPos *cb) @@ -164,7 +210,7 @@ void BaseMeshIOPlugin::open(const QString &formatName, const QString &fileName, tri::io::ImporterPLY::LoadMask(filename.c_str(), mask); // small patch to allow the loading of per wedge color into faces. if (mask & tri::io::Mask::IOM_WEDGCOLOR) mask |= tri::io::Mask::IOM_FACECOLOR; - m.Enable(mask); + m.enable(mask); int result = tri::io::ImporterPLY::Open(m.cm, filename.c_str(), mask, cb); @@ -182,14 +228,14 @@ void BaseMeshIOPlugin::open(const QString &formatName, const QString &fileName, { throw MLException(errorMsgFormat.arg(fileName, tri::io::ImporterSTL::ErrorMsg(tri::io::ImporterSTL::E_MALFORMED))); } - m.Enable(mask); + m.enable(mask); int result = tri::io::ImporterSTL::Open(m.cm, filename.c_str(), mask, cb); if (result != 0) // all the importers return 0 on success { throw MLException(errorMsgFormat.arg(fileName, tri::io::ImporterSTL::ErrorMsg(result))); } - bool stluinf = parlst.getBool(stlUnifyParName()); + bool stluinf = parlst.getBool("unify_vertices"); if (stluinf) { tri::Clean::RemoveDuplicateVertex(m.cm); @@ -204,7 +250,7 @@ void BaseMeshIOPlugin::open(const QString &formatName, const QString &fileName, if (!tri::io::ImporterOBJ::LoadMask(filename.c_str(), oi)){ throw MLException("Error while loading OBJ mask."); } - m.Enable(oi.mask); + m.enable(oi.mask); int result = tri::io::ImporterOBJ::Open(m.cm, filename.c_str(), oi); if (result != tri::io::ImporterOBJ::E_NOERROR) @@ -219,7 +265,7 @@ void BaseMeshIOPlugin::open(const QString &formatName, const QString &fileName, // if (oi.mask & tri::io::Mask::IOM_WEDGNORMAL) // normalsUpdated = true; - m.Enable(oi.mask); + m.enable(oi.mask); if (m.hasDataMask(MeshModel::MM_POLYGONAL)) qDebug("Mesh is Polygonal!"); mask = oi.mask; } @@ -244,7 +290,7 @@ void BaseMeshIOPlugin::open(const QString &formatName, const QString &fileName, // reflectance is stored in quality importparams.mask |= tri::io::Mask::IOM_VERTQUALITY; - m.Enable(importparams.mask); + m.enable(importparams.mask); int result = tri::io::ImporterPTX::Open(m.cm, filename.c_str(), importparams, cb); if (result == 1) @@ -262,7 +308,7 @@ void BaseMeshIOPlugin::open(const QString &formatName, const QString &fileName, { throw MLException(errorMsgFormat.arg(fileName, tri::io::ImporterOFF::ErrorMsg(tri::io::ImporterOFF::InvalidFile))); } - m.Enable(loadMask); + m.enable(loadMask); int result = tri::io::ImporterOFF::Open(m.cm, filename.c_str(), mask, cb); if (result != 0) // OFFCodes enum is protected @@ -276,7 +322,7 @@ void BaseMeshIOPlugin::open(const QString &formatName, const QString &fileName, if (!tri::io::ImporterVMI::LoadMask(filename.c_str(), loadMask)) { throw MLException("Error while loading VMI mask."); } - m.Enable(loadMask); + m.enable(loadMask); int result = tri::io::ImporterVMI::Open(m.cm, filename.c_str(), mask, cb); if (result != 0) @@ -290,7 +336,7 @@ void BaseMeshIOPlugin::open(const QString &formatName, const QString &fileName, if (!tri::io::ImporterGTS::LoadMask(filename.c_str(), loadMask)){ throw MLException("Error while loading GTS mask."); } - m.Enable(loadMask); + m.enable(loadMask); tri::io::ImporterGTS::Options opt; opt.flipFaces = true; @@ -303,7 +349,7 @@ void BaseMeshIOPlugin::open(const QString &formatName, const QString &fileName, } else if (formatName.toUpper() == tr("FBX")) { - m.Enable(tri::io::Mask::IOM_WEDGTEXCOORD); + m.enable(tri::io::Mask::IOM_WEDGTEXCOORD); int result = tri::io::ImporterFBX::Open(m.cm, filename.c_str(),cb); if(m.cm.textures.empty()) @@ -462,77 +508,141 @@ void BaseMeshIOPlugin::save(const QString &formatName, const QString &fileName, } } -void BaseMeshIOPlugin::openRaster(const QString& format, const QString& filename, RasterModel& rm, CallBackPos*) +QImage BaseMeshIOPlugin::openImage( + const QString& format, + const QString& fileName, + vcg::CallBackPos*) { + QImage loadedImage; bool supportedFormat = false; - for (const FileFormat& f : rasterFormatList){ + for (const FileFormat& f : importImageFormatList){ if (f.extensions.first().toUpper() == format.toUpper()) supportedFormat = true; } if (supportedFormat) { - QFileInfo fi(filename); + QFileInfo fi(fileName); - if(!fi.exists()) { + if(!fi.exists()) { QString errorMsgFormat = "Unable to open file:\n\"%1\"\n\nError details: file %1 does not exist."; - throw MLException(errorMsgFormat.arg(filename)); + throw MLException(errorMsgFormat.arg(fileName)); } - if(!fi.isReadable()) { + if(!fi.isReadable()) { QString errorMsgFormat = "Unable to open file:\n\"%1\"\n\nError details: file %1 is not readable."; - throw MLException(errorMsgFormat.arg(filename)); + throw MLException(errorMsgFormat.arg(fileName)); } - rm.setLabel(filename); - rm.addPlane(new RasterPlane(filename,RasterPlane::RGBA)); - - // Read the JPEG file into a buffer - FILE *fp = fopen(qUtf8Printable(filename), "rb"); - if (!fp) { - QString errorMsgFormat = "Exif Parsing: Unable to open file:\n\"%1\"\n\nError details: file %1 is not readable."; - throw MLException(errorMsgFormat.arg(filename)); + loadedImage.load(fileName); + if (loadedImage.isNull()){ + throw MLException("Failed to load the image " + fileName); } - fseek(fp, 0, SEEK_END); - unsigned long fsize = ftell(fp); - rewind(fp); - unsigned char *buf = new unsigned char[fsize]; - if (fread(buf, 1, fsize, fp) != fsize) { - QString errorMsgFormat = "Exif Parsing: Unable to read the content of the opened file:\n\"%1\"\n\nError details: file %1 is not readable."; - delete[] buf; - fclose(fp); - throw MLException(errorMsgFormat.arg(filename)); - } - fclose(fp); - - // Parse EXIF - easyexif::EXIFInfo ImageInfo; - int code = ImageInfo.parseFrom(buf, fsize); - delete[] buf; - if (!code) { - log(GLLogStream::FILTER, "Warning unable to parse exif for file %s", qPrintable(filename)); - } - - if (code && ImageInfo.FocalLengthIn35mm==0.0f) - { - rm.shot.Intrinsics.ViewportPx = vcg::Point2i(rm.currentPlane->image.width(), rm.currentPlane->image.height()); - rm.shot.Intrinsics.CenterPx = Point2m(float(rm.currentPlane->image.width()/2.0), float(rm.currentPlane->image.width()/2.0)); - rm.shot.Intrinsics.PixelSizeMm[0]=36.0f/(float)rm.currentPlane->image.width(); - rm.shot.Intrinsics.PixelSizeMm[1]=rm.shot.Intrinsics.PixelSizeMm[0]; - rm.shot.Intrinsics.FocalMm = 50.0f; - } - else - { - rm.shot.Intrinsics.ViewportPx = vcg::Point2i(ImageInfo.ImageWidth, ImageInfo.ImageHeight); - rm.shot.Intrinsics.CenterPx = Point2m(float(ImageInfo.ImageWidth/2.0), float(ImageInfo.ImageHeight/2.0)); - float ratioFocal=ImageInfo.FocalLength/ImageInfo.FocalLengthIn35mm; - rm.shot.Intrinsics.PixelSizeMm[0]=(36.0f*ratioFocal)/(float)ImageInfo.ImageWidth; - rm.shot.Intrinsics.PixelSizeMm[1]=(24.0f*ratioFocal)/(float)ImageInfo.ImageHeight; - rm.shot.Intrinsics.FocalMm = ImageInfo.FocalLength; - } - // End of EXIF reading } else { wrongOpenFormat(format); } + return loadedImage; +} + +void BaseMeshIOPlugin::saveImage( + const QString& format, + const QString& fileName, + const QImage& image, + int quality, + CallBackPos*) +{ + bool supportedFormat = false; + for (const FileFormat& f : exportImageFormatList){ + if (f.extensions.first().toUpper() == format.toUpper()) + supportedFormat = true; + } + if (supportedFormat){ + bool ok = image.save(fileName, nullptr, quality); + if (!ok){ + throw MLException("Failed to save the image " + fileName); + } + } + else{ + wrongSaveFormat(format); + } +} + +std::list BaseMeshIOPlugin::projectFileRequiresAdditionalFiles( + const QString& format, + const QString&) +{ + if (format.toUpper() == "OUT"){ + return {FileFormat("Image List File", "TXT")}; + } + else + return {}; +} + +std::vector BaseMeshIOPlugin::openProject( + const QString& format, + const QStringList& filenames, + MeshDocument& md, + std::vector& rendOpt, + CallBackPos* cb) +{ + std::vector meshList; + rendOpt.clear(); + if (format.toUpper() == "ALN") { + meshList = loadALN(filenames.first(), md, cb); + } + else if (format.toUpper() == "OUT" || format.toUpper() == "NVM" || + format.toUpper() =="MLP" || format.toUpper() == "MLB") { + std::vector unloadedImgs; + if (format.toUpper() == "OUT") { + meshList = loadOUT(filenames.first(), filenames[1], md, unloadedImgs, cb); + } + else if (format.toUpper() == "NVM"){ + meshList = loadNVM(filenames.first(), md, unloadedImgs, cb); + } + else if (format.toUpper() =="MLP" || format.toUpper() == "MLB") { + meshList = loadMLP(filenames.first(), md, rendOpt, unloadedImgs, cb); + } + if (unloadedImgs.size() > 0){ + QString msg = "Unable to load the following " + + QString::number(unloadedImgs.size()) + " images (using dummy images): \n"; + + unsigned int size = unloadedImgs.size(); + if (size > 5) + size = 5; + + for (unsigned int i = 0; i < size; ++i) + msg += QString::fromStdString(unloadedImgs[i]) + "\n"; + + if (unloadedImgs.size() > 5){ + msg += "\n...\n\n"; + msg += QString::fromStdString(unloadedImgs[unloadedImgs.size()-1]) + "\n"; + } + reportWarning(msg); + } + } + + else { + wrongOpenFormat(format); + } + return meshList; +} + +void BaseMeshIOPlugin::saveProject( + const QString& format, + const QString& fileName, + const MeshDocument& md, + bool onlyVisibleMeshes, + const std::vector& rendOpt, + CallBackPos* cb) +{ + if (format.toUpper() == "MLP" || format.toUpper() == "MLB") { + saveMLP(fileName, md, onlyVisibleMeshes, rendOpt, cb); + } + else if (format.toUpper() == "ALN") { + saveALN(fileName, md, onlyVisibleMeshes, cb); + } + else { + wrongSaveFormat(format); + } } /* @@ -562,15 +672,9 @@ void BaseMeshIOPlugin::exportMaskCapability(const QString &format, int &capabili } -//void BaseMeshIOPlugin::initOpenParameter(const QString &format, MeshModel &/*m*/, RichParameterSet &par) -//{ -// if(format.toUpper() == tr("STL")) -// par.addParam(new RichBool("Unify",true, "Unify Duplicated Vertices", -// "The STL format is not an vertex-indexed format. Each triangle is composed by independent vertices, so, usually, duplicated vertices should be unified")); -//} - -void BaseMeshIOPlugin::initSaveParameter(const QString &format, const MeshModel &m, RichParameterList &par) +RichParameterList BaseMeshIOPlugin::initSaveParameter(const QString &format, const MeshModel &m) const { + RichParameterList par; if (format.toUpper() == tr("STL") || format.toUpper() == tr("PLY")) par.addParam(RichBool("Binary", true, "Binary encoding", "Save the mesh using a binary encoding. If false the mesh is saved in a plain, readable ascii format.")); @@ -606,16 +710,7 @@ void BaseMeshIOPlugin::initSaveParameter(const QString &format, const MeshModel par.addParam(RichBool("PFA3F" + va_name, false, "F(3f): " + va_name, "Save this custom vector (3f) per-face attribute.")); } } + return par; } -//void BaseMeshIOPlugin::applyOpenParameter(const QString &format, MeshModel &m, const RichParameterSet &par) -//{ -// if(format.toUpper() == tr("STL")) -// if (par.findParameter(stlUnifyParName())->value().getBool()) -// { -// tri::Clean::RemoveDuplicateVertex(m.cm); -// tri::Allocator::CompactEveryVector(m.cm); -// } -//} - MESHLAB_PLUGIN_NAME_EXPORTER(BaseMeshIOPlugin) diff --git a/src/meshlabplugins/io_base/baseio.h b/src/meshlabplugins/io_base/baseio.h index ce65fbab6..b73132323 100644 --- a/src/meshlabplugins/io_base/baseio.h +++ b/src/meshlabplugins/io_base/baseio.h @@ -40,7 +40,10 @@ public: std::list importFormats() const; std::list exportFormats() const; - std::list importRasterFormats() const; + std::list importImageFormats() const; + std::list exportImageFormats() const; + std::list importProjectFormats() const; + std::list exportProjectFormats() const; void exportMaskCapability( const QString& format, @@ -63,21 +66,39 @@ public: const RichParameterList& par, vcg::CallBackPos* cb); - void openRaster( + QImage openImage( const QString& format, - const QString& filename, - RasterModel& rm, - vcg::CallBackPos*); + const QString& fileName, + vcg::CallBackPos* cb); - //void initOpenParameter(const QString &format, MeshModel &/*m*/, RichParameterSet & par); - //void applyOpenParameter(const QString &format, MeshModel &m, const RichParameterSet &par); - void initPreOpenParameter(const QString &formatName, RichParameterList &parlst); - void initSaveParameter(const QString &format, const MeshModel &/*m*/, RichParameterList & par); + void saveImage( + const QString& format, + const QString& fileName, + const QImage& image, + int quality, + vcg::CallBackPos* cb); -private: - std::list rasterFormatList; + std::list projectFileRequiresAdditionalFiles( + const QString& format, + const QString& filename); - static QString stlUnifyParName() { return QString("MeshLab::IO::STL::UnifyVertices"); } + std::vector openProject( + const QString& format, + const QStringList& filenames, + MeshDocument& md, + std::vector& rendOpt, + vcg::CallBackPos* cb); + + virtual void saveProject( + const QString& format, + const QString& fileName, + const MeshDocument& md, + bool onlyVisibleMeshes, + const std::vector& rendOpt, + vcg::CallBackPos* /*cb*/ = nullptr); + + RichParameterList initPreOpenParameter(const QString &formatName) const; + RichParameterList initSaveParameter(const QString &format, const MeshModel &/*m*/) const; }; #endif diff --git a/src/meshlabplugins/io_base/io_base.pro b/src/meshlabplugins/io_base/io_base.pro index 3649f4c2d..9ce91ec19 100644 --- a/src/meshlabplugins/io_base/io_base.pro +++ b/src/meshlabplugins/io_base/io_base.pro @@ -2,6 +2,8 @@ include (../../shared.pri) HEADERS += \ baseio.h \ + load_project.h \ + save_project.h \ $$VCGDIR/wrap/io_trimesh/import_ply.h \ $$VCGDIR/wrap/io_trimesh/import_obj.h \ $$VCGDIR/wrap/io_trimesh/import_off.h \ @@ -16,6 +18,8 @@ HEADERS += \ SOURCES += \ baseio.cpp \ + load_project.cpp \ + save_project.cpp \ $$VCGDIR/wrap/ply/plylib.cpp \ $$VCGDIR/wrap/openfbx/src/ofbx.cpp \ $$VCGDIR/wrap/openfbx/src/miniz.c \ diff --git a/src/meshlabplugins/io_base/load_project.cpp b/src/meshlabplugins/io_base/load_project.cpp new file mode 100644 index 000000000..01630a92c --- /dev/null +++ b/src/meshlabplugins/io_base/load_project.cpp @@ -0,0 +1,339 @@ +#include "load_project.h" + +#include + +#include +#include +#include +#include + +#include +#include + +std::vector loadALN( + const QString& filename, + MeshDocument& md, + vcg::CallBackPos* cb) +{ + std::vector meshList; + std::vector rmv; + int retVal = ALNParser::ParseALN(rmv, qUtf8Printable(filename)); + if(retVal != ALNParser::NoError) { + throw MLException("Unable to open ALN file"); + } + QFileInfo fi(filename); + QString curr_path = QDir::currentPath(); + QDir::setCurrent(fi.absolutePath()); + + for(const RangeMap& rm : rmv) { + QString relativeToProj = fi.absoluteDir().absolutePath() + "/" + rm.filename.c_str(); + try { + std::list tmp = + meshlab::loadMeshWithStandardParameters(relativeToProj, md, cb); + md.mm()->cm.Tr.Import(rm.transformation); + meshList.insert(meshList.end(), tmp.begin(), tmp.end()); + } + catch (const MLException& e){ + for (MeshModel* m : meshList) + md.delMesh(m); + throw e; + } + } + QDir::setCurrent(curr_path); + return meshList; +} + +std::vector loadOUT( + const QString& filename, + const QString& imageListFile, + MeshDocument& md, + std::vector& unloadedImgList, + vcg::CallBackPos*) +{ + std::vector meshList; + unloadedImgList.clear(); + QFileInfo fi(filename); + + MeshModel* newMesh = md.addNewMesh("", fi.baseName()); + std::vector shots; + const QString path_im = QFileInfo(imageListFile).absolutePath()+QString("/"); + + std::vector image_filenames; + vcg::tri::io::ImporterOUT::Open(newMesh->cm, shots, image_filenames, qUtf8Printable(filename), qUtf8Printable(imageListFile)); + newMesh->updateDataMask(MeshModel::MM_VERTCOLOR); + + QString curr_path = QDir::currentPath(); + QFileInfo imi(imageListFile); + QDir::setCurrent(imi.absoluteDir().absolutePath()); + // + QStringList image_filenames_q; + for(unsigned int i = 0; i < image_filenames.size(); ++i) + { + QImageReader sizeImg(QString::fromStdString(image_filenames[i])); + if(sizeImg.size()==QSize(-1,-1)) + image_filenames_q.push_back(path_im+QString::fromStdString(image_filenames[i])); + else + image_filenames_q.push_back(QString::fromStdString(image_filenames[i])); + } + + + for(size_t i=0 ; iaddPlane(new RasterPlane(img, fullpath_image_filename, RasterPlane::RGBA)); + int count=fullpath_image_filename.count('\\'); + if (count==0) + { + count=fullpath_image_filename.count('/'); + md.rm()->setLabel(fullpath_image_filename.section('/',count,1)); + } + else + md.rm()->setLabel(fullpath_image_filename.section('\\',count,1)); + md.rm()->shot = shots[i]; + } + QDir::setCurrent(curr_path); + + meshList.push_back(newMesh); + + return meshList; +} + +std::vector loadNVM( + const QString& filename, + MeshDocument& md, + std::vector& unloadedImgList, + vcg::CallBackPos*) +{ + std::vector meshList; + unloadedImgList.clear(); + + QFileInfo fi(filename); + + MeshModel* newMesh = md.addNewMesh(fi.baseName(),QString("model")); + std::vector shots; + + std::vector image_filenames; + vcg::tri::io::ImporterNVM::Open(md.mm()->cm,shots,image_filenames, qUtf8Printable(filename)); + md.mm()->updateDataMask(MeshModel::MM_VERTCOLOR); + + QString curr_path = QDir::currentPath(); + + QDir::setCurrent(fi.absolutePath()); + QStringList image_filenames_q; + for(size_t i = 0; i < image_filenames.size(); ++i) + image_filenames_q.push_back(QString::fromStdString(image_filenames[int(i)])); + + for(size_t i=0 ; iaddPlane(new RasterPlane(fullpath_image_filename,RasterPlane::RGBA)); + md.rm()->setLabel(image_filenames_q[int(i)].section('/',1,2)); + md.rm()->shot = shots[int(i)]; + } + QDir::setCurrent(curr_path); + + meshList.push_back(newMesh); + + return meshList; +} + +std::vector loadMLP( + const QString& filename, + MeshDocument& md, + std::vector& rendOpt, + std::vector& unloadedImgList, + vcg::CallBackPos*) +{ + std::vector meshList; + unloadedImgList.clear(); + + QFile qf(filename); + QFileInfo qfInfo(filename); + bool binary = (QString(qfInfo.suffix()).toLower() == "mlb"); + + if (!qf.open(QIODevice::ReadOnly)) + throw MLException("File not found."); + + QDomDocument doc("MeshLabDocument"); //It represents the XML document + + if (!doc.setContent(&qf)) + throw MLException(filename + " is not a MeshLab project."); + + QDomElement root = doc.documentElement(); + + QDomNode node; + + node = root.firstChild(); + + QDir tmpDir = QDir::current(); + QDir::setCurrent(qfInfo.absoluteDir().absolutePath()); + //Devices + while (!node.isNull()) { + if (QString::compare(node.nodeName(), "MeshGroup") == 0) { + QDomNode mesh; + QString filen, label; + mesh = node.firstChild(); + while (!mesh.isNull()) { + //return true; + filen = mesh.attributes().namedItem("filename").nodeValue(); + label = mesh.attributes().namedItem("label").nodeValue(); + bool visible = true; + if (mesh.attributes().contains("visible")) + visible = (mesh.attributes().namedItem("visible").nodeValue().toInt() == 1); + //MeshModel* mm = md.addNewMesh(filen, label); + + //mm->visible = visible; + + int idInFile = -1; + if (mesh.attributes().contains("idInFile")){ + idInFile = mesh.attributes().namedItem("idInFile").nodeValue().toInt(); + } + if (idInFile <= 0){ + //load the file just if it is the first layer contained + //in the file (or it is the only one) + try { + auto tmp = meshlab::loadMeshWithStandardParameters(filen, md); + for (auto m : tmp){ + m->visible = visible; + m->setLabel(label); + } + meshList.insert(meshList.end(), tmp.begin(), tmp.end()); + } + catch(const MLException& e) { + for (MeshModel* mm : meshList) + md.delMesh(mm); + throw MLException(filen + " mesh file not found."); + } + } + + QDomNode tr = mesh.firstChildElement("MLMatrix44"); + + if (!tr.isNull()) { + vcg::Matrix44f trm; + if (tr.childNodes().size() == 1) { + if (!binary) { + QStringList rows = tr.firstChild().nodeValue().split("\n", QString::SkipEmptyParts); + int i = 0; + for (const QString& row : qAsConst(rows)){ + if (rows.size() > 0) { + QStringList values = row.split(" ", QString::SkipEmptyParts); + int j = 0; + for (const QString& value : qAsConst(values)) { + if (i < 4 && j < 4) { + md.mm()->cm.Tr[i][j] = value.toFloat(); + j++; + } + } + i++; + } + } + } + else { + QString str = tr.firstChild().nodeValue(); + QByteArray value = QByteArray::fromBase64(str.toLocal8Bit()); + memcpy(md.mm()->cm.Tr.V(), value.data(), sizeof(Matrix44m::ScalarType) * 16); + } + } + } + + QDomNode renderingOpt = mesh.firstChildElement("RenderingOption"); + if (!renderingOpt.isNull()) + { + QString value = renderingOpt.firstChild().nodeValue(); + MLRenderingData::GLOptionsType opt; + if (renderingOpt.attributes().contains("pointSize")) + opt._perpoint_pointsize = renderingOpt.attributes().namedItem("pointSize").nodeValue().toFloat(); + if (renderingOpt.attributes().contains("wireWidth")) + opt._perwire_wirewidth = renderingOpt.attributes().namedItem("wireWidth").nodeValue().toFloat(); + if (renderingOpt.attributes().contains("boxColor")) + { + QStringList values = renderingOpt.attributes().namedItem("boxColor").nodeValue().split(" ", QString::SkipEmptyParts); + opt._perbbox_fixed_color = vcg::Color4b(values[0].toInt(), values[1].toInt(), values[2].toInt(), values[3].toInt()); + } + if (renderingOpt.attributes().contains("pointColor")) + { + QStringList values = renderingOpt.attributes().namedItem("pointColor").nodeValue().split(" ", QString::SkipEmptyParts); + opt._perpoint_fixed_color = vcg::Color4b(values[0].toInt(), values[1].toInt(), values[2].toInt(), values[3].toInt()); + } + if (renderingOpt.attributes().contains("wireColor")) + { + QStringList values = renderingOpt.attributes().namedItem("wireColor").nodeValue().split(" ", QString::SkipEmptyParts); + opt._perwire_fixed_color = vcg::Color4b(values[0].toInt(), values[1].toInt(), values[2].toInt(), values[3].toInt()); + } + if (renderingOpt.attributes().contains("solidColor")) + { + QStringList values = renderingOpt.attributes().namedItem("solidColor").nodeValue().split(" ", QString::SkipEmptyParts); + opt._persolid_fixed_color = vcg::Color4b(values[0].toInt(), values[1].toInt(), values[2].toInt(), values[3].toInt()); + } + MLRenderingData data; + data.set(opt); + if (data.deserialize(value.toStdString())) + rendOpt.push_back(data); + } + + mesh = mesh.nextSibling(); + } + } + // READ IN POINT CORRESPONDECES INCOMPLETO!! + else if (QString::compare(node.nodeName(), "RasterGroup") == 0) + { + QDomNode raster; + raster = node.firstChild(); + while (!raster.isNull()) + { + //return true; + md.addNewRaster(); + QString labelRaster = raster.attributes().namedItem("label").nodeValue(); + md.rm()->setLabel(labelRaster); + QDomNode sh = raster.firstChild(); + ReadShotFromQDomNode(md.rm()->shot, sh); + + QDomElement el = raster.firstChildElement("Plane"); + while (!el.isNull()) + { + QString filen = el.attribute("fileName"); + QFileInfo fi(filen); + QString nm = fi.absoluteFilePath(); + QImage img(":/img/dummy.png"); + try { + img = meshlab::loadImage(nm); + } + catch(const MLException& e){ + unloadedImgList.push_back(nm.toStdString()); + } + md.rm()->addPlane(new RasterPlane(img, nm, RasterPlane::RGBA)); + el = node.nextSiblingElement("Plane"); + } + raster = raster.nextSibling(); + } + } + node = node.nextSibling(); + } + + QDir::setCurrent(tmpDir.absolutePath()); + qf.close(); + + if (rendOpt.size() != meshList.size()){ + std::cerr << "cannot load rend options\n"; + } + + return meshList; +} diff --git a/src/meshlabplugins/io_base/load_project.h b/src/meshlabplugins/io_base/load_project.h new file mode 100644 index 000000000..132e17753 --- /dev/null +++ b/src/meshlabplugins/io_base/load_project.h @@ -0,0 +1,31 @@ +#ifndef LOAD_PROJECT_H +#define LOAD_PROJECT_H + +#include + +std::vector loadALN( + const QString& filename, + MeshDocument& md, + vcg::CallBackPos* cb); + +std::vector loadOUT( + const QString& filename, + const QString& imageListFile, + MeshDocument& md, + std::vector& unloadedImgList, + vcg::CallBackPos* cb); + +std::vector loadNVM( + const QString& filename, + MeshDocument& md, + std::vector& unloadedImgList, + vcg::CallBackPos* cb); + +std::vector loadMLP( + const QString& filename, + MeshDocument& md, + std::vector& rendOpt, + std::vector& unloadedImgList, + vcg::CallBackPos* cb); + +#endif // LOAD_PROJECT_H diff --git a/src/meshlabplugins/io_base/save_project.cpp b/src/meshlabplugins/io_base/save_project.cpp new file mode 100644 index 000000000..1d55be4a8 --- /dev/null +++ b/src/meshlabplugins/io_base/save_project.cpp @@ -0,0 +1,169 @@ +#include "save_project.h" + +#include +#include + +#include +#include +#include + +namespace mlp { + +QDomElement matrix44mToXML(const Matrix44m &m, bool binary, QDomDocument &doc) +{ + QDomElement matrixElem = doc.createElement("MLMatrix44"); + QDomText nd; + if (binary) { + QByteArray value = QByteArray::fromRawData((char *)m.V(), sizeof(Matrix44m::ScalarType) * 16).toBase64(); + QDomText nd = doc.createTextNode(QString(value)); + } + else { + QString Row[4]; + for (int i = 0; i < 4; ++i) + Row[i] = QString("%1 %2 %3 %4 \n").arg(m[i][0]).arg(m[i][1]).arg(m[i][2]).arg(m[i][3]); + + nd = doc.createTextNode("\n" + Row[0] + Row[1] + Row[2] + Row[3]); + } + matrixElem.appendChild(nd); + + return matrixElem; +} + +QDomElement meshModelToXML(const MeshModel *mp, QDomDocument &doc, const QString& path, bool binary, bool saveViewState, const MLRenderingData& rendOpt = MLRenderingData()) +{ + QDomElement meshElem = doc.createElement("MLMesh"); + meshElem.setAttribute("label", mp->label()); + meshElem.setAttribute("filename", mp->relativePathName(path)); + meshElem.setAttribute("visible", saveViewState?mp->isVisible():true); + meshElem.setAttribute("idInFile", mp->idInFile()); + + meshElem.appendChild(matrix44mToXML(mp->cm.Tr, binary, doc)); + + if (saveViewState) + { + QDomElement renderingElem = doc.createElement("RenderingOption"); + std::string text; + rendOpt.serialize(text); + QDomText nd = doc.createTextNode(QString(text.c_str())); + renderingElem.appendChild(nd); + MLRenderingData::GLOptionsType opt; + if (rendOpt.get(opt)) + { + renderingElem.setAttribute("boxColor", QString("%1 %2 %3 %4").arg(opt._perbbox_fixed_color[0]).arg(opt._perbbox_fixed_color[1]).arg(opt._perbbox_fixed_color[2]).arg(opt._perbbox_fixed_color[3])); + renderingElem.setAttribute("pointColor", QString("%1 %2 %3 %4").arg(opt._perpoint_fixed_color[0]).arg(opt._perpoint_fixed_color[1]).arg(opt._perpoint_fixed_color[2]).arg(opt._perpoint_fixed_color[3])); + renderingElem.setAttribute("wireColor", QString("%1 %2 %3 %4").arg(opt._perwire_fixed_color[0]).arg(opt._perwire_fixed_color[1]).arg(opt._perwire_fixed_color[2]).arg(opt._perwire_fixed_color[3])); + renderingElem.setAttribute("solidColor", QString("%1 %2 %3 %4").arg(opt._persolid_fixed_color[0]).arg(opt._persolid_fixed_color[1]).arg(opt._persolid_fixed_color[2]).arg(opt._persolid_fixed_color[3])); + renderingElem.setAttribute("pointSize", opt._perpoint_pointsize); + renderingElem.setAttribute("wireWidth", opt._perwire_wirewidth); + } + meshElem.appendChild(renderingElem); + } + + return meshElem; +} + +QDomElement planeToXML(const RasterPlane* pl, const QString& basePath, QDomDocument& doc) +{ + QDomElement planeElem = doc.createElement("Plane"); + QDir dir(basePath); + planeElem.setAttribute("fileName", dir.relativeFilePath(pl->fullPathFileName)); + planeElem.setAttribute("semantic", pl->semantic); + return planeElem; +} + +QDomElement rasterModelToXML(const RasterModel *mp, QDomDocument &doc, bool binary) +{ + QDomElement rasterElem = doc.createElement("MLRaster"); + rasterElem.setAttribute("label", mp->label()); + if (binary) + rasterElem.appendChild(WriteShotToQDomNodeBinary(mp->shot, doc)); + else + rasterElem.appendChild(WriteShotToQDomNode(mp->shot, doc)); + for (int ii = 0; ii < mp->planeList.size(); ++ii) + rasterElem.appendChild(planeToXML(mp->planeList[ii], mp->par->pathName(), doc)); + return rasterElem; +} + +QDomDocument meshDocumentToXML( + const MeshDocument &md, + bool onlyVisibleLayers, + bool binary, + const std::vector& rendOpt) +{ + QDomDocument ddoc("MeshLabDocument"); + + QDomElement root = ddoc.createElement("MeshLabProject"); + ddoc.appendChild(root); + QDomElement mgroot = ddoc.createElement("MeshGroup"); + + unsigned int i = 0; + for(const MeshModel *mmp : md.meshIterator()) + { + if ((!onlyVisibleLayers) || (mmp->visible)) + { + QDomElement meshElem; + if (rendOpt.size() == md.meshNumber()) + meshElem = meshModelToXML(mmp, ddoc, md.pathName(), binary, true, rendOpt[i]); + else + meshElem = meshModelToXML(mmp, ddoc, md.pathName(), binary, false); + mgroot.appendChild(meshElem); + } + ++i; + } + root.appendChild(mgroot); + + QDomElement rgroot = ddoc.createElement("RasterGroup"); + + for(const RasterModel *rmp: md.rasterIterator()) + { + QDomElement rasterElem = mlp::rasterModelToXML(rmp, ddoc, binary); + rgroot.appendChild(rasterElem); + } + + root.appendChild(rgroot); + + return ddoc; +} +} // namespace mlp + +void saveMLP( + const QString& filename, + const MeshDocument& md, + bool onlyVisibleLayers, + const std::vector& rendOpt, + vcg::CallBackPos* cb) +{ + QFileInfo fi(filename); + bool binary = fi.suffix().toUpper() == "MLB"; + QDir tmpDir = QDir::current(); + QDir::setCurrent(fi.absoluteDir().absolutePath()); + QDomDocument doc = mlp::meshDocumentToXML(md, onlyVisibleLayers, binary, rendOpt); + QFile file(filename); + file.open(QIODevice::WriteOnly); + QTextStream qstream(&file); + doc.save(qstream, 1); + file.close(); + QDir::setCurrent(tmpDir.absolutePath()); +} + +void saveALN( + const QString& filename, + const MeshDocument& md, + bool onlyVisibleLayers, + vcg::CallBackPos* cb) +{ + std::vector meshNameVector; + std::vector transfVector; + + for(const MeshModel * mp : md.meshIterator()) + { + if((!onlyVisibleLayers) || (mp->visible)) + { + meshNameVector.push_back(qUtf8Printable(mp->relativePathName(md.pathName()))); + transfVector.push_back(mp->cm.Tr); + } + } + bool ret = ALNParser::SaveALN(qUtf8Printable(filename), meshNameVector, transfVector); + if (!ret) + throw MLException("Impossible to save " + filename); +} diff --git a/src/meshlabplugins/io_base/save_project.h b/src/meshlabplugins/io_base/save_project.h new file mode 100644 index 000000000..e5ac3f892 --- /dev/null +++ b/src/meshlabplugins/io_base/save_project.h @@ -0,0 +1,19 @@ +#ifndef SAVE_PROJECT_H +#define SAVE_PROJECT_H + +#include + +void saveMLP( + const QString& filename, + const MeshDocument& md, + bool onlyVisibleLayers, + const std::vector& rendOpt, + vcg::CallBackPos* cb); + +void saveALN( + const QString& filename, + const MeshDocument& md, + bool onlyVisibleLayers, + vcg::CallBackPos* cb); + +#endif // SAVE_PROJECT_H diff --git a/src/meshlabplugins/io_bre/io_bre.cpp b/src/meshlabplugins/io_bre/io_bre.cpp index 8e4b56734..e63799327 100644 --- a/src/meshlabplugins/io_bre/io_bre.cpp +++ b/src/meshlabplugins/io_bre/io_bre.cpp @@ -73,7 +73,7 @@ int vcg::tri::io::ImporterBRE::Open( MeshModel &meshModel, OpenMes { //enable colors and quality mask = vcg::tri::io::Mask::IOM_VERTCOLOR | vcg::tri::io::Mask::IOM_VERTQUALITY | vcg::tri::io::Mask::IOM_VERTTEXCOORD; - meshModel.Enable(mask); + meshModel.enable(mask); //Add camera position and image width and height m.shot.Extrinsics.Tra() = header.CameraPosition(); @@ -121,28 +121,39 @@ int vcg::tri::io::ImporterBRE::Open( MeshModel &meshModel, OpenMes /////////////////////////////////////////////////////////////////////////////////////////// // initialize importing parameters -void BreMeshIOPlugin::initPreOpenParameter(const QString &formatName, RichParameterList &parlst) +RichParameterList BreMeshIOPlugin::initPreOpenParameter(const QString &formatName) const { - - if (formatName.toUpper() == tr("BRE")) - { + RichParameterList parlst; + if (formatName.toUpper() == tr("BRE")) { parlst.addParam(RichBool("pointsonly",false,"only import points","Just import points, without triangulation")); + parlst.addParam(RichBool( + "unify_vertices", true, "Unify Duplicated Vertices in BRE files", + "The BRE format is not an vertex-indexed format. Each triangle is " + "composed by independent vertices, so, usually, duplicated vertices " + "should be unified")); } - + return parlst; } -void BreMeshIOPlugin::open(const QString &/*formatName*/, const QString &fileName, MeshModel &m, int& mask, const RichParameterList &parlst, CallBackPos *cb) +void BreMeshIOPlugin::open(const QString &formatName, const QString &fileName, MeshModel &m, int& mask, const RichParameterList &parlst, CallBackPos *cb) { - // initializing progress bar status - if (cb != NULL) - (*cb)(0, "Loading..."); - mask = 0; - QString errorMsgFormat = "Error encountered while loading file:\n\"%1\"\n\nError details: %2"; - bool points = parlst.getBool("pointsonly"); - int result = vcg::tri::io::ImporterBRE::Open(m, m.cm, mask, fileName,points, cb); - if (result != 0) // all the importers return 0 on success - { - throw MLException(errorMsgFormat.arg(fileName, ErrorMsg(result))); + if (formatName.toUpper() == tr("BRE")) { + if (cb != NULL) + (*cb)(0, "Loading..."); + mask = 0; + QString errorMsgFormat = "Error encountered while loading file:\n\"%1\"\n\nError details: %2"; + bool points = parlst.getBool("pointsonly"); + int result = vcg::tri::io::ImporterBRE::Open(m, m.cm, mask, fileName,points, cb); + if (result != 0) // all the importers return 0 on success + { + throw MLException(errorMsgFormat.arg(fileName, ErrorMsg(result))); + } + if (parlst.getBool("unify_vertices")){ + tri::Clean::RemoveDuplicateVertex(m.cm); + } + } + else { + wrongOpenFormat(formatName); } } @@ -179,38 +190,6 @@ std::list BreMeshIOPlugin::exportFormats() const */ void BreMeshIOPlugin::exportMaskCapability(const QString &/*format*/, int &/*capability*/, int &/*defaultBits*/) const { - /*if(format.toUpper() == tr("BRE")) - { - capability = 0; - defaultBits = 0; - }*/ -} - -void BreMeshIOPlugin::initOpenParameter(const QString &format, MeshModel &/*m*/, RichParameterList &par) -{ - if(format.toUpper() == tr("BRE")) - par.addParam(RichBool("Unify",true, "Unify Duplicated Vertices", - "The STL format is not an vertex-indexed format. Each triangle is composed by independent vertices, so, usually, duplicated vertices should be unified")); - -} -void BreMeshIOPlugin::initSaveParameter(const QString &/*format*/, const MeshModel &/*m*/, RichParameterList &/*par*/) -{ - /* - if(format.toUpper() == tr("STL") || format.toUpper() == tr("PLY")) - par.addParam(new RichBool("Binary",true, "Binary encoding", - "Save the mesh using a binary encoding. If false the mesh is saved in a plain, readable ascii format")); - */ -} - -void BreMeshIOPlugin::applyOpenParameter(const QString &format, MeshModel &m, const RichParameterList &par) -{ - if(format.toUpper() == tr("BRE")) - { - if(par.getBool("Unify")) - { - tri::Clean::RemoveDuplicateVertex(m.cm); - } - } } ///////////////////////////////////////////////////////////////////////////////// diff --git a/src/meshlabplugins/io_bre/io_bre.h b/src/meshlabplugins/io_bre/io_bre.h index bb4ddfd47..f27d25fe2 100644 --- a/src/meshlabplugins/io_bre/io_bre.h +++ b/src/meshlabplugins/io_bre/io_bre.h @@ -168,11 +168,7 @@ public: void open(const QString &formatName, const QString &fileName, MeshModel &m, int& mask,const RichParameterList & par, vcg::CallBackPos *cb); void save(const QString &formatName, const QString &fileName, MeshModel &m, const int mask, const RichParameterList & par, vcg::CallBackPos *cb); - virtual void initOpenParameter(const QString &format, MeshModel &/*m*/, RichParameterList & par); - virtual void applyOpenParameter(const QString &format, MeshModel &m, const RichParameterList &par); - void initPreOpenParameter(const QString &formatName, RichParameterList &parlst); - virtual void initSaveParameter(const QString &format, const MeshModel &/*m*/, RichParameterList & par); - + RichParameterList initPreOpenParameter(const QString &formatName) const; }; diff --git a/src/meshlabplugins/io_collada/io_collada.cpp b/src/meshlabplugins/io_collada/io_collada.cpp index 550237a48..114bf6b9a 100644 --- a/src/meshlabplugins/io_collada/io_collada.cpp +++ b/src/meshlabplugins/io_collada/io_collada.cpp @@ -123,7 +123,7 @@ void ColladaIOPlugin::open(const QString &formatName, const QString &fileName, M throw MLException("Error while loading DAE mask."); } - m.Enable(info.mask); + m.enable(info.mask); // for(unsigned int tx = 0; tx < info->texturefile.size();++tx) // m.cm.textures.push_back(info->texturefile[tx].toStdString()); diff --git a/src/meshlabplugins/io_ctm/io_ctm.cpp b/src/meshlabplugins/io_ctm/io_ctm.cpp index b1e4df30a..ff8e60b66 100644 --- a/src/meshlabplugins/io_ctm/io_ctm.cpp +++ b/src/meshlabplugins/io_ctm/io_ctm.cpp @@ -98,12 +98,14 @@ void IOMPlugin::exportMaskCapability(const QString &/*format*/, int &capability, capability=defaultBits=vcg::tri::io::ExporterCTM::GetExportMaskCapability(); return; } -void IOMPlugin::initSaveParameter(const QString &/*format*/, const MeshModel &/*m*/, RichParameterList & par) +RichParameterList IOMPlugin::initSaveParameter(const QString &/*format*/, const MeshModel &/*m*/) const { + RichParameterList par; par.addParam(RichBool("LossLess",false, "LossLess compression", "If true it does not apply any lossy compression technique.")); par.addParam(RichFloat("relativePrecisionParam",0.0001f, "Relative Coord Precision", "When using a lossy compression this number control the introduced error and hence the compression factor." "It is a number relative to the average edge length. (e.g. the default means that the error should be roughly 1/10000 of the average edge length)")); + return par; } MESHLAB_PLUGIN_NAME_EXPORTER(IOMPlugin) diff --git a/src/meshlabplugins/io_ctm/io_ctm.h b/src/meshlabplugins/io_ctm/io_ctm.h index 7f4a0ea65..4e2370a89 100644 --- a/src/meshlabplugins/io_ctm/io_ctm.h +++ b/src/meshlabplugins/io_ctm/io_ctm.h @@ -47,7 +47,7 @@ public: std::list exportFormats() const; void exportMaskCapability(const QString &format, int &capability, int &defaultBits) const; - void initSaveParameter(const QString &/*format*/, const MeshModel &/*m*/, RichParameterList & /*par*/); + RichParameterList initSaveParameter(const QString &/*format*/, const MeshModel &/*m*/) const; void open(const QString &formatName, const QString &fileName, MeshModel &m, int& mask,const RichParameterList & par, vcg::CallBackPos *cb=0); void save(const QString &formatName, const QString &fileName, MeshModel &m, const int mask,const RichParameterList & par, vcg::CallBackPos *cb); diff --git a/src/meshlabplugins/io_e57/io_e57.cpp b/src/meshlabplugins/io_e57/io_e57.cpp index bf3165f0e..dec51eef4 100755 --- a/src/meshlabplugins/io_e57/io_e57.cpp +++ b/src/meshlabplugins/io_e57/io_e57.cpp @@ -66,9 +66,7 @@ static inline std::string filenameToString(const QString& fileName) noexcept; */ static inline QString formatImageFilename(const std::string& fileName, const char* format) noexcept; -void E57IOPlugin::initPreOpenParameter(const QString &format, RichParameterList & parlst) {} - -unsigned int E57IOPlugin::numberMeshesContainedInFile(const QString& format, const QString& fileName) const { +unsigned int E57IOPlugin::numberMeshesContainedInFile(const QString& format, const QString& fileName, const RichParameterList&) const { unsigned int count; @@ -147,6 +145,7 @@ void E57IOPlugin::open(const QString &formatName, const QString &fileName, const try { + if (numberPointSize != 0) { // Does the mesh have an imageMetaAndImage from which to extract colors? @@ -434,7 +433,7 @@ void E57IOPlugin::loadMesh(MeshModel &m, int &mask, int scanIndex, size_t buffSi } // set the mask - m.Enable(mask); + m.enable(mask); // read the data from the E57 file try { diff --git a/src/meshlabplugins/io_e57/io_e57.h b/src/meshlabplugins/io_e57/io_e57.h index f238172b5..a34a24eb8 100755 --- a/src/meshlabplugins/io_e57/io_e57.h +++ b/src/meshlabplugins/io_e57/io_e57.h @@ -150,9 +150,8 @@ public: std::list exportFormats() const; virtual void exportMaskCapability(const QString &format, int &capability, int &defaultBits) const; - virtual void initPreOpenParameter(const QString &/*format*/, RichParameterList & /*par*/); - unsigned int numberMeshesContainedInFile(const QString& format, const QString& fileName) const; + unsigned int numberMeshesContainedInFile(const QString& format, const QString& fileName, const RichParameterList& preParams) const; void open(const QString &formatName, const QString &fileName, MeshModel &m, int& mask, const RichParameterList &, vcg::CallBackPos *cb = 0); diff --git a/src/meshlabplugins/io_expe/io_expe.cpp b/src/meshlabplugins/io_expe/io_expe.cpp index 4db6f77e0..08f0724ed 100644 --- a/src/meshlabplugins/io_expe/io_expe.cpp +++ b/src/meshlabplugins/io_expe/io_expe.cpp @@ -61,7 +61,7 @@ void ExpeIOPlugin::open(const QString &formatName, const QString &fileName, Mesh throw MLException("Error while loading [A]PTS mask."); } } - m.Enable(loadMask); + m.enable(loadMask); int result; if(useXYZ) { result = vcg::tri::io::ImporterXYZ::Open(m.cm, filename.c_str(), mask, cb); @@ -86,7 +86,7 @@ void ExpeIOPlugin::open(const QString &formatName, const QString &fileName, Mesh if (!vcg::tri::io::ImporterXYZ::LoadMask(filename.c_str(),loadMask)) { throw MLException("Error while loading XYZ mask."); } - m.Enable(loadMask); + m.enable(loadMask); int result = vcg::tri::io::ImporterXYZ::Open(m.cm, filename.c_str(), mask, cb); diff --git a/src/meshlabplugins/io_pdb/io_pdb.cpp b/src/meshlabplugins/io_pdb/io_pdb.cpp index 49b184f60..d4b0c6da5 100644 --- a/src/meshlabplugins/io_pdb/io_pdb.cpp +++ b/src/meshlabplugins/io_pdb/io_pdb.cpp @@ -40,8 +40,9 @@ using namespace std; using namespace vcg; typedef vcg::SimpleVoxel SimpleVoxelm; // initialize importing parameters -void PDBIOPlugin::initPreOpenParameter(const QString &formatName, RichParameterList &parlst) +RichParameterList PDBIOPlugin::initPreOpenParameter(const QString &formatName) const { + RichParameterList parlst; if (formatName.toUpper() == tr("PDB")) { parlst.addParam(RichBool("usecolors",true,"Use Atoms colors","Atoms are colored according to atomic type")); @@ -62,6 +63,7 @@ void PDBIOPlugin::initPreOpenParameter(const QString &formatName, RichParameterL parlst.addParam(RichBool("flipfaces",false,"Flip all faces","Flip the orientation of all the triangles"); */ } + return parlst; } void PDBIOPlugin::open(const QString &formatName, const QString &fileName, MeshModel &m, int& mask, const RichParameterList &parlst, CallBackPos *cb) @@ -81,7 +83,7 @@ void PDBIOPlugin::open(const QString &formatName, const QString &fileName, MeshM { mask |= vcg::tri::io::Mask::IOM_VERTCOLOR; - m.Enable(mask); + m.enable(mask); if (!parsePDB(qUtf8Printable(fileName), m.cm, parlst, cb)) throw MLException("Error while opening PDB file"); @@ -126,33 +128,6 @@ std::list PDBIOPlugin::exportFormats() const */ void PDBIOPlugin::exportMaskCapability(const QString & /*format*/, int &capability, int &defaultBits) const { - capability=defaultBits=0; - return; -} - -void PDBIOPlugin::initOpenParameter(const QString & /*format*/, MeshModel &/*m*/, RichParameterList & /*par*/) -{ - /* - if(format.toUpper() == tr("STL")) - par.addBool("Unify",true, "Unify Duplicated Vertices", - "The STL format is not an vertex-indexed format. Each triangle is composed by independent vertices, so, usually, duplicated vertices should be unified"); - */ -} -void PDBIOPlugin::initSaveParameter(const QString & /*format*/, const MeshModel &/*m*/, RichParameterList & /*par*/) -{ - /* - if(format.toUpper() == tr("STL") || format.toUpper() == tr("PLY")) - par.addBool("Binary",true, "Binary encoding", - "Save the mesh using a binary encoding. If false the mesh is saved in a plain, readable ascii format"); - */ -} -void PDBIOPlugin::applyOpenParameter(const QString & /*format*/, MeshModel & /*m*/, const RichParameterList & /*par*/) -{ - /* - if(format.toUpper() == tr("STL")) - if(par.getBool("Unify")) - tri::Clean::RemoveDuplicateVertex(m.cm); - */ } MESHLAB_PLUGIN_NAME_EXPORTER(PDBIOPlugin) diff --git a/src/meshlabplugins/io_pdb/io_pdb.h b/src/meshlabplugins/io_pdb/io_pdb.h index 6ac72c43b..da4da436c 100644 --- a/src/meshlabplugins/io_pdb/io_pdb.h +++ b/src/meshlabplugins/io_pdb/io_pdb.h @@ -44,11 +44,7 @@ public: void open(const QString &formatName, const QString &fileName, MeshModel &m, int& mask,const RichParameterList & par, vcg::CallBackPos *cb=0); void save(const QString &formatName, const QString &fileName, MeshModel &m, const int mask, const RichParameterList & par, vcg::CallBackPos *cb=0); - virtual void initOpenParameter(const QString &format, MeshModel &/*m*/, RichParameterList & par); - virtual void applyOpenParameter(const QString &format, MeshModel &m, const RichParameterList &par); - void initPreOpenParameter(const QString &formatName, RichParameterList &parlst); - - virtual void initSaveParameter(const QString &format, const MeshModel &/*m*/, RichParameterList & par); + RichParameterList initPreOpenParameter(const QString &formatName) const; //---------- PDB READER -----------// bool parsePDB(const std::string &filename, CMeshO &m, const RichParameterList &parlst, vcg::CallBackPos *cb=0); diff --git a/src/meshlabplugins/io_tri/io_tri.cpp b/src/meshlabplugins/io_tri/io_tri.cpp index 091ff9787..0fa7d3fe3 100755 --- a/src/meshlabplugins/io_tri/io_tri.cpp +++ b/src/meshlabplugins/io_tri/io_tri.cpp @@ -35,13 +35,15 @@ using namespace vcg; bool parseTRI(const std::string &filename, CMeshO &m); -void TriIOPlugin::initPreOpenParameter(const QString &format, RichParameterList & parlst) +RichParameterList TriIOPlugin::initPreOpenParameter(const QString &format) const { + RichParameterList parlst; if(format.toUpper() == tr("ASC")) { parlst.addParam(RichInt("rowToSkip",0,"Header Row to be skipped","The number of lines that must be skipped at the beginning of the file.")); parlst.addParam(RichBool("triangulate", true, "Grid triangulation", "if true it assumes that the points are arranged in a complete xy grid and it tries to perform a naive height field triangulation of the input data. Length of the lines is detected automatically by searching x jumps. If the input point cloud data is not arranged as a xy regular height field, no triangles are created.")); } + return parlst; } void TriIOPlugin::open(const QString &formatName, const QString &fileName, MeshModel &m, int& mask, const RichParameterList &parlst, CallBackPos *cb) @@ -49,14 +51,14 @@ void TriIOPlugin::open(const QString &formatName, const QString &fileName, MeshM if(formatName.toUpper() == tr("TRI")) { mask |= vcg::tri::io::Mask::IOM_WEDGTEXCOORD; - m.Enable(mask); + m.enable(mask); if (!parseTRI(qUtf8Printable(fileName), m.cm)) throw MLException("Error while opening TRI file"); } else if(formatName.toUpper() == tr("ASC")) { mask |= vcg::tri::io::Mask::IOM_VERTQUALITY; - m.Enable(mask); + m.enable(mask); bool triangulate = parlst.getBool("triangulate"); int rowToSkip = parlst.getInt("rowToSkip"); int result = tri::io::ImporterASC::Open(m.cm, qUtf8Printable(fileName),cb,triangulate,rowToSkip); diff --git a/src/meshlabplugins/io_tri/io_tri.h b/src/meshlabplugins/io_tri/io_tri.h index 3944ef230..091ee95de 100755 --- a/src/meshlabplugins/io_tri/io_tri.h +++ b/src/meshlabplugins/io_tri/io_tri.h @@ -46,7 +46,7 @@ public: std::list importFormats() const; std::list exportFormats() const; virtual void exportMaskCapability(const QString &format, int &capability, int &defaultBits) const; - virtual void initPreOpenParameter(const QString &/*format*/, RichParameterList & /*par*/); + virtual RichParameterList initPreOpenParameter(const QString &/*format*/) const; void open(const QString &formatName, const QString &fileName, MeshModel &m, int& mask, const RichParameterList &, vcg::CallBackPos *cb=0); void save(const QString &formatName, const QString &fileName, MeshModel &m, const int mask, const RichParameterList &, vcg::CallBackPos *cb); diff --git a/src/meshlabplugins/io_txt/io_txt.cpp b/src/meshlabplugins/io_txt/io_txt.cpp index e627bd145..44a7d6070 100755 --- a/src/meshlabplugins/io_txt/io_txt.cpp +++ b/src/meshlabplugins/io_txt/io_txt.cpp @@ -30,8 +30,9 @@ using namespace vcg; bool parseTXT(QString filename, CMeshO &m, int rowToSkip, int dataSeparator, int dataFormat, int rgbMode, int onError); -void TxtIOPlugin::initPreOpenParameter(const QString &format, RichParameterList & parlst) +RichParameterList TxtIOPlugin::initPreOpenParameter(const QString &format) const { + RichParameterList parlst; if(format.toUpper() == tr("TXT")) { QStringList separator = (QStringList() << ";" << "," << "SPACE"); @@ -57,6 +58,7 @@ void TxtIOPlugin::initPreOpenParameter(const QString &format, RichParameterList parlst.addParam(RichEnum("rgbmode", 0, rgbmode,"Color format","Colors may be specified in the [0-255] or [0.0-1.0] interval.")); parlst.addParam(RichEnum("onerror", 0, onerror, "On Parsing Error", "When a line is not properly parsed, it is possible to 'skip' it and continue with the following lines, or 'stop' importing at that point")); } + return parlst; } void TxtIOPlugin::open(const QString &formatName, const QString &fileName, MeshModel &m, int& mask, const RichParameterList &parlst, CallBackPos * /*cb*/) @@ -75,7 +77,7 @@ void TxtIOPlugin::open(const QString &formatName, const QString &fileName, MeshM if((dataFormat==3) || (dataFormat==4) || (dataFormat==5) || (dataFormat>=8)) mask |= vcg::tri::io::Mask::IOM_VERTNORMAL; - m.Enable(mask); + m.enable(mask); if (!parseTXT(fileName, m.cm, rowToSkip, dataSeparator, dataFormat, rgbMode, onError)) throw MLException("Error while opening TXT file."); diff --git a/src/meshlabplugins/io_txt/io_txt.h b/src/meshlabplugins/io_txt/io_txt.h index 63e2b1b83..82a97a755 100755 --- a/src/meshlabplugins/io_txt/io_txt.h +++ b/src/meshlabplugins/io_txt/io_txt.h @@ -39,8 +39,8 @@ public: QString pluginName() const; std::list importFormats() const; std::list exportFormats() const; - virtual void exportMaskCapability(const QString &format, int &capability, int &defaultBits) const; - virtual void initPreOpenParameter(const QString &/*format*/, RichParameterList & /*par*/); + void exportMaskCapability(const QString &format, int &capability, int &defaultBits) const; + RichParameterList initPreOpenParameter(const QString &/*format*/) const; void open(const QString &formatName, const QString &fileName, MeshModel &m, int& mask, const RichParameterList &, vcg::CallBackPos *cb=0); void save(const QString &formatName, const QString &fileName, MeshModel &m, const int mask, const RichParameterList &, vcg::CallBackPos *cb); diff --git a/src/meshlabplugins/io_u3d/CMakeLists.txt b/src/meshlabplugins/io_u3d/CMakeLists.txt index 15a113fe6..637de4a3e 100644 --- a/src/meshlabplugins/io_u3d/CMakeLists.txt +++ b/src/meshlabplugins/io_u3d/CMakeLists.txt @@ -8,7 +8,6 @@ if(TARGET external-IDTFConverter) set(SOURCES io_u3d.cpp) set(HEADERS io_u3d.h) - include_directories("${EXTERNAL_DIR}/u3d/src/IDTF") add_meshlab_plugin(io_u3d ${SOURCES} ${HEADERS}) diff --git a/src/meshlabplugins/io_u3d/io_u3d.cpp b/src/meshlabplugins/io_u3d/io_u3d.cpp index 20b7b557d..d9b70b695 100644 --- a/src/meshlabplugins/io_u3d/io_u3d.cpp +++ b/src/meshlabplugins/io_u3d/io_u3d.cpp @@ -40,7 +40,7 @@ using namespace vcg; U3DIOPlugin::U3DIOPlugin() : - QObject(), IOPlugin(), _param() + QObject(), IOPlugin() { } @@ -76,13 +76,16 @@ void U3DIOPlugin::save( vcg::tri::io::ExporterIDTF::convertInTGATextures( m.cm, QDir::tempPath(), textures_to_be_restored); if(formatName.toUpper() == tr("U3D")) { - saveParameters(par); + vcg::tri::io::u3dparametersclasses::Movie15Parameters _param; + _param._campar = + new vcg::tri::io::u3dparametersclasses::Movie15Parameters::CameraParameters( + m.cm.bbox.Center(),m.cm.bbox.Diag()); + saveParameters(par, _param); QSettings settings; //tmp idtf QString tmp(QDir::tempPath()); QString curr = QDir::currentPath(); - QString out(fileName); QStringList out_trim; vcg::tri::io::QtUtilityFunctions::splitFilePath(fileName,out_trim); tmp = tmp + "/" + @@ -109,6 +112,7 @@ void U3DIOPlugin::save( vcg::tri::io::ExporterIDTF::restoreConvertedTextures( m.cm, textures_to_be_restored); + delete _param._campar; } else if(formatName.toUpper() == tr("IDTF")) { tri::io::ExporterIDTF::Save(m.cm,filename.c_str(),mask); @@ -176,9 +180,11 @@ void U3DIOPlugin::exportMaskCapability( assert(0); } -void U3DIOPlugin::initSaveParameter(const QString &, const MeshModel &m, RichParameterList &par) +RichParameterList U3DIOPlugin::initSaveParameter(const QString &, const MeshModel &m) const { - _param._campar = + RichParameterList par; + vcg::tri::io::u3dparametersclasses::Movie15Parameters _param; + _param._campar = new vcg::tri::io::u3dparametersclasses::Movie15Parameters::CameraParameters( m.cm.bbox.Center(),m.cm.bbox.Diag()); Point3m pos = _param._campar->_obj_pos; @@ -191,9 +197,11 @@ void U3DIOPlugin::initSaveParameter(const QString &, const MeshModel &m, RichPar "Camera's FOV Angle 0..180","Camera's FOV Angle. The values' range is between 0-180 degree. The default value is 60.")); par.addParam(RichInt("compression_val",500,"U3D quality 0..1000", "U3D mesh's compression ratio. The values' range is between 0-1000 degree. The default value is 500.")); + delete _param._campar; + return par; } -void U3DIOPlugin::saveParameters(const RichParameterList &par) +void U3DIOPlugin::saveParameters(const RichParameterList &par, vcg::tri::io::u3dparametersclasses::Movie15Parameters& _param) { Point3m from_target_to_camera = Point3m(par.getPoint3m(QString("position_val")) - par.getPoint3m(QString("target_val"))); diff --git a/src/meshlabplugins/io_u3d/io_u3d.h b/src/meshlabplugins/io_u3d/io_u3d.h index 08dc8b14d..881633933 100644 --- a/src/meshlabplugins/io_u3d/io_u3d.h +++ b/src/meshlabplugins/io_u3d/io_u3d.h @@ -51,15 +51,13 @@ public: void open(const QString &formatName, const QString &fileName, MeshModel &m, int& mask, const RichParameterList &, vcg::CallBackPos *cb=0); void save(const QString &formatName, const QString &fileName, MeshModel &m, const int mask, const RichParameterList &, vcg::CallBackPos *cb=0); - void initSaveParameter(const QString &format, const MeshModel &/*m*/, RichParameterList &par); + RichParameterList initSaveParameter(const QString &format, const MeshModel &/*m*/) const; private: - void saveParameters(const RichParameterList &par); + void saveParameters(const RichParameterList &par, vcg::tri::io::u3dparametersclasses::Movie15Parameters& _param); void saveLatex(const QString& file,const vcg::tri::io::u3dparametersclasses::Movie15Parameters& mov_par); void substituteChar(QString& st, const QChar& ch_remove, const QString& sub); - - vcg::tri::io::u3dparametersclasses::Movie15Parameters _param; }; #endif diff --git a/src/meshlabplugins/io_x3d/io_x3d.cpp b/src/meshlabplugins/io_x3d/io_x3d.cpp index eb54836d2..3210b582b 100644 --- a/src/meshlabplugins/io_x3d/io_x3d.cpp +++ b/src/meshlabplugins/io_x3d/io_x3d.cpp @@ -63,7 +63,7 @@ void IoX3DPlugin::open(const QString &formatName, const QString &fileName, MeshM info->mask &=(~vcg::tri::io::Mask::IOM_WEDGCOLOR); if (info->mask & vcg::tri::io::Mask::IOM_WEDGNORMAL) info->mask &=(~vcg::tri::io::Mask::IOM_WEDGNORMAL); - m.Enable(info->mask); + m.enable(info->mask); errorMsgFormat = "Error encountered while loading file:\n\"%1\"\n\nFile: %2\nLine number: %3\nError details: %4"; result = vcg::tri::io::ImporterX3D::Open(m.cm, filename.c_str(), info, cb); diff --git a/src/meshlabplugins/render_gdp/meshrender.cpp b/src/meshlabplugins/render_gdp/meshrender.cpp index 2823f7f3a..ada74d27d 100644 --- a/src/meshlabplugins/render_gdp/meshrender.cpp +++ b/src/meshlabplugins/render_gdp/meshrender.cpp @@ -486,7 +486,7 @@ void MeshShaderRenderPlugin::render(QAction *a, MeshDocument &md, MLSceneGLShare if ((gla != NULL) && (gla->mvc() != NULL)) { MLSceneGLSharedDataContext* shared = gla->mvc()->sharedDataContext(); - for(MeshModel * mp : md.meshList) + for(MeshModel * mp : md.meshIterator()) { if ((mp != NULL) && (gla->meshVisibilityMap[mp->id()])) shared->draw(mp->id(),gla->context()); diff --git a/src/meshlabplugins/render_radiance_scaling/radianceScalingRenderer.cpp b/src/meshlabplugins/render_radiance_scaling/radianceScalingRenderer.cpp index 12fb85257..78b64ab28 100644 --- a/src/meshlabplugins/render_radiance_scaling/radianceScalingRenderer.cpp +++ b/src/meshlabplugins/render_radiance_scaling/radianceScalingRenderer.cpp @@ -122,7 +122,7 @@ void RadianceScalingRendererPlugin::render(QAction *, MeshDocument &md, MLSceneG vcg::glColor(vcg::Color4b(vcg::Color4b::LightGray)); _buffPass->enable(); - foreach(MeshModel *mp, md.meshList) + for(MeshModel *mp: md.meshIterator()) { if ((mp != NULL) && (gla->meshVisibilityMap[mp->id()])) { diff --git a/src/vcglib b/src/vcglib index 0882d6258..85d666543 160000 --- a/src/vcglib +++ b/src/vcglib @@ -1 +1 @@ -Subproject commit 0882d6258252174ee6635b3d1d337bdedad97ab8 +Subproject commit 85d66654308a4ab80068cad36a41cfe080728ad6 diff --git a/src/meshlabserver/CMakeLists.txt b/unsupported/meshlabserver/CMakeLists.txt similarity index 100% rename from src/meshlabserver/CMakeLists.txt rename to unsupported/meshlabserver/CMakeLists.txt diff --git a/src/meshlabserver/README.md b/unsupported/meshlabserver/README.md similarity index 100% rename from src/meshlabserver/README.md rename to unsupported/meshlabserver/README.md diff --git a/src/meshlabserver/mainserver.cpp b/unsupported/meshlabserver/mainserver.cpp similarity index 98% rename from src/meshlabserver/mainserver.cpp rename to unsupported/meshlabserver/mainserver.cpp index ceaa0a715..7e07c90de 100644 --- a/src/meshlabserver/mainserver.cpp +++ b/unsupported/meshlabserver/mainserver.cpp @@ -27,8 +27,6 @@ #include #include #include -#include -#include #include #include #include @@ -213,7 +211,7 @@ public: vcg::tri::UpdateNormal::PerFace(mm.cm); vcg::tri::UpdateBounding::Box(mm.cm); // updates bounding box } - else mm.UpdateBoxAndNormals(); // the very standard case + else mm.updateBoxAndNormals(); // the very standard case } if(mm.cm.fn==0) @@ -402,11 +400,11 @@ public: bool ret = false; if (!mm->isVisible()) { - mm->Clear(); + mm->clear(); mm->visible = false; } else - mm->Clear(); + mm->clear(); QFileInfo fi(fullPath); QString extension = fi.suffix(); IOPlugin *pCurrentIOPlugin = PM.inputMeshPlugin(extension); @@ -418,14 +416,7 @@ public: //prePar = prePar.join(currentGlobalParams); int mask = 0; QElapsedTimer t;t.start(); - bool open = loadMesh(fullPath,pCurrentIOPlugin,mm,mask,&prePar,mtr, md, stdout); - if(open) - { - RichParameterList par; - pCurrentIOPlugin->initOpenParameter(extension, *mm, par); - pCurrentIOPlugin->applyOpenParameter(extension,*mm,par); - ret = true; - } + ret = loadMesh(fullPath,pCurrentIOPlugin,mm,mask,&prePar,mtr, md, stdout); } return ret; } @@ -624,8 +615,7 @@ public: //A filter in the script file couldn't have all the required parameter not defined (a script file not generated by MeshLab). //So we have to ask to the filter the default values for all the parameters and integrate them with the parameters' values //defined in the script file. - RichParameterList required; - iFilter->initParameterList(action,meshDocument,required); + RichParameterList required = iFilter->initParameterList(action,meshDocument); RichParameterList ¶meterSet = pair.second; //The parameters in the script file are more than the required parameters of the filter. The script file is not correct. @@ -645,11 +635,8 @@ public: //if this is a mesh parameter and the index is valid if(parameter.value().isMesh()) { RichMesh& md = reinterpret_cast(parameter); - if(md.meshindex < meshDocument.size() && md.meshindex >= 0) { - parameterSet.setValue(md.name(), MeshValue(&meshDocument, md.meshindex)); - } - else { - fprintf(fp,"Meshes loaded: %i, meshes asked for: %i \n", meshDocument.size(), md.meshindex ); + if(!(md.value().getMeshId() < (unsigned int) meshDocument.size())) { + fprintf(fp,"Meshes loaded: %i, meshes asked for: %i \n", meshDocument.size(), md.value().getMeshId() ); fprintf(fp,"One of the filters in the script needs more meshes than you have loaded.\n"); exit(-1); } diff --git a/src/meshlabserver/meshlabserver.pro b/unsupported/meshlabserver/meshlabserver.pro similarity index 100% rename from src/meshlabserver/meshlabserver.pro rename to unsupported/meshlabserver/meshlabserver.pro diff --git a/src/meshlabserver/meshlabserver.qrc b/unsupported/meshlabserver/meshlabserver.qrc similarity index 100% rename from src/meshlabserver/meshlabserver.qrc rename to unsupported/meshlabserver/meshlabserver.qrc diff --git a/src/meshlabserver/meshlabserver.txt b/unsupported/meshlabserver/meshlabserver.txt similarity index 100% rename from src/meshlabserver/meshlabserver.txt rename to unsupported/meshlabserver/meshlabserver.txt diff --git a/src/meshlabplugins/filter_csg/CMakeLists.txt b/unsupported/plugins_unsupported/filter_csg/CMakeLists.txt similarity index 100% rename from src/meshlabplugins/filter_csg/CMakeLists.txt rename to unsupported/plugins_unsupported/filter_csg/CMakeLists.txt diff --git a/src/meshlabplugins/filter_csg/filter_csg.cpp b/unsupported/plugins_unsupported/filter_csg/filter_csg.cpp similarity index 95% rename from src/meshlabplugins/filter_csg/filter_csg.cpp rename to unsupported/plugins_unsupported/filter_csg/filter_csg.cpp index bdc0f91cc..05f15665a 100644 --- a/src/meshlabplugins/filter_csg/filter_csg.cpp +++ b/unsupported/plugins_unsupported/filter_csg/filter_csg.cpp @@ -74,12 +74,13 @@ QString FilterCSG::filterInfo(ActionIDType filterId) const } } -void FilterCSG::initParameterList(const QAction *action, MeshDocument & md, RichParameterList & parlst) +RichParameterList FilterCSG::initParameterList(const QAction *action, const MeshDocument & md) { + RichParameterList parlst; switch (ID(action)) { case FP_CSG: { - MeshModel *target = md.mm(); + const MeshModel *target = md.mm(); foreach (target, md.meshList) if (target != md.mm()) break; @@ -87,9 +88,9 @@ void FilterCSG::initParameterList(const QAction *action, MeshDocument & md, Rich CMeshO::ScalarType mindim = min(md.mm()->cm.bbox.Dim().V(md.mm()->cm.bbox.MinDim()), target->cm.bbox.Dim().V(target->cm.bbox.MinDim())); - parlst.addParam(RichMesh("FirstMesh", md.mm(), &md, "First Mesh", + parlst.addParam(RichMesh("FirstMesh", md.mm()->id(), &md, "First Mesh", "The first operand of the CSG operation")); - parlst.addParam(RichMesh("SecondMesh", target, &md, "Second Mesh", + parlst.addParam(RichMesh("SecondMesh", target->id(), &md, "Second Mesh", "The second operand of the CSG operation")); parlst.addParam(RichAbsPerc("Delta", mindim / 100.0, 0, mindim, "Spacing between sampling lines", @@ -114,6 +115,7 @@ void FilterCSG::initParameterList(const QAction *action, MeshDocument & md, Rich default: assert(0); } + return parlst; } std::map FilterCSG::applyFilter(const QAction *filter, const RichParameterList & par, MeshDocument &md, unsigned int& /*postConditionMask*/, vcg::CallBackPos *cb) @@ -121,8 +123,8 @@ std::map FilterCSG::applyFilter(const QAction *filter, co switch(ID(filter)) { case FP_CSG: { - MeshModel *firstMesh = par.getMesh("FirstMesh"); - MeshModel *secondMesh = par.getMesh("SecondMesh"); + MeshModel *firstMesh = md.getMesh(par.getMeshId("FirstMesh")); + MeshModel *secondMesh = md.getMesh(par.getMeshId("SecondMesh")); if ((firstMesh == NULL) || (secondMesh == NULL)) { log("CSG filter: cannot compute, mesh does not exist"); diff --git a/src/meshlabplugins/filter_csg/filter_csg.h b/unsupported/plugins_unsupported/filter_csg/filter_csg.h similarity index 84% rename from src/meshlabplugins/filter_csg/filter_csg.h rename to unsupported/plugins_unsupported/filter_csg/filter_csg.h index a47918976..536ec2545 100644 --- a/src/meshlabplugins/filter_csg/filter_csg.h +++ b/unsupported/plugins_unsupported/filter_csg/filter_csg.h @@ -53,16 +53,16 @@ public: ~FilterCSG() {}; QString pluginName() const; - virtual QString filterName(ActionIDType filter) const; - virtual QString filterInfo(ActionIDType filter) const; + QString filterName(ActionIDType filter) const; + QString filterInfo(ActionIDType filter) const; - virtual bool autoDialog(QAction *) { return true; } + bool autoDialog(QAction *) { return true; } - virtual void initParameterList(const QAction*, MeshDocument &, RichParameterList &); + RichParameterList initParameterList(const QAction*, const MeshDocument &); std::map applyFilter(const QAction* action, const RichParameterList & /*parent*/, MeshDocument &md, unsigned int& postConditionMask, vcg::CallBackPos * cb); - virtual FilterClass getClass(const QAction *) const { return FilterPlugin::FilterClass( FilterPlugin::Layer + FilterPlugin::Remeshing ); } + FilterClass getClass(const QAction *) const { return FilterPlugin::FilterClass( FilterPlugin::Layer + FilterPlugin::Remeshing ); } FilterArity filterArity(const QAction*) const {return FIXED;} }; diff --git a/src/meshlabplugins/filter_csg/filter_csg.pro b/unsupported/plugins_unsupported/filter_csg/filter_csg.pro similarity index 100% rename from src/meshlabplugins/filter_csg/filter_csg.pro rename to unsupported/plugins_unsupported/filter_csg/filter_csg.pro diff --git a/src/meshlabplugins/filter_csg/gmpfrac.h b/unsupported/plugins_unsupported/filter_csg/gmpfrac.h similarity index 100% rename from src/meshlabplugins/filter_csg/gmpfrac.h rename to unsupported/plugins_unsupported/filter_csg/gmpfrac.h diff --git a/src/meshlabplugins/filter_csg/intercept.h b/unsupported/plugins_unsupported/filter_csg/intercept.h similarity index 100% rename from src/meshlabplugins/filter_csg/intercept.h rename to unsupported/plugins_unsupported/filter_csg/intercept.h